Merge pull request #2369 from fengzeroz/v2.11

V2.11
This commit is contained in:
fengzeroz
2025-02-06 14:09:07 +08:00
committed by GitHub
5 changed files with 295 additions and 104 deletions
+16 -6
View File
@@ -52,9 +52,9 @@ jobs:
run: |
./package-sdk.sh -p ${{ matrix.arch[2] }} -n neuron-sdk-$VERSION
- uses: actions/upload-artifact@v3
- uses: actions/upload-artifact@v4
with:
name: neuron-sdk
name: neuron-sdk-${{ matrix.arch[2] }}
path: |
neuron-sdk-*.tar.gz
@@ -83,9 +83,9 @@ jobs:
run: |
./package-sdk.sh -p ${{ matrix.arch[2] }} -n neuron-sdk-debug-$VERSION
- uses: actions/upload-artifact@v3
- uses: actions/upload-artifact@v4
with:
name: neuron-sdk
name: neuron-sdk-debug
path: |
neuron-sdk-debug-*.tar.gz
@@ -102,9 +102,19 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/download-artifact@v3
- uses: actions/download-artifact@v4
with:
name: neuron-sdk
name: neuron-sdk-debug
- uses: actions/download-artifact@v4
with:
name: neuron-sdk-aarch64
- uses: actions/download-artifact@v4
with:
name: neuron-sdk-armv4
- uses: actions/download-artifact@v4
with:
name: neuron-sdk-x86_64
- uses: softprops/action-gh-release@v1
env:
+2 -26
View File
@@ -56,8 +56,8 @@
"format": {
"name": "Upload Format",
"name_zh": "上报数据格式",
"description": "JSON format of the data reported. In Values-format mode, data are split into `values` and `errors` sub objects. In Tags-format mode, tag data are put in a single array. ECP-format is the format for connecting to ECP data storage. Custom format supports user-defined data format. For variable definition specifications, please refer to [https://docs.emqx.com/en/neuronex/latest/configuration/north-apps/mqtt/api.html].",
"description_zh": "上报数据的 JSON 格式。在 Values-format 格式下,数据被分为 `values` 和 `errors` 两个子对象。在 Tags-format 格式下,数据被放在一个数组中。 ECP-format 为对接 ECP 数据存储的格式。自定义格式,支持用户自定义上报数据格式,变量定义规范请参考【https://docs.emqx.com/zh/neuronex/latest/configuration/north-apps/mqtt/api.html】。",
"description": "JSON format of the data reported. In Values-format mode, data are split into `values` and `errors` sub objects. In Tags-format mode, tag data are put in a single array. ECP-format is the format for connecting to ECP data storage. Custom format supports user-defined data format. For variable definition specifications, please refer to 'https://docs.emqx.com/en/neuronex/latest/configuration/north-apps/mqtt/api.html'.",
"description_zh": "上报数据的 JSON 格式。在 Values-format 格式下,数据被分为 `values` 和 `errors` 两个子对象。在 Tags-format 格式下,数据被放在一个数组中。 ECP-format 为对接 ECP 数据存储的格式。自定义格式,支持用户自定义上报数据格式,变量定义规范请参考'https://docs.emqx.com/zh/neuronex/latest/configuration/north-apps/mqtt/api.html'。",
"attribute": "required",
"type": "map",
"default": 0,
@@ -129,30 +129,6 @@
"length": 255
}
},
"driver-action-req-topic": {
"name": "Driver Action Request Topic",
"name_zh": "驱动执行动作请求主题",
"description": "MQTT topic to receive driver action request messages.",
"description_zh": "驱动执行动作请求的 MQTT 主题。",
"attribute": "required",
"type": "string",
"default": "/neuron/${random_str}/action/req",
"valid": {
"length": 255
}
},
"driver-action-resp-topic": {
"name": "Driver Action Response Topic",
"name_zh": "驱动执行动作响应主题",
"description": "MQTT topic to send driver action response messages.",
"description_zh": "驱动执行动作响应的 MQTT 主题。",
"attribute": "required",
"type": "string",
"default": "/neuron/${random_str}/action/resp",
"valid": {
"length": 255
}
},
"upload_drv_state": {
"name": "Driver Status Report",
"name_zh": "驱动状态上报",
+176 -60
View File
@@ -2,6 +2,80 @@
#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));
strcpy(vt->name, key);
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;
strcpy(vt->ud, str_val);
}
}
} 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));
strcpy(vt->name, key);
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)
{
@@ -10,71 +84,24 @@ int mqtt_schema_validate(const char *schema, mqtt_schema_vt_t **vts,
return -1;
}
*vts_len = 0;
*vts = NULL;
const char *key = NULL;
json_t * value = NULL;
json_object_foreach(root, key, value)
{
if (!json_is_string(value)) {
json_decref(root);
if (*vts_len > 0) {
free(*vts);
}
return -1;
}
const char *str_val = json_string_value(value);
if (str_val == NULL) {
json_decref(root);
if (*vts_len > 0) {
free(*vts);
}
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));
strcpy(vt->name, key);
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, "${tag_values}") == 0) {
vt->vt = MQTT_SCHEMA_TAG_VALUES;
} else if (strcmp(str_val, "${static_tags}") == 0) {
vt->vt = MQTT_SCHEMA_STATIC_TAG_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] == '}') {
json_decref(root);
free(*vts);
return -1;
} else {
vt->vt = MQTT_SCHEMA_UD;
strcpy(vt->ud, str_val);
}
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;
}
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)
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();
@@ -95,7 +122,7 @@ int mqtt_schema_encode(char *driver, char *group, neu_json_read_resp_t *tags,
elem.t = NEU_JSON_STR;
elem.v.val_str = group;
break;
case MQTT_SCHEMA_TAG_VALUES: {
case MQTT_SCHEMA_TAGS: {
void *values_array = neu_json_array();
neu_json_read_resp_tag_t *p_tag = tags->tags;
@@ -130,7 +157,37 @@ int mqtt_schema_encode(char *driver, char *group, neu_json_read_resp_t *tags,
elem.v.val_object = values_array;
break;
}
case MQTT_SCHEMA_STATIC_TAG_VALUES: {
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++) {
@@ -153,6 +210,24 @@ int mqtt_schema_encode(char *driver, char *group, neu_json_read_resp_t *tags,
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();
@@ -181,15 +256,56 @@ int mqtt_schema_encode(char *driver, char *group, neu_json_read_resp_t *tags,
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 = NEU_JSON_STR;
elem.v.val_str = vts[i].ud;
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;
+18 -9
View File
@@ -32,20 +32,29 @@ extern "C" {
#include "plugin.h"
typedef enum {
MQTT_SCHEMA_TIMESTAMP = 0,
MQTT_SCHEMA_NODE_NAME = 1,
MQTT_SCHEMA_GROUP_NAME = 2,
MQTT_SCHEMA_TAG_VALUES = 3,
MQTT_SCHEMA_STATIC_TAG_VALUES = 4,
MQTT_SCHEMA_TAG_ERRORS = 5,
MQTT_SCHEMA_UD = 6,
MQTT_SCHEMA_TIMESTAMP = 0,
MQTT_SCHEMA_NODE_NAME = 1,
MQTT_SCHEMA_GROUP_NAME = 2,
MQTT_SCHEMA_TAGS = 3,
MQTT_SCHEMA_STATIC_TAGS = 4,
MQTT_SCHEMA_TAGVALUES = 5,
MQTT_SCHEMA_STATIC_TAGVALUES = 6,
MQTT_SCHEMA_TAG_ERRORS = 7,
MQTT_SCHEMA_TAG_ERROR_VALUES = 8,
MQTT_SCHEMA_UD = 9,
MQTT_SCHEMA_OBJECT = 10,
} mqtt_schema_vt_e;
typedef struct {
typedef struct mqtt_schema_vt mqtt_schema_vt_t;
typedef struct mqtt_schema_vt {
char name[128];
mqtt_schema_vt_e vt;
char ud[128];
char ud[128];
mqtt_schema_vt_t *sub_vts;
size_t n_sub_vts;
} mqtt_schema_vt_t;
int mqtt_schema_validate(const char *schema, mqtt_schema_vt_t **vts,
+83 -3
View File
@@ -29,10 +29,10 @@ TEST(validate_success, schema)
EXPECT_EQ(vts[2].vt, MQTT_SCHEMA_GROUP_NAME);
EXPECT_STREQ(vts[3].name, "tags");
EXPECT_EQ(vts[3].vt, MQTT_SCHEMA_TAG_VALUES);
EXPECT_EQ(vts[3].vt, MQTT_SCHEMA_TAGVALUES);
EXPECT_STREQ(vts[4].name, "static");
EXPECT_EQ(vts[4].vt, MQTT_SCHEMA_STATIC_TAG_VALUES);
EXPECT_EQ(vts[4].vt, MQTT_SCHEMA_STATIC_TAGS);
EXPECT_STREQ(vts[5].name, "errors");
EXPECT_EQ(vts[5].vt, MQTT_SCHEMA_TAG_ERRORS);
@@ -44,6 +44,51 @@ TEST(validate_success, schema)
free(vts);
}
TEST(validate_deep_success, schema)
{
const char *schema = "{\"timestamp\": \"${timestamp}\", \"object\": "
"{\"group\":\"${group}\", \"sub_object\": "
"{\"tags\":\"${tags}\", \"cus\":\"aabb\"}}}";
mqtt_schema_vt_t *vts;
size_t n_vts;
int ret = mqtt_schema_validate(schema, &vts, &n_vts);
EXPECT_EQ(ret, 0);
EXPECT_EQ(n_vts, 2);
EXPECT_STREQ(vts[0].name, "timestamp");
EXPECT_EQ(vts[0].vt, MQTT_SCHEMA_TIMESTAMP);
EXPECT_STREQ(vts[1].name, "object");
EXPECT_EQ(vts[1].vt, MQTT_SCHEMA_OBJECT);
EXPECT_EQ(vts[1].n_sub_vts, 2);
EXPECT_STREQ(vts[1].sub_vts[0].name, "group");
EXPECT_EQ(vts[1].sub_vts[0].vt, MQTT_SCHEMA_GROUP_NAME);
EXPECT_STREQ(vts[1].sub_vts[1].name, "sub_object");
EXPECT_EQ(vts[1].sub_vts[1].vt, MQTT_SCHEMA_OBJECT);
EXPECT_EQ(vts[1].sub_vts[1].n_sub_vts, 2);
EXPECT_STREQ(vts[1].sub_vts[1].sub_vts[0].name, "tags");
EXPECT_EQ(vts[1].sub_vts[1].sub_vts[0].vt, MQTT_SCHEMA_TAGS);
EXPECT_STREQ(vts[1].sub_vts[1].sub_vts[1].name, "cus");
EXPECT_EQ(vts[1].sub_vts[1].sub_vts[1].vt, MQTT_SCHEMA_UD);
for (size_t i = 0; i < n_vts; i++) {
if (vts[i].vt == MQTT_SCHEMA_OBJECT) {
for (size_t k = 0; k < vts[i].n_sub_vts; k++) {
if (vts[i].sub_vts[k].vt == MQTT_SCHEMA_OBJECT) {
free(vts[i].sub_vts[k].sub_vts);
}
}
free(vts[i].sub_vts);
}
}
free(vts);
}
TEST(validate_failed, schema)
{
const char *schema =
@@ -100,6 +145,41 @@ TEST(validate_success, schema_static)
mqtt_static_free(vts, n_vts);
}
TEST(schema_encode_deep, schema_encode)
{
const char *schema = "{\"timestamp\": \"${timestamp}\", \"object\": "
"{\"group\":\"${group}\", \"sub_object\": "
"{\"node\":\"${node}\", \"cus\":\"aabb\"}}}";
mqtt_schema_vt_t *vts;
size_t n_vts;
int ret = mqtt_schema_validate(schema, &vts, &n_vts);
EXPECT_EQ(ret, 0);
EXPECT_EQ(n_vts, 2);
char * result = NULL;
neu_json_read_resp_t tags = { 0 };
ret = mqtt_schema_encode((char *) "driver", (char *) "group", &tags, vts,
n_vts, NULL, 0, &result);
EXPECT_EQ(ret, 0);
EXPECT_STREQ(result,
"{\"timestamp\": 0, \"object\": {\"group\": \"group\", "
"\"sub_object\": {\"node\": \"driver\", \"cus\": \"aabb\"}}}");
free(result);
for (size_t i = 0; i < n_vts; i++) {
if (vts[i].vt == MQTT_SCHEMA_OBJECT) {
for (size_t k = 0; k < vts[i].n_sub_vts; k++) {
if (vts[i].sub_vts[k].vt == MQTT_SCHEMA_OBJECT) {
free(vts[i].sub_vts[k].sub_vts);
}
}
free(vts[i].sub_vts);
}
}
free(vts);
}
TEST(schema_encode, schema_static)
{
const char *schema =
@@ -134,7 +214,7 @@ TEST(schema_encode, schema_static)
EXPECT_STREQ(
result,
"{\"timestamp\": 0, \"node\": \"driver\", \"group\": \"group\", "
"\"tags\": [], \"static\": [{\"name\": \"static_tag1\", \"value\": "
"\"tags\": {}, \"static\": [{\"name\": \"static_tag1\", \"value\": "
"\"string\"}, {\"name\": \"static_tag2\", \"value\": 1234}, {\"name\": "
"\"static_tag3\", \"value\": 11.44}, {\"name\": \"static_tag4\", "
"\"value\": true}, {\"name\": \"static_tag5\", \"value\": \"[1, 3, "