Packages
Chatter is extracted from the ScaleSmall project as a standalone piece. This may be used independently to broadcast messages to a set of nodes. It uses a mixture of UDP multicast and TCP to deliver messages and tries to minimize network traffic while doing so.
Current section
Files
Jump to
Current section
Files
lib/outgoing_supervisor.ex
defmodule Chatter.OutgoingSupervisor do
use Supervisor
require Chatter.Gossip
require Chatter.NetID
require Chatter.BroadcastID
alias Chatter.OutgoingHandler
alias Chatter.Gossip
alias Chatter.NetID
alias Chatter.BroadcastID
alias Chatter.Planner
def start_link(args, opts \\ []) do
case opts do
[name: _name] ->
Supervisor.start_link(__MODULE__, args, opts)
_ ->
Supervisor.start_link(__MODULE__, args, [name: __MODULE__] ++ opts)
end
end
def init(_args) do
children = [ supervisor(OutgoingHandler, [], restart: :temporary) ]
supervise(children, strategy: :simple_one_for_one)
end
def broadcast(gossip, key)
when Gossip.is_valid(gossip) and
is_binary(key) and
byte_size(key) == 32
do
Planner.plan(Gossip.distribution_list(gossip))
|> Enum.each( fn(p) ->
List.flatten(p)
|> Enum.shuffle
|> broadcast_to(gossip, key)
end)
end
defp broadcast_to([], _gossip, _key), do: :ok
defp broadcast_to(distribution_list, gossip, key)
do
[head|rest] = distribution_list
own_id = Gossip.current_id(gossip) |> BroadcastID.origin
case start_handler(locate!, [own_id: own_id, peer_id: head, key: key]) do
{:ok, handler_pid} ->
OutgoingHandler.send(handler_pid, gossip |> Gossip.distribution_list(rest))
_ ->
# use the next id in case of an error
broadcast_to(rest, gossip, key)
end
end
def start_handler(sup_pid, [own_id: own_id, peer_id: peer_id, key: key])
when is_pid(sup_pid) and
NetID.is_valid(peer_id) and
NetID.is_valid(own_id)
do
case OutgoingHandler.locate(peer_id) do
handler_pid when is_pid(handler_pid) ->
{:ok, handler_pid}
_ ->
id = OutgoingHandler.id_atom(peer_id)
Supervisor.start_child(sup_pid, [
[own_id: own_id, peer_id: peer_id, key: key],
[name: id]])
end
end
def locate, do: Process.whereis(id_atom())
def locate! do
case Process.whereis(id_atom()) do
pid when is_pid(pid) ->
pid
end
end
def id_atom, do: __MODULE__
end