Floof.serve should be always tail-recursive

This commit is contained in:
Alain Zscheile 2022-11-26 00:54:03 +01:00
parent e4d71e0b88
commit 8cf076bf5f

View file

@ -17,9 +17,12 @@ defmodule Floof do
] ++ opts
)
Logger.info("Accepting connections on #{port}")
loop_acceptor(socket)
:ok = :gen_tcp.close(socket)
try do
Logger.info("Accepting connections on #{port}")
loop_acceptor(socket)
after
:ok = :gen_tcp.close(socket)
end
end
defp loop_acceptor(socket) do
@ -45,60 +48,70 @@ defmodule Floof do
active: true
)
Floof.Distributor.register(self())
Logger.info("Established connection to #{inspect(host)}:#{port}")
try do
Floof.Distributor.register(self())
Logger.info("Established connection to #{inspect(host)}:#{port}")
if sesskey != nil do
{:ok, encd} = :FloofProtocol.encode(:ProtoMessage, {:session, {:attach, sesskey}})
:ok = :gen_tcp.send(socket, encd)
if sesskey != nil do
{:ok, encd} = :FloofProtocol.encode(:ProtoMessage, {:session, {:attach, sesskey}})
:ok = :gen_tcp.send(socket, encd)
end
serve(socket, %{}, nil)
after
:ok = :gen_tcp.close(socket)
end
serve(socket, %{}, nil)
:ok = :gen_tcp.close(socket)
end
defp serve(client, backlog, sesskey) do
receive do
{:tcp, _, message} ->
message =
if :erlang.is_binary(message) do
message
else
:erlang.list_to_binary(message)
{backlog, sesskey} =
receive do
{:tcp, _, message} ->
message =
if :erlang.is_binary(message) do
message
else
:erlang.list_to_binary(message)
end
{:ok, dcd} = :FloofProtocol.decode(:ProtoMessage, message)
backlog = handle_incoming(client, backlog, sesskey, dcd)
{backlog, sesskey}
{:fwdxfer, {dcdhash, dcd}} ->
backlog =
if sesskey != nil do
# make sure that stuff gets handled uniformly
Floof.SessionManager.set(sesskey, dcdhash, dcd)
else
:ok = send_summary(client, :requestpull, [dcdhash])
Map.put(backlog, dcdhash, dcd)
end
{backlog, sesskey}
{:SessionPushed, sesskey} ->
:ok = send_summary(client, :requestpull, Floof.SessionManager.peek(sesskey))
{backlog, sesskey}
{:SessionDetached, _} ->
{backlog, nil}
{:tcp_closed, _} ->
# put all the backlogged stuff back if possible
if sesskey != nil do
Floof.SessionManager.set_multi(sesskey, backlog)
Floof.SessionManager.detach(sesskey, self())
end
{:ok, dcd} = :FloofProtocol.decode(:ProtoMessage, message)
backlog = handle_incoming(client, backlog, sesskey, dcd)
serve(client, backlog, sesskey)
:erlang.exit(:normal)
{:fwdxfer, {dcdhash, dcd}} ->
if sesskey != nil do
# make sure that stuff gets handled uniformly
Floof.SessionManager.set(sesskey, dcdhash, dcd)
serve(client, backlog, sesskey)
else
:ok = send_summary(client, :requestpull, [dcdhash])
serve(client, Map.put(backlog, dcdhash, dcd), sesskey)
end
x ->
Logger.warn("unable to handle request: #{inspect(x)}")
{backlog, sesskey}
end
{:SessionPushed, sesskey} ->
:ok = send_summary(client, :requestpull, Floof.SessionManager.peek(sesskey))
serve(client, backlog, sesskey)
{:SessionDetached, _} ->
serve(client, backlog, nil)
{:tcp_closed, _} ->
# put all the backlogged stuff back if possible
if sesskey != nil do
Floof.SessionManager.set_multi(sesskey, backlog)
Floof.SessionManager.detach(sesskey, self())
end
x ->
Logger.warn("unable to handle request: #{inspect(x)}")
serve(client, backlog, sesskey)
end
serve(client, backlog, sesskey)
end
defp handle_incoming(client, backlog, sesskey, dcd) do