Files
2023-06-15 11:07:40 +08:00

685 lines
20 KiB
C

/**
* 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;
// ownership moved
json_tag->name = NULL;
json_tag->address = NULL;
json_tag->description = NULL;
if ((NEU_ATTRIBUTE_STATIC & json_tag->attribute) &&
0 !=
neu_tag_set_static_value_json(tag, json_tag->t, &json_tag->value)) {
return NEU_ERR_EINTERNAL;
}
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_TEMPLATE_NAME_LEN) {
return NEU_ERR_TEMPLATE_NAME_TOO_LONG;
}
if (strlen(req->plugin) >= NEU_PLUGIN_NAME_LEN) {
return NEU_ERR_PLUGIN_NAME_TOO_LONG;
}
cmd->n_group = 0;
cmd->groups = calloc(req->groups.len, sizeof(*cmd->groups));
if (NULL == cmd->groups) {
return NEU_ERR_EINTERNAL;
}
for (int i = 0; i < req->groups.len; i++) {
++cmd->n_group;
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 = 0;
cmd_grp->tags = calloc(req_grp->tags.len, 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) {
++cmd_grp->n_tag;
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));
return ret;
error:
for (int i = 0; i < cmd->n_group; ++i) {
for (int j = 0; j < cmd->groups[i].n_tag; ++j) {
neu_tag_fini(&cmd->groups[i].tags[j]);
}
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;
neu_reqresp_template_fini(&cmd);
}
}
if (0 != ret) {
NEU_JSON_RESPONSE_ERROR(
ret, { neu_http_response(aio, ret, result_error); });
}
})
}
void handle_del_template(nng_aio *aio)
{
neu_plugin_t *plugin = neu_rest_get_plugin();
NEU_VALIDATE_JWT(aio);
neu_req_del_template_t cmd = { 0 };
int ret = neu_http_get_param_str(aio, "name", cmd.name, sizeof(cmd.name));
// optional parameter
if (-2 != ret && (ret <= 0 || sizeof(cmd.name) <= (size_t) ret)) {
NEU_JSON_RESPONSE_ERROR(NEU_ERR_PARAM_IS_WRONG, {
neu_http_response(aio, NEU_ERR_PARAM_IS_WRONG, result_error);
});
return;
}
neu_reqresp_head_t header = {
.ctx = aio,
.type = NEU_REQ_DEL_TEMPLATE,
};
if (0 != neu_plugin_op(plugin, header, &cmd)) {
NEU_JSON_RESPONSE_ERROR(NEU_ERR_IS_BUSY, {
neu_http_response(aio, NEU_ERR_IS_BUSY, result_error);
});
}
}
void handle_get_template(nng_aio *aio)
{
neu_plugin_t *plugin = neu_rest_get_plugin();
NEU_VALIDATE_JWT(aio);
neu_reqresp_head_t header = {
.ctx = aio,
};
neu_req_get_template_t cmd = { 0 };
int ret = neu_http_get_param_str(aio, "name", cmd.name, sizeof(cmd.name));
if (0 < ret && (size_t) ret < sizeof(cmd.name)) {
// valid name parameter provided
header.type = NEU_REQ_GET_TEMPLATE;
} else if (-2 == ret) {
// no name parameter
header.type = NEU_REQ_GET_TEMPLATES;
} else {
// invalid name parameter
NEU_JSON_RESPONSE_ERROR(NEU_ERR_PARAM_IS_WRONG, {
neu_http_response(aio, NEU_ERR_PARAM_IS_WRONG, result_error);
});
return;
}
if (0 != neu_plugin_op(plugin, header, &cmd)) {
NEU_JSON_RESPONSE_ERROR(NEU_ERR_IS_BUSY, {
neu_http_response(aio, NEU_ERR_IS_BUSY, result_error);
});
}
}
void handle_get_template_resp(nng_aio *aio, neu_resp_get_template_t *resp)
{
int rv = 0;
int i = 0;
char * result = NULL;
neu_json_template_group_t *grp = NULL;
if (0 == resp->n_group) {
// no groups
goto end;
}
grp = calloc(resp->n_group, sizeof(*grp));
if (NULL == grp) {
rv = NEU_ERR_EINTERNAL;
goto end;
}
for (i = 0; i < resp->n_group; ++i) {
grp[i].name = resp->groups[i].name;
grp[i].interval = resp->groups[i].interval;
if (0 == resp->groups[i].n_tag) {
// no tags
continue;
}
neu_json_tag_array_t tags = { 0 };
tags.len = resp->groups[i].n_tag;
tags.tags = calloc(tags.len, sizeof(*tags.tags));
if (NULL == tags.tags) {
rv = NEU_ERR_EINTERNAL;
goto end;
}
for (int j = 0; j < tags.len; ++j) {
neu_datatag_t *tag = &resp->groups[i].tags[j];
tags.tags[j].name = tag->name;
tags.tags[j].address = tag->address;
tags.tags[j].description = tag->description;
tags.tags[j].type = tag->type;
tags.tags[j].attribute = tag->attribute;
tags.tags[j].precision = tag->precision;
tags.tags[j].decimal = tag->decimal;
if (neu_tag_attribute_test(tag, NEU_ATTRIBUTE_STATIC)) {
neu_tag_get_static_value_json(tag, &tags.tags[j].t,
&tags.tags[j].value);
} else {
tags.tags[j].t = NEU_JSON_UNDEFINE;
}
}
grp[i].tags = tags;
}
end:
if (0 == rv) {
neu_json_template_t res = {
.name = resp->name,
.plugin = resp->plugin,
.groups.len = resp->n_group,
.groups.groups = grp,
};
neu_json_encode_by_fn(&res, neu_json_encode_template, &result);
} else {
neu_json_error_resp_t error_code = { .error = rv };
neu_json_encode_by_fn(&error_code, neu_json_encode_error_resp, &result);
}
neu_http_ok(aio, result);
while (--i >= 0) {
free(grp[i].tags.tags);
}
free(grp);
free(result);
neu_reqresp_template_fini(resp);
return;
}
void handle_get_templates_resp(nng_aio *aio, neu_resp_get_templates_t *resp)
{
neu_json_template_info_t *info = calloc(resp->n_templates, sizeof(*info));
if (NULL == info) {
NEU_JSON_RESPONSE_ERROR(NEU_ERR_EINTERNAL, {
neu_http_response(aio, NEU_ERR_EINTERNAL, result_error);
});
neu_resp_get_templates_fini(resp);
return;
}
for (int i = 0; i < resp->n_templates; ++i) {
info[i].name = resp->templates[i].name;
info[i].plugin = resp->templates[i].plugin;
}
char * result = NULL;
neu_json_template_info_array_t res = {
.len = resp->n_templates,
.info = info,
};
neu_json_encode_by_fn(&res, neu_json_encode_get_templates_resp, &result);
neu_http_ok(aio, result);
free(result);
free(info);
neu_resp_get_templates_fini(resp);
return;
}
static inline int
send_template_mod_group_req(nng_aio *aio, neu_reqresp_type_e type,
neu_json_template_mod_group_req_t *req)
{
neu_plugin_t *plugin = neu_rest_get_plugin();
if (strlen(req->tmpl) >= NEU_TEMPLATE_NAME_LEN) {
return NEU_ERR_TEMPLATE_NAME_TOO_LONG;
} else if (strlen(req->group) >= NEU_GROUP_NAME_LEN) {
return NEU_ERR_GROUP_NAME_TOO_LONG;
} else if (req->interval < NEU_GROUP_INTERVAL_LIMIT) {
return NEU_ERR_GROUP_PARAMETER_INVALID;
}
neu_req_add_template_group_t cmd = { 0 };
strcpy(cmd.tmpl, req->tmpl);
strcpy(cmd.group, req->group);
cmd.interval = req->interval;
neu_reqresp_head_t header = {
.ctx = aio,
.type = type,
};
if (0 != neu_plugin_op(plugin, header, &cmd)) {
return NEU_ERR_IS_BUSY;
}
return 0;
}
static inline void process_mod_template_group(nng_aio * aio,
neu_reqresp_type_e type)
{
NEU_PROCESS_HTTP_REQUEST_VALIDATE_JWT(
aio, neu_json_template_mod_group_req_t,
neu_json_decode_template_mod_group_req, {
int ret = send_template_mod_group_req(aio, type, req);
if (ret != 0) {
NEU_JSON_RESPONSE_ERROR(
ret, { neu_http_response(aio, ret, result_error); });
}
})
}
void handle_add_template_group(nng_aio *aio)
{
process_mod_template_group(aio, NEU_REQ_ADD_TEMPLATE_GROUP);
}
void handle_update_template_group(nng_aio *aio)
{
process_mod_template_group(aio, NEU_REQ_UPDATE_TEMPLATE_GROUP);
}
static inline int
send_template_del_group_req(nng_aio * aio,
neu_json_template_del_group_req_t *req)
{
neu_plugin_t *plugin = neu_rest_get_plugin();
if (strlen(req->tmpl) >= NEU_TEMPLATE_NAME_LEN) {
return NEU_ERR_TEMPLATE_NAME_TOO_LONG;
}
if (strlen(req->group) >= NEU_GROUP_NAME_LEN) {
return NEU_ERR_GROUP_NAME_TOO_LONG;
}
neu_req_add_template_tag_t cmd = { 0 };
strcpy(cmd.tmpl, req->tmpl);
strcpy(cmd.group, req->group);
neu_reqresp_head_t header = {
.ctx = aio,
.type = NEU_REQ_DEL_TEMPLATE_GROUP,
};
if (0 != neu_plugin_op(plugin, header, &cmd)) {
return NEU_ERR_IS_BUSY;
}
return 0;
}
void handle_del_template_group(nng_aio *aio)
{
NEU_PROCESS_HTTP_REQUEST_VALIDATE_JWT(
aio, neu_json_template_del_group_req_t,
neu_json_decode_template_del_group_req, {
int ret = send_template_del_group_req(aio, req);
if (0 != ret) {
NEU_JSON_RESPONSE_ERROR(
ret, { neu_http_response(aio, ret, result_error); });
}
})
}
static int send_template_mod_tags_req(nng_aio *aio, neu_reqresp_type_e type,
neu_json_template_mod_tags_req_t *req)
{
int ret = 0;
neu_plugin_t *plugin = neu_rest_get_plugin();
if (strlen(req->tmpl) >= NEU_TEMPLATE_NAME_LEN) {
return NEU_ERR_TEMPLATE_NAME_TOO_LONG;
}
if (strlen(req->group) >= NEU_GROUP_NAME_LEN) {
return NEU_ERR_GROUP_NAME_TOO_LONG;
}
neu_req_add_template_tag_t cmd = { 0 };
strcpy(cmd.tmpl, req->tmpl);
strcpy(cmd.group, req->group);
cmd.tags = calloc(req->n_tag, sizeof(neu_datatag_t));
if (NULL == cmd.tags) {
return NEU_ERR_EINTERNAL;
}
for (int i = 0; i < req->n_tag; i++) {
cmd.n_tag += 1;
if (0 != (ret = set_tag_by_json(&cmd.tags[i], &req->tags[i]))) {
neu_req_add_template_tag_fini(&cmd);
return ret;
}
}
neu_reqresp_head_t header = {
.ctx = aio,
.type = type,
};
if (0 != neu_plugin_op(plugin, header, &cmd)) {
neu_req_add_template_tag_fini(&cmd);
return NEU_ERR_IS_BUSY;
}
return ret;
}
static int send_template_del_tags_req(nng_aio * aio,
neu_json_template_del_tags_req_t *req)
{
int ret = 0;
neu_plugin_t *plugin = neu_rest_get_plugin();
if (strlen(req->tmpl) >= NEU_TEMPLATE_NAME_LEN) {
return NEU_ERR_TEMPLATE_NAME_TOO_LONG;
}
if (strlen(req->group) >= NEU_GROUP_NAME_LEN) {
return NEU_ERR_GROUP_NAME_TOO_LONG;
}
neu_req_del_template_tag_t cmd = { 0 };
strcpy(cmd.tmpl, req->tmpl);
strcpy(cmd.group, req->group);
cmd.tags = calloc(req->n_tags, sizeof(char *));
if (NULL == cmd.tags) {
return NEU_ERR_EINTERNAL;
}
for (int i = 0; i < req->n_tags; i++) {
if (strlen(req->tags[i]) >= NEU_TAG_NAME_LEN) {
neu_req_del_template_tag_fini(&cmd);
return NEU_ERR_TAG_NAME_TOO_LONG;
}
cmd.tags[i] = req->tags[i];
req->tags[i] = NULL; // ownership moved
cmd.n_tag += 1;
}
neu_reqresp_head_t header = {
.ctx = aio,
.type = NEU_REQ_DEL_TEMPLATE_TAG,
};
if (ret != neu_plugin_op(plugin, header, &cmd)) {
neu_req_del_template_tag_fini(&cmd);
ret = NEU_ERR_IS_BUSY;
}
return ret;
}
void handle_add_template_tags(nng_aio *aio)
{
NEU_PROCESS_HTTP_REQUEST_VALIDATE_JWT(
aio, neu_json_template_mod_tags_req_t,
neu_json_decode_template_mod_tags_req, {
int ret =
send_template_mod_tags_req(aio, NEU_REQ_ADD_TEMPLATE_TAG, req);
if (0 != ret) {
NEU_JSON_RESPONSE_ERROR(
ret, { neu_http_response(aio, ret, result_error); });
}
})
}
void handle_update_template_tags(nng_aio *aio)
{
NEU_PROCESS_HTTP_REQUEST_VALIDATE_JWT(
aio, neu_json_template_mod_tags_req_t,
neu_json_decode_template_mod_tags_req, {
int ret = send_template_mod_tags_req(
aio, NEU_REQ_UPDATE_TEMPLATE_TAG, req);
if (0 != ret) {
NEU_JSON_RESPONSE_ERROR(
ret, { neu_http_response(aio, ret, result_error); });
}
})
}
void handle_del_template_tags(nng_aio *aio)
{
NEU_PROCESS_HTTP_REQUEST_VALIDATE_JWT(
aio, neu_json_template_del_tags_req_t,
neu_json_decode_template_del_tags_req, {
int ret = send_template_del_tags_req(aio, req);
if (0 != ret) {
NEU_JSON_RESPONSE_ERROR(
ret, { neu_http_response(aio, ret, result_error); });
}
})
}
void handle_get_template_tags(nng_aio *aio)
{
neu_plugin_t *plugin = neu_rest_get_plugin();
int ret = 0;
NEU_VALIDATE_JWT(aio);
neu_reqresp_head_t header = {
.ctx = aio,
.type = NEU_REQ_GET_TEMPLATE_TAG,
};
neu_req_get_template_tag_t cmd = { 0 };
ret = neu_http_get_param_str(aio, "template", cmd.tmpl, sizeof(cmd.tmpl));
// required parameter
if (ret <= 0 || sizeof(cmd.tmpl) <= (size_t) ret) {
ret = NEU_ERR_PARAM_IS_WRONG;
goto end;
}
ret = neu_http_get_param_str(aio, "group", cmd.group, sizeof(cmd.group));
// required parameter
if (ret <= 0 || sizeof(cmd.tmpl) <= (size_t) ret) {
ret = NEU_ERR_PARAM_IS_WRONG;
goto end;
}
ret = neu_http_get_param_str(aio, "name", cmd.name, sizeof(cmd.name));
// optional parameter
if (-2 != ret && (ret <= 0 || sizeof(cmd.name) <= (size_t) ret)) {
ret = NEU_ERR_PARAM_IS_WRONG;
goto end;
}
ret = neu_plugin_op(plugin, header, &cmd);
if (0 != ret) {
ret = NEU_ERR_IS_BUSY;
}
end:
if (0 != ret) {
NEU_JSON_RESPONSE_ERROR(ret,
{ neu_http_response(aio, ret, result_error); });
}
}
static inline int send_template_inst_req(nng_aio * aio,
neu_json_template_inst_req_t *req)
{
neu_plugin_t *plugin = neu_rest_get_plugin();
if (strlen(req->name) >= NEU_TEMPLATE_NAME_LEN) {
return NEU_ERR_TEMPLATE_NAME_TOO_LONG;
}
if (strlen(req->node) >= NEU_NODE_NAME_LEN) {
return NEU_ERR_PLUGIN_NAME_TOO_LONG;
}
neu_req_inst_template_t cmd = { 0 };
strncpy(cmd.tmpl, req->name, sizeof(cmd.tmpl));
strncpy(cmd.node, req->node, sizeof(cmd.node));
neu_reqresp_head_t header = {
.ctx = aio,
.type = NEU_REQ_INST_TEMPLATE,
};
if (0 != neu_plugin_op(plugin, header, &cmd)) {
return NEU_ERR_IS_BUSY;
}
return 0;
}
void handle_instantiate_template(nng_aio *aio)
{
NEU_PROCESS_HTTP_REQUEST_VALIDATE_JWT(
aio, neu_json_template_inst_req_t, neu_json_decode_template_inst_req, {
int ret = send_template_inst_req(aio, req);
if (0 != ret) {
NEU_JSON_RESPONSE_ERROR(
ret, { neu_http_response(aio, ret, result_error); });
}
})
}
void handle_get_template_group(nng_aio *aio)
{
neu_plugin_t *plugin = neu_rest_get_plugin();
NEU_VALIDATE_JWT(aio);
neu_reqresp_head_t header = {
.ctx = aio,
.type = NEU_REQ_GET_TEMPLATE_GROUP,
};
neu_req_get_template_group_t cmd = { 0 };
int ret = neu_http_get_param_str(aio, "name", cmd.tmpl, sizeof(cmd.tmpl));
// required parameter
if (ret <= 0 || sizeof(cmd.tmpl) <= (size_t) ret) {
NEU_JSON_RESPONSE_ERROR(NEU_ERR_PARAM_IS_WRONG, {
neu_http_response(aio, NEU_ERR_PARAM_IS_WRONG, result_error);
});
return;
}
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);
});
}
}