implement WHOWAS using Cache to store history
This commit is contained in:
parent
41b7fde963
commit
c3ea3aea6d
|
@ -4,8 +4,9 @@ Logging.init_pretty_writer stderr
|
||||||
Lwt_main.run
|
Lwt_main.run
|
||||||
(Server.run {
|
(Server.run {
|
||||||
port = 6667;
|
port = 6667;
|
||||||
tcp_listen_backlog = 8;
|
listen_backlog = 8;
|
||||||
ping_interval = 60;
|
ping_interval = 60;
|
||||||
|
whowas_history_len = 1000;
|
||||||
hostname = "irc.tali.software";
|
hostname = "irc.tali.software";
|
||||||
(* TODO: motd *)
|
(* TODO: motd *)
|
||||||
})
|
})
|
||||||
|
|
|
@ -61,7 +61,7 @@ let reply t (num, params) =
|
||||||
| None -> "*"
|
| None -> "*"
|
||||||
in
|
in
|
||||||
let always_trailing = match num with
|
let always_trailing = match num with
|
||||||
| "301" | "311" | "312" | "319" | "332" | "353" -> true
|
| "301" | "311" | "312" | "314" | "319" | "332" | "353" -> true
|
||||||
| _ -> false
|
| _ -> false
|
||||||
in
|
in
|
||||||
Outbox.send t.outbox
|
Outbox.send t.outbox
|
||||||
|
@ -634,6 +634,26 @@ let on_msg_whois t nick =
|
||||||
list_whois t user;
|
list_whois t user;
|
||||||
Ok ()
|
Ok ()
|
||||||
|
|
||||||
|
let list_whowas t nick limit =
|
||||||
|
List.iter_up_to ~limit
|
||||||
|
(fun (nick, { username; hostname; realname }) ->
|
||||||
|
reply t ("314", [nick; username; hostname; "*"; realname]))
|
||||||
|
(Router.whowas t.router nick);
|
||||||
|
reply t ("369", [nick; "End of WHOWAS"])
|
||||||
|
|
||||||
|
let on_msg_whowas t nick count =
|
||||||
|
let* _me = require_registered t in
|
||||||
|
let limit =
|
||||||
|
try
|
||||||
|
let n = Option.get (int_of_string_opt count) in
|
||||||
|
if n <= 0 then invalid_arg "count <= 0";
|
||||||
|
n
|
||||||
|
with Invalid_argument _ ->
|
||||||
|
max_int
|
||||||
|
in
|
||||||
|
list_whowas t nick limit;
|
||||||
|
Ok ()
|
||||||
|
|
||||||
|
|
||||||
(* welcome and quit *)
|
(* welcome and quit *)
|
||||||
|
|
||||||
|
@ -834,8 +854,11 @@ let dispatch t = function
|
||||||
| "AWAY", args -> on_msg_away t (concat_args args)
|
| "AWAY", args -> on_msg_away t (concat_args args)
|
||||||
| "MODE", tgt :: args when tgt <> "" -> on_msg_mode t tgt args
|
| "MODE", tgt :: args when tgt <> "" -> on_msg_mode t tgt args
|
||||||
| "WHO", mask :: _ when mask <> "" -> on_msg_who t mask
|
| "WHO", mask :: _ when mask <> "" -> on_msg_who t mask
|
||||||
| "WHOIS", ([] | [""] | (_ :: "" :: _)) -> Error nonicknamegiven
|
| "WHOIS", ([] | [""] | _ :: "" :: _) -> Error nonicknamegiven
|
||||||
| "WHOIS", ([nick] | (_ :: nick :: _)) -> on_msg_whois t nick
|
| "WHOIS", ([nick] | _ :: nick :: _) -> on_msg_whois t nick
|
||||||
|
| "WHOWAS", ([] | "" :: _) -> Error nonicknamegiven
|
||||||
|
| "WHOWAS", [nick] -> on_msg_whowas t nick ""
|
||||||
|
| "WHOWAS", nick :: count :: _ -> on_msg_whowas t nick count
|
||||||
| ("USER" | "JOIN" | "NAMES" | "PART" | "KICK" | "MODE" | "WHO") as cmd, _ ->
|
| ("USER" | "JOIN" | "NAMES" | "PART" | "KICK" | "MODE" | "WHO") as cmd, _ ->
|
||||||
Error (needmoreparams cmd)
|
Error (needmoreparams cmd)
|
||||||
(* TODO: "LIST" *)
|
(* TODO: "LIST" *)
|
||||||
|
@ -847,7 +870,6 @@ let dispatch t = function
|
||||||
(* TODO: "HELP" *)
|
(* TODO: "HELP" *)
|
||||||
(* TODO: "INFO" *)
|
(* TODO: "INFO" *)
|
||||||
(* TODO: "NOTICE" *)
|
(* TODO: "NOTICE" *)
|
||||||
(* TODO: "WHOWAS" *)
|
|
||||||
(* TODO: "KILL" *)
|
(* TODO: "KILL" *)
|
||||||
(* TODO: "REHASH" *)
|
(* TODO: "REHASH" *)
|
||||||
(* TODO: "RESTART" *)
|
(* TODO: "RESTART" *)
|
||||||
|
|
|
@ -5,9 +5,11 @@ include (val Logging.sublogs logger "Router")
|
||||||
|
|
||||||
type t = router
|
type t = router
|
||||||
|
|
||||||
let make () =
|
let make ~whowas_history_len = {
|
||||||
{ users = Hashtbl.create 4096;
|
users = Hashtbl.create 1024;
|
||||||
channels = Hashtbl.create 4096 }
|
channels = Hashtbl.create 1024;
|
||||||
|
whowas = Cache.make whowas_history_len;
|
||||||
|
}
|
||||||
|
|
||||||
let is_nick_available t nick =
|
let is_nick_available t nick =
|
||||||
not (Hashtbl.mem t.users (string_ci nick))
|
not (Hashtbl.mem t.users (string_ci nick))
|
||||||
|
@ -18,6 +20,9 @@ let find_user t nick =
|
||||||
let find_chan t name =
|
let find_chan t name =
|
||||||
Hashtbl.find t.channels (string_ci name)
|
Hashtbl.find t.channels (string_ci name)
|
||||||
|
|
||||||
|
let whowas t nick =
|
||||||
|
Cache.find_all t.whowas (string_ci nick)
|
||||||
|
|
||||||
let relay ~(from : user) (msg : Msg.t) tgts =
|
let relay ~(from : user) (msg : Msg.t) tgts =
|
||||||
let msg =
|
let msg =
|
||||||
if msg.prefix = No_prefix then
|
if msg.prefix = No_prefix then
|
||||||
|
|
|
@ -42,4 +42,5 @@ and priv =
|
||||||
type router = {
|
type router = {
|
||||||
users : (string_ci, user) Hashtbl.t;
|
users : (string_ci, user) Hashtbl.t;
|
||||||
channels : (string_ci, chan) Hashtbl.t;
|
channels : (string_ci, chan) Hashtbl.t;
|
||||||
|
whowas : (string_ci, name * userinfo) Cache.t;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,14 +6,14 @@ include (val Logging.sublogs logger "Server")
|
||||||
|
|
||||||
type ping_wheel = Connection.t Wheel.t
|
type ping_wheel = Connection.t Wheel.t
|
||||||
|
|
||||||
let listener ~(port : int) ~(backlog : int) : (fd * sockaddr) Lwt_stream.t =
|
let listener ~(port : int) ~(listen_backlog : int) : (fd * sockaddr) Lwt_stream.t =
|
||||||
let sock : fd Lwt.t =
|
let sock : fd Lwt.t =
|
||||||
let fd = Lwt_unix.socket PF_INET SOCK_STREAM 0 in
|
let fd = Lwt_unix.socket PF_INET SOCK_STREAM 0 in
|
||||||
Lwt_unix.setsockopt fd SO_KEEPALIVE false;
|
Lwt_unix.setsockopt fd SO_KEEPALIVE false;
|
||||||
Lwt_unix.setsockopt fd SO_REUSEPORT true;
|
Lwt_unix.setsockopt fd SO_REUSEPORT true;
|
||||||
let srv_adr = Unix.ADDR_INET (Unix.inet_addr_any, port) in
|
let srv_adr = Unix.ADDR_INET (Unix.inet_addr_any, port) in
|
||||||
let* () = Lwt_unix.bind fd srv_adr in
|
let* () = Lwt_unix.bind fd srv_adr in
|
||||||
Lwt_unix.listen fd backlog;
|
Lwt_unix.listen fd listen_backlog;
|
||||||
info (fun m -> m "listening on %a" pp_sockaddr srv_adr);
|
info (fun m -> m "listening on %a" pp_sockaddr srv_adr);
|
||||||
Lwt.return fd
|
Lwt.return fd
|
||||||
in
|
in
|
||||||
|
@ -94,26 +94,30 @@ let handle_client
|
||||||
|
|
||||||
type config = {
|
type config = {
|
||||||
port : int;
|
port : int;
|
||||||
tcp_listen_backlog : int;
|
listen_backlog : int;
|
||||||
ping_interval : int;
|
ping_interval : int;
|
||||||
|
whowas_history_len : int;
|
||||||
hostname : string;
|
hostname : string;
|
||||||
(* TODO: motd *)
|
(* TODO: motd *)
|
||||||
}
|
}
|
||||||
|
|
||||||
let run (cfg : config) : unit Lwt.t =
|
let run { port; listen_backlog; ping_interval;
|
||||||
|
whowas_history_len; hostname } : unit Lwt.t
|
||||||
|
=
|
||||||
let server_info =
|
let server_info =
|
||||||
Server_info.make
|
Server_info.make
|
||||||
~hostname:cfg.hostname
|
~hostname
|
||||||
(* ~motd *)
|
(* ~motd *)
|
||||||
in
|
in
|
||||||
|
|
||||||
let router : Router.t =
|
let router : Router.t =
|
||||||
Router.make ()
|
Router.make
|
||||||
|
~whowas_history_len
|
||||||
in
|
in
|
||||||
|
|
||||||
let ping_wheel : _ Wheel.t =
|
let ping_wheel : _ Wheel.t =
|
||||||
Wheel.make
|
Wheel.make
|
||||||
cfg.ping_interval
|
ping_interval
|
||||||
in
|
in
|
||||||
|
|
||||||
let on_tick () =
|
let on_tick () =
|
||||||
|
@ -145,8 +149,8 @@ let run (cfg : config) : unit Lwt.t =
|
||||||
Lwt_stream.iter
|
Lwt_stream.iter
|
||||||
on_con
|
on_con
|
||||||
(listener
|
(listener
|
||||||
~port:cfg.port
|
~port
|
||||||
~backlog:cfg.tcp_listen_backlog)
|
~listen_backlog)
|
||||||
in
|
in
|
||||||
|
|
||||||
listener_promise <&> pinger_promise
|
listener_promise <&> pinger_promise
|
||||||
|
|
|
@ -9,7 +9,7 @@ let%expect_test _ =
|
||||||
with e -> print_endline (Printexc.to_string e)
|
with e -> print_endline (Printexc.to_string e)
|
||||||
in
|
in
|
||||||
|
|
||||||
let router = Router.make () in
|
let router = Router.make ~whowas_history_len:1000 in
|
||||||
|
|
||||||
let u1 =
|
let u1 =
|
||||||
User.make "beenie"
|
User.make "beenie"
|
||||||
|
|
|
@ -27,7 +27,12 @@ let set_nick t new_nick =
|
||||||
t.nick_key <- string_ci new_nick;
|
t.nick_key <- string_ci new_nick;
|
||||||
end
|
end
|
||||||
|
|
||||||
let register t ~router = Hashtbl.add router.users t.nick_key t
|
let register t ~router =
|
||||||
|
begin
|
||||||
|
Hashtbl.add router.users t.nick_key t;
|
||||||
|
Cache.add router.whowas t.nick_key (t.nick, t.userinfo);
|
||||||
|
end
|
||||||
|
|
||||||
let unregister t ~router = Hashtbl.remove router.users t.nick_key
|
let unregister t ~router = Hashtbl.remove router.users t.nick_key
|
||||||
let is_registered t ~router = Hashtbl.mem router.users t.nick_key
|
let is_registered t ~router = Hashtbl.mem router.users t.nick_key
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue