mirror of
https://github.com/emqx/neuron.git
synced 2026-10-17 04:40:42 +08:00
399 lines
13 KiB
C
399 lines
13 KiB
C
#include <jansson.h>
|
|
|
|
#include "schema.h"
|
|
|
|
static int mqtt_schema_parse(json_t *root, mqtt_schema_vt_t **vts,
|
|
size_t *vts_len, int deep)
|
|
{
|
|
*vts_len = 0;
|
|
*vts = NULL;
|
|
|
|
const char *key = NULL;
|
|
json_t * value = NULL;
|
|
|
|
json_object_foreach(root, key, value)
|
|
{
|
|
if (json_is_string(value)) {
|
|
const char *str_val = json_string_value(value);
|
|
if (str_val == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
*vts_len += 1;
|
|
*vts = realloc(*vts, *vts_len * sizeof(mqtt_schema_vt_t));
|
|
mqtt_schema_vt_t *vt = &(*vts)[*vts_len - 1];
|
|
|
|
memset(vt, 0, sizeof(mqtt_schema_vt_t));
|
|
strncpy(vt->name, key, sizeof(vt->name) - 1);
|
|
|
|
if (strcmp(str_val, "${timestamp}") == 0) {
|
|
vt->vt = MQTT_SCHEMA_TIMESTAMP;
|
|
} else if (strcmp(str_val, "${node}") == 0) {
|
|
vt->vt = MQTT_SCHEMA_NODE_NAME;
|
|
} else if (strcmp(str_val, "${group}") == 0) {
|
|
vt->vt = MQTT_SCHEMA_GROUP_NAME;
|
|
} else if (strcmp(str_val, "${tags}") == 0) {
|
|
vt->vt = MQTT_SCHEMA_TAGS;
|
|
} else if (strcmp(str_val, "${static_tags}") == 0) {
|
|
vt->vt = MQTT_SCHEMA_STATIC_TAGS;
|
|
} else if (strcmp(str_val, "${tag_values}") == 0) {
|
|
vt->vt = MQTT_SCHEMA_TAGVALUES;
|
|
} else if (strcmp(str_val, "${static_tag_values}") == 0) {
|
|
vt->vt = MQTT_SCHEMA_STATIC_TAGVALUES;
|
|
} else if (strcmp(str_val, "${tag_error_values}") == 0) {
|
|
vt->vt = MQTT_SCHEMA_TAG_ERROR_VALUES;
|
|
} else if (strcmp(str_val, "${tag_errors}") == 0) {
|
|
vt->vt = MQTT_SCHEMA_TAG_ERRORS;
|
|
} else {
|
|
if (str_val[0] == '$' && str_val[1] == '{' &&
|
|
str_val[strlen(str_val) - 1] == '}') {
|
|
return -1;
|
|
} else {
|
|
vt->vt = MQTT_SCHEMA_UD;
|
|
vt->jtype = NEU_JSON_STR;
|
|
strncpy(vt->ud, str_val, sizeof(vt->ud) - 1);
|
|
}
|
|
}
|
|
} else if (json_is_integer(value) || json_is_real(value) ||
|
|
json_is_boolean(value)) {
|
|
*vts_len += 1;
|
|
*vts = realloc(*vts, *vts_len * sizeof(mqtt_schema_vt_t));
|
|
mqtt_schema_vt_t *vt = &(*vts)[*vts_len - 1];
|
|
|
|
memset(vt, 0, sizeof(mqtt_schema_vt_t));
|
|
strncpy(vt->name, key, sizeof(vt->name) - 1);
|
|
vt->vt = MQTT_SCHEMA_UD;
|
|
|
|
if (json_is_integer(value)) {
|
|
vt->jtype = NEU_JSON_INT;
|
|
vt->jvalue.val_int = json_integer_value(value);
|
|
} else if (json_is_real(value)) {
|
|
vt->jtype = NEU_JSON_DOUBLE;
|
|
vt->jvalue.val_double = json_real_value(value);
|
|
} else {
|
|
vt->jtype = NEU_JSON_BOOL;
|
|
vt->jvalue.val_bool = json_boolean_value(value);
|
|
}
|
|
} else if (json_is_object(value)) {
|
|
if (deep >= 3) {
|
|
return -1;
|
|
}
|
|
|
|
*vts_len += 1;
|
|
*vts = realloc(*vts, *vts_len * sizeof(mqtt_schema_vt_t));
|
|
mqtt_schema_vt_t *vt = &(*vts)[*vts_len - 1];
|
|
|
|
memset(vt, 0, sizeof(mqtt_schema_vt_t));
|
|
strncpy(vt->name, key, sizeof(vt->name) - 1);
|
|
|
|
vt->vt = MQTT_SCHEMA_OBJECT;
|
|
return mqtt_schema_parse(value, &vt->sub_vts, &vt->n_sub_vts,
|
|
deep + 1);
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int mqtt_schema_validate(const char *schema, mqtt_schema_vt_t **vts,
|
|
size_t *vts_len)
|
|
{
|
|
json_t *root = json_loads(schema, 0, NULL);
|
|
if (root == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
int ret = mqtt_schema_parse(root, vts, vts_len, 1);
|
|
if (ret != 0) {
|
|
if (*vts != NULL) {
|
|
free(*vts);
|
|
*vts = NULL;
|
|
}
|
|
json_decref(root);
|
|
return -1;
|
|
}
|
|
|
|
json_decref(root);
|
|
return 0;
|
|
}
|
|
|
|
static void *schema_encode(char *driver, char *group,
|
|
neu_json_read_resp_t *tags, mqtt_schema_vt_t *vts,
|
|
size_t n_vts, mqtt_static_vt_t *s_tags,
|
|
size_t n_s_tags)
|
|
{
|
|
void *root = neu_json_encode_new();
|
|
|
|
for (size_t i = 0; i < n_vts; i++) {
|
|
neu_json_elem_t elem = {
|
|
.name = vts[i].name,
|
|
};
|
|
switch (vts[i].vt) {
|
|
case MQTT_SCHEMA_TIMESTAMP:
|
|
elem.t = NEU_JSON_INT;
|
|
elem.v.val_int = global_timestamp;
|
|
break;
|
|
case MQTT_SCHEMA_NODE_NAME:
|
|
elem.t = NEU_JSON_STR;
|
|
elem.v.val_str = driver;
|
|
break;
|
|
case MQTT_SCHEMA_GROUP_NAME:
|
|
elem.t = NEU_JSON_STR;
|
|
elem.v.val_str = group;
|
|
break;
|
|
case MQTT_SCHEMA_TAGS: {
|
|
void *values_array = neu_json_array();
|
|
|
|
neu_json_read_resp_tag_t *p_tag = tags->tags;
|
|
|
|
for (int j = 0; j < tags->n_tag; j++) {
|
|
neu_json_elem_t tag_elems[2 + NEU_TAG_META_SIZE] = { 0 };
|
|
|
|
if (p_tag->error == 0) {
|
|
tag_elems[0].name = "name";
|
|
tag_elems[0].t = NEU_JSON_STR;
|
|
tag_elems[0].v.val_str = p_tag->name;
|
|
|
|
tag_elems[1].name = "value";
|
|
tag_elems[1].t = p_tag->t;
|
|
tag_elems[1].v = p_tag->value;
|
|
tag_elems[1].precision = p_tag->precision;
|
|
|
|
for (int k = 0; k < p_tag->n_meta; k++) {
|
|
tag_elems[2 + k].name = p_tag->metas[k].name;
|
|
tag_elems[2 + k].t = p_tag->metas[k].t;
|
|
tag_elems[2 + k].v = p_tag->metas[k].value;
|
|
}
|
|
|
|
values_array = neu_json_encode_array(
|
|
values_array, tag_elems, 2 + p_tag->n_meta);
|
|
}
|
|
|
|
p_tag++;
|
|
}
|
|
|
|
elem.t = NEU_JSON_OBJECT;
|
|
elem.v.val_object = values_array;
|
|
break;
|
|
}
|
|
case MQTT_SCHEMA_TAGVALUES: {
|
|
void *values_array = neu_json_encode_new();
|
|
|
|
neu_json_read_resp_tag_t *p_tag = tags->tags;
|
|
|
|
for (int j = 0; j < tags->n_tag; j++) {
|
|
neu_json_elem_t tag_elems[1 + NEU_TAG_META_SIZE] = { 0 };
|
|
|
|
if (p_tag->error == 0) {
|
|
tag_elems[0].name = p_tag->name;
|
|
tag_elems[0].t = p_tag->t;
|
|
tag_elems[0].v = p_tag->value;
|
|
|
|
for (int k = 0; k < p_tag->n_meta; k++) {
|
|
tag_elems[1 + k].name = p_tag->metas[k].name;
|
|
tag_elems[1 + k].t = p_tag->metas[k].t;
|
|
tag_elems[1 + k].v = p_tag->metas[k].value;
|
|
}
|
|
|
|
neu_json_encode_field(values_array, tag_elems,
|
|
1 + p_tag->n_meta);
|
|
}
|
|
|
|
p_tag++;
|
|
}
|
|
|
|
elem.t = NEU_JSON_OBJECT;
|
|
elem.v.val_object = values_array;
|
|
break;
|
|
}
|
|
case MQTT_SCHEMA_STATIC_TAGS: {
|
|
void *static_array = neu_json_array();
|
|
|
|
for (size_t k = 0; k < n_s_tags; k++) {
|
|
neu_json_elem_t tag_elems[2 + NEU_TAG_META_SIZE] = { 0 };
|
|
|
|
tag_elems[0].name = "name";
|
|
tag_elems[0].t = NEU_JSON_STR;
|
|
tag_elems[0].v.val_str = s_tags[k].name;
|
|
|
|
tag_elems[1].name = "value";
|
|
tag_elems[1].t = s_tags[k].jtype;
|
|
tag_elems[1].v = s_tags[k].jvalue;
|
|
|
|
static_array =
|
|
neu_json_encode_array(static_array, tag_elems, 2);
|
|
}
|
|
|
|
elem.t = NEU_JSON_OBJECT;
|
|
elem.v.val_object = static_array;
|
|
|
|
break;
|
|
}
|
|
case MQTT_SCHEMA_STATIC_TAGVALUES: {
|
|
void *static_array = neu_json_encode_new();
|
|
|
|
for (size_t k = 0; k < n_s_tags; k++) {
|
|
neu_json_elem_t tag_elems[1 + NEU_TAG_META_SIZE] = { 0 };
|
|
|
|
tag_elems[0].name = s_tags[k].name;
|
|
tag_elems[0].t = s_tags[k].jtype;
|
|
tag_elems[0].v = s_tags[k].jvalue;
|
|
|
|
neu_json_encode_field(static_array, tag_elems, 1);
|
|
}
|
|
|
|
elem.t = NEU_JSON_OBJECT;
|
|
elem.v.val_object = static_array;
|
|
|
|
break;
|
|
}
|
|
case MQTT_SCHEMA_TAG_ERRORS: {
|
|
void *errors_array = neu_json_array();
|
|
|
|
neu_json_read_resp_tag_t *p_tag = tags->tags;
|
|
|
|
for (int k = 0; k < tags->n_tag; k++) {
|
|
neu_json_elem_t tag_elems[2 + NEU_TAG_META_SIZE] = { 0 };
|
|
|
|
if (p_tag->error != 0) {
|
|
tag_elems[0].name = "name";
|
|
tag_elems[0].t = NEU_JSON_STR;
|
|
tag_elems[0].v.val_str = p_tag->name;
|
|
|
|
tag_elems[1].name = "error";
|
|
tag_elems[1].t = NEU_JSON_INT;
|
|
tag_elems[1].v.val_int = p_tag->error;
|
|
|
|
errors_array =
|
|
neu_json_encode_array(errors_array, tag_elems, 2);
|
|
}
|
|
|
|
p_tag++;
|
|
}
|
|
|
|
elem.t = NEU_JSON_OBJECT;
|
|
elem.v.val_object = errors_array;
|
|
break;
|
|
}
|
|
case MQTT_SCHEMA_TAG_ERROR_VALUES: {
|
|
void *errors_array = neu_json_encode_new();
|
|
|
|
neu_json_read_resp_tag_t *p_tag = tags->tags;
|
|
|
|
for (int k = 0; k < tags->n_tag; k++) {
|
|
neu_json_elem_t tag_elems[1 + NEU_TAG_META_SIZE] = { 0 };
|
|
|
|
if (p_tag->error != 0) {
|
|
tag_elems[0].name = p_tag->name;
|
|
tag_elems[0].t = NEU_JSON_INT;
|
|
tag_elems[0].v.val_int = p_tag->error;
|
|
|
|
neu_json_encode_field(errors_array, tag_elems, 1);
|
|
}
|
|
|
|
p_tag++;
|
|
}
|
|
|
|
elem.t = NEU_JSON_OBJECT;
|
|
elem.v.val_object = errors_array;
|
|
break;
|
|
}
|
|
case MQTT_SCHEMA_UD:
|
|
elem.t = vts[i].jtype;
|
|
if (vts[i].jtype == NEU_JSON_STR) {
|
|
elem.v.val_str = vts[i].ud;
|
|
} else {
|
|
elem.v = vts[i].jvalue;
|
|
}
|
|
break;
|
|
case MQTT_SCHEMA_OBJECT: {
|
|
void *sub_root = schema_encode(driver, group, tags, vts[i].sub_vts,
|
|
vts[i].n_sub_vts, s_tags, n_s_tags);
|
|
elem.t = NEU_JSON_OBJECT;
|
|
elem.v.val_object = sub_root;
|
|
break;
|
|
}
|
|
}
|
|
|
|
neu_json_encode_field(root, &elem, 1);
|
|
}
|
|
|
|
return root;
|
|
}
|
|
|
|
int mqtt_schema_encode(char *driver, char *group, neu_json_read_resp_t *tags,
|
|
mqtt_schema_vt_t *vts, size_t n_vts,
|
|
mqtt_static_vt_t *s_tags, size_t n_s_tags,
|
|
char **result_str)
|
|
{
|
|
void *root =
|
|
schema_encode(driver, group, tags, vts, n_vts, s_tags, n_s_tags);
|
|
|
|
int ret = neu_json_encode(root, result_str);
|
|
neu_json_decode_free(root);
|
|
return ret;
|
|
}
|
|
|
|
int mqtt_static_validate(const char *static_tags, mqtt_static_vt_t **vts,
|
|
size_t *vts_len)
|
|
{
|
|
json_t *root = json_loads(static_tags, 0, NULL);
|
|
if (root == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
*vts_len = 0;
|
|
*vts = NULL;
|
|
|
|
const char *key = NULL;
|
|
json_t * value = NULL;
|
|
|
|
json_t *child = json_object_get(root, "static_tags");
|
|
if (child == NULL) {
|
|
json_decref(root);
|
|
return -1;
|
|
}
|
|
|
|
json_object_foreach(child, key, value)
|
|
{
|
|
*vts_len += 1;
|
|
*vts = realloc(*vts, *vts_len * sizeof(mqtt_static_vt_t));
|
|
mqtt_static_vt_t *vt = &(*vts)[*vts_len - 1];
|
|
|
|
memset(vt, 0, sizeof(mqtt_static_vt_t));
|
|
strncpy(vt->name, key, sizeof(vt->name) - 1);
|
|
|
|
if (json_is_string(value)) {
|
|
vt->jtype = NEU_JSON_STR;
|
|
vt->jvalue.val_str = strdup(json_string_value(value));
|
|
} else if (json_is_real(value)) {
|
|
vt->jtype = NEU_JSON_DOUBLE;
|
|
vt->jvalue.val_double = json_real_value(value);
|
|
} else if (json_is_integer(value)) {
|
|
vt->jtype = NEU_JSON_INT;
|
|
vt->jvalue.val_int = json_integer_value(value);
|
|
} else if (json_is_boolean(value)) {
|
|
vt->jtype = NEU_JSON_BOOL;
|
|
vt->jvalue.val_bool = json_boolean_value(value);
|
|
} else {
|
|
vt->jtype = NEU_JSON_STR;
|
|
vt->jvalue.val_str = json_dumps(value, JSON_ENCODE_ANY);
|
|
}
|
|
}
|
|
|
|
json_decref(root);
|
|
return 0;
|
|
}
|
|
|
|
void mqtt_static_free(mqtt_static_vt_t *vts, size_t vts_len)
|
|
{
|
|
for (size_t i = 0; i < vts_len; i++) {
|
|
if (vts[i].jtype == NEU_JSON_STR) {
|
|
free(vts[i].jvalue.val_str);
|
|
}
|
|
}
|
|
|
|
free(vts);
|
|
} |