Merge pull request #1119 from eeff/eeff/dev

feat(restful): add POST /api/v2/template
This commit is contained in:
eeff
2023-03-16 16:35:41 +08:00
committed by GitHub
10 changed files with 302 additions and 0 deletions
+1
View File
@@ -120,6 +120,7 @@ set(NEURON_SOURCES
plugins/restful/global_config_handle.c
plugins/restful/group_config_handle.c
plugins/restful/plugin_handle.c
plugins/restful/template_handle.c
plugins/restful/version_handle.c
plugins/restful/rest.c
plugins/restful/user.c)
+68
View File
@@ -88,6 +88,13 @@ typedef enum neu_reqresp_type {
NEU_REQ_GET_PLUGIN,
NEU_RESP_GET_PLUGIN,
NEU_REQ_ADD_TEMPLATE,
NEU_REQ_DEL_TEMPLATE,
NEU_REQ_GET_TEMPLATE,
NEU_RESP_GET_TEMPLATE,
NEU_REQ_GET_TEMPLATES,
NEU_RESP_GET_TEMPLATES,
NEU_REQRESP_TRANS_DATA,
NEU_REQRESP_NODES_STATE,
NEU_REQRESP_NODE_DELETED,
@@ -158,6 +165,13 @@ static const char *neu_reqresp_type_string_t[] = {
[NEU_REQ_GET_PLUGIN] = "NEU_REQ_GET_PLUGIN",
[NEU_RESP_GET_PLUGIN] = "NEU_RESP_GET_PLUGIN",
[NEU_REQ_ADD_TEMPLATE] = "NEU_REQ_ADD_TEMPLATE",
[NEU_REQ_DEL_TEMPLATE] = "NEU_REQ_DEL_TEMPLATE",
[NEU_REQ_GET_TEMPLATE] = "NEU_REQ_GET_TEMPLATE",
[NEU_RESP_GET_TEMPLATE] = "NEU_RESP_GET_TEMPLATE",
[NEU_REQ_GET_TEMPLATES] = "NEU_REQ_GET_TEMPLATES",
[NEU_RESP_GET_TEMPLATES] = "NEU_RESP_GET_TEMPLATES",
[NEU_REQRESP_TRANS_DATA] = "NEU_REQRESP_TRANS_DATA",
[NEU_REQRESP_NODES_STATE] = "NEU_REQRESP_NODES_STATE",
[NEU_REQRESP_NODE_DELETED] = "NEU_REQRESP_NODE_DELETED",
@@ -417,6 +431,60 @@ typedef struct {
UT_array *states; // array of neu_nodes_state_t
} neu_resp_get_nodes_state_t, neu_reqresp_nodes_state_t;
typedef struct {
char name[NEU_GROUP_NAME_LEN];
uint32_t interval;
uint16_t n_tag;
neu_datatag_t *tags;
} neu_reqresp_template_group_t;
static inline void
neu_reqresp_template_group_fini(neu_reqresp_template_group_t *grp)
{
for (uint16_t i = 0; i < grp->n_tag; ++i) {
neu_tag_fini(&grp->tags[i]);
}
free(grp->tags);
}
typedef struct {
char name[NEU_TEMPLATE_NAME_LEN];
char plugin[NEU_PLUGIN_NAME_LEN];
uint16_t n_group;
neu_reqresp_template_group_t *groups;
} neu_reqresp_template_t;
static inline void neu_reqresp_template_fini(neu_reqresp_template_t *tmpl)
{
for (uint16_t i = 0; i < tmpl->n_group; ++i) {
neu_reqresp_template_group_fini(&tmpl->groups[i]);
}
free(tmpl->groups);
}
typedef neu_reqresp_template_t neu_req_add_template_t;
typedef struct {
char name[NEU_TEMPLATE_NAME_LEN];
} neu_req_del_template_t;
typedef neu_req_del_template_t neu_req_get_template_t;
typedef neu_reqresp_template_t neu_resp_get_template_t;
typedef struct {
} neu_req_get_templates_t;
typedef struct {
char name[NEU_TEMPLATE_NAME_LEN];
char plugin[NEU_PLUGIN_NAME_LEN];
} neu_resp_template_info_t;
typedef struct {
uint16_t n_templates;
neu_resp_template_info_t *templates;
} neu_resp_get_templates_t;
typedef struct neu_req_update_license {
} neu_req_update_license_t;
+1
View File
@@ -31,6 +31,7 @@
#define NEU_PLUGIN_NAME_LEN 32
#define NEU_PLUGIN_LIBRARY_LEN 32
#define NEU_PLUGIN_DESCRIPTION_LEN 512
#define NEU_TEMPLATE_NAME_LEN 128
#define NEU_DRIVER_TAG_CACHE_EXPIRE_TIME 15
#define NEU_APP_SUBSCRIBE_MSG_SIZE 4
#define NEU_TAG_FLOAG_PRECISION_MAX 17
+6
View File
@@ -94,6 +94,10 @@ typedef enum {
NEU_ERR_LICENSE_TOKEN_NOT_MATCH = 2406,
NEU_ERR_LICENSE_BAD_CLOCK = 2407,
NEU_ERR_TEMPLATE_EXIST = 2500,
NEU_ERR_TEMPLATE_NOT_FOUND = 2501,
NEU_ERR_TEMPLATE_NAME_TOO_LONG = 2502,
// common error codes for plugins
NEU_ERR_PLUGIN_READ_FAILURE = 3000,
NEU_ERR_PLUGIN_WRITE_FAILURE = 3001,
@@ -106,6 +110,8 @@ typedef enum {
NEU_ERR_PLUGIN_NOT_RUNNING = 3010,
NEU_ERR_PLUGIN_TAG_NOT_READY = 3011,
NEU_ERR_PLUGIN_PACKET_OUT_OF_ORDER = 3012,
NEU_ERR_PLUGIN_NAME_TOO_LONG = 3013,
NEU_ERR_PLUGIN_NOT_FOUND = 3014,
NEU_ERR_MQTT_FAILURE = 4000,
NEU_ERR_MQTT_NO_CERTFILESET = 4001,
+10
View File
@@ -33,6 +33,7 @@
#include "normal_handle.h"
#include "plugin_handle.h"
#include "rw_handle.h"
#include "template_handle.h"
#include "utils/http.h"
#include "version_handle.h"
@@ -108,6 +109,9 @@ static struct neu_http_handler cors_handler[] = {
{
.url = "/api/v2/global/config",
},
{
.url = "/api/v2/template",
},
};
static struct neu_http_handler rest_handlers[] = {
@@ -335,6 +339,12 @@ static struct neu_http_handler rest_handlers[] = {
.url = "/api/v2/global/config",
.value.handler = handle_put_global_config,
},
{
.method = NEU_HTTP_METHOD_POST,
.type = NEU_HTTP_HANDLER_FUNCTION,
.url = "/api/v2/template",
.value.handler = handle_add_template,
},
};
void neu_rest_handler(const struct neu_http_handler **handlers, uint32_t *size)
+1
View File
@@ -34,6 +34,7 @@
#include "plugin_handle.h"
#include "rest.h"
#include "rw_handle.h"
#include "template_handle.h"
#include "utils/http.h"
#include "utils/log.h"
#include "utils/neu_jwt.h"
+162
View File
@@ -0,0 +1,162 @@
/**
* NEURON IIoT System for Industry 4.0
* Copyright (C) 2020-2023 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 "define.h"
#include "errcodes.h"
#include "tag.h"
#include "utils/http.h"
#include "utils/http_handler.h"
#include "utils/log.h"
#include "json/neu_json_error.h"
#include "json/neu_json_fn.h"
#include "parser/neu_json_template.h"
#include "handle.h"
static int set_tag_by_json(neu_datatag_t *tag, neu_json_tag_t *json_tag)
{
if (strlen(json_tag->name) >= NEU_TAG_NAME_LEN) {
return NEU_ERR_TAG_NAME_TOO_LONG;
}
if (strlen(json_tag->address) >= NEU_TAG_ADDRESS_LEN) {
return NEU_ERR_TAG_ADDRESS_TOO_LONG;
}
if (NULL == json_tag->description &&
NULL == (json_tag->description = strdup(""))) {
return NEU_ERR_EINTERNAL;
}
tag->name = json_tag->name;
tag->type = json_tag->type;
tag->address = json_tag->address;
tag->attribute = json_tag->attribute;
tag->precision = json_tag->precision;
tag->decimal = json_tag->decimal;
tag->description = json_tag->description;
if (NEU_ATTRIBUTE_STATIC & json_tag->attribute) {
neu_tag_set_static_value_json(tag, json_tag->t, &json_tag->value);
}
return 0;
}
static int move_template_json(neu_req_add_template_t *cmd,
neu_json_template_t * req)
{
int ret = 0;
if (strlen(req->name) >= NEU_NODE_NAME_LEN) {
return NEU_ERR_NODE_NAME_TOO_LONG;
}
if (strlen(req->plugin) >= NEU_PLUGIN_NAME_LEN) {
return NEU_ERR_PLUGIN_NAME_TOO_LONG;
}
cmd->n_group = req->groups.len;
cmd->groups = calloc(cmd->n_group, sizeof(*cmd->groups));
if (NULL == cmd->groups) {
return NEU_ERR_EINTERNAL;
}
for (int i = 0; i < req->groups.len; i++) {
neu_json_template_group_t * req_grp = &req->groups.groups[i];
neu_reqresp_template_group_t *cmd_grp = &cmd->groups[i];
if (strlen(req_grp->name) >= NEU_GROUP_NAME_LEN) {
ret = NEU_ERR_GROUP_NAME_TOO_LONG;
goto error;
}
if (req_grp->interval < NEU_GROUP_INTERVAL_LIMIT) {
ret = NEU_ERR_GROUP_PARAMETER_INVALID;
goto error;
}
cmd_grp->n_tag = req_grp->tags.len;
cmd_grp->tags = calloc(cmd_grp->n_tag, sizeof(*cmd_grp->tags));
if (NULL == cmd_grp->tags) {
ret = NEU_ERR_EINTERNAL;
goto error;
}
strncpy(cmd_grp->name, req_grp->name, sizeof(cmd_grp->name));
cmd_grp->interval = req_grp->interval;
for (int j = 0; j < req_grp->tags.len; ++j) {
neu_datatag_t * tag = &cmd_grp->tags[j];
neu_json_tag_t *req_tag = &req_grp->tags.tags[j];
if (0 != (ret = set_tag_by_json(tag, req_tag))) {
goto error;
}
}
}
strncpy(cmd->name, req->name, sizeof(cmd->name));
strncpy(cmd->plugin, req->plugin, sizeof(cmd->plugin));
for (int i = 0; i < req->groups.len; ++i) {
for (int j = 0; j < req->groups.groups[i].tags.len; ++j) {
// ownership moved
req->groups.groups[i].tags.tags[j].name = NULL;
req->groups.groups[i].tags.tags[j].address = NULL;
req->groups.groups[i].tags.tags[j].description = NULL;
}
}
return ret;
error:
for (int i = 0; i < cmd->n_group && cmd->groups[i].tags; ++i) {
free(cmd->groups[i].tags);
}
free(cmd->groups);
return ret;
}
void handle_add_template(nng_aio *aio)
{
neu_plugin_t *plugin = neu_rest_get_plugin();
NEU_PROCESS_HTTP_REQUEST_VALIDATE_JWT(
aio, neu_json_template_t, neu_json_decode_template, {
int ret = 0;
neu_reqresp_head_t header = { 0 };
header.type = NEU_REQ_ADD_TEMPLATE;
header.ctx = aio;
neu_req_add_template_t cmd = { 0 };
ret = move_template_json(&cmd, req);
if (0 == ret) {
if (0 != neu_plugin_op(plugin, header, &cmd)) {
ret = NEU_ERR_IS_BUSY;
}
}
if (0 != ret) {
NEU_JSON_RESPONSE_ERROR(
ret, { neu_http_response(aio, ret, result_error); });
}
})
}
+29
View File
@@ -0,0 +1,29 @@
/**
* NEURON IIoT System for Industry 4.0
* Copyright (C) 2020-2023 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_TEMPLATE_HANDLE_H_
#define _NEU_TEMPLATE_HANDLE_H_
#include <nng/nng.h>
#include "adapter.h"
void handle_add_template(nng_aio *aio);
#endif
+20
View File
@@ -391,6 +391,8 @@ static int adapter_loop(enum neu_event_io_type type, int fd, void *usr_data)
case NEU_RESP_GET_TAG:
case NEU_RESP_GET_NODE:
case NEU_RESP_GET_PLUGIN:
case NEU_RESP_GET_TEMPLATE:
case NEU_RESP_GET_TEMPLATES:
case NEU_RESP_GET_GROUP:
case NEU_RESP_ERROR:
case NEU_REQRESP_TRANS_DATA:
@@ -1127,6 +1129,24 @@ void *neu_msg_gen(neu_reqresp_head_t *header, void *data)
case NEU_RESP_GET_PLUGIN:
data_size = sizeof(neu_resp_get_plugin_t);
break;
case NEU_REQ_ADD_TEMPLATE:
data_size = sizeof(neu_req_add_template_t);
break;
case NEU_REQ_DEL_TEMPLATE:
data_size = sizeof(neu_req_del_template_t);
break;
case NEU_REQ_GET_TEMPLATE:
data_size = sizeof(neu_req_get_template_t);
break;
case NEU_RESP_GET_TEMPLATE:
data_size = sizeof(neu_resp_get_template_t);
break;
case NEU_REQ_GET_TEMPLATES:
data_size = sizeof(neu_req_get_templates_t);
break;
case NEU_RESP_GET_TEMPLATES:
data_size = sizeof(neu_resp_get_templates_t);
break;
case NEU_REQ_ADD_NODE:
case NEU_REQ_ADD_NODE_EVENT:
data_size = sizeof(neu_req_add_node_t);
+4
View File
@@ -325,6 +325,7 @@ int neu_http_response(nng_aio *aio, neu_err_code_e code, char *content)
case NEU_ERR_GROUP_NAME_TOO_LONG:
case NEU_ERR_INVALID_PASSWORD_LEN:
case NEU_ERR_DUPLICATE_PASSWORD:
case NEU_ERR_TEMPLATE_NAME_TOO_LONG:
status = NNG_HTTP_STATUS_BAD_REQUEST;
break;
case NEU_ERR_FILE_NOT_EXIST:
@@ -337,6 +338,8 @@ int neu_http_response(nng_aio *aio, neu_err_code_e code, char *content)
case NEU_ERR_GROUP_NOT_EXIST:
case NEU_ERR_GROUP_NOT_SUBSCRIBE:
case NEU_ERR_COMMAND_EXECUTION_FAILED:
case NEU_ERR_TEMPLATE_NOT_FOUND:
case NEU_ERR_PLUGIN_NOT_FOUND:
status = NNG_HTTP_STATUS_NOT_FOUND;
break;
case NEU_ERR_NODE_EXIST:
@@ -350,6 +353,7 @@ int neu_http_response(nng_aio *aio, neu_err_code_e code, char *content)
case NEU_ERR_GROUP_NOT_ALLOW:
case NEU_ERR_LIBRARY_NOT_ALLOW_CREATE_INSTANCE:
case NEU_ERR_NODE_NOT_ALLOW_DELETE:
case NEU_ERR_TEMPLATE_EXIST:
status = NNG_HTTP_STATUS_CONFLICT;
break;
case NEU_ERR_TAG_ATTRIBUTE_NOT_SUPPORT: