From 9cf1db1c56736baca7f4e87a8c5968873b38b38b Mon Sep 17 00:00:00 2001 From: mattiasdrp Date: Wed, 4 Dec 2024 14:48:01 +0100 Subject: [PATCH 1/6] P2p: Move stat printing from client commands to services with the help of an RPC definition --- .../client_p2p_commands.ml | 87 +---------- src/lib_p2p_services/p2p_services.ml | 145 ++++++++++++++++++ src/lib_p2p_services/p2p_services.mli | 23 +++ tezt/tests/p2p.ml | 34 ++-- 4 files changed, 200 insertions(+), 89 deletions(-) diff --git a/src/lib_client_commands/client_p2p_commands.ml b/src/lib_client_commands/client_p2p_commands.ml index 699c3d6a16a3..b1c0fb2b0d5a 100644 --- a/src/lib_client_commands/client_p2p_commands.ml +++ b/src/lib_client_commands/client_p2p_commands.ml @@ -29,9 +29,6 @@ let group = title = "Commands for monitoring and controlling p2p-layer state"; } -let pp_connection_info ppf conn = - P2p_connection.Info.pp (fun _ _ -> ()) ppf conn - let addr_parameter = let open Tezos_clic in param @@ -48,6 +45,12 @@ let p2p_peer_id_param ~name ~desc t = Lwt.return (P2p_peer.Id.of_b58check str))) t +let p2p_stat () (cctxt : #Client_context.full) = + let open Lwt_result_syntax in + let* full_stats = P2p_services.Full_stat.full_stat cctxt in + let*! () = cctxt#message "%s" (P2p_services.Full_stat.to_string full_stats) in + return_unit + let commands () = let open Lwt_result_syntax in let open Tezos_clic in @@ -57,83 +60,7 @@ let commands () = ~desc:"show global network status" no_options (prefixes ["p2p"; "stat"] stop) - (fun () (cctxt : #Client_context.full) -> - let* stat = Shell_services.P2p.stat cctxt in - let* conns = Shell_services.P2p.Connections.list cctxt in - let* peers = Shell_services.P2p.Peers.list cctxt in - let* points = Shell_services.P2p.Points.list cctxt in - let*! () = cctxt#message "GLOBAL STATS" in - let*! () = cctxt#message " %a" P2p_stat.pp stat in - let*! () = cctxt#message "CONNECTIONS" in - let incoming, outgoing = - List.partition (fun c -> c.P2p_connection.Info.incoming) conns - in - let*! () = - List.iter_s - (fun conn -> cctxt#message " %a" pp_connection_info conn) - incoming - in - let*! () = - List.iter_s - (fun conn -> cctxt#message " %a" pp_connection_info conn) - outgoing - in - let*! () = cctxt#message "KNOWN PEERS" in - let*! () = - List.iter_s - (fun (p, pi) -> - cctxt#message - " %a %.0f %a %a %s" - P2p_peer.State.pp_digram - pi.P2p_peer.Info.state - pi.score - P2p_peer.Id.pp - p - P2p_stat.pp - pi.stat - (if pi.trusted then "★" else " ")) - peers - in - let*! () = cctxt#message "KNOWN POINTS" in - let*! () = - List.iter_s - (fun (p, pi) -> - match pi.P2p_point.Info.state with - | Running peer_id -> - cctxt#message - " %a %a %a %s" - P2p_point.State.pp_digram - pi.state - P2p_point.Id.pp - p - P2p_peer.Id.pp - peer_id - (if pi.trusted then "★" else " ") - | _ -> ( - match pi.last_seen with - | Some (peer_id, ts) -> - cctxt#message - " %a %a (last seen: %a %a) %s" - P2p_point.State.pp_digram - pi.state - P2p_point.Id.pp - p - P2p_peer.Id.pp - peer_id - Time.System.pp_hum - ts - (if pi.trusted then "★" else " ") - | None -> - cctxt#message - " %a %a %s" - P2p_point.State.pp_digram - pi.state - P2p_point.Id.pp - p - (if pi.trusted then "★" else " "))) - points - in - return_unit); + p2p_stat; command ~group ~desc:"Connect to a new point." diff --git a/src/lib_p2p_services/p2p_services.ml b/src/lib_p2p_services/p2p_services.ml index 07a66101c7e2..ec9218eaa205 100644 --- a/src/lib_p2p_services/p2p_services.ml +++ b/src/lib_p2p_services/p2p_services.ml @@ -354,6 +354,151 @@ module Peers = struct let banned ctxt peer_id = make_call1 S.banned ctxt peer_id () () end +module Full_stat = struct + type t = { + stat : P2p_stat.t; + incoming_connections : Connection_metadata.t P2p_connection.Info.t list; + outgoing_connections : Connection_metadata.t P2p_connection.Info.t list; + peers : + (P2p_peer.Id.t * (Peer_metadata.t, Connection_metadata.t) P2p_peer.Info.t) + list; + points : (P2p_point.Id.t * P2p_point.Info.t) list; + } + + let encoding = + let open Data_encoding in + def + "client_p2p_stat" + ~description:"Stored statistics about the p2p network." + @@ conv + (fun {stat; incoming_connections; outgoing_connections; peers; points} -> + (stat, incoming_connections, outgoing_connections, peers, points)) + (fun (stat, incoming_connections, outgoing_connections, peers, points) -> + {stat; incoming_connections; outgoing_connections; peers; points}) + (obj5 + (req "stat" P2p_stat.encoding) + (req + "incoming_connections" + (list + (P2p_connection.Info.encoding Connection_metadata.encoding))) + (req + "outgoing_connections" + (list + (P2p_connection.Info.encoding Connection_metadata.encoding))) + (req + "peers" + (list + (tup2 + P2p_peer.Id.encoding + (P2p_peer.Info.encoding + Peer_metadata.encoding + Connection_metadata.encoding)))) + (req + "points" + (list (tup2 P2p_point.Id.encoding P2p_point.Info.encoding)))) + + let pp_list pp ppf l = + match l with + | [] -> () + | l -> + Format.fprintf ppf "@," ; + Format.(pp_print_list ~pp_sep:pp_print_cut pp ppf) l + + let pp_peer ppf (p, pi) = + Format.fprintf + ppf + "%a %.0f %a %a %s" + P2p_peer.State.pp_digram + pi.P2p_peer.Info.state + pi.score + P2p_peer.Id.pp + p + P2p_stat.pp + pi.stat + (if pi.trusted then "★" else " ") + + let pp_peers ppf peers = (pp_list pp_peer ppf) peers + + let pp_point ppf (p, pi) = + match pi.P2p_point.Info.state with + | Running peer_id -> + Format.fprintf + ppf + "%a %a %a %s" + P2p_point.State.pp_digram + pi.state + P2p_point.Id.pp + p + P2p_peer.Id.pp + peer_id + (if pi.trusted then "★" else " ") + | _ -> ( + match pi.last_seen with + | Some (peer_id, ts) -> + Format.fprintf + ppf + "%a %a (last seen: %a %a) %s" + P2p_point.State.pp_digram + pi.state + P2p_point.Id.pp + p + P2p_peer.Id.pp + peer_id + Time.System.pp_hum + ts + (if pi.trusted then "★" else " ") + | None -> + Format.fprintf + ppf + "%a %a %s" + P2p_point.State.pp_digram + pi.state + P2p_point.Id.pp + p + (if pi.trusted then "★" else " ")) + + let pp_connection_info ppf conn = + P2p_connection.Info.pp (fun _ _ -> ()) ppf conn + + let to_string + {stat; incoming_connections; outgoing_connections; peers; points} = + let reset = + Tezos_stdlib.Pretty_printing.add_ansi_marking Format.str_formatter + in + Format.fprintf + Format.str_formatter + "@[GLOBAL STATS@,\ + %a@]@,\ + @[CONNECTIONS@,\ + @[INCOMING%a@]@,\ + @[OUTGOING%a@]@]@,\ + @[KNOWN PEERS%a@]@,\ + @[KNOWN POINTS%a@." + P2p_stat.pp + stat + (pp_list pp_connection_info) + incoming_connections + (pp_list pp_connection_info) + outgoing_connections + pp_peers + peers + (pp_list pp_point) + points ; + reset () ; + Format.flush_str_formatter () + + module S = struct + let full_stat = + Tezos_rpc.Service.get_service + ~description:"Full network statistics." + ~query:Tezos_rpc.Query.empty + ~output:encoding + Tezos_rpc.Path.(root / "network" / "full_stat") + end + + let full_stat ctxt = make_call S.full_stat ctxt () () () +end + module ACL = struct type ip_list = {ips : Ipaddr.V6.t list; not_reliable_since : Ptime.t option} diff --git a/src/lib_p2p_services/p2p_services.mli b/src/lib_p2p_services/p2p_services.mli index 1dca13ed4b15..0de11e1c12a1 100644 --- a/src/lib_p2p_services/p2p_services.mli +++ b/src/lib_p2p_services/p2p_services.mli @@ -241,6 +241,29 @@ module Peers : sig end end +module Full_stat : sig + type t = { + stat : P2p_stat.t; + incoming_connections : Connection_metadata.t P2p_connection.Info.t list; + outgoing_connections : Connection_metadata.t P2p_connection.Info.t list; + peers : + (P2p_peer.Id.t * (Peer_metadata.t, Connection_metadata.t) P2p_peer.Info.t) + list; + points : (P2p_point.Id.t * P2p_point.Info.t) list; + } + + val encoding : t Data_encoding.t + + val to_string : t -> string + + module S : sig + val full_stat : + ([`GET], unit, unit, unit, unit, t) Tezos_rpc.Service.service + end + + val full_stat : #simple -> t tzresult Lwt.t +end + module ACL : sig (** Structure that provides a friendly and bounded list of currently greylisted IPs. *) diff --git a/tezt/tests/p2p.ml b/tezt/tests/p2p.ml index ae6f45b2b0ac..3cfaf9e2be0a 100644 --- a/tezt/tests/p2p.ml +++ b/tezt/tests/p2p.ml @@ -1198,13 +1198,14 @@ module P2p_stat = struct } let parse_p2p_stat client_output = - let fail ~__LOC__ line = + let fail ~__LOC__ section line = Test.fail ~__LOC__ - "[parse_p2p_stat] Could not parse line:\n\ + "[parse_p2p_stat] Could not parse %s from line:\n\ %s\n\ \ when parsing client output:\n\ %s" + section line client_output in @@ -1212,26 +1213,41 @@ module P2p_stat = struct let _prefix, lines = span (( <> ) "GLOBAL STATS") lines in let _global_stats, lines = span (( <> ) "CONNECTIONS") lines in let connections, lines = span (( <> ) "KNOWN PEERS") lines in + let incoming, outgoing = span (( <> ) " OUTGOING") connections in let known_peers, known_points = span (( <> ) "KNOWN POINTS") lines in - let connections = + let incoming_connections = (* Example: *) (* ↘ idscnVnp4ZgHbxBem9ZkaGtmVDdPt3 127.0.0.1:16392 (TEZOS.2 (p2p: 1)) *\) *) List.map (fun line -> match line =~* rex "(id\\w+)" with | Some peer_id -> Peer_id peer_id - | None -> fail ~__LOC__ line) - (List.tl connections) + | None -> fail ~__LOC__ "incoming connections" line) + (* Removing the lines: + - CONNECTIONS + - INCOMING *) + (List.tl (List.tl incoming)) in + let outgoing_connections = + (* Example: *) + (* ↘ idscnVnp4ZgHbxBem9ZkaGtmVDdPt3 127.0.0.1:16392 (TEZOS.2 (p2p: 1)) *\) *) + List.map + (fun line -> + match line =~* rex "(id\\w+)" with + | Some peer_id -> Peer_id peer_id + | None -> fail ~__LOC__ "outgoing connections" line) + (List.tl outgoing) + in + let connections = incoming_connections @ outgoing_connections in let known_peers = (* Example: *) (* ⚏ 1 idtn1bQKkQvzgPH5zbD86Bi3eTgQhB ↗ 0 B (0 B/s) ↘ 0 B (0 B/s) *\) *) List.map (fun line -> - match line =~** rex "(⚏|⚌).* (id\\w+)" with + match line =~** rex " (⚏|⚌).* (id\\w+)" with | Some (connection, peer_id) -> {id = Peer_id peer_id; connected = connection = "⚌"} - | None -> fail ~__LOC__ line) + | None -> fail ~__LOC__ "peers" line) (List.tl known_peers) in let known_points = @@ -1239,13 +1255,13 @@ module P2p_stat = struct (* ⚏ 127.0.0.1:16388 (last seen: idtn1bQKkQvzgPH5zbD86Bi3eTgQhB 2023-01-16T13:23:08.499-00:00) *) List.map (fun line -> - match line =~*** rex "(⚏|⚌)\\s+(\\S+:\\S+).* (id\\w+)" with + match line =~*** rex " (⚏|⚌)\\s+(\\S+:\\S+).* (id\\w+)" with | Some (connection, point_id, peer_id) -> { id = point_id_of_string point_id; peer = {connected = connection = "⚌"; id = Peer_id peer_id}; } - | None -> fail ~__LOC__ line) + | None -> fail ~__LOC__ "points" line) (List.tl known_points) in {connections; known_peers; known_points} -- GitLab From ecef781970f7e071fce662513216ea58d9dc6285 Mon Sep 17 00:00:00 2001 From: mattiasdrp Date: Wed, 4 Dec 2024 14:48:56 +0100 Subject: [PATCH 2/6] P2p: Pretty print p2p stat with colours and emphasis --- src/lib_base/p2p_peer.ml | 6 +++--- src/lib_base/p2p_stat.ml | 15 ++++++--------- src/lib_crypto/helpers.ml | 4 ++-- src/lib_p2p_services/p2p_services.ml | 13 ++++++++++++- src/lib_stdlib/pretty_printing.ml | 4 ++++ src/lib_stdlib/pretty_printing.mli | 2 ++ tezt/tests/p2p.ml | 7 +++++-- 7 files changed, 34 insertions(+), 17 deletions(-) diff --git a/src/lib_base/p2p_peer.ml b/src/lib_base/p2p_peer.ml index 80cc2e1ef5b7..a7c905f8c769 100644 --- a/src/lib_base/p2p_peer.ml +++ b/src/lib_base/p2p_peer.ml @@ -51,9 +51,9 @@ module State = struct type t = Accepted | Running | Disconnected let pp_digram ppf = function - | Accepted -> Format.fprintf ppf "⚎" - | Running -> Format.fprintf ppf "⚌" - | Disconnected -> Format.fprintf ppf "⚏" + | Accepted -> Format.fprintf ppf "@{⚎@}" + | Running -> Format.fprintf ppf "@{⚌@}" + | Disconnected -> Format.fprintf ppf "@{⚏@}" let encoding = let open Data_encoding in diff --git a/src/lib_base/p2p_stat.ml b/src/lib_base/p2p_stat.ml index 738bb7c884e0..a2d99e5fb6cc 100644 --- a/src/lib_base/p2p_stat.ml +++ b/src/lib_base/p2p_stat.ml @@ -48,18 +48,15 @@ let print_size64 ppf sz = else if sz < shift_left 1L 40 then Format.fprintf ppf "%.2f GiB" (ratio 30) else Format.fprintf ppf "%.2f TiB" (ratio 40) +let pp_flow total current = + Format.asprintf "%a (%a/s)" print_size64 total print_size current + let pp ppf stat = Format.fprintf ppf - "↗ %a (%a/s) ↘ %a (%a/s)" - print_size64 - stat.total_sent - print_size - stat.current_outflow - print_size64 - stat.total_recv - print_size - stat.current_inflow + "@{@{↗@} %27s@} @{@{↘@} %27s@} " + (pp_flow stat.total_sent stat.current_outflow) + (pp_flow stat.total_recv stat.current_inflow) let encoding = let open Data_encoding in diff --git a/src/lib_crypto/helpers.ml b/src/lib_crypto/helpers.ml index 12955b77e0ef..218981d58234 100644 --- a/src/lib_crypto/helpers.ml +++ b/src/lib_crypto/helpers.ml @@ -122,9 +122,9 @@ module MakeEncoder (H : sig val raw_encoding : t Data_encoding.t end) = struct - let pp ppf t = Format.pp_print_string ppf (H.to_b58check t) + let pp ppf t = Format.fprintf ppf "@{%s@}" (H.to_b58check t) - let pp_short ppf t = Format.pp_print_string ppf (H.to_short_b58check t) + let pp_short ppf t = Format.fprintf ppf "@{%s@}" (H.to_short_b58check t) let encoding = let open Data_encoding in diff --git a/src/lib_p2p_services/p2p_services.ml b/src/lib_p2p_services/p2p_services.ml index ec9218eaa205..0be4c7cf87a1 100644 --- a/src/lib_p2p_services/p2p_services.ml +++ b/src/lib_p2p_services/p2p_services.ml @@ -417,7 +417,18 @@ module Full_stat = struct pi.stat (if pi.trusted then "★" else " ") - let pp_peers ppf peers = (pp_list pp_peer ppf) peers + let pp_peers ppf peers = + Format.fprintf + ppf + "@,@[@{St Sc %a%a%a Tr@}%a@]" + (Tezos_stdlib.Pretty_printing.pp_centered 30) + "Peer Id" + (Tezos_stdlib.Pretty_printing.pp_centered 30) + "Upload" + (Tezos_stdlib.Pretty_printing.pp_centered 30) + "Download" + (pp_list pp_peer) + peers let pp_point ppf (p, pi) = match pi.P2p_point.Info.state with diff --git a/src/lib_stdlib/pretty_printing.ml b/src/lib_stdlib/pretty_printing.ml index 7dd15d731e38..3ce799685db0 100644 --- a/src/lib_stdlib/pretty_printing.ml +++ b/src/lib_stdlib/pretty_printing.ml @@ -208,3 +208,7 @@ module Semantic_tag = struct end include Semantic_tag + +let pp_centered width ppf s = + let start = (width / 2) + (String.length s / 2) in + Format.fprintf ppf "%*s%*s" start s (width - start) "" diff --git a/src/lib_stdlib/pretty_printing.mli b/src/lib_stdlib/pretty_printing.mli index 12c014bea273..080ea6fa0036 100644 --- a/src/lib_stdlib/pretty_printing.mli +++ b/src/lib_stdlib/pretty_printing.mli @@ -36,3 +36,5 @@ \] *) val add_ansi_marking : Format.formatter -> unit -> unit + +val pp_centered : int -> Format.formatter -> string -> unit diff --git a/tezt/tests/p2p.ml b/tezt/tests/p2p.ml index 3cfaf9e2be0a..a6cc22f75e18 100644 --- a/tezt/tests/p2p.ml +++ b/tezt/tests/p2p.ml @@ -1230,7 +1230,7 @@ module P2p_stat = struct in let outgoing_connections = (* Example: *) - (* ↘ idscnVnp4ZgHbxBem9ZkaGtmVDdPt3 127.0.0.1:16392 (TEZOS.2 (p2p: 1)) *\) *) + (* ↗ idscnVnp4ZgHbxBem9ZkaGtmVDdPt3 127.0.0.1:16392 (TEZOS.2 (p2p: 1)) *\) *) List.map (fun line -> match line =~* rex "(id\\w+)" with @@ -1248,7 +1248,10 @@ module P2p_stat = struct | Some (connection, peer_id) -> {id = Peer_id peer_id; connected = connection = "⚌"} | None -> fail ~__LOC__ "peers" line) - (List.tl known_peers) + (* Removing the lines: + - KNOWNPEERS + - St Sc Peer Id Upload Download Tr *) + (List.tl (List.tl known_peers)) in let known_points = (* Example: *) -- GitLab From 197e9e681649617e7b454d766cf6a8be697ab932 Mon Sep 17 00:00:00 2001 From: mattiasdrp Date: Wed, 4 Dec 2024 10:53:41 +0100 Subject: [PATCH 3/6] Add a colorize flag option to client commands (only p2p stat for now) --- src/lib_client_commands/client_commands.ml | 3 +++ src/lib_client_commands/client_commands.mli | 3 +++ src/lib_client_commands/client_p2p_commands.ml | 12 +++++++++--- src/lib_p2p_services/p2p_services.ml | 6 ++++-- src/lib_p2p_services/p2p_services.mli | 2 +- 5 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/lib_client_commands/client_commands.ml b/src/lib_client_commands/client_commands.ml index c7bc47d017df..69bef384cc86 100644 --- a/src/lib_client_commands/client_commands.ml +++ b/src/lib_client_commands/client_commands.ml @@ -43,6 +43,9 @@ let register name commands = Protocol_hash.Table.replace versions name (fun network_opt -> commands network_opt @ previous network_opt) +let dont_colorize () = + Tezos_clic.switch ~doc:"Don't colorize the output" ~long:"no-color" () + let commands_for_version version = WithExceptions.Option.to_exn ~none:Version_not_found @@ Protocol_hash.Table.find versions version diff --git a/src/lib_client_commands/client_commands.mli b/src/lib_client_commands/client_commands.mli index 650b9ab101b2..5385d1824fe0 100644 --- a/src/lib_client_commands/client_commands.mli +++ b/src/lib_client_commands/client_commands.mli @@ -35,5 +35,8 @@ val register : Protocol_hash.t -> (network option -> command list) -> unit val commands_for_version : Protocol_hash.t -> network option -> command list +(** Tezos_clic option to disable coloring *) +val dont_colorize : unit -> (bool, 'a) Tezos_clic.arg + val get_versions : unit -> (Protocol_hash.t * (network option -> command list)) Seq.t diff --git a/src/lib_client_commands/client_p2p_commands.ml b/src/lib_client_commands/client_p2p_commands.ml index b1c0fb2b0d5a..6d28e81e5b79 100644 --- a/src/lib_client_commands/client_p2p_commands.ml +++ b/src/lib_client_commands/client_p2p_commands.ml @@ -45,10 +45,16 @@ let p2p_peer_id_param ~name ~desc t = Lwt.return (P2p_peer.Id.of_b58check str))) t -let p2p_stat () (cctxt : #Client_context.full) = +let p2p_stat dont_colorize (cctxt : #Client_context.full) = let open Lwt_result_syntax in let* full_stats = P2p_services.Full_stat.full_stat cctxt in - let*! () = cctxt#message "%s" (P2p_services.Full_stat.to_string full_stats) in + let*! () = + cctxt#message + "%s" + (P2p_services.Full_stat.to_string + ~colorize:((not dont_colorize) && Unix.isatty Unix.stdout) + full_stats) + in return_unit let commands () = @@ -58,7 +64,7 @@ let commands () = command ~group ~desc:"show global network status" - no_options + (args1 (Client_commands.dont_colorize ())) (prefixes ["p2p"; "stat"] stop) p2p_stat; command diff --git a/src/lib_p2p_services/p2p_services.ml b/src/lib_p2p_services/p2p_services.ml index 0be4c7cf87a1..40371623f3b8 100644 --- a/src/lib_p2p_services/p2p_services.ml +++ b/src/lib_p2p_services/p2p_services.ml @@ -471,10 +471,12 @@ module Full_stat = struct let pp_connection_info ppf conn = P2p_connection.Info.pp (fun _ _ -> ()) ppf conn - let to_string + let to_string ~colorize {stat; incoming_connections; outgoing_connections; peers; points} = let reset = - Tezos_stdlib.Pretty_printing.add_ansi_marking Format.str_formatter + if colorize then + Tezos_stdlib.Pretty_printing.add_ansi_marking Format.str_formatter + else fun () -> () in Format.fprintf Format.str_formatter diff --git a/src/lib_p2p_services/p2p_services.mli b/src/lib_p2p_services/p2p_services.mli index 0de11e1c12a1..984c80b10486 100644 --- a/src/lib_p2p_services/p2p_services.mli +++ b/src/lib_p2p_services/p2p_services.mli @@ -254,7 +254,7 @@ module Full_stat : sig val encoding : t Data_encoding.t - val to_string : t -> string + val to_string : colorize:bool -> t -> string module S : sig val full_stat : -- GitLab From 3f7f98ab8642ae14ebba50b16f35bc6ec5e7e02f Mon Sep 17 00:00:00 2001 From: mattiasdrp Date: Wed, 4 Dec 2024 14:34:48 +0100 Subject: [PATCH 4/6] P2p_directory: Move some code blocks to their own functions These functions will be reused in a full stat RPC --- src/lib_p2p/p2p_directory.ml | 92 ++++++++++++++++++++++-------------- 1 file changed, 56 insertions(+), 36 deletions(-) diff --git a/src/lib_p2p/p2p_directory.ml b/src/lib_p2p/p2p_directory.ml index bf3800a9e632..e8a5b4875509 100644 --- a/src/lib_p2p/p2p_directory.ml +++ b/src/lib_p2p/p2p_directory.ml @@ -31,6 +31,57 @@ let info_of_peer_info = P2p_pool.Peers.info_of_peer_info let build_rpc_directory net = let open Lwt_result_syntax in let dir = Tezos_rpc.Directory.empty in + + (* Utility functions *) + let get_stat () () = + match P2p.connect_handler net with + | None -> tzfail P2p_errors.P2p_layer_disabled + | Some connect_handler -> return (P2p_connect_handler.stat connect_handler) + in + + let get_connections () () = + match P2p.pool net with + | None -> tzfail P2p_errors.P2p_layer_disabled + | Some pool -> + return + @@ P2p_pool.Connection.fold pool ~init:[] ~f:(fun _peer_id c acc -> + P2p_conn.info c :: acc) + in + + let get_peers_list ?q () = + match P2p.pool net with + | None -> tzfail P2p_errors.P2p_layer_disabled + | Some pool -> + return + @@ P2p_pool.Peers.fold_known pool ~init:[] ~f:(fun peer_id i a -> + let info = info_of_peer_info pool i in + match q with + | None -> (peer_id, info) :: a + | Some q -> ( + match q#filters with + | [] -> (peer_id, info) :: a + | filters when P2p_peer.State.filter filters info.state -> + (peer_id, info) :: a + | _ -> a)) + in + + let get_points_list ?q () = + match P2p.pool net with + | None -> tzfail P2p_errors.P2p_layer_disabled + | Some pool -> + return + @@ P2p_pool.Points.fold_known pool ~init:[] ~f:(fun point i a -> + let info = info_of_point_info i in + match q with + | None -> (point, info) :: a + | Some q -> ( + match q#filters with + | [] -> (point, info) :: a + | filters when P2p_point.State.filter filters info.state -> + (point, info) :: a + | _ -> a)) + in + (* Network : Global *) let dir = Tezos_rpc.Directory.register0 dir P2p_services.S.self (fun () () -> @@ -38,13 +89,7 @@ let build_rpc_directory net = | None -> tzfail P2p_errors.P2p_layer_disabled | Some pool -> return (P2p_pool.config pool).identity.peer_id) in - let dir = - Tezos_rpc.Directory.register0 dir P2p_services.S.stat (fun () () -> - match P2p.connect_handler net with - | None -> tzfail P2p_errors.P2p_layer_disabled - | Some connect_handler -> - return (P2p_connect_handler.stat connect_handler)) - in + let dir = Tezos_rpc.Directory.register0 dir P2p_services.S.stat get_stat in let dir = Tezos_rpc.Directory.gen_register0 dir P2p_services.S.events (fun () () -> let stream, stopper = P2p.watcher net in @@ -94,29 +139,14 @@ let build_rpc_directory net = Tezos_rpc.Directory.register0 dir P2p_services.Connections.S.list - (fun () () -> - match P2p.pool net with - | None -> tzfail P2p_errors.P2p_layer_disabled - | Some pool -> - return - @@ P2p_pool.Connection.fold pool ~init:[] ~f:(fun _peer_id c acc -> - P2p_conn.info c :: acc)) + get_connections in (* Network : Peer_id *) let dir = Tezos_rpc.Directory.register0 dir P2p_services.Peers.S.list (fun q () -> - match P2p.pool net with - | None -> tzfail P2p_errors.P2p_layer_disabled - | Some pool -> - return - @@ P2p_pool.Peers.fold_known pool ~init:[] ~f:(fun peer_id i a -> - let info = info_of_peer_info pool i in - match q#filters with - | [] -> (peer_id, info) :: a - | filters when P2p_peer.State.filter filters info.state -> - (peer_id, info) :: a - | _ -> a)) + get_peers_list ~q ()) in + let dir = Tezos_rpc.Directory.opt_register1 dir @@ -211,17 +241,7 @@ let build_rpc_directory net = (* Network : Point *) let dir = Tezos_rpc.Directory.register0 dir P2p_services.Points.S.list (fun q () -> - match P2p.pool net with - | None -> tzfail P2p_errors.P2p_layer_disabled - | Some pool -> - return - @@ P2p_pool.Points.fold_known pool ~init:[] ~f:(fun point i a -> - let info = info_of_point_info i in - match q#filters with - | [] -> (point, info) :: a - | filters when P2p_point.State.filter filters info.state -> - (point, info) :: a - | _ -> a)) + get_points_list ~q ()) in let dir = Tezos_rpc.Directory.opt_register1 -- GitLab From 71c914ede07ffe24e4e08bb992097adfe4f0ee13 Mon Sep 17 00:00:00 2001 From: mattiasdrp Date: Wed, 4 Dec 2024 14:35:41 +0100 Subject: [PATCH 5/6] P2p_directory: Register RPC call to network/full/stat --- src/lib_p2p/p2p_directory.ml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/lib_p2p/p2p_directory.ml b/src/lib_p2p/p2p_directory.ml index e8a5b4875509..2a87344e1553 100644 --- a/src/lib_p2p/p2p_directory.ml +++ b/src/lib_p2p/p2p_directory.ml @@ -110,6 +110,23 @@ let build_rpc_directory net = in return_unit) in + let dir = + Tezos_rpc.Directory.register0 + dir + P2p_services.Full_stat.S.full_stat + (fun () () -> + let* stat = get_stat () () in + let* connections = get_connections () () in + let* peers = get_peers_list () in + let* points = get_points_list () in + let incoming_connections, outgoing_connections = + List.partition (fun c -> c.P2p_connection.Info.incoming) connections + in + Lwt.return_ok + P2p_services.Full_stat. + {stat; incoming_connections; outgoing_connections; peers; points}) + in + (* Network : Connection *) let dir = Tezos_rpc.Directory.opt_register1 -- GitLab From dc3302a72290252903d048a92bc9d10e2e679237 Mon Sep 17 00:00:00 2001 From: mattiasdrp Date: Tue, 24 Dec 2024 12:27:51 +0100 Subject: [PATCH 6/6] Add a handles function to the pretty_printing module This allows to check that a tag that is not recognized by tezos_clic doesn't lead to a failure if it's a tag that should be handled by Pretty_printing --- src/lib_clic/tezos_clic.ml | 2 ++ src/lib_stdlib/pretty_printing.ml | 38 ++++++++++++++++++++++++++++++ src/lib_stdlib/pretty_printing.mli | 9 +++++++ 3 files changed, 49 insertions(+) diff --git a/src/lib_clic/tezos_clic.ml b/src/lib_clic/tezos_clic.ml index 6c06805e375c..66f245b0c3ed 100644 --- a/src/lib_clic/tezos_clic.ml +++ b/src/lib_clic/tezos_clic.ml @@ -479,6 +479,7 @@ let setup_formatter ppf format verbosity = | "details" -> push_level (Details, op) | "short" -> push_level (Short, op) | "terse" -> push_level (Terse, op) + | tag when Pretty_printing.handles tag -> () | tag -> Stdlib.failwith ("Tezos_clic: invalid semantic string tag <" ^ tag ^ ">") @@ -504,6 +505,7 @@ let setup_formatter ppf format verbosity = | Format.String_tag "=short" | Format.String_tag "=terse" -> pop_level () + | Format.String_tag tag when Pretty_printing.handles tag -> () | Format.String_tag tag -> Stdlib.failwith ("Tezos_clic: invalid semantic string tag <" ^ tag ^ ">") diff --git a/src/lib_stdlib/pretty_printing.ml b/src/lib_stdlib/pretty_printing.ml index 3ce799685db0..4f4799c36b6b 100644 --- a/src/lib_stdlib/pretty_printing.ml +++ b/src/lib_stdlib/pretty_printing.ml @@ -6,6 +6,44 @@ (*****************************************************************************) open Format +module Handled_tags = Set.Make (String) + +let handled_tags = + let colors = + [ + "default"; + "black"; + "blue"; + "cyan"; + "green"; + "magenta"; + "red"; + "white"; + "yellow"; + ] + in + let grounds = ["fg"; "bg"] in + let ansi_colors = + List.fold_left + (fun acc ground -> + List.fold_left + (fun acc color -> (ground ^ "_" ^ color) :: acc) + acc + colors) + [] + grounds + in + let emphasis = ["bold"; "italic"; "underline"] in + let negate tag = "/" ^ tag in + let shorten tag = String.sub tag 0 1 in + List.fold_left + (fun acc tag -> + tag :: shorten tag :: negate tag :: negate (shorten tag) :: acc) + ansi_colors + emphasis + |> Handled_tags.of_list + +let handles tag = Handled_tags.mem tag handled_tags module type Attribute = sig type t diff --git a/src/lib_stdlib/pretty_printing.mli b/src/lib_stdlib/pretty_printing.mli index 080ea6fa0036..3cf4cdc6d086 100644 --- a/src/lib_stdlib/pretty_printing.mli +++ b/src/lib_stdlib/pretty_printing.mli @@ -38,3 +38,12 @@ val add_ansi_marking : Format.formatter -> unit -> unit val pp_centered : int -> Format.formatter -> string -> unit + +module Handled_tags : Set.S with type elt = string + +(** [handles tag] returns [true] if [tag] is handled by this module. + + This is useful when there's a possibility that a different handler for + semantic tags is defined or used with a function that already uses this + module to ignore these tags (see {!module:Tezos_base.Tezos_clic}) *) +val handles : string -> bool -- GitLab