* Separate EventHandler according to broadcast_type event, so the frontend realtime does not need to ignore the catchup events.pull/1267/head
parent
8a926c1b05
commit
bf46d3ee51
@ -1,34 +0,0 @@ |
||||
defmodule BlockScoutWeb.EventHandler do |
||||
@moduledoc """ |
||||
Subscribing process for broadcast events from Chain context. |
||||
""" |
||||
|
||||
use GenServer |
||||
|
||||
alias BlockScoutWeb.Notifier |
||||
alias Explorer.Chain |
||||
|
||||
# Client |
||||
|
||||
def start_link(_) do |
||||
GenServer.start_link(__MODULE__, [], name: __MODULE__) |
||||
end |
||||
|
||||
# Server |
||||
|
||||
def init([]) do |
||||
Chain.subscribe_to_events(:addresses) |
||||
Chain.subscribe_to_events(:address_coin_balances) |
||||
Chain.subscribe_to_events(:blocks) |
||||
Chain.subscribe_to_events(:exchange_rate) |
||||
Chain.subscribe_to_events(:internal_transactions) |
||||
Chain.subscribe_to_events(:transactions) |
||||
Chain.subscribe_to_events(:token_transfers) |
||||
{:ok, []} |
||||
end |
||||
|
||||
def handle_info(event, state) do |
||||
Notifier.handle_event(event) |
||||
{:noreply, state} |
||||
end |
||||
end |
@ -0,0 +1,33 @@ |
||||
defmodule BlockScoutWeb.RealtimeEventHandler do |
||||
@moduledoc """ |
||||
Subscribing process for broadcast events from realtime. |
||||
""" |
||||
|
||||
use GenServer |
||||
|
||||
alias BlockScoutWeb.Notifier |
||||
alias Explorer.Chain.Events.Subscriber |
||||
|
||||
def start_link(_) do |
||||
GenServer.start_link(__MODULE__, [], name: __MODULE__) |
||||
end |
||||
|
||||
@impl true |
||||
def init([]) do |
||||
Subscriber.to(:addresses, :realtime) |
||||
Subscriber.to(:address_coin_balances, :realtime) |
||||
Subscriber.to(:blocks, :realtime) |
||||
Subscriber.to(:internal_transactions, :realtime) |
||||
Subscriber.to(:transactions, :realtime) |
||||
Subscriber.to(:token_transfers, :realtime) |
||||
# Does not come from the indexer |
||||
Subscriber.to(:exchange_rate) |
||||
{:ok, []} |
||||
end |
||||
|
||||
@impl true |
||||
def handle_info(event, state) do |
||||
Notifier.handle_event(event) |
||||
{:noreply, state} |
||||
end |
||||
end |
@ -0,0 +1,41 @@ |
||||
defmodule Explorer.Chain.Events.Publisher do |
||||
@moduledoc """ |
||||
Publishes events related to the Chain context. |
||||
""" |
||||
|
||||
@allowed_events ~w(addresses address_coin_balances blocks internal_transactions token_transfers transactions)a |
||||
|
||||
def broadcast(_data, false), do: :ok |
||||
|
||||
def broadcast(data, broadcast_type) do |
||||
for {event_type, event_data} <- data, event_type in @allowed_events do |
||||
send_data(event_type, broadcast_type, event_data) |
||||
end |
||||
end |
||||
|
||||
@spec broadcast(atom()) :: :ok |
||||
def broadcast(event_type) do |
||||
send_data(event_type) |
||||
end |
||||
|
||||
defp send_data(event_type) do |
||||
Registry.dispatch(Registry.ChainEvents, event_type, fn entries -> |
||||
for {pid, _registered_val} <- entries do |
||||
send(pid, {:chain_event, event_type}) |
||||
end |
||||
end) |
||||
end |
||||
|
||||
# The :catchup type of event is not being consumed right now. |
||||
# To avoid a large number of unread messages in the `mailbox` the dispatch of |
||||
# these type of events is disabled for now. |
||||
defp send_data(_event_type, :catchup, _event_data), do: :ok |
||||
|
||||
defp send_data(event_type, broadcast_type, event_data) do |
||||
Registry.dispatch(Registry.ChainEvents, {event_type, broadcast_type}, fn entries -> |
||||
for {pid, _registered_val} <- entries do |
||||
send(pid, {:chain_event, event_type, broadcast_type, event_data}) |
||||
end |
||||
end) |
||||
end |
||||
end |
@ -0,0 +1,48 @@ |
||||
defmodule Explorer.Chain.Events.Subscriber do |
||||
@moduledoc """ |
||||
Subscribes to events related to the Chain context. |
||||
""" |
||||
|
||||
@allowed_broadcast_events ~w(addresses address_coin_balances blocks internal_transactions token_transfers transactions)a |
||||
|
||||
@allowed_broadcast_types ~w(catchup realtime)a |
||||
|
||||
@allowed_events ~w(exchange_rate)a |
||||
|
||||
@type broadcast_type :: :realtime | :catchup |
||||
|
||||
@doc """ |
||||
Subscribes the caller process to a specified subset of chain-related events. |
||||
|
||||
## Handling An Event |
||||
|
||||
A subscribed process should handle an event message. The message is in the |
||||
format of a three-element tuple. |
||||
|
||||
* Element 0 - `:chain_event` |
||||
* Element 1 - event subscribed to |
||||
* Element 2 - event data in list form |
||||
|
||||
# A new block event in a GenServer |
||||
def handle_info({:chain_event, :blocks, blocks}, state) do |
||||
# Do something with the blocks |
||||
end |
||||
|
||||
## Example |
||||
|
||||
iex> Explorer.Chain.Events.Subscriber.to(:blocks, :realtime) |
||||
:ok |
||||
""" |
||||
@spec to(atom(), broadcast_type()) :: :ok |
||||
def to(event_type, broadcast_type) |
||||
when event_type in @allowed_broadcast_events and broadcast_type in @allowed_broadcast_types do |
||||
Registry.register(Registry.ChainEvents, {event_type, broadcast_type}, []) |
||||
:ok |
||||
end |
||||
|
||||
@spec to(atom()) :: :ok |
||||
def to(event_type) when event_type in @allowed_events do |
||||
Registry.register(Registry.ChainEvents, event_type, []) |
||||
:ok |
||||
end |
||||
end |
@ -0,0 +1,65 @@ |
||||
defmodule Explorer.Chain.Events.PublisherTest do |
||||
use ExUnit.Case, async: true |
||||
|
||||
doctest Explorer.Chain.Events.Publisher |
||||
|
||||
alias Explorer.Chain.Events.{Publisher, Subscriber} |
||||
|
||||
describe "broadcast/2" do |
||||
test "sends chain_event of realtime type" do |
||||
event_type = :blocks |
||||
broadcast_type = :realtime |
||||
event_data = [] |
||||
|
||||
Subscriber.to(event_type, broadcast_type) |
||||
|
||||
Publisher.broadcast([{event_type, event_data}], broadcast_type) |
||||
|
||||
assert_received {:chain_event, ^event_type, ^broadcast_type, []} |
||||
end |
||||
|
||||
test "won't send chain_event of catchup type" do |
||||
event_type = :blocks |
||||
broadcast_type = :catchup |
||||
event_data = [] |
||||
|
||||
Subscriber.to(event_type, broadcast_type) |
||||
|
||||
Publisher.broadcast([{event_type, event_data}], broadcast_type) |
||||
|
||||
refute_received {:chain_event, ^event_type, ^broadcast_type, []} |
||||
end |
||||
|
||||
test "won't send event that is not allowed" do |
||||
event_type = :not_allowed |
||||
broadcast_type = :catchup |
||||
event_data = [] |
||||
|
||||
Publisher.broadcast([{event_type, event_data}], broadcast_type) |
||||
|
||||
refute_received {:chain_event, ^event_type, ^broadcast_type, []} |
||||
end |
||||
|
||||
test "won't send event of broadcast type not allowed" do |
||||
event_type = :blocks |
||||
broadcast_type = :something |
||||
event_data = [] |
||||
|
||||
Publisher.broadcast([{event_type, event_data}], broadcast_type) |
||||
|
||||
refute_received {:chain_event, ^event_type, ^broadcast_type, []} |
||||
end |
||||
end |
||||
|
||||
describe "broadcast/1" do |
||||
test "sends event whithout type of broadcast" do |
||||
event_type = :exchange_rate |
||||
|
||||
Subscriber.to(event_type) |
||||
|
||||
Publisher.broadcast(event_type) |
||||
|
||||
assert_received {:chain_event, ^event_type} |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,33 @@ |
||||
defmodule Explorer.Chain.Events.SubscriberTest do |
||||
use ExUnit.Case, async: true |
||||
|
||||
doctest Explorer.Chain.Events.Subscriber |
||||
|
||||
alias Explorer.Chain.Events.{Publisher, Subscriber} |
||||
|
||||
describe "to/2" do |
||||
test "receives event when there is a type of broadcast" do |
||||
event_type = :blocks |
||||
broadcast_type = :realtime |
||||
event_data = [] |
||||
|
||||
Subscriber.to(event_type, broadcast_type) |
||||
|
||||
Publisher.broadcast([{event_type, event_data}], broadcast_type) |
||||
|
||||
assert_received {:chain_event, :blocks, :realtime, []} |
||||
end |
||||
end |
||||
|
||||
describe "to/1" do |
||||
test "receives event when there is not a type of broadcast" do |
||||
event_type = :exchange_rate |
||||
|
||||
Subscriber.to(event_type) |
||||
|
||||
Publisher.broadcast(event_type) |
||||
|
||||
assert_received {:chain_event, :exchange_rate} |
||||
end |
||||
end |
||||
end |
Loading…
Reference in new issue