outbox module + fix quit handling yet again

This commit is contained in:
tali 2024-01-09 19:35:03 -05:00
parent bdf31dac5b
commit c4be8f45a8
4 changed files with 54 additions and 42 deletions

View File

@ -4,9 +4,8 @@ module User = Router.User
type t = { type t = {
addr : sockaddr; addr : sockaddr;
user : User.t; user : User.t;
outbox : Outbox.t;
mutable pending_nick : string option; mutable pending_nick : string option;
outbox : Irc.Msg.t Lwt_stream.t;
push_outbox : (Irc.Msg.t option -> unit);
} }
let make ~(router : Router.t) ~(addr : sockaddr) : t = let make ~(router : Router.t) ~(addr : sockaddr) : t =
@ -14,17 +13,15 @@ let make ~(router : Router.t) ~(addr : sockaddr) : t =
| ADDR_INET (ia, _) -> Unix.string_of_inet_addr ia | ADDR_INET (ia, _) -> Unix.string_of_inet_addr ia
| ADDR_UNIX path -> path | ADDR_UNIX path -> path
in in
let user = User.make router ~hostname in let outbox = Outbox.make () in
let outbox, push_outbox = Lwt_stream.create () in let user = User.make ~router ~hostname ~outbox in
{ addr; user; pending_nick = None; outbox; push_outbox } { addr; user; outbox; pending_nick = None }
let outbox t = Lwt_stream.choose [t.outbox; User.inbox t.user] let outbox t = t.outbox
let send t msg = try t.push_outbox (Some msg) with Lwt_stream.Closed -> ()
let close t = try t.push_outbox None with Lwt_stream.Closed -> ()
let cleanup t = let shutdown t =
close t; User.quit t.user;
User.cleanup t.user Outbox.close t.outbox
(* message handling *) (* message handling *)
@ -43,9 +40,12 @@ let attempt_to_register t =
begin match User.set_nick t.user nick with begin match User.set_nick t.user nick with
| `nick_in_use -> `nicknameinuse nick | `nick_in_use -> `nicknameinuse nick
| `nick_set -> | `nick_set ->
Logs.debug (fun m -> m "init mode: +%a" Irc.Mode.pp t.user.mode); let send_mode () =
send t (Irc.Msg.make "MODE" [nick; Fmt.str "+%a" Irc.Mode.pp t.user.mode] Outbox.send t.outbox
~prefix:(User.prefix t.user)); (Irc.Msg.make "MODE" [nick; Fmt.str "+%a" Irc.Mode.pp t.user.mode]
~prefix:(User.prefix t.user));
in
Lwt.on_success (Lwt.pause ()) send_mode;
`welcome `welcome
end end
| _, _ -> `ok | _, _ -> `ok
@ -80,7 +80,8 @@ let on_msg_privmsg t tgt msg _ =
| Some dst -> Router.privmsg t.user (`user dst) msg; `ok | Some dst -> Router.privmsg t.user (`user dst) msg; `ok
let on_msg_join t tgt _ = let on_msg_join t tgt _ =
send t (Irc.Msg.make "JOIN" [tgt] ~prefix:(User.prefix t.user)); Outbox.send t.outbox
(Irc.Msg.make "JOIN" [tgt] ~prefix:(User.prefix t.user));
`names ("@", tgt, ["@", User.nick t.user; "", "moe"; "", "barry"]) `names ("@", tgt, ["@", User.nick t.user; "", "moe"; "", "barry"])
let on_msg_privmsg t tgt msg = require_registered t (on_msg_privmsg t tgt msg) let on_msg_privmsg t tgt msg = require_registered t (on_msg_privmsg t tgt msg)
@ -113,7 +114,7 @@ let srv_motd_lines = [
let rpl t cmd params = let rpl t cmd params =
let prefix = Irc.Msg.Server_prefix srv_host in let prefix = Irc.Msg.Server_prefix srv_host in
let target = User.nick t.user in let target = User.nick t.user in
send t (Irc.Msg.make ~prefix cmd (target :: params)) Outbox.send t.outbox (Irc.Msg.make ~prefix cmd (target :: params))
let rpl_tryagain t cmd = rpl t "263" [cmd; "Please wait a while and try again."] let rpl_tryagain t cmd = rpl t "263" [cmd; "Please wait a while and try again."]
@ -172,7 +173,7 @@ let on_msg t (msg : Irc.Msg.t) : unit =
in in
match result with match result with
| `ok -> () | `ok -> ()
| `quit -> cleanup t | `quit -> shutdown t
| `welcome -> rpl_welcome t; rpl_motd t | `welcome -> rpl_welcome t; rpl_motd t
| `motd -> rpl_motd t | `motd -> rpl_motd t
| `names (cp, ch, us) -> rpl_names t cp ch us | `names (cp, ch, us) -> rpl_names t cp ch us

View File

@ -56,19 +56,20 @@ let writer (fd : fd) (obox : Irc.Msg.t Lwt_stream.t) : unit Lwt.t =
| exn -> Lwt.fail exn) | exn -> Lwt.fail exn)
let handle_client (router : Router.t) (conn_fd : fd) (conn_addr : sockaddr) = let handle_client (router : Router.t) (conn_fd : fd) (conn_addr : sockaddr) =
Logs.info (fun m -> m "new connection %a" pp_sockaddr conn_addr);
let conn : Connection.t = let conn : Connection.t =
Connection.make Connection.make
~router ~router
~addr:conn_addr ~addr:conn_addr
in in
let rd = Lwt_stream.iter (Connection.on_msg conn) (reader conn_fd) in let reader = Lwt_stream.iter (Connection.on_msg conn) (reader conn_fd) in
let wr = writer conn_fd (Connection.outbox conn) in let writer = writer conn_fd (Outbox.stream (Connection.outbox conn)) in
let shutdown () = Connection.shutdown conn in
Lwt.on_termination reader shutdown;
Lwt.on_termination writer shutdown;
Lwt.finalize Lwt.finalize
(fun () -> writer)
(fun () -> (fun () ->
Logs.info (fun m -> m "new connection %a" pp_sockaddr conn_addr);
Lwt.choose [rd; wr])
(fun () ->
Connection.cleanup conn;
Lwt_unix.close conn_fd >|= fun () -> Lwt_unix.close conn_fd >|= fun () ->
Logs.info (fun m -> m "connection closed %a" pp_sockaddr conn_addr)) Logs.info (fun m -> m "connection closed %a" pp_sockaddr conn_addr))

14
lib/server/outbox.ml Normal file
View File

@ -0,0 +1,14 @@
open! Import
type t = {
stream : Irc.Msg.t Lwt_stream.t;
push : Irc.Msg.t option -> unit;
}
let make () =
let stream, push = Lwt_stream.create () in
{ stream; push }
let stream t = t.stream
let send t msg = try t.push (Some msg) with Lwt_stream.Closed -> ()
let close t = try t.push None with Lwt_stream.Closed -> ()

View File

@ -8,12 +8,11 @@ type t = {
and user = { and user = {
router : t; router : t;
hostname : string; hostname : string;
outbox : Outbox.t;
mutable key : string_ci; mutable key : string_ci;
mutable nick : Irc.nick; mutable nick : Irc.nick;
mutable userinfo : Irc.userinfo option; mutable userinfo : Irc.userinfo option;
mutable mode : Irc.Mode.t; mutable mode : Irc.Mode.t;
inbox : Irc.Msg.t Lwt_stream.t;
push_inbox : (Irc.Msg.t option -> unit);
} }
let make () = let make () =
@ -25,8 +24,7 @@ let find_user t nick =
module User = struct module User = struct
type t = user type t = user
let make router ~hostname = let make ~router ~hostname ~outbox =
let inbox, push_inbox = Lwt_stream.create () in
{ {
router; router;
hostname; hostname;
@ -34,17 +32,14 @@ module User = struct
nick = "*"; nick = "*";
userinfo = None; userinfo = None;
mode = Irc.Mode.of_string "iw"; mode = Irc.Mode.of_string "iw";
inbox; push_inbox; outbox;
} }
let outbox t = t.outbox
let nick t = t.nick let nick t = t.nick
let prefix t = Irc.Msg.User_prefix (t.nick, t.userinfo, Some t.hostname) let prefix t = Irc.Msg.User_prefix (t.nick, t.userinfo, Some t.hostname)
let is_registered t = t.key <> empty_string_ci let is_registered t = t.key <> empty_string_ci
let inbox t = t.inbox
let send t msg = try t.push_inbox (Some msg) with Lwt_stream.Closed -> ()
let close t = try t.push_inbox None with Lwt_stream.Closed -> ()
let unregister t = let unregister t =
Hashtbl.remove t.router.users t.key; Hashtbl.remove t.router.users t.key;
t.key <- empty_string_ci t.key <- empty_string_ci
@ -56,9 +51,10 @@ module User = struct
else begin else begin
((* TODO: relay NICK message *)); ((* TODO: relay NICK message *));
if is_registered t then if is_registered t then
send t (Irc.Msg.make "NICK" [new_nick] Outbox.send t.outbox
~prefix:(prefix t) (Irc.Msg.make "NICK" [new_nick]
~always_trailing:true); ~prefix:(prefix t)
~always_trailing:true);
unregister t; unregister t;
Hashtbl.add t.router.users key t; Hashtbl.add t.router.users key t;
t.key <- key; t.key <- key;
@ -66,16 +62,16 @@ module User = struct
`nick_set `nick_set
end end
let cleanup t = let quit t =
if is_registered t then begin if is_registered t then begin
(* TODO: quit reason *) (* TODO: quit reason *)
send t (Irc.Msg.make "QUIT" ["Closed"] Outbox.send t.outbox
~prefix:(prefix t) (Irc.Msg.make "QUIT" ["Closed"]
~always_trailing:true); ~prefix:(prefix t)
~always_trailing:true);
(* TODO: relay QUIT message *) (* TODO: relay QUIT message *)
unregister t unregister t
end; end
close t
end end
let privmsg src dst txt = let privmsg src dst txt =
@ -83,4 +79,4 @@ let privmsg src dst txt =
match dst with match dst with
| `user dst -> | `user dst ->
let msg = Irc.Msg.make "PRIVMSG" [User.nick dst; txt] ~prefix in let msg = Irc.Msg.make "PRIVMSG" [User.nick dst; txt] ~prefix in
User.send dst msg Outbox.send (User.outbox dst) msg