From d4ffd61aa7fef561ad0cff20a7ec31d03d9fdafc Mon Sep 17 00:00:00 2001
From: "pavel.uhanov" <pavel.uhanov@demlabs.net>
Date: Wed, 19 Mar 2025 09:48:52 +0300
Subject: [PATCH] [*] add rpc role

---
 modules/net/dap_chain_node_cli.c         |   4 +-
 modules/net/dap_chain_node_rpc.c         | 140 ++++++++++++++---------
 modules/net/include/dap_chain_node_rpc.h |  12 ++
 3 files changed, 102 insertions(+), 54 deletions(-)

diff --git a/modules/net/dap_chain_node_cli.c b/modules/net/dap_chain_node_cli.c
index 5e9a92d98a..03ab818b4f 100644
--- a/modules/net/dap_chain_node_cli.c
+++ b/modules/net/dap_chain_node_cli.c
@@ -65,9 +65,7 @@ int dap_chain_node_cli_init(dap_config_t * g_config)
     s_debug_cli = dap_config_get_item_bool_default(g_config, "cli-server", "debug-cli", false);
     if ( dap_cli_server_init(s_debug_cli, "cli-server") )
         return log_it(L_ERROR, "Can't init CLI server!"), -1;
-    if (dap_config_get_item_bool_default(g_config, "cli-server", "rpc", false)) {
-        dap_chain_node_rpc_init(g_config);
-    }
+    dap_chain_node_rpc_init(g_config);
 
     dap_cli_server_cmd_add("global_db", com_global_db, "Work with global database",
             "global_db flush\n"
diff --git a/modules/net/dap_chain_node_rpc.c b/modules/net/dap_chain_node_rpc.c
index 7e1de0b0bc..6c9f210f71 100644
--- a/modules/net/dap_chain_node_rpc.c
+++ b/modules/net/dap_chain_node_rpc.c
@@ -19,39 +19,35 @@
  along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <time.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <string.h>
-
-
-#include <sys/sysinfo.h>
-#include <sys/vfs.h>
-
-#include "dap_chain_net.h"
+#include "dap_chain_node_rpc.h"
 #include "dap_global_db.h"
+#include "dap_global_db_cluster.h"
 #include "dap_stream.h"
 
 #define LOG_TAG "dap_chain_node_rpc"
 #define DAP_CHAIN_NODE_RPC_STATES_INFO_CURRENT_VERSION 1
-typedef struct dap_chain_node_rpc_states_info
-{
-    uint32_t version;
-    dap_chain_node_addr_t address;
-    uint32_t location;
-    uint32_t links_count;
-    uint32_t cli_thread_count;
-    struct sysinfo sysinfo;
-} DAP_ALIGN_PACKED dap_chain_node_rpc_states_info_t;
+
+typedef enum {
+    RPC_ROLE_INVALID = 0,
+    RPC_ROLE_BALANCER,
+    RPC_ROLE_SERVER,
+    RPC_ROLE_ROOT
+} rpc_role_t;
 
 static const uint64_t s_timer_update_states_info = 10 /*sec*/ * 1000;
-static const char s_rpc_states_group[] = "rpc.states";
-static const char s_rpc_list_group[] = "rpc.list";
-static dap_global_db_cluster_t *s_rpc_states_cluster = NULL;
-static dap_global_db_cluster_t *s_rpc_list_cluster = NULL;
+static const char s_rpc_server_states_group[] = "rpc.states";
+static const char s_rpc_node_list_group[] = "rpc.list";
+static dap_global_db_cluster_t *s_rpc_server_states_cluster = NULL;
+static dap_global_db_cluster_t *s_rpc_node_list_cluster = NULL;
+
+DAP_STATIC_INLINE s_get_role_from_str(const char *a_str)
+{
+    if (!a_str) return RPC_ROLE_INVALID;
+    if (!strcmp(a_str, "balancer")) return RPC_ROLE_BALANCER;
+    if (!strcmp(a_str, "server")) return RPC_ROLE_SERVER;
+    if (!strcmp(a_str, "root")) return RPC_ROLE_SERVER;
+    return RPC_ROLE_INVALID;
+}
 
 /**
  * @brief get states info about current
@@ -66,32 +62,49 @@ static void s_update_node_rpc_states_info(UNUSED_ARG void *a_arg)
     sysinfo(&l_info->sysinfo);
 
     const char *l_node_addr_str = dap_stream_node_addr_to_str_static(l_info->address);
-    dap_global_db_set_sync(s_rpc_states_group, l_node_addr_str, l_info, sizeof(dap_chain_node_rpc_states_info_t), false);
+    dap_global_db_set_sync(s_rpc_server_states_group, l_node_addr_str, l_info, sizeof(dap_chain_node_rpc_states_info_t), false);
     DAP_DELETE(l_info);
 }
 
+static int s_rpc_node_cmp(dap_list_t *a_list1, dap_list_t *a_list2)
+{
+    return 0;
+}
+
 void dap_chain_node_rpc_init(dap_config_t *a_cfg)
 {
-    if (!(s_rpc_states_cluster = dap_global_db_cluster_add(
-              dap_global_db_instance_get_default(), DAP_STREAM_CLUSTER_GLOBAL,
-              *(dap_guuid_t *)&uint128_0, s_rpc_states_group,
-              0,
-              true, DAP_GDB_MEMBER_ROLE_USER, DAP_CLUSTER_TYPE_EMBEDDED)))
-        return;
-    if (!(s_rpc_list_cluster = dap_global_db_cluster_add(
-              dap_global_db_instance_get_default(), DAP_STREAM_CLUSTER_GLOBAL,
-              *(dap_guuid_t *)&uint128_0, s_rpc_list_group,
-              0,
-              true, DAP_GDB_MEMBER_ROLE_GUEST, DAP_CLUSTER_TYPE_EMBEDDED)))
-        return;
-    dap_stream_node_addr_t *l_authorized_nodes = NULL;
-    uint16_t l_authorized_nodes_count = 0;
-    dap_config_stream_addrs_parse(a_cfg, "cli-server", "authorized_nodes_addrs_rpc", &l_authorized_nodes, &l_authorized_nodes_count);
-    for (uint16_t i = 0; i < l_authorized_nodes_count; ++i)
-        dap_global_db_cluster_member_add(s_rpc_list_cluster, l_authorized_nodes + i, DAP_GDB_MEMBER_ROLE_ROOT);
-    DAP_DELETE(l_authorized_nodes);
-    if (dap_proc_thread_timer_add(NULL, s_update_node_rpc_states_info, NULL, s_timer_update_states_info))
-        log_it(L_ERROR, "Can't activate timer on node states update");
+    rpc_role_t l_role = s_get_role_from_str(dap_config_get_item_str(a_cfg, "rpc", "role"));
+    
+    if (l_role == RPC_ROLE_SERVER || l_role == RPC_ROLE_BALANCER) {
+        if (!(s_rpc_server_states_cluster = dap_global_db_cluster_add(
+            dap_global_db_instance_get_default(), DAP_STREAM_CLUSTER_GLOBAL,
+            *(dap_guuid_t *)&uint128_0, s_rpc_server_states_group,
+            0,
+            true, DAP_GDB_MEMBER_ROLE_USER, DAP_CLUSTER_TYPE_EMBEDDED)))
+        {
+            log_it(L_ERROR, "Can't create rpc server states cluster");
+            return;
+        }
+        if (l_role == RPC_ROLE_SERVER && dap_proc_thread_timer_add(NULL, s_update_node_rpc_states_info, NULL, s_timer_update_states_info))
+            log_it(L_ERROR, "Can't activate timer on node states update");
+    }
+    if (l_role == RPC_ROLE_ROOT || l_role == RPC_ROLE_BALANCER) {
+        if (!(s_rpc_node_list_cluster = dap_global_db_cluster_add(
+                dap_global_db_instance_get_default(), DAP_STREAM_CLUSTER_GLOBAL,
+                *(dap_guuid_t *)&uint128_0, s_rpc_node_list_group,
+                0,
+                true, DAP_GDB_MEMBER_ROLE_GUEST, DAP_CLUSTER_TYPE_EMBEDDED)))
+        {
+            log_it(L_ERROR, "Can't create rpc node list cluster");
+            return;
+        }
+        dap_stream_node_addr_t *l_authorized_nodes = NULL;
+        uint16_t l_authorized_nodes_count = 0;
+        dap_config_stream_addrs_parse(a_cfg, "rpc", "authorized_nodes_addrs", &l_authorized_nodes, &l_authorized_nodes_count);
+        for (uint16_t i = 0; i < l_authorized_nodes_count; ++i)
+            dap_global_db_cluster_member_add(s_rpc_node_list_cluster, l_authorized_nodes + i, DAP_GDB_MEMBER_ROLE_ROOT);
+        DAP_DELETE(l_authorized_nodes);
+    }
 }
 
 /**
@@ -104,7 +117,7 @@ dap_string_t *dap_chain_node_rpc_states_info_read(dap_stream_node_addr_t a_addr)
     size_t l_data_size = 0;
     dap_string_t *l_ret = dap_string_new("");
     const char *l_node_addr_str = dap_stream_node_addr_to_str_static(a_addr.uint64 ? a_addr : g_node_addr);
-    dap_chain_node_rpc_states_info_t *l_node_info = (dap_chain_node_rpc_states_info_t *)dap_global_db_get_sync(s_rpc_states_group, l_node_addr_str, &l_data_size, NULL, &l_timestamp);
+    dap_chain_node_rpc_states_info_t *l_node_info = (dap_chain_node_rpc_states_info_t *)dap_global_db_get_sync(s_rpc_server_states_group, l_node_addr_str, &l_data_size, NULL, &l_timestamp);
     if (!l_node_info) {
         log_it(L_ERROR, "Can't find state of rpc node %s", l_node_addr_str);
         dap_string_append_printf(l_ret, "Can't find state of %s rpc node", l_node_addr_str);
@@ -123,7 +136,7 @@ dap_string_t *dap_chain_node_rpc_states_info_read(dap_stream_node_addr_t a_addr)
 
 bool dap_chain_node_rpc_is_my_node_authorized()
 {
-    return dap_cluster_member_find_role(s_rpc_list_cluster->role_cluster, &g_node_addr) == DAP_GDB_MEMBER_ROLE_ROOT;
+    return dap_cluster_member_find_role(s_rpc_node_list_cluster->role_cluster, &g_node_addr) == DAP_GDB_MEMBER_ROLE_ROOT;
 }
 
 /**
@@ -135,7 +148,7 @@ int dap_chain_node_rpc_info_save(dap_chain_node_info_t *a_node_info)
 {
     return !a_node_info || !a_node_info->address.uint64
         ? log_it(L_ERROR,"Can't save node rpc info, %s", a_node_info ? "null arg" : "zero address"), -1
-        : dap_global_db_set_sync( s_rpc_list_group,
+        : dap_global_db_set_sync( s_rpc_node_list_group,
                                  dap_stream_node_addr_to_str_static(a_node_info->address),
                                  a_node_info,
                                  dap_chain_node_info_get_size(a_node_info), false );
@@ -149,7 +162,7 @@ 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);
+    dap_global_db_obj_t *l_objs = dap_global_db_get_all_sync(s_rpc_node_list_group, &l_nodes_count);
 
     if(!l_nodes_count || !l_objs) {
         dap_string_append_printf(l_ret, "No records\n");
@@ -176,4 +189,29 @@ dap_string_t *dap_chain_node_rpc_list()
     }
     dap_global_db_objs_delete(l_objs, l_nodes_count);
     return l_ret;
+}
+
+/**
+ * @brief get states rpc info about current
+ * @param a_arg - pointer to callback arg
+ */
+dap_list_t *dap_chain_node_rpc_get_sorted_list(size_t *a_count)
+{
+    size_t l_count = 0;
+    dap_list_t *l_ret = NULL;
+    dap_global_db_obj_t *l_nodes_obj = dap_global_db_get_all_sync(s_rpc_node_list_group, &l_count);
+    for (size_t i = 0; i < l_count; ++i) {
+        size_t l_data_size = 0;
+        dap_chain_node_info_t *l_node_info_curr = dap_global_db_get_sync(s_rpc_server_states_group, (l_nodes_obj + i)->key, &l_data_size, NULL, NULL);
+        if (!l_node_info_curr) {
+            log_it(L_ERROR, "Can't find info about rpc node %s", (l_nodes_obj + i)->key);
+            continue;
+        }
+        if (l_data_size != sizeof(l_node_info_curr)) {
+            log_it(L_ERROR, "Error data size in rpc node state, get %zu expected %zu", l_data_size, sizeof(l_node_info_curr));
+            continue;
+        }
+        l_ret = dap_list_insert_sorted(l_ret, (void *)l_node_info_curr, s_rpc_node_cmp);
+    }
+    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 6c02eadc4f..eb1f6afffb 100644
--- a/modules/net/include/dap_chain_node_rpc.h
+++ b/modules/net/include/dap_chain_node_rpc.h
@@ -18,6 +18,18 @@
  You should have received a copy of the GNU General Public License
  along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
  */
+#include <sys/sysinfo.h>
+#include "dap_chain_node.h"
+#include "dap_config.h"
+
+ typedef struct dap_chain_node_rpc_states_info {
+    uint32_t version;
+    dap_chain_node_addr_t address;
+    uint32_t location;
+    uint32_t links_count;
+    uint32_t cli_thread_count;
+    struct sysinfo sysinfo;
+} DAP_ALIGN_PACKED dap_chain_node_rpc_states_info_t;
 
  void dap_chain_node_rpc_init(dap_config_t *a_cfg);
  bool dap_chain_node_rpc_is_my_node_authorized();
-- 
GitLab