-module(peer).
-export([dial/2, start_server/2]).
-record(state, {handler, db, connections=0}).
dial(Host, Port) ->
{ok, Sock} = gen_tcp:connect(Host, Port, [binary, {packet, 0}]),
io:format("Connection established (~p:~p)~n", [Host, Port]),
[{binary, Bin}, _ ] = examples:post_request(),
gen_tcp:send(Sock, Bin),
timer:sleep(1000),
[{binary, Bin2}, _ ] = examples:cancel_request(),
gen_tcp:send(Sock, Bin2),
timer:sleep(1000),
[{binary, Bin3}, _ ] = examples:channel_time_range_request(),
gen_tcp:send(Sock, Bin3),
timer:sleep(1000),
gen_tcp:close(Sock).
start_server(Host, Port) ->
{ok, LisAddr} = inet:getaddr(Host, inet),
LisOpts = [binary, {packet, 0}, {active, false}, {reuseaddr, true}, {ifaddr, LisAddr}],
{ok, Lis} = gen_tcp:listen(Port, LisOpts),
io:format("Listening on ~p:~p~n", [LisAddr, Port]),
{ok, Db} = sqlite3:open(cabal),
init_tables(Db),
Handler = spawn(fun() -> handle_messages() end),
State = #state{handler= Handler, db = Db},
server_loop(State, Lis).
server_loop(State, Lis) ->
{ok, Sock} = gen_tcp:accept(Lis),
Handler = spawn(fun() -> decode_loop(State, Sock) end),
% TODO: read docs of this linkage
ok = gen_tcp:controlling_process(Sock, Handler),
{ok, {RemoteIp, _}} = inet:peername(Sock),
io:format("~n~nIncoming Connection ~p~n", [RemoteIp]),
server_loop(State, Lis).
decode_loop(State = #state{handler=Handler}, Conn) ->
case gen_tcp:recv(Conn, 0) of
{ok, Data} ->
Msg = wire:decode_header(Data),
Handler ! {incoming, Conn, Msg},
decode_loop(State, Conn);
{error, closed} ->
io:format("Connection closed ~p~n", [Conn])
end.
handle_messages() ->
receive
{incoming, Conn, Msg} ->
Type = proplists:get_value(msgType, Msg),
io:format("Received MsgType: ~p from ~p~n", [Type, Conn]),
handle_messages()
end.
% sql helpers
%%%%%%%%%%%%%
init_tables(Db) ->
ColId = {id, integer, [{primary_key, [asc, autoincrement]}]},
Tables = #{
channels => [ColId, {name, text, not_null}],
users => [ColId, {pubkey, blob, not_null}, {name, text, not_null}],
posts => [ColId, {pubkey, blob, not_null}, {type, integer, not_null}]
},
case tables_exist(Db, maps:keys(Tables)) of
missing ->
CreateTable = fun(T, Cols) ->
ok = sqlite3:create_table(Db, T, Cols),
io:format("Created table: ~p~n", [T])
end,
maps:foreach(CreateTable, Tables);
ok ->
ok
end.
tables_exist(Db, [T | Rest]) ->
case lists:member(T, sqlite3:list_tables(Db)) of
true -> tables_exist(Db, Rest);
false -> missing
end;
tables_exist(_, []) -> ok.
drop_table_if_exists(Db, Table) ->
case lists:member(Table, sqlite3:list_tables(Db)) of
true -> sqlite3:drop_table(Db, Table);
false -> ok
end.
rows(SqlExecReply) ->
case SqlExecReply of
[{columns, _Columns}, {rows, Rows}] -> Rows;
{error, Code, Reason} -> {error, Code, Reason}
end.