some stupid bug
This commit is contained in:
@@ -208,3 +208,21 @@
|
|||||||
% 2. Control sequences reference: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html
|
% 2. Control sequences reference: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html
|
||||||
% 3. Historical background: https://invisible-island.net/xterm/modified-keys.html
|
% 3. Historical background: https://invisible-island.net/xterm/modified-keys.html
|
||||||
%-define(XTERM_
|
%-define(XTERM_
|
||||||
|
|
||||||
|
% readline keys
|
||||||
|
-define(KBD_ESC, [27]).
|
||||||
|
-define(KBD_C_a, [1]).
|
||||||
|
-define(KBD_C_b, [2]).
|
||||||
|
-define(KBD_C_d, [4]).
|
||||||
|
-define(KBD_C_e, [5]).
|
||||||
|
-define(KBD_C_f, [6]).
|
||||||
|
-define(KBD_C_g, [7]).
|
||||||
|
-define(KBD_C_k, [11]).
|
||||||
|
-define(KBD_C_l, [12]).
|
||||||
|
-define(KBD_C_n, [14]).
|
||||||
|
-define(KBD_C_p, [16]).
|
||||||
|
|
||||||
|
% M-b -> [ESC, $b]
|
||||||
|
-define(KBD_M_b, [?KBD_ESC, $b]).
|
||||||
|
-define(KBD_M_d, [?KBD_ESC, $d]).
|
||||||
|
-define(KBD_M_f, [?KBD_ESC, $f]).
|
||||||
|
|||||||
Executable
+12
@@ -0,0 +1,12 @@
|
|||||||
|
#!/usr/bin/env escript
|
||||||
|
|
||||||
|
%% script for keycode mapping
|
||||||
|
|
||||||
|
main([]) ->
|
||||||
|
ok = shell:start_interactive({noshell, raw}),
|
||||||
|
dum([]).
|
||||||
|
|
||||||
|
dum(Q) ->
|
||||||
|
io:format("~tw\r\n", [Q]),
|
||||||
|
NewChar = io:get_chars("", 1),
|
||||||
|
dum(Q ++ NewChar).
|
||||||
+82
-10
@@ -1,18 +1,32 @@
|
|||||||
#!/usr/bin/env escript
|
#!/usr/bin/env escript
|
||||||
|
|
||||||
|
%% needs:
|
||||||
|
%% - line parsing
|
||||||
|
%% - keyboard input
|
||||||
|
%% - drawing to screen
|
||||||
|
|
||||||
-mode(compile).
|
-mode(compile).
|
||||||
|
|
||||||
% john state
|
% john state
|
||||||
-record(js,
|
-record(js,
|
||||||
{tsock = none :: gen_tcp:socket(),
|
{rcv = <<>> :: binary(),
|
||||||
nsock = none :: enoise:noise_socket()}).
|
kbdq = [] :: iolist(),
|
||||||
|
ibuf = [] :: string(),
|
||||||
|
tsock = none :: none | gen_tcp:socket(),
|
||||||
|
nsock = none :: none | enoise:noise_socket()}).
|
||||||
|
|
||||||
|
|
||||||
main([]) ->
|
main([]) -> main_ii(6969);
|
||||||
|
main([PortNum]) -> main_ii(list_to_integer(PortNum)).
|
||||||
|
|
||||||
|
main_ii(PortNum) ->
|
||||||
TcpOpts = [binary, {packet, 0}, {active, once}],
|
TcpOpts = [binary, {packet, 0}, {active, once}],
|
||||||
{ok, TSock} = gen_tcp:connect("localhost", 6969, TcpOpts),
|
{ok, TSock} = gen_tcp:connect("localhost", PortNum, TcpOpts),
|
||||||
ok = inet:setopts(TSock, [{active, once}]),
|
ok = inet:setopts(TSock, [{active, once}]),
|
||||||
{ok, NSock, _HandshakeState} = enoise:connect(TSock, noise_options()),
|
{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}).
|
j_loop(#js{tsock = TSock, nsock = NSock}).
|
||||||
|
|
||||||
noise_options() ->
|
noise_options() ->
|
||||||
@@ -22,15 +36,73 @@ noise_options() ->
|
|||||||
{e, KP}].
|
{e, KP}].
|
||||||
|
|
||||||
|
|
||||||
j_loop(JS = #js{nsock = NSock}) ->
|
j_loop(JS = #js{rcv = Rcv, tsock = TSock, nsock = NSock}) ->
|
||||||
|
ok = inet:setopts(TSock, [{active, once}]),
|
||||||
receive
|
receive
|
||||||
{noise, NSock, Bytes} ->
|
{noise, NSock, Bytes} ->
|
||||||
ok = io:format("< ~tp~n", [Bytes]),
|
NewRcv = <<Rcv/binary, Bytes/binary>>,
|
||||||
j_loop(JS);
|
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 ->
|
Unknown ->
|
||||||
ok = io:format("~tp unknown message, killing self: ~tp~n",
|
ok = io:format("unknown message ~tp~n", [Unknown]),
|
||||||
[self(), Unknown]),
|
j_loop(JS)
|
||||||
exit(normal)
|
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.
|
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).
|
||||||
|
|||||||
+41
-20
@@ -5,9 +5,10 @@
|
|||||||
|
|
||||||
% ho from pimp pov
|
% ho from pimp pov
|
||||||
-record(pho,
|
-record(pho,
|
||||||
{pid :: pid(),
|
{pid = none :: none | pid(),
|
||||||
ref :: reference(),
|
ref = none :: none | reference(),
|
||||||
name :: string()}).
|
taken = false :: boolean(),
|
||||||
|
name = none :: none | string()}).
|
||||||
|
|
||||||
%% pimp state
|
%% pimp state
|
||||||
-record(ps,
|
-record(ps,
|
||||||
@@ -25,10 +26,9 @@
|
|||||||
|
|
||||||
|
|
||||||
main([]) ->
|
main([]) ->
|
||||||
io:format("RBX example 4 telnet echo server daemon~n"
|
p_init(6969);
|
||||||
"`one' part of the many-to-one relationship~n",
|
main([PortNum]) ->
|
||||||
[]),
|
p_init(list_to_integer(PortNum)).
|
||||||
p_init().
|
|
||||||
|
|
||||||
|
|
||||||
noise_options() ->
|
noise_options() ->
|
||||||
@@ -43,9 +43,8 @@ noise_options() ->
|
|||||||
|
|
||||||
|
|
||||||
% pimp process startup
|
% pimp process startup
|
||||||
p_init() ->
|
p_init(Port) ->
|
||||||
p_logln("pimp startup (p_init)"),
|
p_logln("pimp startup (p_init)"),
|
||||||
Port = 6969,
|
|
||||||
Opts = [binary, {packet, 0}, {active, once}],
|
Opts = [binary, {packet, 0}, {active, once}],
|
||||||
case gen_tcp:listen(Port, Opts) of
|
case gen_tcp:listen(Port, Opts) of
|
||||||
{ok, LSock} ->
|
{ok, LSock} ->
|
||||||
@@ -60,12 +59,12 @@ p_init() ->
|
|||||||
|
|
||||||
p_loop(PS = #ps{hos = Hos}) ->
|
p_loop(PS = #ps{hos = Hos}) ->
|
||||||
receive
|
receive
|
||||||
{ho, _HoPid, taken} ->
|
{ho, HoPid, taken} ->
|
||||||
NewPS = p_spawn_ho(PS),
|
NewPS = p_taken(HoPid, PS),
|
||||||
p_loop(NewPS);
|
p_loop(NewPS);
|
||||||
{ho, HoPid, sent, Data} ->
|
{ho, HoPid, sent, Data} ->
|
||||||
HoName = p_ho_name(HoPid, PS),
|
HoName = p_ho_name(HoPid, PS),
|
||||||
SendMessage = io_lib:format("~ts :: ~ts\r\n", [HoName, Data]),
|
SendMessage = io_lib:format("~ts> ~ts\r\n", [HoName, Data]),
|
||||||
ok = p_echo_except(HoPid, HoName, SendMessage, Hos),
|
ok = p_echo_except(HoPid, HoName, SendMessage, Hos),
|
||||||
p_loop(PS);
|
p_loop(PS);
|
||||||
Down = {'DOWN', _, _, _, _} ->
|
Down = {'DOWN', _, _, _, _} ->
|
||||||
@@ -76,6 +75,20 @@ p_loop(PS = #ps{hos = Hos}) ->
|
|||||||
p_loop(PS)
|
p_loop(PS)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
p_taken(Pid, PS = #ps{hos = Hos}) ->
|
||||||
|
Hos_II = mark_taken(Pid, Hos, []),
|
||||||
|
PS_II = PS#ps{hos = Hos_II},
|
||||||
|
PS_III = p_spawn_ho(PS_II),
|
||||||
|
PS_III.
|
||||||
|
|
||||||
|
mark_taken(Pid, [Ho = #pho{pid = Pid} | Rest], Acc) ->
|
||||||
|
NewHo = Ho#pho{taken = true},
|
||||||
|
lists:reverse(Acc) ++ [NewHo | Rest];
|
||||||
|
mark_taken(Pid, [WrongHo | Rest], Acc) ->
|
||||||
|
mark_taken(Pid, Rest, [WrongHo | Acc]);
|
||||||
|
mark_taken(_, [], Acc) ->
|
||||||
|
lists:reverse(Acc).
|
||||||
|
|
||||||
% given pid of ho, get her name
|
% given pid of ho, get her name
|
||||||
p_ho_name(HoPid, #ps{hos = Hos}) ->
|
p_ho_name(HoPid, #ps{hos = Hos}) ->
|
||||||
case lists:keyfind(HoPid, #pho.pid, Hos) of
|
case lists:keyfind(HoPid, #pho.pid, Hos) of
|
||||||
@@ -100,7 +113,8 @@ p_spawn_ho(PS = #ps{lsock = LSock, hos = Hos, ho_names = Names}) ->
|
|||||||
|
|
||||||
% ho down, remove her from roster
|
% ho down, remove her from roster
|
||||||
p_ho_down({'DOWN', _Ref, process, Pid, Info}, PS = #ps{hos = Hos}) ->
|
p_ho_down({'DOWN', _Ref, process, Pid, Info}, PS = #ps{hos = Hos}) ->
|
||||||
ok = p_logfln("ho down: ~tp; reason: ~tw", [Pid, Info]),
|
Ho = lists:keyfind(Pid, #pho.pid, Hos),
|
||||||
|
ok = p_logfln("ho down: ~ts; reason: ~tw", [Ho#pho.name, Info]),
|
||||||
NewHos = lists:keydelete(Pid, #pho.pid, Hos),
|
NewHos = lists:keydelete(Pid, #pho.pid, Hos),
|
||||||
NewPS = PS#ps{hos = NewHos},
|
NewPS = PS#ps{hos = NewHos},
|
||||||
NewPS.
|
NewPS.
|
||||||
@@ -110,7 +124,10 @@ p_ho_down({'DOWN', _Ref, process, Pid, Info}, PS = #ps{hos = Hos}) ->
|
|||||||
% skip if equal
|
% skip if equal
|
||||||
p_echo_except(SrcPid, SrcName, Data, [#pho{pid = SrcPid} | Rest]) ->
|
p_echo_except(SrcPid, SrcName, Data, [#pho{pid = SrcPid} | Rest]) ->
|
||||||
p_echo_except(SrcPid, SrcName, Data, Rest);
|
p_echo_except(SrcPid, SrcName, Data, Rest);
|
||||||
p_echo_except(SrcPid, SrcName, Data, [#pho{pid = DstPid} | Rest]) ->
|
% skip if not taken
|
||||||
|
p_echo_except(SrcPid, SrcName, Data, [#pho{taken = false} | Rest]) ->
|
||||||
|
p_echo_except(SrcPid, SrcName, Data, Rest);
|
||||||
|
p_echo_except(SrcPid, SrcName, Data, [#pho{pid = DstPid, taken = true} | Rest]) ->
|
||||||
DstPid ! {pimp, send, Data},
|
DstPid ! {pimp, send, Data},
|
||||||
p_echo_except(SrcPid, SrcName, Data, Rest);
|
p_echo_except(SrcPid, SrcName, Data, Rest);
|
||||||
p_echo_except(_, _, _, []) ->
|
p_echo_except(_, _, _, []) ->
|
||||||
@@ -147,7 +164,8 @@ h_loop(HS = #hs{name = Name, daddy = Daddy, asock = ASock, nsock = NSock}) ->
|
|||||||
ok = h_rcvd(Name, Data_II),
|
ok = h_rcvd(Name, Data_II),
|
||||||
Daddy ! {ho, self(), sent, Data_II},
|
Daddy ! {ho, self(), sent, Data_II},
|
||||||
h_loop(HS);
|
h_loop(HS);
|
||||||
{pimp, send, Data} ->
|
{pimp, send, Data} = M ->
|
||||||
|
io:format("~p received ~p~n", [self(), M]),
|
||||||
ok = h_send(Name, NSock, Data),
|
ok = h_send(Name, NSock, Data),
|
||||||
h_loop(HS);
|
h_loop(HS);
|
||||||
{tcp_closed, ASock} ->
|
{tcp_closed, ASock} ->
|
||||||
@@ -160,7 +178,7 @@ h_loop(HS = #hs{name = Name, daddy = Daddy, asock = ASock, nsock = NSock}) ->
|
|||||||
|
|
||||||
% pimp log in bold
|
% pimp log in bold
|
||||||
p_logln(LogStr) ->
|
p_logln(LogStr) ->
|
||||||
Msg = io_lib:format("!! Daddy :: ~ts~n", [LogStr]),
|
Msg = io_lib:format("Daddy: ~ts~n", [LogStr]),
|
||||||
PimpChars = ?ANSI_BOLD([Msg]),
|
PimpChars = ?ANSI_BOLD([Msg]),
|
||||||
io:put_chars(PimpChars).
|
io:put_chars(PimpChars).
|
||||||
|
|
||||||
@@ -170,7 +188,7 @@ p_logfln(LogStr, Args) ->
|
|||||||
|
|
||||||
% ho log dimmed
|
% ho log dimmed
|
||||||
h_logln(HoName, LogStr) ->
|
h_logln(HoName, LogStr) ->
|
||||||
FMsg = io_lib:format("!! ~ts :: ~ts~n", [HoName, LogStr]),
|
FMsg = io_lib:format("~ts: ~ts~n", [HoName, LogStr]),
|
||||||
HoChars = ?ANSI_DIM([FMsg]),
|
HoChars = ?ANSI_DIM([FMsg]),
|
||||||
io:put_chars(HoChars).
|
io:put_chars(HoChars).
|
||||||
|
|
||||||
@@ -179,12 +197,15 @@ h_logfln(HoName, MsgStr, Args) ->
|
|||||||
|
|
||||||
% normal: john messages
|
% normal: john messages
|
||||||
h_rcvd(Name, MsgStr) ->
|
h_rcvd(Name, MsgStr) ->
|
||||||
Msg = io_lib:format("<< ~ts :: ~ts~n", [Name, MsgStr]),
|
Msg = io_lib:format("~ts< ~ts~n", [Name, string:chomp(MsgStr)]),
|
||||||
io:put_chars(Msg).
|
io:put_chars(Msg).
|
||||||
|
|
||||||
h_send(Name, NSock, Msg) ->
|
h_send(Name, NSock, Msg) ->
|
||||||
ok = io:format(">> ~ts :: ~ts~n", [Name, Msg]),
|
FMsg = io_lib:format("~ts> ~ts~n", [Name, string:chomp(Msg)]),
|
||||||
enoise:send(NSock, Msg).
|
HoChars = [?ANSI_DIM(FMsg)],
|
||||||
|
ok = io:put_chars(HoChars),
|
||||||
|
Send = unicode:characters_to_binary([string:chomp(Msg), "\r\n"]),
|
||||||
|
ok = enoise:send(NSock, Send).
|
||||||
|
|
||||||
|
|
||||||
init_ho_names() ->
|
init_ho_names() ->
|
||||||
|
|||||||
Reference in New Issue
Block a user