From 394de07e6f657b7e467375b62667bf6bd3a1149f Mon Sep 17 00:00:00 2001 From: hxy7yx <1595670487@qq.com> Date: Sun, 7 Sep 2025 20:39:43 -0700 Subject: [PATCH] feat:support builtin tags --- docs/api/cn/http.md | 49 ++++- docs/api/english/http.md | 49 ++++- include/neuron/errcodes.h | 1 + include/neuron/msg.h | 28 ++- plugins/restful/adapter_handle.c | 3 + plugins/restful/datatag_handle.c | 45 ++++ plugins/restful/datatag_handle.h | 2 + plugins/restful/handle.c | 6 + plugins/restful/rest.c | 7 + src/adapter/adapter.c | 357 +++++++++++++++++++++++++++++++ src/adapter/adapter_internal.h | 11 + src/base/msg_internal.h | 3 + src/core/manager.c | 14 ++ src/parser/neu_json_node.c | 5 + src/parser/neu_json_node.h | 1 + src/parser/neu_json_tag.c | 81 +++++++ src/parser/neu_json_tag.h | 15 ++ src/utils/http.c | 1 + 18 files changed, 665 insertions(+), 13 deletions(-) diff --git a/docs/api/cn/http.md b/docs/api/cn/http.md index 782fdd23..ccb22623 100644 --- a/docs/api/cn/http.md +++ b/docs/api/cn/http.md @@ -328,11 +328,13 @@ Neuron 将为 IIoT 平台提供一系列 API 服务,用于查询基本信息 //node name "name": "sample-driver-adapter", //plugin name - "plugin": "Modbus TCP" + "plugin": "Modbus TCP", + "support_import_tags": false }, { "name": "modbus-tcp-adapter", - "plugin": "Modbus TCP" + "plugin": "Modbus TCP", + "support_import_tags": false } ] } @@ -863,6 +865,49 @@ Neuron 将为 IIoT 平台提供一系列 API 服务,用于查询基本信息 ``` +### 响应 + +```json +{ + //tags count + "index": 4, + "error": 0 +} +``` + +## 导入内置 Tag + +*POST* /api/v2/tags/import + +### 请求头部 + +**Content-Type** application/json + +**Authorization** Bearer \ + +### 响应状态 + +* 200 OK +* 206 + * 2202 tag name conflict + * 2203 tag attribute not support + * 2204 tag type not support + * 2205 tag address format invalid +* 404 + * 2003 node not exist + * 3029 not support import tags + +### 请求体 + +```json +{ + //node name + "node": "cnc-node" +} + +``` + + ### 响应 ```json diff --git a/docs/api/english/http.md b/docs/api/english/http.md index ee8ff345..0422336d 100644 --- a/docs/api/english/http.md +++ b/docs/api/english/http.md @@ -320,11 +320,13 @@ Neuron provide a series of API services for IIoT platform, to query the basic in //node name "name": "sample-driver-adapter", //plugin name - "plugin": "Modbus TCP" + "plugin": "Modbus TCP", + "support_import_tags": false }, { "name": "modbus-tcp-adapter", - "plugin": "Modbus TCP" + "plugin": "Modbus TCP", + "support_import_tags": false } ] } @@ -844,6 +846,49 @@ To update both group name and interval: ``` +### Response + +```json +{ + //tags count + "index": 4, + "error": 0 +} +``` + +## Add builtin Tag + +*POST* /api/v2/tags/import + +### Request Headers + +**Content-Type** application/json + +**Authorization** Bearer \ + +### Response Status + +* 200 OK +* 206 + * 2202 tag name conflict + * 2203 tag attribute not support + * 2204 tag type not support + * 2205 tag address format invalid +* 404 + * 2003 node not exist + * 3029 not support import tags + +### Body + +```json +{ + //node name + "node": "cnc-node" +} + +``` + + ### Response ```json diff --git a/include/neuron/errcodes.h b/include/neuron/errcodes.h index 67db6789..1848bc1b 100644 --- a/include/neuron/errcodes.h +++ b/include/neuron/errcodes.h @@ -152,6 +152,7 @@ typedef enum { NEU_ERR_PLUGIN_NOT_SUPPORT_FDOWN_OPEN = 3026, NEU_ERR_PLUGIN_NOT_SUPPORT_FUP_DATA = 3027, NEU_ERR_PLUGIN_NOT_SUPPORT_FDOWN_DATA = 3028, + NEU_ERR_PLUGIN_NOT_SUPPORT_IMPORT_TAGS = 3029, NEU_ERR_MQTT_FAILURE = 4000, NEU_ERR_MQTT_NO_CERTFILESET = 4001, diff --git a/include/neuron/msg.h b/include/neuron/msg.h index f8120f05..858b46a4 100644 --- a/include/neuron/msg.h +++ b/include/neuron/msg.h @@ -106,6 +106,8 @@ typedef enum neu_reqresp_type { NEU_RESP_ADD_TAG, NEU_REQ_ADD_GTAG, NEU_RESP_ADD_GTAG, + NEU_REQ_IMPORT_TAGS, + NEU_RESP_IMPORT_TAGS, NEU_REQ_DEL_TAG, NEU_REQ_UPDATE_TAG, NEU_RESP_UPDATE_TAG, @@ -164,6 +166,7 @@ typedef enum neu_reqresp_type { NEU_REQ_ADD_TAG_EVENT, NEU_REQ_DEL_TAG_EVENT, NEU_REQ_UPDATE_TAG_EVENT, + NEU_REQ_IMPORT_TAGS_EVENT, NEU_REQ_ADD_GTAG_EVENT, @@ -238,15 +241,17 @@ static const char *neu_reqresp_type_string_t[] = { [NEU_REQ_GET_DRIVER_GROUP] = "NEU_REQ_GET_DRIVER_GROUP", [NEU_RESP_GET_DRIVER_GROUP] = "NEU_RESP_GET_DRIVER_GROUP", - [NEU_REQ_ADD_TAG] = "NEU_REQ_ADD_TAG", - [NEU_RESP_ADD_TAG] = "NEU_RESP_ADD_TAG", - [NEU_REQ_ADD_GTAG] = "NEU_REQ_ADD_GTAG", - [NEU_RESP_ADD_GTAG] = "NEU_RESP_ADD_GTAG", - [NEU_REQ_DEL_TAG] = "NEU_REQ_DEL_TAG", - [NEU_REQ_UPDATE_TAG] = "NEU_REQ_UPDATE_TAG", - [NEU_RESP_UPDATE_TAG] = "NEU_RESP_UPDATE_TAG", - [NEU_REQ_GET_TAG] = "NEU_REQ_GET_TAG", - [NEU_RESP_GET_TAG] = "NEU_RESP_GET_TAG", + [NEU_REQ_ADD_TAG] = "NEU_REQ_ADD_TAG", + [NEU_RESP_ADD_TAG] = "NEU_RESP_ADD_TAG", + [NEU_REQ_ADD_GTAG] = "NEU_REQ_ADD_GTAG", + [NEU_RESP_ADD_GTAG] = "NEU_RESP_ADD_GTAG", + [NEU_REQ_IMPORT_TAGS] = "NEU_REQ_IMPORT_TAGS", + [NEU_RESP_IMPORT_TAGS] = "NEU_RESP_IMPORT_TAGS", + [NEU_REQ_DEL_TAG] = "NEU_REQ_DEL_TAG", + [NEU_REQ_UPDATE_TAG] = "NEU_REQ_UPDATE_TAG", + [NEU_RESP_UPDATE_TAG] = "NEU_RESP_UPDATE_TAG", + [NEU_REQ_GET_TAG] = "NEU_REQ_GET_TAG", + [NEU_RESP_GET_TAG] = "NEU_RESP_GET_TAG", [NEU_REQ_ADD_PLUGIN] = "NEU_REQ_ADD_PLUGIN", [NEU_REQ_DEL_PLUGIN] = "NEU_REQ_DEL_PLUGIN", @@ -299,6 +304,7 @@ static const char *neu_reqresp_type_string_t[] = { [NEU_REQ_ADD_TAG_EVENT] = "NEU_REQ_ADD_TAG_EVENT", [NEU_REQ_DEL_TAG_EVENT] = "NEU_REQ_DEL_TAG_EVENT", [NEU_REQ_UPDATE_TAG_EVENT] = "NEU_REQ_UPDATE_TAG_EVENT", + [NEU_REQ_IMPORT_TAGS_EVENT] = "NEU_REQ_IMPORT_TAGS_EVENT", [NEU_REQ_ADD_GTAG_EVENT] = "NEU_REQ_ADD_GTAG_EVENT", [NEU_REQ_ADD_PLUGIN_EVENT] = "NEU_REQ_ADD_PLUGIN_EVENT", [NEU_REQ_DEL_PLUGIN_EVENT] = "NEU_REQ_DEL_PLUGIN_EVENT", @@ -562,6 +568,10 @@ typedef struct { neu_gdatatag_t *groups; } neu_req_add_gtag_t; +typedef struct { + char node[NEU_NODE_NAME_LEN]; +} neu_req_import_tags_t; + typedef struct { char driver[NEU_NODE_NAME_LEN]; char group[NEU_GROUP_NAME_LEN]; diff --git a/plugins/restful/adapter_handle.c b/plugins/restful/adapter_handle.c index 14e736e5..0de2d3f3 100644 --- a/plugins/restful/adapter_handle.c +++ b/plugins/restful/adapter_handle.c @@ -20,6 +20,7 @@ #include #include "adapter.h" +#include "adapter/adapter_internal.h" #include "define.h" #include "errcodes.h" #include "plugin.h" @@ -235,6 +236,8 @@ void handle_get_adapter_resp(nng_aio *aio, neu_resp_get_node_t *nodes) nodes_res.nodes[index].name = info->node; nodes_res.nodes[index].plugin = info->plugin; + nodes_res.nodes[index].support_import_tags = + neu_plugin_support_import_tags_simple(info->plugin); } neu_json_encode_by_fn(&nodes_res, neu_json_encode_get_nodes_resp, &result); diff --git a/plugins/restful/datatag_handle.c b/plugins/restful/datatag_handle.c index 9cf8ccfb..574ab283 100644 --- a/plugins/restful/datatag_handle.c +++ b/plugins/restful/datatag_handle.c @@ -248,6 +248,51 @@ void handle_add_gtags_resp(nng_aio *aio, neu_resp_add_tag_t *resp) free(result); } +void handle_import_tags(nng_aio *aio) +{ + neu_plugin_t *plugin = neu_rest_get_plugin(); + + NEU_PROCESS_HTTP_REQUEST_VALIDATE_JWT( + aio, neu_json_import_tags_req_t, neu_json_decode_import_tags_req, { + if (strlen(req->node) >= NEU_NODE_NAME_LEN) { + NEU_JSON_RESPONSE_ERROR(NEU_ERR_NODE_NAME_TOO_LONG, { + neu_http_response(aio, NEU_ERR_NODE_NAME_TOO_LONG, + result_error); + }); + } else { + neu_reqresp_head_t header = { 0 }; + neu_req_import_tags_t cmd = { 0 }; + + header.ctx = aio; + header.type = NEU_REQ_IMPORT_TAGS; + header.otel_trace_type = NEU_OTEL_TRACE_TYPE_REST_COMM; + + strcpy(cmd.node, req->node); + + int ret = neu_plugin_op(plugin, header, &cmd); + if (ret != 0) { + NEU_JSON_RESPONSE_ERROR(NEU_ERR_IS_BUSY, { + neu_http_response(aio, NEU_ERR_IS_BUSY, result_error); + }); + } + } + }) +} + +void handle_import_tags_resp(nng_aio *aio, neu_resp_add_tag_t *resp) +{ + neu_json_import_tags_res_t res = { 0 }; + char * result = NULL; + + res.error = resp->error; + res.index = resp->index; + + neu_json_encode_by_fn(&res, neu_json_encode_import_tags_resp, &result); + NEU_JSON_RESPONSE_ERROR(resp->error, + { neu_http_response(aio, resp->error, result); }); + free(result); +} + void handle_del_tags(nng_aio *aio) { neu_plugin_t *plugin = neu_rest_get_plugin(); diff --git a/plugins/restful/datatag_handle.h b/plugins/restful/datatag_handle.h index 35fd9e5b..4d754e8e 100644 --- a/plugins/restful/datatag_handle.h +++ b/plugins/restful/datatag_handle.h @@ -28,6 +28,8 @@ void handle_add_tags(nng_aio *aio); void handle_add_tags_resp(nng_aio *aio, neu_resp_add_tag_t *resp); void handle_add_gtags(nng_aio *aio); void handle_add_gtags_resp(nng_aio *aio, neu_resp_add_tag_t *resp); +void handle_import_tags(nng_aio *aio); +void handle_import_tags_resp(nng_aio *aio, neu_resp_add_tag_t *resp); void handle_del_tags(nng_aio *aio); void handle_update_tags(nng_aio *aio); void handle_update_tags_resp(nng_aio *aio, neu_resp_update_tag_t *resp); diff --git a/plugins/restful/handle.c b/plugins/restful/handle.c index 322bcc6b..c1462ccc 100644 --- a/plugins/restful/handle.c +++ b/plugins/restful/handle.c @@ -210,6 +210,12 @@ static struct neu_http_handler rest_handlers[] = { .url = "/api/v2/gtags", .value.handler = handle_add_gtags, }, + { + .method = NEU_HTTP_METHOD_POST, + .type = NEU_HTTP_HANDLER_FUNCTION, + .url = "/api/v2/tags/import", + .value.handler = handle_import_tags, + }, { .method = NEU_HTTP_METHOD_PUT, .type = NEU_HTTP_HANDLER_FUNCTION, diff --git a/plugins/restful/rest.c b/plugins/restful/rest.c index 49615e80..da46ba0f 100644 --- a/plugins/restful/rest.c +++ b/plugins/restful/rest.c @@ -264,6 +264,13 @@ static int dashb_plugin_request(neu_plugin_t * plugin, scope, "error", ((neu_resp_add_tag_t *) data)->error); } break; + case NEU_RESP_IMPORT_TAGS: + handle_import_tags_resp(header->ctx, (neu_resp_add_tag_t *) data); + if (neu_otel_control_is_started() && trace) { + neu_otel_scope_add_span_attr_int( + scope, "error", ((neu_resp_add_tag_t *) data)->error); + } + break; case NEU_RESP_UPDATE_TAG: handle_update_tags_resp(header->ctx, (neu_resp_update_tag_t *) data); if (neu_otel_control_is_started() && trace) { diff --git a/src/adapter/adapter.c b/src/adapter/adapter.c index 38f404a6..88ee8155 100644 --- a/src/adapter/adapter.c +++ b/src/adapter/adapter.c @@ -548,6 +548,11 @@ static int adapter_command(neu_adapter_t *adapter, neu_reqresp_head_t header, strcpy(pheader->receiver, cmd->driver); break; } + case NEU_REQ_IMPORT_TAGS: { + neu_req_import_tags_t *cmd = (neu_req_import_tags_t *) data; + strcpy(pheader->receiver, cmd->node); + break; + } case NEU_REQ_ADD_GTAG: { neu_req_add_gtag_t *cmd = (neu_req_add_gtag_t *) data; strcpy(pheader->receiver, cmd->driver); @@ -778,6 +783,7 @@ static int adapter_loop(enum neu_event_io_type type, int fd, void *usr_data) case NEU_RESP_GET_DATALAYERS_TAG: case NEU_RESP_ADD_TAG: case NEU_RESP_ADD_GTAG: + case NEU_RESP_IMPORT_TAGS: case NEU_RESP_UPDATE_TAG: case NEU_RESP_GET_TAG: case NEU_RESP_GET_NODE: @@ -1414,6 +1420,62 @@ static int adapter_loop(enum neu_event_io_type type, int fd, void *usr_data) reply(adapter, header, &resp); break; } + case NEU_REQ_IMPORT_TAGS: { + neu_req_import_tags_t *cmd = (neu_req_import_tags_t *) &header[1]; + neu_resp_add_tag_t resp = { 0 }; + + if (adapter->module->type != NEU_NA_TYPE_DRIVER) { + resp.error = NEU_ERR_GROUP_NOT_ALLOW; + } else { + const char *plugin_name = adapter->module->module_name; + if (!neu_plugin_support_import_tags(adapter, plugin_name)) { + resp.error = NEU_ERR_PLUGIN_NOT_SUPPORT_IMPORT_TAGS; + } else { + char json_file_path[512] = { 0 }; + if (neu_adapter_get_json_path_for_plugin( + adapter, plugin_name, json_file_path, + sizeof(json_file_path)) != 0) { + resp.error = NEU_ERR_LIBRARY_NOT_FOUND; + } else { + neu_req_add_gtag_t gtag_cmd = { 0 }; + strcpy(gtag_cmd.driver, cmd->node); + + if (neu_adapter_parse_json_to_gtags(json_file_path, + >ag_cmd) == 0) { + if (neu_adapter_validate_gtags(adapter, >ag_cmd, + &resp) == 0 && + neu_adapter_try_add_gtags(adapter, >ag_cmd, + &resp) == 0 && + neu_adapter_add_gtags(adapter, >ag_cmd, &resp) == + 0) { + + for (int i = 0; i < gtag_cmd.n_group; i++) { + adapter_storage_add_tags( + gtag_cmd.driver, gtag_cmd.groups[i].group, + gtag_cmd.groups[i].tags, + gtag_cmd.groups[i].n_tag); + } + } + + for (int i = 0; i < gtag_cmd.n_group; i++) { + for (int j = 0; j < gtag_cmd.groups[i].n_tag; j++) { + neu_tag_fini(>ag_cmd.groups[i].tags[j]); + } + free(gtag_cmd.groups[i].tags); + } + free(gtag_cmd.groups); + } else { + resp.error = NEU_ERR_FILE_READ_FAILURE; + } + } + } + } + + neu_msg_exchange(header); + header->type = NEU_RESP_IMPORT_TAGS; + reply(adapter, header, &resp); + break; + } case NEU_REQ_UPDATE_TAG: { neu_req_update_tag_t *cmd = (neu_req_update_tag_t *) &header[1]; neu_resp_update_tag_t resp = { 0 }; @@ -1997,4 +2059,299 @@ inline static void notify_monitor(neu_adapter_t * adapter, errno); neu_msg_free(msg); } +} + +static const struct { + const char *plugin_name; + const char *json_file_path; +} plugin_json_mapping[] = { + { "Fanuc Focas Ethernet", "plugins/tags/focas_cnc.json" }, + { "focas", "plugins/tags/focas_cnc.json" }, + + { "HEIDENHAIN CNC", "plugins/tags/heidenhain_cnc.json" }, + { "heidenhain_cnc", "plugins/tags/heidenhain_cnc.json" }, + + { "KND CNC", "plugins/tags/knd_cnc.json" }, + { "knd", "plugins/tags/knd_cnc.json" }, + + // neuhub SYNTEC CNC + // neuhub MITSUBISHI CNC + + { NULL, NULL } +}; + +int neu_adapter_get_json_path_for_plugin(neu_adapter_t *adapter, + const char * plugin_name, + char *json_file_path, size_t path_size) +{ + if (!plugin_name || !json_file_path) { + return -1; + } + + if (strcmp(plugin_name, "neuhub") == 0 || + strcmp(plugin_name, "Neuron HUB") == 0) { + if (adapter && adapter->setting) { + json_t *setting_json = json_loads(adapter->setting, 0, NULL); + if (setting_json) { + json_t *params_obj = json_object_get(setting_json, "params"); + if (params_obj) { + json_t *type_obj = json_object_get(params_obj, "type"); + if (json_is_integer(type_obj)) { + int type_value = json_integer_value(type_obj); + if (type_value == 2) { + snprintf(json_file_path, path_size, + "plugins/tags/syntec_cnc.json"); + json_decref(setting_json); + return 0; + } else if (type_value == 3) { + snprintf(json_file_path, path_size, + "plugins/tags/mitsubishi_cnc.json"); + json_decref(setting_json); + return 0; + } + } + } + json_decref(setting_json); + } + } + return -1; + } + + for (int i = 0; plugin_json_mapping[i].plugin_name != NULL; i++) { + if (strcmp(plugin_json_mapping[i].plugin_name, plugin_name) == 0) { + strncpy(json_file_path, plugin_json_mapping[i].json_file_path, + path_size - 1); + json_file_path[path_size - 1] = '\0'; + return 0; + } + } + + char safe_plugin_name[256]; + strncpy(safe_plugin_name, plugin_name, sizeof(safe_plugin_name) - 1); + safe_plugin_name[sizeof(safe_plugin_name) - 1] = '\0'; + + for (char *p = safe_plugin_name; *p; p++) { + if (*p == ' ') { + *p = '_'; + } + } + + snprintf(json_file_path, path_size, "plugins/tags/%s.json", + safe_plugin_name); + return 0; +} + +bool neu_plugin_support_import_tags(neu_adapter_t *adapter, + const char * plugin_name) +{ + if (!plugin_name) { + return false; + } + + if (strcmp(plugin_name, "neuhub") == 0 || + strcmp(plugin_name, "Neuron HUB") == 0) { + if (adapter && adapter->setting) { + json_t *setting_json = json_loads(adapter->setting, 0, NULL); + if (setting_json) { + json_t *params_obj = json_object_get(setting_json, "params"); + if (params_obj) { + json_t *type_obj = json_object_get(params_obj, "type"); + if (json_is_integer(type_obj)) { + int type_value = json_integer_value(type_obj); + json_decref(setting_json); + return (type_value == 2 || + type_value == + 3); // SYNTEC CNC(2) MITSUBISHI CNC(3) + } + } + json_decref(setting_json); + } + } + return false; + } + + for (int i = 0; plugin_json_mapping[i].plugin_name != NULL; i++) { + if (strcmp(plugin_json_mapping[i].plugin_name, plugin_name) == 0) { + return true; + } + } + + return false; +} + +bool neu_plugin_support_import_tags_simple(const char *plugin_name) +{ + if (!plugin_name) { + return false; + } + + if (strcmp(plugin_name, "neuhub") == 0 || + strcmp(plugin_name, "Neuron HUB") == 0) { + return true; + } + + for (int i = 0; plugin_json_mapping[i].plugin_name != NULL; i++) { + if (strcmp(plugin_json_mapping[i].plugin_name, plugin_name) == 0) { + return true; + } + } + + return false; +} + +int neu_adapter_parse_json_to_gtags(const char * json_file_path, + neu_req_add_gtag_t *gtag_cmd) +{ + FILE * fp = NULL; + json_t * root = NULL; + json_error_t error; + int ret = -1; + + if (!json_file_path || !gtag_cmd) { + return -1; + } + + fp = fopen(json_file_path, "r"); + if (!fp) { + nlog_error("Failed to open JSON file: %s", json_file_path); + return -1; + } + + root = json_loadf(fp, 0, &error); + fclose(fp); + + if (!root) { + nlog_error("Failed to parse JSON file %s: %s", json_file_path, + error.text); + return -1; + } + + json_t *groups_array = json_object_get(root, "groups"); + if (!json_is_array(groups_array)) { + nlog_error("JSON file %s does not contain valid 'groups' array", + json_file_path); + goto cleanup; + } + + size_t group_count = json_array_size(groups_array); + if (group_count == 0) { + nlog_warn("JSON file %s contains empty groups array", json_file_path); + ret = 0; + goto cleanup; + } + + gtag_cmd->n_group = group_count; + gtag_cmd->groups = calloc(group_count, sizeof(neu_gdatatag_t)); + if (!gtag_cmd->groups) { + nlog_error("Failed to allocate memory for groups"); + goto cleanup; + } + + for (size_t i = 0; i < group_count; i++) { + json_t *group_obj = json_array_get(groups_array, i); + if (!json_is_object(group_obj)) { + nlog_error("Group %zu is not a valid object", i); + goto cleanup; + } + + json_t *group_name = json_object_get(group_obj, "group"); + if (!json_is_string(group_name)) { + nlog_error("Group %zu missing valid 'group' name", i); + goto cleanup; + } + strncpy(gtag_cmd->groups[i].group, json_string_value(group_name), + NEU_GROUP_NAME_LEN - 1); + + json_t *interval = json_object_get(group_obj, "interval"); + gtag_cmd->groups[i].interval = + json_is_integer(interval) ? json_integer_value(interval) : 1000; + + json_t *tags_array = json_object_get(group_obj, "tags"); + if (!json_is_array(tags_array)) { + nlog_error("Group %zu does not contain valid 'tags' array", i); + goto cleanup; + } + + size_t tag_count = json_array_size(tags_array); + gtag_cmd->groups[i].n_tag = tag_count; + + if (tag_count > 0) { + gtag_cmd->groups[i].tags = calloc(tag_count, sizeof(neu_datatag_t)); + if (!gtag_cmd->groups[i].tags) { + nlog_error("Failed to allocate memory for tags in group %zu", + i); + goto cleanup; + } + + for (size_t j = 0; j < tag_count; j++) { + json_t *tag_obj = json_array_get(tags_array, j); + if (!json_is_object(tag_obj)) { + nlog_error("Tag %zu in group %zu is not a valid object", j, + i); + goto cleanup; + } + + json_t *name = json_object_get(tag_obj, "name"); + json_t *address = json_object_get(tag_obj, "address"); + json_t *type = json_object_get(tag_obj, "type"); + json_t *attribute = json_object_get(tag_obj, "attribute"); + json_t *description = json_object_get(tag_obj, "description"); + + if (!json_is_string(name) || !json_is_string(address) || + !json_is_integer(type)) { + nlog_error("Tag %zu in group %zu missing required fields", + j, i); + goto cleanup; + } + + gtag_cmd->groups[i].tags[j].name = + strdup(json_string_value(name)); + gtag_cmd->groups[i].tags[j].address = + strdup(json_string_value(address)); + gtag_cmd->groups[i].tags[j].type = json_integer_value(type); + gtag_cmd->groups[i].tags[j].attribute = + json_is_integer(attribute) ? json_integer_value(attribute) + : NEU_ATTRIBUTE_READ; + gtag_cmd->groups[i].tags[j].description = + json_is_string(description) + ? strdup(json_string_value(description)) + : strdup(""); + + json_t *precision = json_object_get(tag_obj, "precision"); + json_t *decimal = json_object_get(tag_obj, "decimal"); + json_t *bias = json_object_get(tag_obj, "bias"); + + gtag_cmd->groups[i].tags[j].precision = + json_is_integer(precision) ? json_integer_value(precision) + : 0; + gtag_cmd->groups[i].tags[j].decimal = + json_is_number(decimal) ? json_number_value(decimal) : 0.0; + gtag_cmd->groups[i].tags[j].bias = + json_is_number(bias) ? json_number_value(bias) : 0.0; + } + } + } + + ret = 0; + +cleanup: + if (root) { + json_decref(root); + } + + if (ret != 0 && gtag_cmd->groups) { + for (int i = 0; i < gtag_cmd->n_group; i++) { + if (gtag_cmd->groups[i].tags) { + for (int j = 0; j < gtag_cmd->groups[i].n_tag; j++) { + neu_tag_fini(>ag_cmd->groups[i].tags[j]); + } + free(gtag_cmd->groups[i].tags); + } + } + free(gtag_cmd->groups); + gtag_cmd->groups = NULL; + gtag_cmd->n_group = 0; + } + + return ret; } \ No newline at end of file diff --git a/src/adapter/adapter_internal.h b/src/adapter/adapter_internal.h index d9954795..3ff190c7 100644 --- a/src/adapter/adapter_internal.h +++ b/src/adapter/adapter_internal.h @@ -124,4 +124,15 @@ int neu_adapter_try_add_gtags(neu_adapter_t *adapter, neu_req_add_gtag_t *cmd, int neu_adapter_add_gtags(neu_adapter_t *adapter, neu_req_add_gtag_t *cmd, neu_resp_add_tag_t *resp); +// Import tags functions +int neu_adapter_get_json_path_for_plugin(neu_adapter_t *adapter, + const char * plugin_name, + char * json_file_path, + size_t path_size); +int neu_adapter_parse_json_to_gtags(const char * json_file_path, + neu_req_add_gtag_t *gtag_cmd); +bool neu_plugin_support_import_tags(neu_adapter_t *adapter, + const char * plugin_name); +bool neu_plugin_support_import_tags_simple(const char *plugin_name); + #endif diff --git a/src/base/msg_internal.h b/src/base/msg_internal.h index aaf4f432..077c24e4 100644 --- a/src/base/msg_internal.h +++ b/src/base/msg_internal.h @@ -83,6 +83,8 @@ extern "C" { XX(NEU_RESP_ADD_TAG, neu_resp_add_tag_t) \ XX(NEU_REQ_ADD_GTAG, neu_req_add_gtag_t) \ XX(NEU_RESP_ADD_GTAG, neu_resp_add_tag_t) \ + XX(NEU_REQ_IMPORT_TAGS, neu_req_import_tags_t) \ + XX(NEU_RESP_IMPORT_TAGS, neu_resp_add_tag_t) \ XX(NEU_REQ_DEL_TAG, neu_req_del_tag_t) \ XX(NEU_REQ_UPDATE_TAG, neu_req_update_tag_t) \ XX(NEU_RESP_UPDATE_TAG, neu_resp_update_tag_t) \ @@ -128,6 +130,7 @@ extern "C" { XX(NEU_REQ_DEL_TAG_EVENT, neu_req_del_tag_t) \ XX(NEU_REQ_UPDATE_TAG_EVENT, neu_req_update_tag_t) \ XX(NEU_REQ_ADD_GTAG_EVENT, neu_req_add_gtag_t) \ + XX(NEU_REQ_IMPORT_TAGS_EVENT, neu_req_import_tags_t) \ XX(NEU_REQ_ADD_PLUGIN_EVENT, neu_req_add_plugin_t) \ XX(NEU_REQ_DEL_PLUGIN_EVENT, neu_req_del_plugin_t) \ XX(NEU_REQ_SUBSCRIBE_GROUP_EVENT, neu_req_subscribe_t) \ diff --git a/src/core/manager.c b/src/core/manager.c index 6e3d5109..53727ef8 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -1474,6 +1474,19 @@ static int manager_loop(enum neu_event_io_type type, int fd, void *usr_data) break; } + case NEU_REQ_IMPORT_TAGS: { + if (neu_node_manager_find(manager->node_manager, header->receiver) == + NULL) { + neu_resp_error_t e = { .error = NEU_ERR_NODE_NOT_EXIST }; + header->type = NEU_RESP_ERROR; + neu_msg_exchange(header); + reply(manager, header, &e); + } else { + forward_msg(manager, header, header->receiver); + } + + break; + } case NEU_REQ_NODE_SETTING: case NEU_REQ_NODE_SETTING_EVENT: { neu_req_node_setting_t *cmd = (neu_req_node_setting_t *) &header[1]; @@ -1493,6 +1506,7 @@ static int manager_loop(enum neu_event_io_type type, int fd, void *usr_data) case NEU_RESP_ADD_TAG: case NEU_RESP_ADD_GTAG: + case NEU_RESP_IMPORT_TAGS: case NEU_RESP_UPDATE_TAG: case NEU_RESP_GET_TAG: case NEU_RESP_GET_GROUP: diff --git a/src/parser/neu_json_node.c b/src/parser/neu_json_node.c index 9025560a..f4e8a3a8 100644 --- a/src/parser/neu_json_node.c +++ b/src/parser/neu_json_node.c @@ -325,6 +325,11 @@ int neu_json_encode_get_nodes_resp(void *json_object, void *param) .t = NEU_JSON_STR, .v.val_str = p_node->name, }, + { + .name = "support_import_tags", + .t = NEU_JSON_BOOL, + .v.val_bool = p_node->support_import_tags, + }, }; node_array = neu_json_encode_array(node_array, node_elems, NEU_JSON_ELEM_SIZE(node_elems)); diff --git a/src/parser/neu_json_node.h b/src/parser/neu_json_node.h index b66efb15..b984b574 100644 --- a/src/parser/neu_json_node.h +++ b/src/parser/neu_json_node.h @@ -86,6 +86,7 @@ int neu_json_encode_get_nodes_state_resp(void *json_object, void *param); typedef struct { char *name; char *plugin; + bool support_import_tags; } neu_json_get_nodes_resp_node_t; typedef struct { diff --git a/src/parser/neu_json_tag.c b/src/parser/neu_json_tag.c index cbdded9e..b1125f5e 100644 --- a/src/parser/neu_json_tag.c +++ b/src/parser/neu_json_tag.c @@ -937,3 +937,84 @@ void neu_json_decode_update_tags_req_free(neu_json_update_tags_req_t *req) free(req); } + +int neu_json_decode_import_tags_req(char * buf, + neu_json_import_tags_req_t **result) +{ + int ret = 0; + void * json_obj; + neu_json_import_tags_req_t *req; + neu_json_elem_t req_elems[] = { { + .name = "node", + .t = NEU_JSON_STR, + } }; + + *result = NULL; + + json_obj = neu_json_decode_new(buf); + if (NULL == json_obj) { + return -1; + } + + req = calloc(1, sizeof(neu_json_import_tags_req_t)); + if (NULL == req) { + ret = -1; + goto error; + } + + ret = neu_json_decode_by_json(json_obj, NEU_JSON_ELEM_SIZE(req_elems), + req_elems); + if (ret != 0) { + goto error; + } + + req->node = req_elems[0].v.val_str; + + *result = req; + goto success; + +error: + if (req) { + neu_json_decode_import_tags_req_free(req); + } + +success: + if (json_obj) { + neu_json_decode_free(json_obj); + } + return ret; +} + +void neu_json_decode_import_tags_req_free(neu_json_import_tags_req_t *req) +{ + if (!req) { + return; + } + + free(req->node); + free(req); +} + +int neu_json_encode_import_tags_resp(void *json_object, void *param) +{ + int ret = 0; + neu_json_import_tags_res_t *res = param; + + neu_json_elem_t res_elems[] = { + { + .name = "error", + .t = NEU_JSON_INT, + .v.val_int = res->error, + }, + { + .name = "index", + .t = NEU_JSON_INT, + .v.val_int = res->index, + }, + }; + + ret = neu_json_encode_field(json_object, res_elems, + NEU_JSON_ELEM_SIZE(res_elems)); + + return ret; +} diff --git a/src/parser/neu_json_tag.h b/src/parser/neu_json_tag.h index 4e974b90..bc98979e 100644 --- a/src/parser/neu_json_tag.h +++ b/src/parser/neu_json_tag.h @@ -144,6 +144,21 @@ int neu_json_decode_update_tags_req(char * buf, neu_json_update_tags_req_t **result); void neu_json_decode_update_tags_req_free(neu_json_update_tags_req_t *req); +typedef struct { + char *node; +} neu_json_import_tags_req_t; + +int neu_json_decode_import_tags_req(char * buf, + neu_json_import_tags_req_t **result); +void neu_json_decode_import_tags_req_free(neu_json_import_tags_req_t *req); + +typedef struct { + uint16_t index; + int error; +} neu_json_import_tags_res_t; + +int neu_json_encode_import_tags_resp(void *json_object, void *param); + #ifdef __cplusplus } #endif diff --git a/src/utils/http.c b/src/utils/http.c index 9f3cec58..d7384f75 100644 --- a/src/utils/http.c +++ b/src/utils/http.c @@ -355,6 +355,7 @@ int neu_http_response(nng_aio *aio, neu_err_code_e code, char *content) case NEU_ERR_TEMPLATE_NOT_FOUND: case NEU_ERR_PLUGIN_NOT_FOUND: case NEU_ERR_PLUGIN_NOT_SUPPORT_WRITE_TAGS: + case NEU_ERR_PLUGIN_NOT_SUPPORT_IMPORT_TAGS: status = NNG_HTTP_STATUS_NOT_FOUND; break; case NEU_ERR_NODE_EXIST: