From c21f4cea5993e89a469cb250822eda41a0f04c7e Mon Sep 17 00:00:00 2001
From: Olzhas <oljas.jarasbaev@demlabs.net>
Date: Mon, 16 Dec 2024 12:45:40 +0700
Subject: [PATCH] [*] port

---
 core/include/dap_common.h                     |  5 +-
 core/src/dap_common.c                         | 88 ++++++++++++++++++-
 net/server/cli_server/dap_cli_server.c        |  3 +-
 .../rpc_core/src/dap_json_rpc_response.c      | 40 ++++++++-
 4 files changed, 129 insertions(+), 7 deletions(-)

diff --git a/core/include/dap_common.h b/core/include/dap_common.h
index 5af3beb1d..164650a20 100755
--- a/core/include/dap_common.h
+++ b/core/include/dap_common.h
@@ -913,7 +913,10 @@ void dap_common_deinit(void);
 // set max items in log list
 void dap_log_set_max_item(unsigned int a_max);
 // get logs from list
-char *dap_log_get_item(time_t a_start_time, int a_limit);
+char *dap_log_get_item(const char *filename, time_t a_start_time, int a_limit);
+char* dap_log_get_last_n_lines(const char *filename, int N);
+int dap_log_export_string_to_file(const char *a_string, const char *dest_file_str);
+int dap_log_clear_file(const char *filename);
 
 DAP_PRINTF_ATTR(5, 6) void _log_it(const char * func_name, int line_num, const char * log_tag, enum dap_log_level, const char * format, ... );
 #define log_it_fl(_log_level, ...) _log_it(__FUNCTION__, __LINE__, LOG_TAG, _log_level, ##__VA_ARGS__)
diff --git a/core/src/dap_common.c b/core/src/dap_common.c
index bf525bee7..2be86cf82 100755
--- a/core/src/dap_common.c
+++ b/core/src/dap_common.c
@@ -710,11 +710,11 @@ struct timespec now;
  * @param a_limit
  * @return
  */
-char *dap_log_get_item(time_t a_start_time, int a_limit)
+char *dap_log_get_item(const char *filename, time_t a_start_time, int a_limit)
 {
     unsigned l_len = LOG_FORMAT_LEN * 8;
     char l_line[l_len];
-	FILE *fp = fopen(s_log_file_path, "rb+"); // rb+ is for unignoring \r
+	FILE *fp = fopen(filename, "rb+"); // rb+ is for unignoring \r
 	if (!fp) {
 		return NULL;
 	}
@@ -757,6 +757,90 @@ char *dap_log_get_item(time_t a_start_time, int a_limit)
     return l_buf;
 }
 
+char* dap_log_get_last_n_lines(const char *filename, int N) {
+
+    unsigned l_len = 2048 * 8;
+    char l_line[l_len];
+	FILE *file = fopen(filename, "rb+"); // rb+ is for unignoring \r
+	if (!file) {
+		return NULL;
+	}
+    int counter = 0;
+    if (fseek(file, 0, SEEK_END) != 0) {
+        return NULL;
+    }
+
+    long l_ret = ftell(file);
+    if (l_ret < 0) {
+        return NULL;
+    }
+    unsigned l_file_pos = l_ret;
+    unsigned l_end_pos = l_file_pos;
+    unsigned l_n_line_pos = 0;
+    while (l_file_pos > 0) {
+        char buf[l_len];
+        size_t to_read = (l_file_pos >= l_len) ? l_len : l_file_pos;
+        l_file_pos -= to_read;
+
+        if (fseek(file, l_file_pos, SEEK_SET) != 0) {
+            return NULL;
+        }
+
+        size_t res = fread(buf, 1, to_read, file);
+        if (ferror(file)) {
+            return NULL;
+        }
+
+        for (int i = res - 1; i >= 0; i--) {
+            if (buf[i] == '\n') {
+                counter++;
+                if (counter > N) {
+                    l_n_line_pos = l_file_pos + i + 1;
+                    break;
+                }
+            }
+        }
+
+        if (l_file_pos == 0 || l_n_line_pos > 0) {
+            break;
+        }
+    }
+
+    long l_read_size = l_end_pos - l_n_line_pos - 1;
+    char * l_res = DAP_NEW_Z_SIZE(char, l_read_size + 1);
+    fseek(file, l_n_line_pos, SEEK_SET);
+    fread(l_res, l_read_size, 1, file);
+	fclose(file);
+
+    return l_res;
+}
+
+
+int dap_log_export_string_to_file(const char *a_string, const char *dest_file_str) {
+    if (!a_string)
+        return -1;
+
+    FILE *dest_file = fopen(dest_file_str, "w");
+    if (!dest_file)
+        return -2;
+
+    size_t l_read_size = strlen(a_string);
+
+    fwrite(a_string, l_read_size, 1, dest_file);
+    fclose(dest_file);
+    return 0;
+}
+
+int dap_log_clear_file(const char *filename) {
+    FILE *file = fopen(filename, "w");
+    if (!file) {
+        return -1;
+    }
+
+    fclose(file);
+    return 0;
+}
+
 /**
  * @brief log_error Error log
  * @return
diff --git a/net/server/cli_server/dap_cli_server.c b/net/server/cli_server/dap_cli_server.c
index 6fff5c176..af1d9d55d 100644
--- a/net/server/cli_server/dap_cli_server.c
+++ b/net/server/cli_server/dap_cli_server.c
@@ -215,7 +215,8 @@ int json_commands(const char * a_name) {
             "srv_stake",
             "voting",
             "emit_delegate",
-            "exec_cmd"
+            "exec_cmd",
+            "file"
     };
     for (size_t i = 0; i < sizeof(long_cmd)/sizeof(long_cmd[0]); i++) {
         if (!strcmp(a_name, long_cmd[i])) {
diff --git a/net/server/json_rpc/rpc_core/src/dap_json_rpc_response.c b/net/server/json_rpc/rpc_core/src/dap_json_rpc_response.c
index e43417420..11be2aec1 100644
--- a/net/server/json_rpc/rpc_core/src/dap_json_rpc_response.c
+++ b/net/server/json_rpc/rpc_core/src/dap_json_rpc_response.c
@@ -166,7 +166,8 @@ dap_json_rpc_response_t* dap_json_rpc_response_from_string(const char* json_stri
 
 int json_print_commands(const char * a_name) {
     const char* long_cmd[] = {
-            "tx_history"
+            "tx_history",
+            "file"
     };
     for (size_t i = 0; i < sizeof(long_cmd)/sizeof(long_cmd[0]); i++) {
         if (!strcmp(a_name, long_cmd[i])) {
@@ -277,6 +278,38 @@ void json_print_for_tx_history(dap_json_rpc_response_t* response) {
     }
 }
 
+void json_print_for_file_cmd(dap_json_rpc_response_t* response) {
+    if (!response || !response->result_json_object) {
+        printf("Response is empty\n");
+        return;
+    }
+    if (json_object_get_type(response->result_json_object) == json_type_array) {
+        int result_count = json_object_array_length(response->result_json_object);
+        if (result_count <= 0) {
+            printf("Response array is empty\n");
+            return;
+        }
+        if (json_object_is_type(json_object_array_get_idx(response->result_json_object, 0), json_type_array)) {
+            for (int i = 0; i < result_count; i++) {
+                struct json_object *json_obj_result = json_object_array_get_idx(response->result_json_object, i);
+                if (!json_obj_result) {
+                    printf("Failed to get array element at index %d\n", i);
+                    continue;
+                }
+                for (size_t j = 0; j < json_object_array_length(json_obj_result); j++) {
+                    struct json_object *json_obj = json_object_array_get_idx(json_obj_result, j);
+                    if (json_obj)
+                        printf("%s", json_object_get_string(json_obj));
+                }
+            }
+        } else {
+            json_print_object(response->result_json_object, -1);
+        }
+    } else {
+        json_print_object(response->result_json_object, -1);
+    }
+}
+
 void  json_print_for_mempool_list(dap_json_rpc_response_t* response){
     json_object * json_obj_response = json_object_array_get_idx(response->result_json_object, 0);
     json_object * j_obj_net_name, * j_arr_chains, * j_obj_chain, *j_obj_removed, *j_arr_datums, *j_arr_total;
@@ -326,8 +359,9 @@ int dap_json_rpc_response_printf_result(dap_json_rpc_response_t* response, char
                 return -2;
             }
             switch(json_print_commands(cmd_name)) {
-                case 1: json_print_for_tx_history(response); break; return 0;
-                // case 2: json_print_for_mempool_list(response); break; return 0;
+                case 1: json_print_for_tx_history(response); break;
+                case 2: json_print_for_file_cmd(response); break;
+                // case 2: json_print_for_mempool_list(response); break;
                 default: {
                         json_print_object(response->result_json_object, 0);
                     }
-- 
GitLab