mirror of
https://dev.iopsys.eu/bbf/bbfdm.git
synced 2025-12-10 07:44:39 +01:00
Support of event and operates from json plugin
This commit is contained in:
parent
977693a9ba
commit
d895f2d4cd
4 changed files with 419 additions and 11 deletions
127
README.md
127
README.md
|
|
@ -436,7 +436,7 @@ BBF_VENDOR_PREFIX="X_TEST_COM_"
|
|||
- The directory **'dmtree/vendor/test/'** contains an example of **test** vendor implementation
|
||||
|
||||
|
||||
## BBFDM Dynamic Object/Parameter/Operate
|
||||
## BBFDM Dynamic Object/Parameter/Operate/Event
|
||||
|
||||
`bbfdm` library allows all applications installed on the box to import its own Data Model parameters at run time in two formats:
|
||||
|
||||
|
|
@ -682,6 +682,131 @@ The application should bring its JSON file under **'/etc/bbfdm/json/'** path wit
|
|||
}
|
||||
```
|
||||
|
||||
**5. Object with Event and Operate command:**
|
||||
|
||||
```bash
|
||||
{
|
||||
"Device.X_IOPSYS_Test.": {
|
||||
"type": "object",
|
||||
"protocols": [
|
||||
"cwmp",
|
||||
"usp"
|
||||
],
|
||||
"array": false,
|
||||
"Push!": {
|
||||
"type": "event",
|
||||
"version": "2.13",
|
||||
"protocols": [
|
||||
"usp"
|
||||
],
|
||||
"data": {
|
||||
"type": "string",
|
||||
"read": true,
|
||||
"write": true,
|
||||
"version": "2.13",
|
||||
"protocols": [
|
||||
"usp"
|
||||
],
|
||||
"datatype": "string"
|
||||
}
|
||||
},
|
||||
"Status()": {
|
||||
"type": "command",
|
||||
"async": true,
|
||||
"version" : "2.12",
|
||||
"protocols": [
|
||||
"usp"
|
||||
],
|
||||
"input": {
|
||||
"Option" : {
|
||||
"type" : "string",
|
||||
"read" : "true",
|
||||
"write" : "true",
|
||||
"protocol" : [
|
||||
"usp"
|
||||
],
|
||||
"datatype" : "string"
|
||||
}
|
||||
},
|
||||
"output": {
|
||||
"Result" : {
|
||||
"type" : "string",
|
||||
"read" : "true",
|
||||
"write" : "false",
|
||||
"protocol" : [
|
||||
"usp"
|
||||
],
|
||||
"datatype" : "string"
|
||||
}
|
||||
},
|
||||
"mapping": [
|
||||
{
|
||||
"type" : "ubus",
|
||||
"ubus" : {
|
||||
"object" : "test",
|
||||
"method" : "status"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- **UBUS command:** ubus call usp operate '{"path":"Device.X_IOPSYS_Test.", "action":"Status()", "input":{"Option":"Last"}}'
|
||||
|
||||
```bash
|
||||
{
|
||||
"Results": [
|
||||
{
|
||||
"path": "Device.X_IOPSYS_Test.Status()",
|
||||
"result": [
|
||||
{
|
||||
"Result": "Success"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
- **UBUS command:** ubus call usp get_supported_dm
|
||||
|
||||
```bash
|
||||
{
|
||||
"parameters": [
|
||||
{
|
||||
"parameter": "Device.X_IOPSYS_Test.Push!",
|
||||
"type": "xsd:event",
|
||||
"in": [
|
||||
"data"
|
||||
]
|
||||
},
|
||||
...
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
- **UBUS command:** ubus call usp list_operate
|
||||
|
||||
```bash
|
||||
{
|
||||
"parameters": [
|
||||
{
|
||||
"parameter": "Device.X_IOPSYS_Test.Status()",
|
||||
"type": "async",
|
||||
"in": [
|
||||
"Option"
|
||||
],
|
||||
"out": [
|
||||
"Result"
|
||||
]
|
||||
},
|
||||
...
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
> Note1: JSON File can only add vendor or standard objects that are not implemented by `libbbfdm`
|
||||
|
||||
> Note2: JSON File is not allowed to overwrite objects/parameters
|
||||
|
|
|
|||
262
dmdynamicjson.c
262
dmdynamicjson.c
|
|
@ -19,6 +19,14 @@
|
|||
static LIST_HEAD(loaded_json_files);
|
||||
static LIST_HEAD(json_list);
|
||||
static LIST_HEAD(json_memhead);
|
||||
static operation_args empty_cmd = {
|
||||
.in = (const char**)NULL,
|
||||
.out = (const char**)NULL
|
||||
};
|
||||
|
||||
static event_args empty_event = {
|
||||
.param = (const char**)NULL,
|
||||
};
|
||||
|
||||
struct loaded_json_file
|
||||
{
|
||||
|
|
@ -30,17 +38,36 @@ struct dm_json_obj {
|
|||
struct list_head list;
|
||||
json_object *data;
|
||||
char *name;
|
||||
operation_args command_arg;
|
||||
event_args event_arg;
|
||||
};
|
||||
|
||||
static void save_json_data(struct list_head *json_list, char *name, json_object *data)
|
||||
static void save_json_data(struct list_head *json_list, char *name, json_object *data,
|
||||
const char **in_p, const char **out_p, const char **ev_arg)
|
||||
{
|
||||
struct dm_json_obj *dm_json_obj = dm_dynamic_calloc(&json_memhead, 1, sizeof(struct dm_json_obj));
|
||||
|
||||
if (name) dm_json_obj->name = dm_dynamic_strdup(&json_memhead, name);
|
||||
if (data) dm_json_obj->data = data;
|
||||
dm_json_obj->command_arg.in = in_p;
|
||||
dm_json_obj->command_arg.out = out_p;
|
||||
dm_json_obj->event_arg.param = ev_arg;
|
||||
list_add_tail(&dm_json_obj->list, json_list);
|
||||
}
|
||||
|
||||
static void free_event_command_args(const char **arg_p)
|
||||
{
|
||||
if (arg_p) {
|
||||
int i = 0;
|
||||
while (arg_p[i]) {
|
||||
dmfree((char *)arg_p[i]);
|
||||
i++;
|
||||
}
|
||||
|
||||
free((char **)arg_p);
|
||||
}
|
||||
}
|
||||
|
||||
static void free_json_data(struct list_head *json_list)
|
||||
{
|
||||
struct dm_json_obj *dm_json_obj = NULL;
|
||||
|
|
@ -49,6 +76,9 @@ static void free_json_data(struct list_head *json_list)
|
|||
dm_json_obj = list_entry(json_list->next, struct dm_json_obj, list);
|
||||
list_del(&dm_json_obj->list);
|
||||
dmfree(dm_json_obj->name);
|
||||
free_event_command_args(dm_json_obj->command_arg.in);
|
||||
free_event_command_args(dm_json_obj->command_arg.out);
|
||||
free_event_command_args(dm_json_obj->event_arg.param);
|
||||
dmfree(dm_json_obj);
|
||||
}
|
||||
}
|
||||
|
|
@ -539,6 +569,118 @@ static int getvalue_param(char *refparam, struct dmctx *ctx, void *data, char *i
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ubus_set_operate(json_object *mapping_obj, struct dmctx *ctx, void *data, void *value, char *instance)
|
||||
{
|
||||
struct json_object *ubus_obj = NULL;
|
||||
struct json_object *object = NULL;
|
||||
struct json_object *method = NULL;
|
||||
struct json_object *res = NULL;
|
||||
char obj_name[128] = {0}, *opt = NULL;
|
||||
|
||||
json_object_object_get_ex(mapping_obj, "ubus", &ubus_obj);
|
||||
json_object_object_get_ex(ubus_obj, "object", &object);
|
||||
json_object_object_get_ex(ubus_obj, "method", &method);
|
||||
|
||||
if ((opt = strstr(json_object_get_string(object), "@Name"))) {
|
||||
*opt = '\0';
|
||||
snprintf(obj_name, sizeof(obj_name), "%s%s", json_object_get_string(object), section_name((struct uci_section *)data));
|
||||
} else if ((opt = strstr(json_object_get_string(object), "@i-1"))) {
|
||||
*opt = '\0';
|
||||
snprintf(obj_name, sizeof(obj_name), "%s%d", json_object_get_string(object), atoi(instance) - 1);
|
||||
} else {
|
||||
DM_STRNCPY(obj_name, json_object_get_string(object), sizeof(obj_name));
|
||||
}
|
||||
|
||||
dmubus_operate_blob_set(obj_name, json_object_get_string(method), value, &res);
|
||||
|
||||
if (res) {
|
||||
json_object_object_foreach(res, key, val) {
|
||||
add_list_parameter(ctx, dmstrdup(key), dmstrdup(json_object_to_json_string(val)), DMT_TYPE[DMT_STRING], NULL);
|
||||
}
|
||||
json_object_put(res);
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static int setcommand_param(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
|
||||
{
|
||||
struct dm_json_obj *leaf_node = NULL;
|
||||
struct json_object *p_obj = NULL, *map_arr = NULL, *map_obj = NULL, *type = NULL;
|
||||
|
||||
char *obj = generate_path_without_instance(refparam, false);
|
||||
list_for_each_entry(leaf_node, &json_list, list) {
|
||||
if (strcmp(leaf_node->name, obj) == 0) {
|
||||
p_obj = leaf_node->data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (p_obj == NULL) {
|
||||
return CMD_FAIL;
|
||||
}
|
||||
|
||||
json_object_object_get_ex(p_obj, "mapping", &map_arr);
|
||||
if (map_arr && json_object_get_type(map_arr) == json_type_array)
|
||||
map_obj = json_object_array_get_idx(map_arr, 0);
|
||||
|
||||
if (!map_obj) {
|
||||
return CMD_FAIL;
|
||||
}
|
||||
|
||||
json_object_object_get_ex(map_obj, "type", &type);
|
||||
|
||||
if (type && strcmp(json_object_get_string(type), "ubus") == 0) {
|
||||
return ubus_set_operate(map_obj, ctx, data, value, instance);
|
||||
}
|
||||
|
||||
return CMD_FAIL;
|
||||
}
|
||||
|
||||
static int getcommand_param(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
|
||||
{
|
||||
struct dm_json_obj *leaf = NULL;
|
||||
bool found = false;
|
||||
|
||||
char *obj = generate_path_without_instance(refparam, false);
|
||||
list_for_each_entry(leaf, &json_list, list) {
|
||||
if (strcmp(leaf->name, obj) == 0) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
*value = (char *)&leaf->command_arg;
|
||||
} else {
|
||||
*value = (char *)&empty_cmd;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int getevent_param(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
|
||||
{
|
||||
struct dm_json_obj *leaf = NULL;
|
||||
bool found = false;
|
||||
|
||||
char *obj = generate_path_without_instance(refparam, false);
|
||||
list_for_each_entry(leaf, &json_list, list) {
|
||||
if (strcmp(leaf->name, obj) == 0) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
*value = (char *)&leaf->event_arg;
|
||||
} else {
|
||||
*value = (char *)&empty_event;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fill_all_arguments(struct json_object *range, struct range_args range_arg[], int range_len)
|
||||
{
|
||||
for (int i = 0; i < range_len; i++) {
|
||||
|
|
@ -841,15 +983,53 @@ static void parse_mapping_obj(char *object, json_object *mapping_obj, struct lis
|
|||
if (!mapping_obj)
|
||||
return;
|
||||
|
||||
save_json_data(list, object, mapping_obj);
|
||||
save_json_data(list, object, mapping_obj, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static bool valid_event_param(char *param)
|
||||
{
|
||||
bool ret;
|
||||
|
||||
if (strcmp(param, "type") == 0) {
|
||||
ret = false;
|
||||
} else if (strcmp(param, "version") == 0) {
|
||||
ret = false;
|
||||
} else if (strcmp(param, "protocols") == 0) {
|
||||
ret = false;
|
||||
} else {
|
||||
ret = true;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static char** fill_command_param(int count, struct json_object *obj)
|
||||
{
|
||||
char **res_p = NULL;
|
||||
if (!obj)
|
||||
return res_p;
|
||||
|
||||
res_p = malloc(sizeof(char *) * (count + 1));
|
||||
if (res_p) {
|
||||
res_p[count] = NULL;
|
||||
int id = 0;
|
||||
|
||||
json_object_object_foreach(obj, key, res_obj) {
|
||||
res_p[id] = dm_dynamic_strdup(&json_memhead, key);
|
||||
id++;
|
||||
}
|
||||
}
|
||||
|
||||
return res_p;
|
||||
}
|
||||
|
||||
static void parse_param(char *object, char *param, json_object *jobj, DMLEAF *pleaf, int i, struct list_head *list)
|
||||
{
|
||||
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type(6)*/
|
||||
struct json_object *type = NULL, *protocols = NULL, *write = NULL;
|
||||
struct json_object *type = NULL, *protocols = NULL, *write = NULL, *async = NULL;
|
||||
char full_param[512] = {0};
|
||||
size_t n_proto;
|
||||
char **in_p = NULL, **out_p = NULL, **ev_arg = NULL;
|
||||
|
||||
if (!jobj || !pleaf)
|
||||
return;
|
||||
|
|
@ -857,10 +1037,6 @@ static void parse_param(char *object, char *param, json_object *jobj, DMLEAF *pl
|
|||
//PARAM
|
||||
pleaf[i].parameter = dm_dynamic_strdup(&json_memhead, param);
|
||||
|
||||
//permission
|
||||
json_object_object_get_ex(jobj, "write", &write);
|
||||
pleaf[i].permission = (write && json_object_get_boolean(write)) ? &DMWRITE : &DMREAD;
|
||||
|
||||
//type
|
||||
json_object_object_get_ex(jobj, "type", &type);
|
||||
if (type && strcmp(json_object_get_string(type), "boolean") == 0)
|
||||
|
|
@ -879,14 +1055,84 @@ static void parse_param(char *object, char *param, json_object *jobj, DMLEAF *pl
|
|||
pleaf[i].type = DMT_TIME;
|
||||
else if (type && strcmp(json_object_get_string(type), "base64") == 0)
|
||||
pleaf[i].type = DMT_BASE64;
|
||||
else if (type && strcmp(json_object_get_string(type), "command") == 0)
|
||||
pleaf[i].type = DMT_COMMAND;
|
||||
else if (type && strcmp(json_object_get_string(type), "event") == 0)
|
||||
pleaf[i].type = DMT_EVENT;
|
||||
else
|
||||
pleaf[i].type = DMT_STRING;
|
||||
|
||||
//permission
|
||||
if (pleaf[i].type == DMT_EVENT) {
|
||||
pleaf[i].permission = &DMREAD;
|
||||
} else if (pleaf[i].type == DMT_COMMAND) {
|
||||
json_object_object_get_ex(jobj, "async", &async);
|
||||
pleaf[i].permission = (async && json_object_get_boolean(async)) ? &DMASYNC : &DMSYNC;
|
||||
} else {
|
||||
json_object_object_get_ex(jobj, "write", &write);
|
||||
pleaf[i].permission = (write && json_object_get_boolean(write)) ? &DMWRITE : &DMREAD;
|
||||
}
|
||||
|
||||
//getvalue
|
||||
if (pleaf[i].type == DMT_EVENT) {
|
||||
int param_count = 0;
|
||||
json_object_object_foreach(jobj, param, val) {
|
||||
if (valid_event_param(param)) {
|
||||
param_count++;
|
||||
if (!ev_arg) {
|
||||
ev_arg = malloc(sizeof(char*) * param_count);
|
||||
if (!ev_arg)
|
||||
break;
|
||||
} else {
|
||||
ev_arg = realloc(ev_arg, sizeof(char*) * param_count);
|
||||
if (!ev_arg)
|
||||
break;
|
||||
}
|
||||
|
||||
ev_arg[param_count - 1] = dm_dynamic_strdup(&json_memhead, param);
|
||||
}
|
||||
}
|
||||
|
||||
if (ev_arg) {
|
||||
param_count++;
|
||||
ev_arg = realloc(ev_arg, sizeof(char*) * param_count);
|
||||
ev_arg[param_count - 1] = NULL;
|
||||
}
|
||||
|
||||
pleaf[i].getvalue = getevent_param;
|
||||
} else if (pleaf[i].type == DMT_COMMAND) {
|
||||
struct json_object *input_obj = NULL, *output_obj = NULL;
|
||||
|
||||
json_object_object_get_ex(jobj, "input", &input_obj);
|
||||
json_object_object_get_ex(jobj, "output", &output_obj);
|
||||
|
||||
if (input_obj && json_object_get_type(input_obj) == json_type_object) {
|
||||
int count = json_object_object_length(input_obj);
|
||||
if (count) {
|
||||
in_p = fill_command_param(count, input_obj);
|
||||
}
|
||||
}
|
||||
|
||||
if (output_obj && json_object_get_type(output_obj) == json_type_object) {
|
||||
int count = json_object_object_length(output_obj);
|
||||
if (count) {
|
||||
out_p = fill_command_param(count, output_obj);
|
||||
}
|
||||
}
|
||||
|
||||
pleaf[i].getvalue = getcommand_param;
|
||||
} else {
|
||||
pleaf[i].getvalue = getvalue_param;
|
||||
}
|
||||
|
||||
//setvalue
|
||||
if (pleaf[i].type == DMT_EVENT) {
|
||||
pleaf[i].setvalue = NULL;
|
||||
} else if (pleaf[i].type == DMT_COMMAND) {
|
||||
pleaf[i].setvalue = setcommand_param;
|
||||
} else {
|
||||
pleaf[i].setvalue = (write && json_object_get_boolean(write)) ? setvalue_param : NULL;
|
||||
}
|
||||
|
||||
//bbfdm_type
|
||||
json_object_object_get_ex(jobj, "protocols", &protocols);
|
||||
|
|
@ -905,7 +1151,7 @@ static void parse_param(char *object, char *param, json_object *jobj, DMLEAF *pl
|
|||
pleaf[i].bbfdm_type = BBFDM_BOTH;
|
||||
|
||||
snprintf(full_param, sizeof(full_param), "%s%s", object, param);
|
||||
save_json_data(list, full_param, jobj);
|
||||
save_json_data(list, full_param, jobj, (const char**)in_p, (const char**)out_p, (const char**)ev_arg);
|
||||
}
|
||||
|
||||
static void count_obj_param_under_jsonobj(json_object *jsonobj, int *obj_number, int *param_number)
|
||||
|
|
|
|||
|
|
@ -123,6 +123,42 @@ int dmubus_call_set(char *obj, char *method, struct ubus_arg u_args[], int u_arg
|
|||
return rc;
|
||||
}
|
||||
|
||||
int dmubus_operate_blob_set(char *obj, char *method, void *value, json_object **resp)
|
||||
{
|
||||
uint32_t id;
|
||||
struct blob_buf blob;
|
||||
int rc = -1;
|
||||
|
||||
json_res = NULL;
|
||||
*resp = NULL;
|
||||
|
||||
if (ubus_ctx == NULL) {
|
||||
ubus_ctx = dm_libubus_init();
|
||||
if (ubus_ctx == NULL)
|
||||
return rc;
|
||||
}
|
||||
|
||||
memset(&blob, 0, sizeof(struct blob_buf));
|
||||
blob_buf_init(&blob, 0);
|
||||
|
||||
if (value != NULL) {
|
||||
if (!blobmsg_add_object(&blob, (json_object *)value)) {
|
||||
blob_buf_free(&blob);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ubus_lookup_id(ubus_ctx, obj, &id)) {
|
||||
rc = ubus_invoke(ubus_ctx, id, method, blob.head,
|
||||
receive_call_result_data, NULL, timeout);
|
||||
}
|
||||
|
||||
*resp = json_res;
|
||||
blob_buf_free(&blob);
|
||||
return rc;
|
||||
|
||||
}
|
||||
|
||||
static inline json_object *ubus_call_req(char *obj, char *method, struct ubus_arg u_args[], int u_args_size)
|
||||
{
|
||||
__dm_ubus_call(obj, method, u_args, u_args_size);
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ struct ubus_arg {
|
|||
|
||||
int dmubus_call(char *obj, char *method, struct ubus_arg u_args[], int u_args_size, json_object **req_res);
|
||||
int dmubus_call_set(char *obj, char *method, struct ubus_arg u_args[], int u_args_size);
|
||||
int dmubus_operate_blob_set(char *obj, char *method, void *value, json_object **resp);
|
||||
bool dmubus_object_method_exists(const char *obj);
|
||||
void dmubus_free();
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue