Add basic forwarding/multiplexing functionality
This commit is contained in:
79
lib/peer.ex
Normal file
79
lib/peer.ex
Normal file
@@ -0,0 +1,79 @@
|
||||
defmodule Frajtano.Peer do
|
||||
alias Frajtano.Proto
|
||||
require Logger
|
||||
use GenServer, restart: :temporary
|
||||
|
||||
def start(path) do
|
||||
DynamicSupervisor.start_child(Frajtano.Peer, {__MODULE__, path})
|
||||
end
|
||||
|
||||
def start_link(path) do
|
||||
GenServer.start_link(__MODULE__, path)
|
||||
end
|
||||
|
||||
@impl true
|
||||
def init(path) do
|
||||
{:ok, conn} = :gen_tcp.connect({:local, path}, 0, [:binary, active: :once])
|
||||
{:ok, %{conn: conn, clients: :queue.new(), buffer: <<>>}}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_call(packet, from, %{conn: conn, clients: clients} = state) do
|
||||
case :gen_tcp.send(conn, Proto.encode(packet)) do
|
||||
:ok ->
|
||||
{:noreply, %{state | clients: :queue.in(from, clients)}}
|
||||
|
||||
{:error, :closed} ->
|
||||
{:noreply, state, {:continue, :closed}}
|
||||
|
||||
{:error, e} ->
|
||||
raise(e)
|
||||
end
|
||||
end
|
||||
|
||||
defp handle_messages(%{clients: clients, buffer: buffer} = state) do
|
||||
case Proto.decode(buffer) do
|
||||
{nil, buffer} ->
|
||||
{:noreply, %{state | buffer: buffer}}
|
||||
|
||||
{msg, buffer} ->
|
||||
{{:value, client}, clients} = :queue.out(clients)
|
||||
GenServer.reply(client, {:ok, msg})
|
||||
handle_messages(%{state | clients: clients, buffer: buffer})
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_info({:tcp, conn, msg}, %{conn: conn, buffer: buffer} = state) do
|
||||
:inet.setopts(conn, active: :once)
|
||||
buffer = buffer <> msg
|
||||
|
||||
handle_messages(%{ state | buffer: buffer })
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_info({:tcp_closed, _}, state) do
|
||||
{:noreply, state, {:continue, :closed}}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_continue(:closed, %{clients: clients}) do
|
||||
clients
|
||||
|> :queue.to_list()
|
||||
|> Enum.each(&GenServer.reply(&1, {:error, :closed}))
|
||||
|
||||
{:stop, :closed, %{}}
|
||||
end
|
||||
|
||||
def identities(peer) do
|
||||
with {:ok, {:agent_identities_answer, identities}} <-
|
||||
GenServer.call(peer, {:agentc_request_identities, nil}),
|
||||
do: {:ok, identities}
|
||||
end
|
||||
|
||||
def sign(peer, request) do
|
||||
with {:ok, {:agent_sign_response, signature}} <-
|
||||
GenServer.call(peer, {:agentc_sign_request, request}),
|
||||
do: {:ok, signature}
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user