Merge pull request #1792 from eeff/eeff/dev

feat(core): read group support filter
This commit is contained in:
fengzeroz
2024-01-03 17:47:12 +08:00
committed by GitHub
10 changed files with 156 additions and 36 deletions
+2
View File
@@ -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;
+4
View File
@@ -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 {
+2
View File
@@ -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;
+1 -1
View File
@@ -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
View File
@@ -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)
{
+2
View File
@@ -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,
-3
View File
@@ -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;
}
+30
View File
@@ -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);
+39 -5
View File
@@ -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(
+6 -3
View File
@@ -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']))