mirror of
https://github.com/emqx/neuron.git
synced 2026-10-17 04:40:42 +08:00
Merge pull request #2934 from ZhouBox/main
restful: support querying nodes by multiple plugins
This commit is contained in:
+1
-1
@@ -307,7 +307,7 @@ Neuron 将为 IIoT 平台提供一系列 API 服务,用于查询基本信息
|
||||
|
||||
**type** 必需
|
||||
|
||||
**plugin** 可选
|
||||
**plugin** 可选,支持逗号分隔多个插件名,如 `plugin=Modbus TCP,Modbus RTU`
|
||||
|
||||
**node** 可选
|
||||
|
||||
|
||||
@@ -299,7 +299,7 @@ Neuron provide a series of API services for IIoT platform, to query the basic in
|
||||
|
||||
**type** required
|
||||
|
||||
**plugin** optional
|
||||
**plugin** optional, support multiple plugin names separated by comma, e.g. `plugin=Modbus TCP,Modbus RTU`
|
||||
|
||||
**node** optional
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#define NEU_DEFAULT_GROUP_INTERVAL 100
|
||||
#define NEU_NODE_NAME_LEN 128
|
||||
#define NEU_PLUGIN_NAME_LEN 32
|
||||
#define NEU_PLUGIN_FILTER_MAX 16
|
||||
#define NEU_NODE_TAGS_LEN 256
|
||||
#define NEU_PLUGIN_LIBRARY_LEN 64
|
||||
#define NEU_PLUGIN_DESCRIPTION_LEN 512
|
||||
|
||||
@@ -556,7 +556,8 @@ typedef struct neu_req_del_node {
|
||||
|
||||
typedef struct neu_req_get_node {
|
||||
neu_node_type_e type;
|
||||
char plugin[NEU_PLUGIN_NAME_LEN];
|
||||
int n_plugin;
|
||||
char plugin[NEU_PLUGIN_FILTER_MAX][NEU_PLUGIN_NAME_LEN];
|
||||
char node[NEU_NODE_NAME_LEN];
|
||||
|
||||
struct {
|
||||
|
||||
@@ -203,10 +203,10 @@ void handle_del_adapter(nng_aio *aio)
|
||||
|
||||
void handle_get_adapter(nng_aio *aio)
|
||||
{
|
||||
int ret = 0;
|
||||
char plugin_name[NEU_PLUGIN_NAME_LEN] = { 0 };
|
||||
char node_name[NEU_NODE_NAME_LEN] = { 0 };
|
||||
char group_name[NEU_GROUP_NAME_LEN] = { 0 };
|
||||
int ret = 0;
|
||||
char plugin_name[NEU_PLUGIN_FILTER_MAX * NEU_PLUGIN_NAME_LEN] = { 0 };
|
||||
char node_name[NEU_NODE_NAME_LEN] = { 0 };
|
||||
char group_name[NEU_GROUP_NAME_LEN] = { 0 };
|
||||
|
||||
neu_plugin_t * plugin = neu_rest_get_plugin();
|
||||
neu_node_type_e node_type = { 0 };
|
||||
@@ -226,9 +226,40 @@ void handle_get_adapter(nng_aio *aio)
|
||||
return;
|
||||
}
|
||||
|
||||
if (neu_http_get_param_str(aio, "plugin", plugin_name,
|
||||
sizeof(plugin_name)) > 0) {
|
||||
strncpy(cmd.plugin, plugin_name, NEU_PLUGIN_NAME_LEN - 1);
|
||||
ssize_t plugin_len =
|
||||
neu_http_get_param_str(aio, "plugin", plugin_name, sizeof(plugin_name));
|
||||
if (plugin_len > 0) {
|
||||
if (plugin_len >= (ssize_t) sizeof(plugin_name)) {
|
||||
NEU_JSON_RESPONSE_ERROR(NEU_ERR_PARAM_IS_WRONG, {
|
||||
neu_http_response(aio, error_code.error, result_error);
|
||||
})
|
||||
return;
|
||||
}
|
||||
|
||||
char *save = NULL;
|
||||
char *p = strtok_r(plugin_name, ",", &save);
|
||||
while (p != NULL) {
|
||||
while (' ' == *p || '\t' == *p) {
|
||||
p++;
|
||||
}
|
||||
size_t len = strlen(p);
|
||||
while (len > 0 && (' ' == p[len - 1] || '\t' == p[len - 1])) {
|
||||
p[--len] = '\0';
|
||||
}
|
||||
if (len == 0) {
|
||||
p = strtok_r(NULL, ",", &save);
|
||||
continue;
|
||||
}
|
||||
if (cmd.n_plugin >= NEU_PLUGIN_FILTER_MAX) {
|
||||
NEU_JSON_RESPONSE_ERROR(NEU_ERR_PARAM_IS_WRONG, {
|
||||
neu_http_response(aio, error_code.error, result_error);
|
||||
})
|
||||
return;
|
||||
}
|
||||
strncpy(cmd.plugin[cmd.n_plugin], p, NEU_PLUGIN_NAME_LEN - 1);
|
||||
cmd.n_plugin++;
|
||||
p = strtok_r(NULL, ",", &save);
|
||||
}
|
||||
}
|
||||
|
||||
if (neu_http_get_param_str(aio, "node", node_name, sizeof(node_name)) > 0) {
|
||||
|
||||
+11
-5
@@ -495,8 +495,11 @@ static int manager_loop(enum neu_event_io_type type, int fd, void *usr_data)
|
||||
neu_req_del_plugin_t *cmd = (neu_req_del_plugin_t *) &header[1];
|
||||
neu_resp_error_t e = { 0 };
|
||||
|
||||
char plugins[1][NEU_PLUGIN_NAME_LEN] = { 0 };
|
||||
strncpy(plugins[0], cmd->plugin, NEU_PLUGIN_NAME_LEN - 1);
|
||||
|
||||
UT_array *nodes = neu_manager_get_nodes(
|
||||
manager, NEU_NA_TYPE_DRIVER | NEU_NA_TYPE_APP, cmd->plugin, "",
|
||||
manager, NEU_NA_TYPE_DRIVER | NEU_NA_TYPE_APP, plugins, 1, "",
|
||||
false, false, 0, false, 0, "");
|
||||
|
||||
if (nodes != NULL) {
|
||||
@@ -690,8 +693,11 @@ static int manager_loop(enum neu_event_io_type type, int fd, void *usr_data)
|
||||
break;
|
||||
}
|
||||
|
||||
char plugins[1][NEU_PLUGIN_NAME_LEN] = { 0 };
|
||||
strncpy(plugins[0], module_name, NEU_PLUGIN_NAME_LEN - 1);
|
||||
|
||||
UT_array *nodes = neu_manager_get_nodes(
|
||||
manager, NEU_NA_TYPE_DRIVER | NEU_NA_TYPE_APP, module_name, "",
|
||||
manager, NEU_NA_TYPE_DRIVER | NEU_NA_TYPE_APP, plugins, 1, "",
|
||||
false, false, 0, false, 0, "");
|
||||
|
||||
if (nodes != NULL) {
|
||||
@@ -957,9 +963,9 @@ static int manager_loop(enum neu_event_io_type type, int fd, void *usr_data)
|
||||
case NEU_REQ_GET_NODE: {
|
||||
neu_req_get_node_t *cmd = (neu_req_get_node_t *) &header[1];
|
||||
UT_array * nodes = neu_manager_get_nodes(
|
||||
manager, cmd->type, cmd->plugin, cmd->node, cmd->query.s_delay,
|
||||
cmd->query.q_state, cmd->query.state, cmd->query.q_link,
|
||||
cmd->query.link, cmd->query.q_group_name);
|
||||
manager, cmd->type, cmd->plugin, cmd->n_plugin, cmd->node,
|
||||
cmd->query.s_delay, cmd->query.q_state, cmd->query.state,
|
||||
cmd->query.q_link, cmd->query.link, cmd->query.q_group_name);
|
||||
neu_resp_get_node_t resp = { .nodes = nodes };
|
||||
|
||||
header->type = NEU_RESP_GET_NODE;
|
||||
|
||||
@@ -113,15 +113,15 @@ int neu_manager_del_node(neu_manager_t *manager, const char *node_name)
|
||||
neu_node_manager_del(manager->node_manager, node_name);
|
||||
return NEU_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
UT_array *neu_manager_get_nodes(neu_manager_t *manager, int type,
|
||||
const char *plugin, const char *node,
|
||||
const char (*plugins)[NEU_PLUGIN_NAME_LEN],
|
||||
int n_plugins, const char *node,
|
||||
bool sort_delay, bool q_state, int state,
|
||||
bool q_link, int link, const char *q_group_name)
|
||||
{
|
||||
return neu_node_manager_filter(manager->node_manager, type, plugin, node,
|
||||
sort_delay, q_state, state, q_link, link,
|
||||
q_group_name);
|
||||
return neu_node_manager_filter(manager->node_manager, type, plugins,
|
||||
n_plugins, node, sort_delay, q_state, state,
|
||||
q_link, link, q_group_name);
|
||||
}
|
||||
|
||||
int neu_manager_update_node_name(neu_manager_t *manager, const char *node,
|
||||
|
||||
@@ -59,7 +59,8 @@ int neu_manager_add_node(neu_manager_t *manager, const char *node_name,
|
||||
bool load);
|
||||
int neu_manager_del_node(neu_manager_t *manager, const char *node_name);
|
||||
UT_array *neu_manager_get_nodes(neu_manager_t *manager, int type,
|
||||
const char *plugin, const char *node,
|
||||
const char (*plugins)[NEU_PLUGIN_NAME_LEN],
|
||||
int n_plugins, const char *node,
|
||||
bool sort_delay, bool q_state, int state,
|
||||
bool q_link, int link,
|
||||
const char *q_group_name);
|
||||
|
||||
+14
-4
@@ -272,7 +272,8 @@ static bool find_tag_in_tags(const char *tags, const char *tag)
|
||||
}
|
||||
|
||||
UT_array *neu_node_manager_filter(neu_node_manager_t *mgr, int type,
|
||||
const char *plugin, const char *node,
|
||||
const char (*plugins)[NEU_PLUGIN_NAME_LEN],
|
||||
int n_plugins, const char *node,
|
||||
bool sort_delay, bool q_state, int state,
|
||||
bool q_link, int link,
|
||||
const char *q_group_name)
|
||||
@@ -287,9 +288,18 @@ UT_array *neu_node_manager_filter(neu_node_manager_t *mgr, int type,
|
||||
{
|
||||
if (!el->is_static && el->display) {
|
||||
if (el->adapter->module->type & type) {
|
||||
if (strlen(plugin) > 0 &&
|
||||
strcmp(el->adapter->module->module_name, plugin) != 0) {
|
||||
continue;
|
||||
if (n_plugins > 0) {
|
||||
bool matched = false;
|
||||
for (int i = 0; i < n_plugins; i++) {
|
||||
if (strcmp(el->adapter->module->module_name,
|
||||
plugins[i]) == 0) {
|
||||
matched = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!matched) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (strlen(node) > 0) {
|
||||
char *name_find = strstr(el->adapter->name, node);
|
||||
|
||||
@@ -52,7 +52,8 @@ uint16_t neu_node_manager_size(neu_node_manager_t *mgr);
|
||||
// neu_resp_node_info array
|
||||
UT_array *neu_node_manager_get(neu_node_manager_t *mgr, int type);
|
||||
UT_array *neu_node_manager_filter(neu_node_manager_t *mgr, int type,
|
||||
const char *plugin, const char *node,
|
||||
const char (*plugins)[NEU_PLUGIN_NAME_LEN],
|
||||
int n_plugins, const char *node,
|
||||
bool sort_delay, bool q_state, int state,
|
||||
bool q_link, int link,
|
||||
const char *q_group_name);
|
||||
|
||||
@@ -94,11 +94,13 @@ def del_node(node, jwt=config.default_jwt):
|
||||
return requests.delete(url=config.BASE_URL + '/api/v2/node', headers={"Authorization": jwt}, json={"name": node})
|
||||
|
||||
|
||||
def get_nodes(type, jwt=config.default_jwt, group=""):
|
||||
if group == "":
|
||||
return requests.get(url=config.BASE_URL + '/api/v2/node', headers={"Authorization": jwt}, params={"type": type})
|
||||
else:
|
||||
return requests.get(url=config.BASE_URL + '/api/v2/node?group=' + group, headers={"Authorization": jwt}, params={"type": type})
|
||||
def get_nodes(type, jwt=config.default_jwt, group="", plugins=None):
|
||||
params = {"type": type}
|
||||
if plugins:
|
||||
params["plugin"] = ",".join(plugins)
|
||||
if group != "":
|
||||
params["group"] = group
|
||||
return requests.get(url=config.BASE_URL + '/api/v2/node', headers={"Authorization": jwt}, params=params)
|
||||
|
||||
|
||||
def get_nodes_by_tags(type, tags, jwt=config.default_jwt):
|
||||
|
||||
@@ -59,6 +59,33 @@ class TestNode:
|
||||
assert 200 == response.status_code
|
||||
assert "mqtt" == response.json()['nodes'][0]["name"]
|
||||
|
||||
@description(given="a driver node", when="get driver node by single plugin", then="get success")
|
||||
def test_get_driver_by_single_plugin(self):
|
||||
response = api.get_nodes(type=NEU_NODE_DRIVER, plugins=[PLUGIN_MODBUS_TCP])
|
||||
assert 200 == response.status_code
|
||||
assert 1 == len(response.json()['nodes'])
|
||||
assert "modbus-tcp" == response.json()['nodes'][0]["name"]
|
||||
|
||||
@description(given="driver and app nodes", when="get driver nodes by multiple plugins", then="get success")
|
||||
def test_get_driver_by_multiple_plugins(self):
|
||||
response = api.get_nodes(type=NEU_NODE_DRIVER, plugins=[PLUGIN_MODBUS_TCP, PLUGIN_MODBUS_RTU])
|
||||
assert 200 == response.status_code
|
||||
assert 1 == len(response.json()['nodes'])
|
||||
assert "modbus-tcp" == response.json()['nodes'][0]["name"]
|
||||
|
||||
@description(given="driver node and non-existent plugin", when="get driver node by plugins with unmatched", then="get success")
|
||||
def test_get_driver_by_plugin_with_unmatched(self):
|
||||
response = api.get_nodes(type=NEU_NODE_DRIVER, plugins=[PLUGIN_MODBUS_TCP, "non-existent-plugin"])
|
||||
assert 200 == response.status_code
|
||||
assert 1 == len(response.json()['nodes'])
|
||||
assert "modbus-tcp" == response.json()['nodes'][0]["name"]
|
||||
|
||||
@description(given="driver node", when="get driver node by plugins no match", then="get empty")
|
||||
def test_get_driver_by_plugin_no_match(self):
|
||||
response = api.get_nodes(type=NEU_NODE_DRIVER, plugins=[PLUGIN_MODBUS_RTU])
|
||||
assert 200 == response.status_code
|
||||
assert [] == response.json()['nodes']
|
||||
|
||||
@description(given="existent driver node", when="update the node name to empty string", then="update failed")
|
||||
def test_update_node_name_to_empty(self):
|
||||
response = api.update_node(node="modbus-tcp", new_name="")
|
||||
|
||||
Reference in New Issue
Block a user