Skip to content

Commit 821db3f

Browse files
committed
Allow simpler use by specifying key and value
1 parent 4a166bc commit 821db3f

File tree

2 files changed

+56
-29
lines changed

2 files changed

+56
-29
lines changed

README.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ mos config-get wifi.sta.enable
4646
true</code></pre>
4747

4848
## Config.Set
49-
Set device configuration parameters. Arguments:
49+
Set device configuration parameters. Arguments, either:
5050

5151
```javascript
5252
{
@@ -56,6 +56,15 @@ Set device configuration parameters. Arguments:
5656
}
5757
```
5858

59+
or
60+
61+
```
62+
{
63+
"key": "debug.level", // Config key in dotted notation
64+
"value": 3, // Config value, as JSON.
65+
}
66+
```
67+
5968
Example usage - set `debug.level` to `3`:
6069

6170
<pre class="command-line language-bash" data-user="chris" data-host="localhost" data-output="2-6,8"><code>mos call Config.Set '{"config": {"debug": {"level": 3}}}'</code></pre>

src/mgos_service_config.c

Lines changed: 46 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "mgos_service_config.h"
1919
#include "mgos_rpc.h"
2020

21+
#include "common/cs_dbg.h"
2122
#include "common/mg_str.h"
2223
#include "mgos_config_util.h"
2324
#include "mgos_hal.h"
@@ -78,25 +79,6 @@ static void mgos_config_get_handler(struct mg_rpc_request_info *ri,
7879
(void) fi;
7980
}
8081

81-
/*
82-
* Called by json_scanf() for the "config" field, and parses all the given
83-
* JSON as sys config
84-
*/
85-
static void set_handler(const char *str, int len, void *user_data) {
86-
struct mgos_config *cfg = (struct mgos_config *) user_data;
87-
char *acl_copy = (mgos_sys_config_get_conf_acl() != NULL
88-
? strdup(mgos_sys_config_get_conf_acl())
89-
: NULL);
90-
mgos_conf_parse(mg_mk_str_n(str, len), acl_copy, mgos_config_schema(), cfg);
91-
free(acl_copy);
92-
}
93-
94-
static void dummy_set_handler(const char *str, int len, void *user_data) {
95-
(void) str;
96-
(void) len;
97-
(void) user_data;
98-
}
99-
10082
static void do_save(struct mg_rpc_request_info *ri,
10183
const struct mgos_config *cfg, int level, bool try_once,
10284
bool reboot) {
@@ -136,12 +118,19 @@ static void do_save(struct mg_rpc_request_info *ri,
136118
static void mgos_config_set_handler(struct mg_rpc_request_info *ri,
137119
void *cb_arg, struct mg_rpc_frame_info *fi,
138120
struct mg_str args) {
139-
struct mgos_config *cfg = &mgos_sys_config;
140-
int level = -1, save = 1, try_once = 0, reboot = 0, dummy;
141-
// Parse with dummy config handler first to get other flags.
142-
json_scanf(args.p, args.len, ri->args_fmt, dummy_set_handler, NULL, &level,
121+
int level = -1;
122+
void *cfgp = NULL;
123+
struct mgos_config *cfg = NULL;
124+
const struct mgos_conf_entry *schema = NULL;
125+
struct json_token value = JSON_INVALID_TOKEN;
126+
char *key = NULL, *err_msg = NULL;
127+
bool save = false, try_once = false, reboot = false, free_config = false;
128+
json_scanf(args.p, args.len, ri->args_fmt, &key, &value, &value, &level,
143129
&save, &try_once, &reboot);
144-
130+
if (value.len == 0) {
131+
mg_rpc_send_errorf(ri, 400, "%s is required", "value");
132+
goto out;
133+
}
145134
if (level == 0) {
146135
mg_rpc_send_errorf(ri, 400, "not allowed");
147136
goto out;
@@ -151,13 +140,39 @@ static void mgos_config_set_handler(struct mg_rpc_request_info *ri,
151140
mg_rpc_send_errorf(ri, 400, "failed to load config");
152141
goto out;
153142
}
143+
free_config = true;
154144
} else {
155145
cfg = &mgos_sys_config;
156146
level = MGOS_CONFIG_LEVEL_USER;
157147
}
158148

159-
json_scanf(args.p, args.len, ri->args_fmt, set_handler, cfg, &dummy, &save,
160-
&try_once, &reboot);
149+
if (key != NULL) {
150+
schema = mgos_conf_find_schema_entry(key, mgos_config_schema());
151+
if (schema == NULL) {
152+
mg_rpc_send_errorf(ri, 404, "invalid config key");
153+
goto out;
154+
}
155+
cfgp = ((char *) cfg) + schema->offset;
156+
} else {
157+
schema = mgos_config_schema();
158+
cfgp = cfg;
159+
}
160+
161+
/* Include the quotes around the string value. */
162+
if (value.type == JSON_TYPE_STRING) {
163+
value.ptr--;
164+
value.len += 2;
165+
}
166+
LOG(LL_DEBUG, ("key: '%s' value '%.*s'", key, (int) value.len, value.ptr));
167+
168+
/* Note that we always use top-level ACL as it may be
169+
* more restrictive than on lower levels. */
170+
if (!mgos_conf_parse_sub_msg(mg_mk_str_n(value.ptr, value.len), schema,
171+
mgos_sys_config_get_conf_acl(), cfgp,
172+
&err_msg)) {
173+
mg_rpc_send_errorf(ri, 400, "invalid config value: %s", err_msg);
174+
goto out;
175+
}
161176

162177
if (save) {
163178
do_save(ri, cfg, level, try_once, reboot);
@@ -166,9 +181,11 @@ static void mgos_config_set_handler(struct mg_rpc_request_info *ri,
166181
}
167182

168183
out:
169-
if (cfg != &mgos_sys_config) {
184+
if (free_config) {
170185
mgos_conf_free(mgos_config_schema(), cfg);
171186
}
187+
free(err_msg);
188+
free(key);
172189
(void) cb_arg;
173190
(void) fi;
174191
}
@@ -190,8 +207,9 @@ bool mgos_rpc_service_config_init(void) {
190207
struct mg_rpc *c = mgos_rpc_get_global();
191208
mg_rpc_add_handler(c, "Config.Get", "{key: %Q, level: %d}",
192209
mgos_config_get_handler, NULL);
210+
/* value is a synonym for config. */
193211
mg_rpc_add_handler(c, "Config.Set",
194-
"{config: %M, level: %d, "
212+
"{key: %Q, config: %T, value: %T, level: %d, "
195213
"save: %B, try_once: %B, reboot: %B}",
196214
mgos_config_set_handler, NULL);
197215
mg_rpc_add_handler(c, "Config.Save", "{try_once: %B, reboot: %B}",

0 commit comments

Comments
 (0)