outbox module + fix quit handling yet again
This commit is contained in:
parent
bdf31dac5b
commit
c4be8f45a8
|
@ -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
|
||||||
|
|
|
@ -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))
|
||||||
|
|
||||||
|
|
|
@ -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 -> ()
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue