Current section
Files
Jump to
Current section
Files
src/platybelodon_network.erl
-module(platybelodon_network).
-include_lib("kernel/include/logger.hrl").
-export([start_receive_link/2, start_send_link/2, receive_loop/1, send_loop/1, parser_loop/1]).
start_receive_link(Platybelodon, Socket) ->
spawn_link(?MODULE, receive_loop, [{Platybelodon, Socket}]).
start_send_link(Platybelodon, Socket) ->
spawn_link(?MODULE, send_loop, [{Platybelodon, Socket}]).
receive_loop({Platybelodon, Socket}) ->
ParserPid = spawn_link(?MODULE, parser_loop, [Platybelodon]),
inet:setopts(Socket, [{active, true}]),
receive_loop({Platybelodon, Socket, ParserPid, infinity});
receive_loop({Platybelodon, Socket, Parser, Timeout}) ->
receive
terminate -> ok;
{set_heartbeat, Heartbeat} ->
receive_loop({Platybelodon, Socket, Parser, Heartbeat});
{tcp, Socket, Data} ->
Parser ! Data,
receive_loop({Platybelodon, Socket, Parser, Timeout});
{tcp_closed, Socket} ->
Platybelodon ! {platybelodon, disconnect, closed},
ok;
{tcp_error, Socket} ->
Platybelodon ! {platybelodon, disconnect, error},
ok
after Timeout ->
Platybelodon ! {platybelodon, disconnect, heartbeat_timeout},
ok
end.
parser_loop(Platybelodon) ->
parser_loop(Platybelodon, {command, undefined, undefined, <<>>}).
parser_loop(Platybelodon, {Command, Frame, Length, Remainder}) ->
receive
terminate -> ok;
Data ->
{ParseState, Frames} = platybelodon_frame:parse_all({Command, Frame, Length, <<Remainder/binary, Data/binary>>}),
Platybelodon ! {platybelodon, frames, Frames},
parser_loop(Platybelodon, ParseState)
end.
send_loop({Platybelodon, Socket}) ->
send_loop({Platybelodon, Socket, infinity});
send_loop({Platybelodon, Socket, Timeout}) ->
receive
terminate -> ok;
{set_heartbeat, Heartbeat} ->
send_loop({Platybelodon, Socket, Heartbeat});
Frames ->
Composed = platybelodon_frame:format(Frames),
case gen_tcp:send(Socket, Composed) of
ok -> send_loop({Platybelodon, Socket, Timeout});
{error, {timeout, _Remainder}} ->
Platybelodon ! {platybelodon, disconnect, timeout};
{error, closed} ->
Platybelodon ! {platybelodon, disconnect, closed}
end
after Timeout ->
self() ! [],
send_loop({Platybelodon, Socket, Timeout})
end.