diff --git a/lib/exw3.ex b/lib/exw3.ex index 6bbe97c..9a19178 100644 --- a/lib/exw3.ex +++ b/lib/exw3.ex @@ -462,4 +462,74 @@ defmodule ExW3 do {:reply, {:ok, {receipt, formatted_logs}}, state} end end + + defmodule Poller do + use GenServer + + def start_link do + GenServer.start_link(__MODULE__, [], name: EventPoller) + end + + def subscribe(event) do + GenServer.cast(EventPoller, {:subscribe, event}) + end + + @impl true + def init(state) do + schedule_work() # Schedule work to be performed on start + {:ok, state} + end + + @impl true + def handle_cast({:subscribe, event}, state) do + {:noreply, [event | state]} + end + + @impl true + def handle_info(:work, state) do + # Do the desired work here + Enum.each state, fn event -> + send EventListener, {:event, event, "Hello, World"} + end + + schedule_work() # Reschedule once more + {:noreply, state} + end + + defp schedule_work() do + Process.send_after(self(), :work, 1000) # In 1 sec + end + end + + defmodule Listener do + def start_link do + Poller.start_link() + {:ok, pid} = Task.start_link(fn -> loop(%{}) end) + Process.register(pid, EventListener) + :ok + end + + def subscribe(event, pid) do + Poller.subscribe(event) + send EventListener, {:subscribe, event, pid} + end + + def listen(callback) do + receive do + {:event, result} -> apply callback, [result] + end + listen(callback) + end + + defp loop(map) do + receive do + {:subscribe, event, pid} -> + loop(Map.put(map, event, pid)) + {:event, event, data} -> + send Map.get(map, event), {:event, {event, data}} + loop(map) + end + end + end + end diff --git a/test/exw3_test.exs b/test/exw3_test.exs index 8cf1ced..ac101d6 100644 --- a/test/exw3_test.exs +++ b/test/exw3_test.exs @@ -133,6 +133,39 @@ defmodule EXW3Test do assert data == "Hello, World!" end + test "starts a Contract GenServer and uses the event listener", context do + ExW3.Contract.start_link(EventTester, abi: context[:event_tester_abi]) + + {:ok, address} = + ExW3.Contract.deploy( + EventTester, + bin: ExW3.load_bin("test/examples/build/EventTester.bin"), + options: %{ + gas: 300_000, + from: Enum.at(context[:accounts], 0) + } + ) + + ExW3.Contract.at(EventTester, address) + + {:ok, tx_hash} = + ExW3.Contract.send( + EventTester, + :simple, + ["Hello, World!"], + %{from: Enum.at(context[:accounts], 0)} + ) + + ExW3.Listener.start_link() + + ExW3.Listener.subscribe("Hello", self()) + + receive do + {:event, {"Frank", data}} -> IO.inspect data + after 3_000 -> raise "Never received event" + end + end + test "starts a Contract GenServer for Complex contract", context do ExW3.Contract.start_link(Complex, abi: context[:complex_abi]) @@ -217,4 +250,3 @@ defmodule EXW3Test do assert ExW3.is_valid_checksum_address("0x2f015c60e0be116b1f0cd534704db9c92118fb6a") == false end end -