mirror of
https://github.com/emqx/neuron.git
synced 2026-10-19 14:23:05 +08:00
Merge pull request #1792 from eeff/eeff/dev
feat(core): read group support filter
This commit is contained in:
@@ -126,6 +126,8 @@ void neu_json_decode_write_free(neu_json_write_t *req);
|
||||
typedef struct {
|
||||
char *group;
|
||||
char *node;
|
||||
char *name;
|
||||
char *desc;
|
||||
bool sync;
|
||||
} neu_json_read_req_t;
|
||||
|
||||
|
||||
@@ -576,6 +576,8 @@ typedef struct {
|
||||
typedef struct neu_req_read_group {
|
||||
char *driver;
|
||||
char *group;
|
||||
char *name;
|
||||
char *desc;
|
||||
bool sync;
|
||||
} neu_req_read_group_t;
|
||||
|
||||
@@ -583,6 +585,8 @@ static inline void neu_req_read_group_fini(neu_req_read_group_t *req)
|
||||
{
|
||||
free(req->driver);
|
||||
free(req->group);
|
||||
free(req->name);
|
||||
free(req->desc);
|
||||
}
|
||||
|
||||
typedef struct neu_req_write_tag {
|
||||
|
||||
@@ -43,6 +43,8 @@ void handle_read(nng_aio *aio)
|
||||
|
||||
cmd.driver = req->node;
|
||||
cmd.group = req->group;
|
||||
cmd.name = req->name;
|
||||
cmd.desc = req->desc;
|
||||
cmd.sync = req->sync;
|
||||
req->node = NULL;
|
||||
req->group = NULL;
|
||||
|
||||
@@ -406,7 +406,7 @@ void neu_adapter_driver_read_group(neu_adapter_driver_t *driver,
|
||||
|
||||
neu_resp_read_group_t resp = { 0 };
|
||||
neu_group_t * group = g->group;
|
||||
UT_array * tags = neu_group_get_read_tag(group);
|
||||
UT_array *tags = neu_group_query_read_tag(group, cmd->name, cmd->desc);
|
||||
|
||||
utarray_new(resp.tags, neu_resp_tag_value_meta_icd());
|
||||
|
||||
|
||||
+70
-24
@@ -44,7 +44,6 @@ struct neu_group {
|
||||
};
|
||||
|
||||
static UT_array *to_array(tag_elem_t *tags);
|
||||
static UT_array *to_read_array(tag_elem_t *tags);
|
||||
static void split_static_array(tag_elem_t *tags, UT_array **static_tags,
|
||||
UT_array **other_tags);
|
||||
static void update_timestamp(neu_group_t *group);
|
||||
@@ -192,19 +191,84 @@ UT_array *neu_group_get_tag(neu_group_t *group)
|
||||
return array;
|
||||
}
|
||||
|
||||
UT_array *neu_group_query_tag(neu_group_t *group, const char *name)
|
||||
static inline UT_array *
|
||||
filter_tags(tag_elem_t *tags,
|
||||
bool (*predicate)(const neu_datatag_t *, void *data), void *data)
|
||||
{
|
||||
tag_elem_t *el = NULL, *tmp = NULL;
|
||||
UT_array * array = NULL;
|
||||
|
||||
pthread_mutex_lock(&group->mtx);
|
||||
utarray_new(array, neu_tag_get_icd());
|
||||
HASH_ITER(hh, group->tags, el, tmp)
|
||||
HASH_ITER(hh, tags, el, tmp)
|
||||
{
|
||||
if (strstr(el->tag->name, name) != NULL) {
|
||||
if (predicate(el->tag, data)) {
|
||||
utarray_push_back(array, el->tag);
|
||||
}
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
static inline bool is_readable(const neu_datatag_t *tag, void *data)
|
||||
{
|
||||
(void) data;
|
||||
return neu_tag_attribute_test(tag, NEU_ATTRIBUTE_READ) ||
|
||||
neu_tag_attribute_test(tag, NEU_ATTRIBUTE_SUBSCRIBE) ||
|
||||
neu_tag_attribute_test(tag, NEU_ATTRIBUTE_STATIC);
|
||||
}
|
||||
|
||||
static inline bool name_contains(const neu_datatag_t *tag, void *data)
|
||||
{
|
||||
const char *name = data;
|
||||
return strstr(tag->name, name) != NULL;
|
||||
}
|
||||
|
||||
static inline bool description_contains(const neu_datatag_t *tag, void *data)
|
||||
{
|
||||
const char *str = data;
|
||||
return tag->description && strstr(tag->description, str) != NULL;
|
||||
}
|
||||
|
||||
struct query {
|
||||
char *name;
|
||||
char *desc;
|
||||
};
|
||||
|
||||
static inline bool match_query(const neu_datatag_t *tag, void *data)
|
||||
{
|
||||
struct query *q = data;
|
||||
return (!q->name || name_contains(tag, q->name)) &&
|
||||
(!q->desc || description_contains(tag, q->desc));
|
||||
}
|
||||
|
||||
static inline bool is_readable_and_match_query(const neu_datatag_t *tag,
|
||||
void * data)
|
||||
{
|
||||
return is_readable(tag, NULL) && match_query(tag, data);
|
||||
}
|
||||
|
||||
UT_array *neu_group_query_tag(neu_group_t *group, const char *name)
|
||||
{
|
||||
UT_array *array = NULL;
|
||||
|
||||
pthread_mutex_lock(&group->mtx);
|
||||
array = filter_tags(group->tags, name_contains, (void *) name);
|
||||
pthread_mutex_unlock(&group->mtx);
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
UT_array *neu_group_query_read_tag(neu_group_t *group, const char *name,
|
||||
const char *desc)
|
||||
{
|
||||
UT_array * array = NULL;
|
||||
struct query q = {
|
||||
.name = (char *) name,
|
||||
.desc = (char *) desc,
|
||||
};
|
||||
|
||||
pthread_mutex_lock(&group->mtx);
|
||||
array = filter_tags(group->tags, is_readable_and_match_query, &q);
|
||||
pthread_mutex_unlock(&group->mtx);
|
||||
|
||||
return array;
|
||||
@@ -215,7 +279,7 @@ UT_array *neu_group_get_read_tag(neu_group_t *group)
|
||||
UT_array *array = NULL;
|
||||
|
||||
pthread_mutex_lock(&group->mtx);
|
||||
array = to_read_array(group->tags);
|
||||
array = filter_tags(group->tags, is_readable, NULL);
|
||||
pthread_mutex_unlock(&group->mtx);
|
||||
|
||||
return array;
|
||||
@@ -290,24 +354,6 @@ static UT_array *to_array(tag_elem_t *tags)
|
||||
return array;
|
||||
}
|
||||
|
||||
static UT_array *to_read_array(tag_elem_t *tags)
|
||||
{
|
||||
tag_elem_t *el = NULL, *tmp = NULL;
|
||||
UT_array * array = NULL;
|
||||
|
||||
utarray_new(array, neu_tag_get_icd());
|
||||
HASH_ITER(hh, tags, el, tmp)
|
||||
{
|
||||
if (neu_tag_attribute_test(el->tag, NEU_ATTRIBUTE_READ) ||
|
||||
neu_tag_attribute_test(el->tag, NEU_ATTRIBUTE_SUBSCRIBE) ||
|
||||
neu_tag_attribute_test(el->tag, NEU_ATTRIBUTE_STATIC)) {
|
||||
utarray_push_back(array, el->tag);
|
||||
}
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
static void split_static_array(tag_elem_t *tags, UT_array **static_tags,
|
||||
UT_array **other_tags)
|
||||
{
|
||||
|
||||
@@ -41,6 +41,8 @@ int neu_group_del_tag(neu_group_t *group, const char *tag_name);
|
||||
UT_array * neu_group_get_tag(neu_group_t *group);
|
||||
UT_array * neu_group_query_tag(neu_group_t *group, const char *name);
|
||||
UT_array * neu_group_get_read_tag(neu_group_t *group);
|
||||
UT_array * neu_group_query_read_tag(neu_group_t *group, const char *name,
|
||||
const char *desc);
|
||||
uint16_t neu_group_tag_size(const neu_group_t *group);
|
||||
neu_datatag_t *neu_group_find_tag(neu_group_t *group, const char *tag);
|
||||
void neu_group_split_static_tags(neu_group_t *group, UT_array **static_tags,
|
||||
|
||||
@@ -149,9 +149,6 @@ static inline neu_msg_t *neu_msg_new(neu_reqresp_type_e t, void *ctx,
|
||||
case NEU_REQ_GET_NODES_STATE:
|
||||
body_size = neu_reqresp_size(NEU_RESP_GET_NODES_STATE);
|
||||
break;
|
||||
case NEU_REQ_READ_GROUP:
|
||||
body_size = neu_reqresp_size(NEU_RESP_READ_GROUP);
|
||||
break;
|
||||
default:
|
||||
body_size = data_size;
|
||||
}
|
||||
|
||||
@@ -430,6 +430,11 @@ int neu_json_decode_read_req(char *buf, neu_json_read_req_t **result)
|
||||
.t = NEU_JSON_BOOL,
|
||||
.attribute = NEU_JSON_ATTRIBUTE_OPTIONAL,
|
||||
},
|
||||
{
|
||||
.name = "query",
|
||||
.t = NEU_JSON_OBJECT,
|
||||
.attribute = NEU_JSON_ATTRIBUTE_OPTIONAL,
|
||||
},
|
||||
};
|
||||
ret = neu_json_decode_by_json(json_obj, NEU_JSON_ELEM_SIZE(req_elems),
|
||||
req_elems);
|
||||
@@ -441,11 +446,36 @@ int neu_json_decode_read_req(char *buf, neu_json_read_req_t **result)
|
||||
req->group = req_elems[1].v.val_str;
|
||||
req->sync = req_elems[2].v.val_bool;
|
||||
|
||||
neu_json_elem_t query_elems[] = {
|
||||
{
|
||||
.name = "name",
|
||||
.t = NEU_JSON_STR,
|
||||
.attribute = NEU_JSON_ATTRIBUTE_OPTIONAL,
|
||||
},
|
||||
{
|
||||
.name = "description",
|
||||
.t = NEU_JSON_STR,
|
||||
.attribute = NEU_JSON_ATTRIBUTE_OPTIONAL,
|
||||
},
|
||||
};
|
||||
if (req_elems[3].v.val_object) {
|
||||
ret = neu_json_decode_by_json(req_elems[3].v.val_object,
|
||||
NEU_JSON_ELEM_SIZE(query_elems),
|
||||
query_elems);
|
||||
if (ret != 0) {
|
||||
goto error;
|
||||
}
|
||||
req->name = query_elems[0].v.val_str;
|
||||
req->desc = query_elems[1].v.val_str;
|
||||
}
|
||||
|
||||
*result = req;
|
||||
neu_json_decode_free(json_obj);
|
||||
return ret;
|
||||
|
||||
error:
|
||||
free(query_elems[0].v.val_str);
|
||||
free(query_elems[1].v.val_str);
|
||||
free(req_elems[0].v.val_str);
|
||||
free(req_elems[1].v.val_str);
|
||||
free(req);
|
||||
|
||||
@@ -68,15 +68,15 @@ coil_bit_5 = [{"name": "coil_bit_5", "address": "1!000010",
|
||||
"attribute": config.NEU_TAG_ATTRIBUTE_RW, "type": config.NEU_TYPE_BIT}]
|
||||
|
||||
input_bit_1 = [{"name": "input_bit_1", "address": "1!100001",
|
||||
"attribute": config.NEU_TAG_ATTRIBUTE_READ, "type": config.NEU_TYPE_BIT}]
|
||||
"attribute": config.NEU_TAG_ATTRIBUTE_READ, "type": config.NEU_TYPE_BIT, "description": "bit_1"}]
|
||||
input_bit_2 = [{"name": "input_bit_2", "address": "1!100002",
|
||||
"attribute": config.NEU_TAG_ATTRIBUTE_READ, "type": config.NEU_TYPE_BIT}]
|
||||
"attribute": config.NEU_TAG_ATTRIBUTE_READ, "type": config.NEU_TYPE_BIT, "description": "bit_2"}]
|
||||
input_bit_3 = [{"name": "input_bit_3", "address": "1!100003",
|
||||
"attribute": config.NEU_TAG_ATTRIBUTE_READ, "type": config.NEU_TYPE_BIT}]
|
||||
"attribute": config.NEU_TAG_ATTRIBUTE_READ, "type": config.NEU_TYPE_BIT, "description": "bit_3"}]
|
||||
input_bit_4 = [{"name": "input_bit_4", "address": "1!100005",
|
||||
"attribute": config.NEU_TAG_ATTRIBUTE_READ, "type": config.NEU_TYPE_BIT}]
|
||||
"attribute": config.NEU_TAG_ATTRIBUTE_READ, "type": config.NEU_TYPE_BIT, "description": "bit_4"}]
|
||||
input_bit_5 = [{"name": "input_bit_5", "address": "1!100010",
|
||||
"attribute": config.NEU_TAG_ATTRIBUTE_READ, "type": config.NEU_TYPE_BIT}]
|
||||
"attribute": config.NEU_TAG_ATTRIBUTE_READ, "type": config.NEU_TYPE_BIT, "description": "bit_5"}]
|
||||
|
||||
input_register_bit = [{"name": "input_register_bit", "address": "1!30101.15",
|
||||
"attribute": config.NEU_TAG_ATTRIBUTE_READ, "type": config.NEU_TYPE_BIT}]
|
||||
@@ -568,6 +568,40 @@ class TestModbus:
|
||||
assert 0 == api.read_tag(
|
||||
node=param[0], group='group', tag=input_bit_5[0]['name'])
|
||||
|
||||
@description(given="created modbus node and tags", when="read tags fuzz", then="should return correct result")
|
||||
def test_read_tags_fuzz(self, param):
|
||||
response = api.read_tags(
|
||||
node=param[0], group='group', query={"name": "input_bit"})
|
||||
assert 200 == response.status_code
|
||||
assert 5 == len(response.json()["tags"])
|
||||
|
||||
response = api.read_tags(
|
||||
node=param[0], group='group', query={"name": "input_bit_1"})
|
||||
assert 200 == response.status_code
|
||||
assert 1 == len(response.json()["tags"])
|
||||
|
||||
response = api.read_tags(
|
||||
node=param[0], group='group', query={"description": "bit"})
|
||||
assert 200 == response.status_code
|
||||
assert 5 == len(response.json()["tags"])
|
||||
|
||||
response = api.read_tags(
|
||||
node=param[0], group='group', query={"description": "bit_1"})
|
||||
assert 200 == response.status_code
|
||||
assert 1 == len(response.json()["tags"])
|
||||
|
||||
response = api.read_tags(
|
||||
node=param[0], group='group', query={"name": "input_bit", "description": "bit"})
|
||||
assert 200 == response.status_code
|
||||
assert 5 == len(response.json()["tags"])
|
||||
|
||||
response = api.read_tags(
|
||||
node=param[0], group='group', query={"name": "input_bit_1", "description": "bit_1"})
|
||||
assert 200 == response.status_code
|
||||
assert 1 == len(response.json()["tags"])
|
||||
|
||||
|
||||
|
||||
@description(given="created modbus node and tags", when="read tags synchronously", then="read fail")
|
||||
def test_read_tags_sync(self, param):
|
||||
assert error.NEU_ERR_PLUGIN_NOT_SUPPORT_READ_SYNC == api.read_tag_error(
|
||||
|
||||
@@ -145,12 +145,15 @@ def get_tags(node, group):
|
||||
return requests.get(url=config.BASE_URL + "/api/v2/tags", headers={"Authorization": config.default_jwt}, params={"node": node, "group": group})
|
||||
|
||||
|
||||
def read_tags(node, group, sync=False):
|
||||
return requests.post(url=config.BASE_URL + "/api/v2/read", headers={"Authorization": config.default_jwt}, json={"node": node, "group": group, "sync": sync})
|
||||
def read_tags(node, group, sync=False, query=None):
|
||||
body = {"node": node, "group": group, "sync": sync}
|
||||
if query:
|
||||
body["query"] = query
|
||||
return requests.post(url=config.BASE_URL + "/api/v2/read", headers={"Authorization": config.default_jwt}, json=body)
|
||||
|
||||
|
||||
def read_tag(node, group, tag, sync=False):
|
||||
response = read_tags(node, group, sync)
|
||||
response = read_tags(node, group, sync, query={"name": tag})
|
||||
assert 200 == response.status_code
|
||||
x = list(filter(lambda x: x['name'] == tag,
|
||||
response.json()['tags']))
|
||||
|
||||
Reference in New Issue
Block a user