109 lines
2.9 KiB
Erlang
Executable File
109 lines
2.9 KiB
Erlang
Executable File
#!/usr/bin/env escript
|
|
|
|
%% needs:
|
|
%% - line parsing
|
|
%% - keyboard input
|
|
%% - drawing to screen
|
|
|
|
-mode(compile).
|
|
|
|
% john state
|
|
-record(js,
|
|
{rcv = <<>> :: binary(),
|
|
kbdq = [] :: iolist(),
|
|
ibuf = [] :: string(),
|
|
tsock = none :: none | gen_tcp:socket(),
|
|
nsock = none :: none | enoise:noise_socket()}).
|
|
|
|
|
|
main([]) -> main_ii(6969);
|
|
main([PortNum]) -> main_ii(list_to_integer(PortNum)).
|
|
|
|
main_ii(PortNum) ->
|
|
TcpOpts = [binary, {packet, 0}, {active, once}],
|
|
{ok, TSock} = gen_tcp:connect("localhost", PortNum, TcpOpts),
|
|
ok = inet:setopts(TSock, [{active, once}]),
|
|
{ok, NSock, _HandshakeState} = enoise:connect(TSock, noise_options()),
|
|
% need keyboard process
|
|
Self = self(),
|
|
spawn_link(fun() -> kbd_loop(Self) end),
|
|
j_loop(#js{tsock = TSock, nsock = NSock}).
|
|
|
|
noise_options() ->
|
|
% totally safe crypto
|
|
KP = enoise_keypair:new(dh25519),
|
|
[{noise, "Noise_NN_25519_ChaChaPoly_BLAKE2b"},
|
|
{e, KP}].
|
|
|
|
|
|
j_loop(JS = #js{rcv = Rcv, tsock = TSock, nsock = NSock}) ->
|
|
ok = inet:setopts(TSock, [{active, once}]),
|
|
receive
|
|
{noise, NSock, Bytes} ->
|
|
NewRcv = <<Rcv/binary, Bytes/binary>>,
|
|
io:format("NewRcv = ~p~n", [NewRcv]),
|
|
NewJS = j_received(NewRcv, JS),
|
|
j_loop(NewJS);
|
|
{kbd, line, Line} ->
|
|
NewJS = j_kbdln(Line, JS),
|
|
j_loop(NewJS);
|
|
{tcp_closed, TSock} ->
|
|
io:format("tcp socket closed unexpectedly, exiting~n"),
|
|
exit(tcp_closed);
|
|
Unknown ->
|
|
ok = io:format("unknown message ~tp~n", [Unknown]),
|
|
j_loop(JS)
|
|
end.
|
|
|
|
j_kbdln(Line, JS = #js{nsock = NS}) ->
|
|
FinalMsg = unicode:characters_to_binary([string:chomp(Line), "\r\n"]),
|
|
ok = enoise:send(NS, FinalMsg),
|
|
JS.
|
|
|
|
% not the time for readline
|
|
% % user hit return, flush queue
|
|
% j_kbd("\r", JS = #js{kbdq = KQ, nsock = NS}) ->
|
|
% FinalMsg = unicode:characters_to_binary([KQ, "\r\n"]),
|
|
% ok = enoise:send(NS, FinalMsg),
|
|
% NewJS = JS#js{kbdq = []}
|
|
% NewJS;
|
|
% % user hit something else, add to queue
|
|
% % fixme: parse ANSI escape sequences here, maybe xterm
|
|
% j_kbd(Str1, JS = #js{kbdq = KQ}) ->
|
|
% JS#js{kbdq = KQ ++ Str1}.
|
|
|
|
|
|
j_received(Rcv, JS) ->
|
|
case takeln(Rcv) of
|
|
none ->
|
|
JS#js{rcv = Rcv};
|
|
{line, Line, Rcv2} ->
|
|
ok = j_rln(Line),
|
|
j_received(Rcv2, JS)
|
|
end.
|
|
|
|
|
|
j_rln(Line) ->
|
|
io:format("< ~ts~n", [string:chomp(Line)]).
|
|
|
|
takeln(X) ->
|
|
takeln(<<>>, X).
|
|
|
|
takeln(Acc, <<"\r\n", Rest/binary>>) ->
|
|
{line, <<Acc/binary, "\r\n">>, Rest};
|
|
takeln(Acc, <<B:8, Rest/binary>>) ->
|
|
takeln(<<Acc/binary, B:8>>, Rest);
|
|
takeln(_Acc, <<>>) ->
|
|
none.
|
|
|
|
|
|
kbd_loop(Parent) ->
|
|
Line = io:get_line("> "),
|
|
Parent ! {kbd, line, Line},
|
|
kbd_loop(Parent).
|
|
|
|
%kbd_loop(Parent) ->
|
|
% Char = io:get_chars("", 1),
|
|
% Parent ! {kbd, Char},
|
|
% kbd_loop(Parent).
|