From 5c1c410cff3dd0cfe65f33714f8092f2fc91b5c7 Mon Sep 17 00:00:00 2001
From: "pavel.uhanov" <pavel.uhanov@demlabs.net>
Date: Tue, 18 Mar 2025 12:06:10 +0300
Subject: [PATCH] [*] add node list -rpc command

---
 modules/net/dap_chain_node_cli_cmd.c     | 27 ++++++++++++-----
 modules/net/dap_chain_node_rpc.c         | 37 ++++++++++++++++++++++++
 modules/net/include/dap_chain_node_rpc.h |  3 +-
 3 files changed, 59 insertions(+), 8 deletions(-)

diff --git a/modules/net/dap_chain_node_cli_cmd.c b/modules/net/dap_chain_node_cli_cmd.c
index a86f34cdcc..5faab630d1 100644
--- a/modules/net/dap_chain_node_cli_cmd.c
+++ b/modules/net/dap_chain_node_cli_cmd.c
@@ -837,16 +837,16 @@ int com_node(int a_argc, char ** a_argv, void **a_str_reply)
 {
     enum {
         CMD_NONE, CMD_ADD, CMD_DEL, CMD_ALIAS, CMD_HANDSHAKE, CMD_CONNECT, CMD_LIST, CMD_DUMP, CMD_CONNECTIONS, CMD_BALANCER,
-        CMD_BAN, CMD_UNBAN, CMD_BANLIST, CMD_ADD_RPC
+        CMD_BAN, CMD_UNBAN, CMD_BANLIST, CMD_ADD_RPC, CMD_LIST_RPC
     };
     int arg_index = 1;
     int cmd_num = CMD_NONE;
     if(dap_cli_server_cmd_find_option_val(a_argv, arg_index, dap_min(a_argc, arg_index + 1), "add", NULL)) {
-        cmd_num = CMD_ADD;
+        if (dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-rpc", NULL))
+            cmd_num = CMD_ADD_RPC;
+        else
+            cmd_num = CMD_ADD;
     }
-    else if(dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "add_rpc", NULL)) {
-        cmd_num = CMD_ADD_RPC;
-    } 
     else if(dap_cli_server_cmd_find_option_val(a_argv, arg_index, dap_min(a_argc, arg_index + 1), "del", NULL)) {
         cmd_num = CMD_DEL;
     } // find  add parameter ('alias' or 'handshake')
@@ -860,7 +860,10 @@ int com_node(int a_argc, char ** a_argv, void **a_str_reply)
         cmd_num = CMD_ALIAS;
     }
     else if(dap_cli_server_cmd_find_option_val(a_argv, arg_index, dap_min(a_argc, arg_index + 1), "list", NULL)) {
-        cmd_num = CMD_LIST;
+        if (dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-rpc", NULL))
+            cmd_num = CMD_LIST_RPC;
+        else
+            cmd_num = CMD_LIST;
     }
     else if(dap_cli_server_cmd_find_option_val(a_argv, arg_index, dap_min(a_argc, arg_index + 1), "dump", NULL)) {
         cmd_num = CMD_DUMP;
@@ -888,7 +891,7 @@ int com_node(int a_argc, char ** a_argv, void **a_str_reply)
     dap_chain_net_t *l_net = NULL;
 
     int l_net_parse_val = dap_chain_node_cli_cmd_values_parse_net_chain(&arg_index, a_argc, a_argv, a_str_reply, NULL, &l_net, CHAIN_TYPE_INVALID);
-    if(l_net_parse_val < 0 && cmd_num != CMD_BANLIST && cmd_num != CMD_ADD_RPC) {
+    if(l_net_parse_val < 0 && cmd_num != CMD_BANLIST && cmd_num != CMD_ADD_RPC && cmd_num != CMD_LIST_RPC) {
         if ((cmd_num != CMD_CONNECTIONS && cmd_num != CMD_DUMP) || l_net_parse_val == -102)
             return -11;
     }
@@ -1032,6 +1035,16 @@ int com_node(int a_argc, char ** a_argv, void **a_str_reply)
         bool l_is_full = dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-full", NULL);
         return s_node_info_list_with_reply(l_net, &l_node_addr, l_is_full, alias_str, a_str_reply);
     }
+    case CMD_LIST_RPC: {
+        dap_string_t *l_string_reply = dap_chain_node_rpc_list();
+        if (!l_string_reply) {
+            dap_cli_server_cmd_set_reply_text(a_str_reply, "Error in rpc node list forming");
+            return -1;
+        }
+        dap_cli_server_cmd_set_reply_text(a_str_reply, "%s", l_string_reply->str);
+        dap_string_free(l_string_reply, true);
+        return 0;
+    }
     case CMD_DUMP: {
         dap_string_t *l_string_reply = dap_chain_node_states_info_read(l_net, l_node_info->address);
         dap_cli_server_cmd_set_reply_text(a_str_reply, "%s", l_string_reply->str);
diff --git a/modules/net/dap_chain_node_rpc.c b/modules/net/dap_chain_node_rpc.c
index 9525dbe861..eb999a33c2 100644
--- a/modules/net/dap_chain_node_rpc.c
+++ b/modules/net/dap_chain_node_rpc.c
@@ -198,4 +198,41 @@ int dap_chain_node_rpc_info_save(dap_chain_node_info_t *a_node_info)
                                  dap_stream_node_addr_to_str_static(a_node_info->address),
                                  a_node_info,
                                  dap_chain_node_info_get_size(a_node_info), false );
+}
+
+/**
+ * @brief Return string by rpc nore list
+ * @return pointer to dap_string_t if Ok, NULL if error
+ */
+dap_string_t *dap_chain_node_rpc_list()
+{
+    dap_string_t *l_ret = dap_string_new("RPC node list:\n");
+    size_t l_nodes_count = 0;
+    dap_global_db_obj_t *l_objs = dap_global_db_get_all_sync(s_rpc_list_group, &l_nodes_count);
+
+    if(!l_nodes_count || !l_objs) {
+        dap_string_append_printf(l_ret, "No records\n");
+        return NULL;
+    } else {
+        dap_string_append_printf(l_ret, "Got %zu nodes:\n", l_nodes_count);
+        dap_string_append_printf(l_ret, "%-26s%-20s%-8s%s", "Address", "IPv4", "Port", "Timestamp\n");
+
+        for (size_t i = 0; i < l_nodes_count; i++) {
+            dap_chain_node_info_t *l_node_info = (dap_chain_node_info_t*)l_objs[i].value;
+            if (dap_chain_node_addr_is_blank(&l_node_info->address)){
+                log_it(L_ERROR, "Node address is empty");
+                continue;
+            }
+
+            char l_ts[DAP_TIME_STR_SIZE] = { '\0' };
+            dap_nanotime_to_str_rfc822(l_ts, sizeof(l_ts), l_objs[i].timestamp);
+
+            dap_string_append_printf(l_ret, NODE_ADDR_FP_STR"    %-20s%-8d%-32s\n",
+                                        NODE_ADDR_FP_ARGS_S(l_node_info->address),
+                                        l_node_info->ext_host, l_node_info->ext_port,
+                                        l_ts);
+        }
+    }
+    dap_global_db_objs_delete(l_objs, l_nodes_count);
+    return l_ret;
 }
\ No newline at end of file
diff --git a/modules/net/include/dap_chain_node_rpc.h b/modules/net/include/dap_chain_node_rpc.h
index b9c9b3b028..6c02eadc4f 100644
--- a/modules/net/include/dap_chain_node_rpc.h
+++ b/modules/net/include/dap_chain_node_rpc.h
@@ -21,4 +21,5 @@
 
  void dap_chain_node_rpc_init(dap_config_t *a_cfg);
  bool dap_chain_node_rpc_is_my_node_authorized();
- int dap_chain_node_rpc_info_save(dap_chain_node_info_t *a_node_info);
\ No newline at end of file
+ int dap_chain_node_rpc_info_save(dap_chain_node_info_t *a_node_info);
+ dap_string_t *dap_chain_node_rpc_list();
\ No newline at end of file
-- 
GitLab