147 lines
4.2 KiB
OCaml
147 lines
4.2 KiB
OCaml
|
|
open Import
|
||
|
|
module Client = Dune_rpc_client.Client
|
||
|
|
|
||
|
|
let ( let** ) x f =
|
||
|
|
let open Fiber.O in
|
||
|
|
let* x = x in
|
||
|
|
match x with
|
||
|
|
| Ok s -> f s
|
||
|
|
| Error e -> Fiber.return (Error e)
|
||
|
|
;;
|
||
|
|
|
||
|
|
let ( let++ ) x f =
|
||
|
|
let open Fiber.O in
|
||
|
|
let+ x = x in
|
||
|
|
match x with
|
||
|
|
| Ok s -> Ok (f s)
|
||
|
|
| Error e -> Error e
|
||
|
|
;;
|
||
|
|
|
||
|
|
(** Get the status of a server at a given location and apply a function to the
|
||
|
|
list of clients *)
|
||
|
|
let server_response_map ~where ~f =
|
||
|
|
(* TODO: add timeout for status check *)
|
||
|
|
let open Fiber.O in
|
||
|
|
let** conn =
|
||
|
|
Client.Connection.connect where >>| Result.map_error ~f:User_message.to_string
|
||
|
|
in
|
||
|
|
Dune_rpc_impl.Client.client
|
||
|
|
conn
|
||
|
|
(Dune_rpc.Initialize.Request.create ~id:(Dune_rpc.Id.make (Sexp.Atom "status")))
|
||
|
|
~f:(fun session ->
|
||
|
|
let open Fiber.O in
|
||
|
|
let++ response =
|
||
|
|
let** decl =
|
||
|
|
Client.Versioned.prepare_request
|
||
|
|
session
|
||
|
|
(Dune_rpc_private.Decl.Request.witness Dune_rpc_impl.Decl.status)
|
||
|
|
>>| Result.map_error ~f:Dune_rpc_private.Version_error.message
|
||
|
|
in
|
||
|
|
Client.request session decl ()
|
||
|
|
>>| Result.map_error ~f:Dune_rpc.Response.Error.message
|
||
|
|
in
|
||
|
|
f response.Dune_rpc_impl.Decl.Status.clients)
|
||
|
|
;;
|
||
|
|
|
||
|
|
(** Get a list of registered Dunes from the RPC registry *)
|
||
|
|
let registered_dunes () : Dune_rpc.Registry.Dune.t list Fiber.t =
|
||
|
|
let config = Dune_rpc_private.Registry.Config.create (Lazy.force Dune_util.xdg) in
|
||
|
|
let registry = Dune_rpc_private.Registry.create config in
|
||
|
|
let open Fiber.O in
|
||
|
|
let+ _result = Dune_rpc_impl.Poll_active.poll registry in
|
||
|
|
Dune_rpc_private.Registry.current registry
|
||
|
|
;;
|
||
|
|
|
||
|
|
(** The type of server statuses *)
|
||
|
|
type status =
|
||
|
|
{ root : string
|
||
|
|
; pid : Pid.t
|
||
|
|
; result : (int, string) result
|
||
|
|
}
|
||
|
|
|
||
|
|
(** Fetch the status of a single Dune instance *)
|
||
|
|
let get_status (dune : Dune_rpc.Registry.Dune.t) =
|
||
|
|
let root = Dune_rpc_private.Registry.Dune.root dune in
|
||
|
|
let pid = Dune_rpc_private.Registry.Dune.pid dune |> Pid.of_int in
|
||
|
|
let where = Dune_rpc_private.Registry.Dune.where dune in
|
||
|
|
let open Fiber.O in
|
||
|
|
let+ result = server_response_map ~where ~f:List.length in
|
||
|
|
{ root; pid; result }
|
||
|
|
;;
|
||
|
|
|
||
|
|
(** Print a list of statuses to the console *)
|
||
|
|
let print_statuses statuses =
|
||
|
|
List.sort statuses ~compare:(fun x y -> String.compare x.root y.root)
|
||
|
|
|> Pp.concat_map ~sep:Pp.space ~f:(fun { root; pid; result } ->
|
||
|
|
Pp.concat
|
||
|
|
~sep:Pp.space
|
||
|
|
[ Pp.textf "root: %s" root
|
||
|
|
; Pp.enumerate
|
||
|
|
~f:Fun.id
|
||
|
|
[ Pp.textf "pid: %d" (Pid.to_int pid)
|
||
|
|
; Pp.textf
|
||
|
|
"clients: %s"
|
||
|
|
(match result with
|
||
|
|
| Ok n -> string_of_int n
|
||
|
|
| Error e -> e)
|
||
|
|
]
|
||
|
|
])
|
||
|
|
|> Pp.vbox
|
||
|
|
|> List.singleton
|
||
|
|
|> Console.print
|
||
|
|
;;
|
||
|
|
|
||
|
|
let term =
|
||
|
|
let+ builder = Common.Builder.term
|
||
|
|
and+ all =
|
||
|
|
Arg.(
|
||
|
|
value
|
||
|
|
& flag
|
||
|
|
& info
|
||
|
|
[ "all" ]
|
||
|
|
~doc:
|
||
|
|
"Show all running Dune instances together with their root, pids and number \
|
||
|
|
of clients.")
|
||
|
|
in
|
||
|
|
Rpc_common.client_term builder
|
||
|
|
@@ fun () ->
|
||
|
|
let open Fiber.O in
|
||
|
|
if all
|
||
|
|
then
|
||
|
|
let* dunes = registered_dunes () in
|
||
|
|
let+ statuses = Fiber.parallel_map ~f:get_status dunes in
|
||
|
|
print_statuses statuses
|
||
|
|
else (
|
||
|
|
let where = Rpc_common.active_server_exn () in
|
||
|
|
Console.print
|
||
|
|
[ Pp.textf "Server is listening on %s" (Dune_rpc.Where.to_string where)
|
||
|
|
; Pp.text "Connected clients (including this one):"
|
||
|
|
];
|
||
|
|
server_response_map ~where ~f:(fun clients ->
|
||
|
|
List.iter clients ~f:(fun (client, menu) ->
|
||
|
|
let id =
|
||
|
|
let sexp = Dune_rpc.Conv.to_sexp Dune_rpc.Id.sexp client in
|
||
|
|
Sexp.to_string sexp
|
||
|
|
in
|
||
|
|
let message =
|
||
|
|
match (menu : Dune_rpc_impl.Decl.Status.Menu.t) with
|
||
|
|
| Uninitialized -> [ Pp.textf "Client [%s], conducting version negotiation" id ]
|
||
|
|
| Menu menu ->
|
||
|
|
[ Pp.textf "Client [%s] with the following RPC versions:" id
|
||
|
|
; Pp.enumerate menu ~f:(fun (method_, version) ->
|
||
|
|
Pp.textf "%s: %d" method_ version)
|
||
|
|
]
|
||
|
|
in
|
||
|
|
Console.print message))
|
||
|
|
>>| function
|
||
|
|
| Ok () -> ()
|
||
|
|
| Error e -> Printf.printf "Error: %s\n" e)
|
||
|
|
;;
|
||
|
|
|
||
|
|
let info =
|
||
|
|
let doc = "show active connections" in
|
||
|
|
Cmd.info "status" ~doc
|
||
|
|
;;
|
||
|
|
|
||
|
|
let cmd = Cmd.v info term
|