From e738e41b5d67d46064ea368712a7b63bf5bc38d0 Mon Sep 17 00:00:00 2001 From: fengzero Date: Fri, 22 Oct 2021 09:40:59 +0000 Subject: [PATCH] Add api: get plugin schema & config node check the param according to the schema --- CMakeLists.txt | 6 +- include/neu_adapter.h | 9 +- include/neu_plugin.h | 3 + neuron.yaml | 2 +- plugin_param.json => plugin_param_schema.json | 0 plugins/modbus/modbus_tcp.c | 3 +- plugins/restful/adapter_handle.c | 22 ++ plugins/restful/adapter_handle.h | 1 + plugins/restful/handle.c | 18 ++ plugins/restful/normal_handle.c | 17 ++ plugins/restful/normal_handle.h | 1 + src/adapter/adapter.c | 45 +++- src/adapter/adapter_internal.h | 1 + src/base/neu_plugin_common.c | 16 ++ src/core/neu_manager.c | 31 +++ src/core/neu_manager.h | 4 + src/parser/neu_json_fn.c | 33 +++ src/parser/neu_json_node.c | 29 +++ src/parser/neu_json_node.h | 7 + src/parser/neu_json_param.h | 36 +++ src/schema/schema.c | 218 ++++++++++++++++++ src/schema/schema.h | 48 ++++ src/utils/json.c | 25 ++ src/utils/json.h | 11 +- tests/config_test.cc | 2 +- 25 files changed, 566 insertions(+), 22 deletions(-) rename plugin_param.json => plugin_param_schema.json (100%) create mode 100644 src/parser/neu_json_param.h create mode 100644 src/schema/schema.c create mode 100644 src/schema/schema.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 845ef007..87bcb708 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -71,6 +71,7 @@ endif() # define neuron executalbe program aux_source_directory(src/parser NEURON_SRC_PARSE) +aux_source_directory(src/schema NEURON_SRC_SCHEMA) set(NEURON_SOURCES src/main.c src/config.c @@ -92,7 +93,7 @@ set(NEURON_SOURCES set(NEURON_INCLUDE_DIRECTORIES include src plugins) add_executable(neuron) -target_sources(neuron PRIVATE ${NEURON_SOURCES} ${NEURON_SRC_PARSE}) +target_sources(neuron PRIVATE ${NEURON_SOURCES} ${NEURON_SRC_PARSE} ${NEURON_SRC_SCHEMA}) target_include_directories(neuron PRIVATE ${NEURON_INCLUDE_DIRECTORIES}) if(APPLE) target_link_libraries(neuron nng::nng jansson yaml neuron-base) @@ -128,8 +129,9 @@ target_include_directories(neuron-base target_link_libraries(neuron-base vector-static csptr jansson crypto ${CMAKE_THREAD_LIBS_INIT}) -#copy yaml to build +#copy file for run and unit test file(COPY ${CMAKE_SOURCE_DIR}/neuron.yaml DESTINATION ${CMAKE_BINARY_DIR}) +file(COPY ${CMAKE_SOURCE_DIR}/plugin_param_schema.json DESTINATION ${CMAKE_BINARY_DIR}) # define for plugins add_subdirectory(plugins/sample) diff --git a/include/neu_adapter.h b/include/neu_adapter.h index 7f9dcb06..de9e4388 100644 --- a/include/neu_adapter.h +++ b/include/neu_adapter.h @@ -72,6 +72,7 @@ typedef enum neu_reqresp_type { NEU_REQRESP_DATATAGS, NEU_REQRESP_SELF_NODE_ID, NEU_REQRESP_NODE_ID, + NEU_REQRESP_NODE_SETTING, } neu_reqresp_type_e; typedef uint32_t neu_node_id_t; @@ -260,6 +261,12 @@ typedef struct neu_represp_node_id { neu_node_id_t node_id; } neu_reqresp_node_id_t; +/* NEU_REQRESP_NODE_SETTING */ +typedef struct neu_cmd_node_setting { + neu_node_id_t node_id; + const char * setting; +} neu_cmd_node_setting_t; + typedef struct neu_request { uint32_t req_id; neu_reqresp_type_e req_type; @@ -304,7 +311,7 @@ typedef struct neu_event_reply { */ typedef enum neu_config_type { NEU_CONFIG_UNKNOW, - NEU_CONFIG_ADDRESS, + NEU_CONFIG_SETTING, } neu_config_type_e; typedef struct neu_config { diff --git a/include/neu_plugin.h b/include/neu_plugin.h index c5bb1f66..7e3d8a51 100644 --- a/include/neu_plugin.h +++ b/include/neu_plugin.h @@ -133,6 +133,9 @@ int neu_plugin_tag_count_by_attribute(neu_taggrp_config_t *grp_config, neu_datatag_table_t *tag_table, neu_attributetype_e attribute); +intptr_t neu_plugin_node_config_setting(neu_plugin_t *plugin, + neu_node_id_t node_id, + const char * setting); #ifdef __cplusplus } #endif diff --git a/neuron.yaml b/neuron.yaml index c3141f34..22bcaa5e 100644 --- a/neuron.yaml +++ b/neuron.yaml @@ -8,7 +8,7 @@ mqtt: clean_session: 1 broker: connection: tcp:// - host: localhost + host: broker.emqx.io port: 1883 web: host: 0.0.0.0 diff --git a/plugin_param.json b/plugin_param_schema.json similarity index 100% rename from plugin_param.json rename to plugin_param_schema.json diff --git a/plugins/modbus/modbus_tcp.c b/plugins/modbus/modbus_tcp.c index 020c845d..0d2786d5 100644 --- a/plugins/modbus/modbus_tcp.c +++ b/plugins/modbus/modbus_tcp.c @@ -539,7 +539,8 @@ static int modbus_tcp_config(neu_plugin_t *plugin, neu_config_t *configs) (void) plugin; int ret = 0; - log_info("modbus config............."); + log_info("modbus config............. type: %d, config: %s", configs->type, + configs->buf); return ret; } diff --git a/plugins/restful/adapter_handle.c b/plugins/restful/adapter_handle.c index b7f08952..370dbbe3 100644 --- a/plugins/restful/adapter_handle.c +++ b/plugins/restful/adapter_handle.c @@ -122,4 +122,26 @@ void handle_get_adapter(nng_aio *aio) index += 1; } vector_uninit(&nodes); +} + +void handle_node_setting(nng_aio *aio) +{ + neu_plugin_t *plugin = neu_rest_get_plugin(); + + REST_PROCESS_HTTP_REQUEST( + aio, neu_parse_node_setting_req_t, neu_parse_decode_node_setting, { + char * config_buf = calloc(req_data_size + 1, sizeof(char)); + intptr_t err = 0; + + memcpy(config_buf, req_data, req_data_size); + err = neu_plugin_node_config_setting(plugin, req->node_id, + config_buf); + free(config_buf); + + if (err != 0) { + http_bad_request(aio, "{\"error\": 1}"); + } else { + http_ok(aio, "{\"error\": 0}"); + } + }) } \ No newline at end of file diff --git a/plugins/restful/adapter_handle.h b/plugins/restful/adapter_handle.h index 88c87c69..68d1f618 100644 --- a/plugins/restful/adapter_handle.h +++ b/plugins/restful/adapter_handle.h @@ -25,5 +25,6 @@ void handle_add_adapter(nng_aio *aio); void handle_del_adapter(nng_aio *aio); void handle_update_adapter(nng_aio *aio); void handle_get_adapter(nng_aio *aio); +void handle_node_setting(nng_aio *aio); #endif \ No newline at end of file diff --git a/plugins/restful/handle.c b/plugins/restful/handle.c index 52646ad7..91515392 100644 --- a/plugins/restful/handle.c +++ b/plugins/restful/handle.c @@ -89,6 +89,12 @@ struct neu_rest_handler cors_handler[] = { { .url = "/api/v2/subscribe", }, + { + .url = "/api/v2/plugin/schema", + }, + { + .url = "/api/v2/node/setting", + }, }; struct neu_rest_handler api_handlers[] = { @@ -244,6 +250,18 @@ struct neu_rest_handler api_handlers[] = { .url = "/api/v2/subscribe", .value.handler = handle_grp_get_subscribe, }, + { + .method = NEU_REST_METHOD_GET, + .type = NEU_REST_HANDLER_FUNCTION, + .url = "/api/v2/schema/plugin", + .value.handler = handle_get_plugin_schema, + }, + { + .method = NEU_REST_METHOD_POST, + .type = NEU_REST_HANDLER_FUNCTION, + .url = "/api/v2/node/setting", + .value.handler = handle_node_setting, + }, }; void neu_rest_web_handler(const struct neu_rest_handler **handlers, diff --git a/plugins/restful/normal_handle.c b/plugins/restful/normal_handle.c index 5bcecc1b..5c46008c 100644 --- a/plugins/restful/normal_handle.c +++ b/plugins/restful/normal_handle.c @@ -100,4 +100,21 @@ void handle_login(nng_aio *aio) void handle_logout(nng_aio *aio) { (void) aio; +} + +void handle_get_plugin_schema(nng_aio *aio) +{ + char buf[4096] = { 0 }; + FILE *fp = fopen("./plugin_param_schema.json", "r"); + + if (fp == NULL) { + log_info("open ./plugin_param_schema.json error: %d", errno); + http_not_found(aio, "{\"status\": \"error\"}"); + return; + } + + fread(buf, 1, sizeof(buf), fp); + fclose(fp); + + http_ok(aio, buf); } \ No newline at end of file diff --git a/plugins/restful/normal_handle.h b/plugins/restful/normal_handle.h index bd6a363f..93e70766 100644 --- a/plugins/restful/normal_handle.h +++ b/plugins/restful/normal_handle.h @@ -26,5 +26,6 @@ void handle_get_ttys(nng_aio *aio); void handle_ping(nng_aio *aio); void handle_login(nng_aio *aio); void handle_logout(nng_aio *aio); +void handle_get_plugin_schema(nng_aio *aio); #endif \ No newline at end of file diff --git a/src/adapter/adapter.c b/src/adapter/adapter.c index aba90328..77a895db 100644 --- a/src/adapter/adapter.c +++ b/src/adapter/adapter.c @@ -125,7 +125,6 @@ struct neu_adapter { uint32_t new_req_id; plugin_id_t plugin_id; plugin_kind_e plugin_kind; - char * plugin_lib_name; void * plugin_lib; // handle of dynamic lib neu_plugin_module_t *plugin_module; neu_plugin_t * plugin; @@ -705,6 +704,16 @@ static int adapter_command(neu_adapter_t *adapter, neu_request_t *cmd, break; } + case NEU_REQRESP_NODE_SETTING: { + ADAPTER_RESP_CODE(adapter, cmd, intptr_t, neu_cmd_node_setting_t, rv, + NEU_REQRESP_ERR_CODE, p_result, { + ret = neu_manager_adapter_config_setting( + adapter->manager, req_cmd->node_id, + req_cmd->setting); + }); + break; + } + default: rv = -1; break; @@ -888,14 +897,10 @@ neu_adapter_t *neu_adapter_create(neu_adapter_info_t *info, adapter->plugin_kind = info->plugin_kind; adapter->manager = manager; - adapter->plugin_lib_name = strdup(info->plugin_lib_name); - if (adapter->name == NULL || adapter->plugin_lib_name == NULL) { + if (adapter->name == NULL || info->plugin_lib_name == NULL) { if (adapter->name != NULL) { free(adapter->name); } - if (adapter->plugin_lib_name != NULL) { - free(adapter->plugin_lib_name); - } nng_mtx_free(adapter->mtx); free(adapter); log_error("Failed duplicate string for create adapter"); @@ -904,11 +909,11 @@ neu_adapter_t *neu_adapter_create(neu_adapter_info_t *info, void * handle; neu_plugin_module_t *plugin_module; - handle = load_plugin_library(adapter->plugin_lib_name, adapter->plugin_kind, - &plugin_module); + handle = load_plugin_library((char *) info->plugin_lib_name, + adapter->plugin_kind, &plugin_module); if (handle == NULL) { neu_panic("Can't to load library(%s) for plugin(%s)", - adapter->plugin_lib_name, adapter->name); + info->plugin_lib_name, adapter->name); } neu_plugin_t *plugin; @@ -954,9 +959,6 @@ void neu_adapter_destroy(neu_adapter_t *adapter) if (adapter->name != NULL) { free(adapter->name); } - if (adapter->plugin_lib_name != NULL) { - free(adapter->plugin_lib_name); - } nng_mtx_free(adapter->mtx); free(adapter); return; @@ -1061,4 +1063,23 @@ plugin_id_t neu_adapter_get_plugin_id(neu_adapter_t *adapter) } return adapter->plugin_id; +} + +int neu_adapter_config(neu_adapter_t *adapter, neu_config_t *config) +{ + int rv = 0; + + if (adapter == NULL) { + log_error("Config adapter with NULL adapter"); + return -1; + } + + if (adapter->plugin_module != NULL) { + const neu_plugin_intf_funs_t *intf_funs; + + intf_funs = adapter->plugin_module->intf_funs; + intf_funs->config(adapter->plugin, config); + } + + return rv; } \ No newline at end of file diff --git a/src/adapter/adapter_internal.h b/src/adapter/adapter_internal.h index 67d5e068..114bfaae 100644 --- a/src/adapter/adapter_internal.h +++ b/src/adapter/adapter_internal.h @@ -38,5 +38,6 @@ nng_socket neu_adapter_get_sock(neu_adapter_t *adapter); adapter_id_t neu_adapter_get_id(neu_adapter_t *adapter); adapter_type_e neu_adapter_get_type(neu_adapter_t *adapter); plugin_id_t neu_adapter_get_plugin_id(neu_adapter_t *adapter); +int neu_adapter_config(neu_adapter_t *adapter, neu_config_t *config); #endif diff --git a/src/base/neu_plugin_common.c b/src/base/neu_plugin_common.c index 3035d3db..202a9c8c 100644 --- a/src/base/neu_plugin_common.c +++ b/src/base/neu_plugin_common.c @@ -422,3 +422,19 @@ int neu_plugin_tag_count_by_attribute(neu_taggrp_config_t *grp_config, return count; } + +intptr_t neu_plugin_node_config_setting(neu_plugin_t *plugin, + neu_node_id_t node_id, + const char * setting) +{ + intptr_t errorcode = -1; + neu_cmd_node_setting_t node_setting = { 0 }; + + node_setting.node_id = node_id; + node_setting.setting = setting; + + PLUGIN_CALL_CMD(plugin, NEU_REQRESP_NODE_SETTING, node_setting, intptr_t, + { errorcode = (intptr_t) resp; }) + + return errorcode; +} \ No newline at end of file diff --git a/src/core/neu_manager.c b/src/core/neu_manager.c index b757b970..6e839af0 100644 --- a/src/core/neu_manager.c +++ b/src/core/neu_manager.c @@ -1776,3 +1776,34 @@ neu_datatag_table_t *neu_manager_get_datatag_tbl(neu_manager_t *manager, return tag_table; } + +int neu_manager_adapter_config_setting(neu_manager_t *manager, + neu_node_id_t node_id, + const char * config) +{ + adapter_id_t adapter_id = { 0 }; + adapter_reg_entity_t *reg_entity = NULL; + int ret = 0; + neu_config_t neu_config = { .type = NEU_CONFIG_SETTING }; + + nng_mtx_lock(manager->adapters_mtx); + + adapter_id = neu_manager_adapter_id_from_node_id(manager, node_id); + reg_entity = find_reg_adapter_by_id(&manager->reg_adapters, adapter_id); + + if (reg_entity == NULL) { + log_error("Can't find matched src registered adapter"); + nng_mtx_unlock(manager->adapters_mtx); + return -1; + } + + neu_config.buf_len = strlen(config); + neu_config.buf = strdup(config); + + ret = neu_adapter_config(reg_entity->adapter, &neu_config); + nng_mtx_unlock(manager->adapters_mtx); + + free(neu_config.buf); + + return ret; +} \ No newline at end of file diff --git a/src/core/neu_manager.h b/src/core/neu_manager.h index 7c7fb4bd..4c500dc0 100644 --- a/src/core/neu_manager.h +++ b/src/core/neu_manager.h @@ -64,4 +64,8 @@ neu_node_id_t neu_manager_adapter_id_to_node_id(neu_manager_t *manager, adapter_id_t adapter_id); adapter_id_t neu_manager_adapter_id_from_node_id(neu_manager_t *manager, neu_node_id_t node_id); +int neu_manager_adapter_config_setting(neu_manager_t *manager, + neu_node_id_t node_id, + const char * config); + #endif diff --git a/src/parser/neu_json_fn.c b/src/parser/neu_json_fn.c index 86a1e15c..d3e193dc 100644 --- a/src/parser/neu_json_fn.c +++ b/src/parser/neu_json_fn.c @@ -17,11 +17,14 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. **/ +#include #include +#include #include "utils/json.h" #include "neu_json_fn.h" +#include "neu_json_param.h" int neu_json_encode_by_fn(void *param, neu_json_encode_fn fn, char **result) { @@ -73,4 +76,34 @@ int neu_parse_encode_error(void *json_object, void *param) }; return neu_json_encode_field(json_object, elems, 1); +} + +int neu_parse_param(char *buf, char **err_param, int n, neu_json_elem_t *ele, + ...) +{ + void * json = neu_json_decode_new(buf); + neu_json_elem_t params_ele = { .name = "params", .t = NEU_JSON_OBJECT }; + va_list ap; + int ret = 0; + + if (neu_json_decode_value(json, ¶ms_ele) != 0) { + neu_json_decode_free(json); + *err_param = strdup("params"); + return -1; + } + + va_start(ap, ele); + for (int i = 0; i < n; i++) { + neu_json_elem_t *tmp_ele = va_arg(ap, neu_json_elem_t *); + if (neu_json_decode_value(params_ele.v.object, tmp_ele) != 0) { + *err_param = strdup(tmp_ele->name); + ret = -1; + break; + } + } + + va_end(ap); + + neu_json_decode_free(json); + return ret; } \ No newline at end of file diff --git a/src/parser/neu_json_node.c b/src/parser/neu_json_node.c index ecc30d31..9a152fec 100644 --- a/src/parser/neu_json_node.c +++ b/src/parser/neu_json_node.c @@ -184,3 +184,32 @@ int neu_parse_encode_get_nodes(void *json_object, void *param) return neu_json_encode_field(json_object, elems, 1); } + +int neu_parse_decode_node_setting(char * buf, + neu_parse_node_setting_req_t **result) +{ + neu_parse_node_setting_req_t *req = + calloc(1, sizeof(neu_parse_node_setting_req_t)); + neu_json_elem_t elem[] = { + { + .name = "node_id", + .t = NEU_JSON_INT, + }, + }; + + int ret = neu_json_decode(buf, NEU_JSON_ELEM_SIZE(elem), elem); + if (ret != 0) { + free(req); + return -1; + } + req->node_id = elem[0].v.val_int; + + *result = req; + + return 0; +} + +void neu_parse_decode_node_setting_free(neu_parse_node_setting_req_t *req) +{ + free(req); +} \ No newline at end of file diff --git a/src/parser/neu_json_node.h b/src/parser/neu_json_node.h index e30fe63a..a4d43567 100644 --- a/src/parser/neu_json_node.h +++ b/src/parser/neu_json_node.h @@ -73,6 +73,13 @@ int neu_parse_decode_update_node(char * buf, neu_parse_update_node_req_t **result); void neu_parse_decode_update_node_free(neu_parse_update_node_req_t *req); +typedef struct { + uint32_t node_id; +} neu_parse_node_setting_req_t; +int neu_parse_decode_node_setting(char * buf, + neu_parse_node_setting_req_t **result); +void neu_parse_decode_node_setting_free(neu_parse_node_setting_req_t *req); + #ifdef __cplusplus } #endif diff --git a/src/parser/neu_json_param.h b/src/parser/neu_json_param.h new file mode 100644 index 00000000..93b3ddb8 --- /dev/null +++ b/src/parser/neu_json_param.h @@ -0,0 +1,36 @@ +/** + * NEURON IIoT System for Industry 4.0 + * Copyright (C) 2020-2021 EMQ Technologies Co., Ltd All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + **/ + +#ifndef _NEU_JSON_PARAM_H +#define _NEU_JSON_PARAM_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "utils/json.h" + +int neu_parse_param(char *buf, char **err_param, int n, neu_json_elem_t *ele, + ...); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/src/schema/schema.c b/src/schema/schema.c new file mode 100644 index 00000000..11e78bc2 --- /dev/null +++ b/src/schema/schema.c @@ -0,0 +1,218 @@ +/** + * NEURON IIoT System for Industry 4.0 + * Copyright (C) 2020-2021 EMQ Technologies Co., Ltd All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + **/ +#include +#include +#include +#include +#include + +#include "neu_log.h" +#include "schema.h" +#include "utils/json.h" + +struct neu_schema_valid { + void *json; + char *content; +}; + +static bool valid_init(void *json, neu_json_elem_t *ele, char *name); +static int valid_int(neu_schema_valid_t *v, void *value, char *name); +static int valid_real(neu_schema_valid_t *v, void *value, char *name); +static int valid_string(neu_schema_valid_t *v, void *value, char *name); +static int valid_enum(neu_schema_valid_t *v, void *value, char *name); + +neu_schema_valid_t *neu_schema_load(char *buf, char *plugin) +{ + void * json = neu_json_decode_new(buf); + neu_json_elem_t elem = { .name = plugin, .t = NEU_JSON_OBJECT }; + int ret = 0; + neu_schema_valid_t *st = NULL; + + assert(json != NULL); + ret = neu_json_decode_value(json, &elem); + if (ret != 0) { + neu_json_decode_free(json); + return st; + } + + st = calloc(1, sizeof(neu_schema_valid_t)); + st->json = json; + neu_json_encode(json, &st->content); + + return st; +} + +void neu_schema_free(neu_schema_valid_t *v) +{ + neu_json_decode_free(v->json); + free(v->content); + free(v); +} + +int neu_schema_valid_param(neu_schema_valid_t *v, void *value, char *name, + neu_schema_valid_type_e type) +{ + int ret = 0; + + switch (type) { + case NEU_SCHEMA_VALID_INT: + ret = valid_int(v, value, name); + break; + case NEU_SCHEMA_VALID_REAL: + ret = valid_real(v, value, name); + break; + case NEU_SCHEMA_VALID_STRING: + ret = valid_string(v, value, name); + break; + case NEU_SCHEMA_VALID_ENUM: + ret = valid_enum(v, value, name); + break; + } + + return ret; +} + +int neu_schema_valid_tag_type(neu_schema_valid_t *v, uint8_t t) +{ + int size = neu_json_decode_array_size(v->content, "tag_type"); + + if (size <= 0) { + return -1; + } + + for (int i = 0; i < size; i++) { + neu_json_elem_t e = { .name = NULL, .t = NEU_JSON_INT }; + if (neu_json_decode_array(v->content, "tag_type", i, 1, &e) == 0) { + if (t == e.v.val_int) { + return 0; + } + } + } + + return -1; +} + +static bool valid_init(void *json, neu_json_elem_t *vele, char *name) +{ + neu_json_elem_t ele = { .name = name, .t = NEU_JSON_OBJECT }; + + vele->name = "valid"; + vele->t = NEU_JSON_OBJECT; + + return neu_json_decode_value(json, &ele) == 0 && + neu_json_decode_value(ele.v.object, vele) == 0; +} + +static int valid_int(neu_schema_valid_t *v, void *value, char *name) +{ + neu_json_elem_t valid_ele = { 0 }; + neu_json_elem_t min_ele = { .name = "min", .t = NEU_JSON_INT }; + neu_json_elem_t max_ele = { .name = "max", .t = NEU_JSON_INT }; + int64_t * vv = (int64_t *) value; + + if (!valid_init(v->json, &valid_ele, name)) { + return -1; + } + + if (neu_json_decode_value(valid_ele.v.object, &min_ele) != 0 || + neu_json_decode_value(valid_ele.v.object, &max_ele) != 0) { + return 0; + } + + if (*vv >= min_ele.v.val_int && *vv <= max_ele.v.val_int) { + return 0; + } + + return -1; +} + +static int valid_real(neu_schema_valid_t *v, void *value, char *name) +{ + neu_json_elem_t valid_ele = { 0 }; + neu_json_elem_t min_ele = { .name = "min", .t = NEU_JSON_DOUBLE }; + neu_json_elem_t max_ele = { .name = "max", .t = NEU_JSON_DOUBLE }; + double * vv = (double *) value; + + if (!valid_init(v->json, &valid_ele, name)) { + return -1; + } + + if (neu_json_decode_value(valid_ele.v.object, &min_ele) != 0 || + neu_json_decode_value(valid_ele.v.object, &max_ele) != 0) { + return 0; + } + + if (*vv >= min_ele.v.val_int && *vv <= max_ele.v.val_int) { + return 0; + } + + return -1; +} + +static int valid_string(neu_schema_valid_t *v, void *value, char *name) +{ + neu_json_elem_t valid_ele = { 0 }; + neu_json_elem_t len_ele = { .name = "length", .t = NEU_JSON_INT }; + char * vv = (char *) value; + + if (!valid_init(v->json, &valid_ele, name)) { + return -1; + } + + if (neu_json_decode_value(valid_ele.v.object, &len_ele) != 0) { + return 0; + } + + if ((uint64_t) len_ele.v.val_int >= strlen(vv)) { + return 0; + } + + return -1; +} + +static int valid_enum(neu_schema_valid_t *v, void *value, char *name) +{ + neu_json_elem_t valid_ele = { 0 }; + char * valid_content = NULL; + int64_t * vv = (int64_t *) value; + int size = 0; + + if (!valid_init(v->json, &valid_ele, name)) { + return -1; + } + + neu_json_encode(valid_ele.v.object, &valid_content); + size = neu_json_decode_array_size(valid_content, "value"); + if (size <= 0) { + return -1; + } + + for (int i = 0; i < size; i++) { + neu_json_elem_t ve = { .name = NULL, .t = NEU_JSON_INT }; + if (neu_json_decode_array(valid_content, "value", i, 1, &ve) == 0) { + if (ve.v.val_int == *vv) { + free(valid_content); + return 0; + } + } + } + + free(valid_content); + return -1; +} \ No newline at end of file diff --git a/src/schema/schema.h b/src/schema/schema.h new file mode 100644 index 00000000..df5a64dd --- /dev/null +++ b/src/schema/schema.h @@ -0,0 +1,48 @@ +/** + * NEURON IIoT System for Industry 4.0 + * Copyright (C) 2020-2021 EMQ Technologies Co., Ltd All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + **/ + +#ifndef _NEU_SCHEMA_H_ +#define _NEU_SCHEMA_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +typedef enum neu_schema_valid_type { + NEU_SCHEMA_VALID_INT, + NEU_SCHEMA_VALID_REAL, + NEU_SCHEMA_VALID_STRING, + NEU_SCHEMA_VALID_ENUM, +} neu_schema_valid_type_e; + +typedef struct neu_schema_valid neu_schema_valid_t; + +neu_schema_valid_t *neu_schema_load(char *buf, char *plugin); +void neu_schema_free(neu_schema_valid_t *v); +int neu_schema_valid_param(neu_schema_valid_t *v, void *value, char *name, + neu_schema_valid_type_e); +int neu_schema_valid_tag_type(neu_schema_valid_t *v, uint8_t t); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/utils/json.c b/src/utils/json.c index de2e4181..ac845da0 100644 --- a/src/utils/json.c +++ b/src/utils/json.c @@ -287,3 +287,28 @@ int neu_json_encode(void *json_object, char **str) return 0; } + +void *neu_json_decode_new(char *buf) +{ + json_error_t error; + json_t * root = json_loads(buf, 0, &error); + + if (root == NULL) { + log_error( + "json load error, line: %d, column: %d, position: %d, info: %s", + error.line, error.column, error.position, error.text); + return NULL; + } + + return root; +} + +void neu_json_decode_free(void *ob) +{ + json_decref(ob); +} + +int neu_json_decode_value(void *object, neu_json_elem_t *ele) +{ + return decode_object(object, ele); +} \ No newline at end of file diff --git a/src/utils/json.h b/src/utils/json.h index e4e30dda..9c413c05 100644 --- a/src/utils/json.h +++ b/src/utils/json.h @@ -56,10 +56,13 @@ typedef struct neu_json_elem { #define NEU_JSON_ELEM_SIZE(elems) sizeof(elems) / sizeof(neu_json_elem_t) -int neu_json_decode(char *buf, int size, neu_json_elem_t *ele); -int neu_json_decode_array_size(char *buf, char *child); -int neu_json_decode_array(char *buf, char *name, int index, int size, - neu_json_elem_t *ele); +int neu_json_decode(char *buf, int size, neu_json_elem_t *ele); +int neu_json_decode_array_size(char *buf, char *child); +int neu_json_decode_array(char *buf, char *name, int index, int size, + neu_json_elem_t *ele); +void *neu_json_decode_new(char *buf); +void neu_json_decode_free(void *ob); +int neu_json_decode_value(void *object, neu_json_elem_t *ele); void *neu_json_encode_new(); void neu_json_encode_free(void *json_object); diff --git a/tests/config_test.cc b/tests/config_test.cc index e6280dde..cf288a7d 100644 --- a/tests/config_test.cc +++ b/tests/config_test.cc @@ -13,7 +13,7 @@ TEST(JsonTest, DecodeField) result = neu_config_get_value((char *) "./neuron.yaml", 3, (char *) "mqtt", (char *) "broker", (char *) "host"); - EXPECT_STREQ("localhost", result); + EXPECT_STREQ("broker.emqx.io", result); free(result); result = neu_config_get_value((char *) "./neuron.yaml", 3, (char *) "mqtt",