85 lines
2.5 KiB
Elixir
85 lines
2.5 KiB
Elixir
defmodule Floof do
|
|
@moduledoc """
|
|
Documentation for `Floof`.
|
|
"""
|
|
|
|
require Logger
|
|
|
|
def accept(port) do
|
|
{:ok, socket} = :gen_tcp.listen(port, [
|
|
:binary,
|
|
packet: 4,
|
|
active: false,
|
|
reuseaddr: true
|
|
])
|
|
Logger.info("Accepting connections on #{port}")
|
|
loop_acceptor(socket)
|
|
end
|
|
|
|
defp loop_acceptor(socket) do
|
|
{:ok, client} = :gen_tcp.accept(socket)
|
|
{:ok, pid} = Task.Supervisor.start_child(
|
|
Floof.TaskSupervisor, fn -> serve(client, []) end)
|
|
:ok = :gen_tcp.controlling_process(client, pid)
|
|
# switch to active now that we handed over the client
|
|
:inet.setopts(client, [{:active, true}])
|
|
send(Floof.Distributor, {:register, pid})
|
|
loop_acceptor(socket)
|
|
end
|
|
|
|
defp serve(client, backlog) do
|
|
receive do
|
|
{:tcp, _, message} ->
|
|
{:ok, dcd} = :FloofProtocol.decode(:ProtoMessage, message)
|
|
backlog2 = handle_incoming(client, backlog, dcd)
|
|
serve(client, backlog2)
|
|
{:fwdxfer, dcdmessage} ->
|
|
dcdid = get_xfer_id dcdmessage
|
|
handle_outgoing(client, dcdid)
|
|
serve(client, [{dcdid, dcdmessage} | backlog])
|
|
{:havewe, id, res} ->
|
|
dat = {:Summary, if res do :rejectpush else :pull end, id}
|
|
{:ok, encd} = :FloofProtocol.encode(:ProtoMessage, {:summary, dat})
|
|
:ok = client.send(encd)
|
|
serve(client, backlog)
|
|
x -> Logger.warn("unable to handle request: #{inspect(x)}")
|
|
serve(client, backlog)
|
|
end
|
|
end
|
|
|
|
defp handle_incoming(client, backlog, dcd) do
|
|
Logger.debug("got packet #{inspect(dcd)}")
|
|
case dcd do
|
|
{:summary, {:Summary, direction, id}} ->
|
|
case direction do
|
|
:requestpull ->
|
|
send(Floof.Distributor, {:havewe, self(), id})
|
|
backlog
|
|
:pull ->
|
|
case List.keytake(backlog, id, 0) do
|
|
{{_, item}, backlog2} ->
|
|
{:ok, encd} = :FloofProtocol.encode(:ProtoMessage, {:xfer, item})
|
|
:ok = client.send(encd)
|
|
backlog2
|
|
nil -> backlog
|
|
end
|
|
:rejectpush ->
|
|
List.keydelete(backlog, id, 0)
|
|
end
|
|
{:xfer, xf} ->
|
|
send(Floof.Distributor, xf)
|
|
backlog
|
|
end
|
|
end
|
|
|
|
defp handle_outgoing(client, dcdid) do
|
|
dat = {:Summary, :requestpull, dcdid}
|
|
{:ok, encd} = :FloofProtocol.encode(:ProtoMessage, {:summary, dat})
|
|
:ok = client.send(encd)
|
|
end
|
|
|
|
def get_xfer_id({:XferBlob, _, _, _, _, {:XferInner, id, _, _, _, _, _}}) do
|
|
id
|
|
end
|
|
end
|