mirror of
https://github.com/cesanta/mongoose.git
synced 2026-10-16 10:39:49 +00:00
Dash levels
This commit is contained in:
1 parent
5c3ffdb570
commit
1536b6a38b
5 files changed
+254
-51
No files matched your search
+31
-21
@@ -150,19 +150,22 @@ static struct mg_str trimq(struct mg_str s) { // Trim double quotes
|
||||
return s;
|
||||
}
|
||||
|
||||
static void mg_dash_broadcast(struct mg_mgr *mgr, const char *fmt, ...) {
|
||||
static void mg_dash_broadcast(struct mg_mgr *mgr, int level, const char *fmt,
|
||||
...) {
|
||||
struct mg_connection *c;
|
||||
va_list ap;
|
||||
for (c = mgr->conns; c != NULL; c = c->next) {
|
||||
int user_level = *(int *) c->data;
|
||||
if (!c->is_websocket) continue;
|
||||
if (level > 0 && user_level < level) continue;
|
||||
if (c->send.len > MG_DASH_MAX_SEND_BUF_SIZE) {
|
||||
MG_ERROR(("%lu buffered data %lu > MG_DASH_MAX_SEND_BUF_SIZE, throttled",
|
||||
c->id, c->send.len));
|
||||
continue;
|
||||
mg_error(c, "%lu buffered data %lu > MG_DASH_MAX_SEND_BUF_SIZE", c->id,
|
||||
c->send.len);
|
||||
} else {
|
||||
va_start(ap, fmt);
|
||||
mg_ws_vprintf(c, WEBSOCKET_OP_TEXT, fmt, &ap);
|
||||
va_end(ap);
|
||||
}
|
||||
va_start(ap, fmt);
|
||||
mg_ws_vprintf(c, WEBSOCKET_OP_TEXT, fmt, &ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -246,6 +249,7 @@ static size_t mg_print_field_set(mg_pfn_t fn, void *arg, va_list *ap) {
|
||||
static size_t mg_dash_print_name(mg_pfn_t fn, void *arg, va_list *ap) {
|
||||
struct mg_dash *dash = va_arg(*ap, struct mg_dash *);
|
||||
struct mg_str *name = va_arg(*ap, struct mg_str *);
|
||||
int level = va_arg(*ap, int);
|
||||
struct mg_field_set *set = mg_dash_find_field_set(dash, *name);
|
||||
size_t n = 0;
|
||||
if (name->len == 0) {
|
||||
@@ -253,6 +257,7 @@ static size_t mg_dash_print_name(mg_pfn_t fn, void *arg, va_list *ap) {
|
||||
const char *comma = "";
|
||||
n += mg_xprintf(fn, arg, "{");
|
||||
for (fs = dash->sets; fs != NULL; fs = fs->next) {
|
||||
if (fs->read_level > 0 && level < fs->read_level) continue;
|
||||
if (fs->reader) fs->reader();
|
||||
n += mg_xprintf(fn, arg, comma);
|
||||
n += mg_xprintf(fn, arg, "%m:", MG_ESC(fs->name));
|
||||
@@ -260,7 +265,8 @@ static size_t mg_dash_print_name(mg_pfn_t fn, void *arg, va_list *ap) {
|
||||
comma = ",";
|
||||
}
|
||||
n += mg_xprintf(fn, arg, "}");
|
||||
} else if (set != NULL) {
|
||||
} else if (set != NULL &&
|
||||
(set->read_level <= 0 || level >= set->read_level)) {
|
||||
if (set->reader) set->reader();
|
||||
n += mg_xprintf(fn, arg, "%M", mg_print_field_set, set);
|
||||
} else {
|
||||
@@ -272,15 +278,16 @@ static size_t mg_dash_print_name(mg_pfn_t fn, void *arg, va_list *ap) {
|
||||
static size_t mg_dash_print(mg_pfn_t fn, void *arg, va_list *ap) {
|
||||
struct mg_str *req = va_arg(*ap, struct mg_str *);
|
||||
struct mg_dash *dash = va_arg(*ap, struct mg_dash *);
|
||||
int level = va_arg(*ap, int);
|
||||
struct mg_str name = trimq(mg_json_get_tok(*req, "$.params"));
|
||||
return mg_xprintf(fn, arg, "%M", mg_dash_print_name, dash, &name);
|
||||
return mg_xprintf(fn, arg, "%M", mg_dash_print_name, dash, &name, level);
|
||||
}
|
||||
|
||||
void mg_dash_send_change(struct mg_mgr *mgr, struct mg_field_set *set) {
|
||||
if (set->reader) set->reader();
|
||||
mg_dash_broadcast(mgr, "{%m:%m,%m:{%m:%M}}", MG_ESC("method"),
|
||||
MG_ESC("change"), MG_ESC("params"), MG_ESC(set->name),
|
||||
mg_print_field_set, set);
|
||||
mg_dash_broadcast(mgr, set->read_level, "{%m:%m,%m:{%m:%M}}",
|
||||
MG_ESC("method"), MG_ESC("change"), MG_ESC("params"),
|
||||
MG_ESC(set->name), mg_print_field_set, set);
|
||||
}
|
||||
|
||||
static int mg_dash_parse_field(struct mg_str json, struct mg_field *f) {
|
||||
@@ -310,14 +317,14 @@ static int mg_dash_parse_field(struct mg_str json, struct mg_field *f) {
|
||||
}
|
||||
|
||||
static int mg_dash_apply(struct mg_connection *c, struct mg_dash *dash,
|
||||
struct mg_str json) {
|
||||
struct mg_str json, int level) {
|
||||
struct mg_str key, val;
|
||||
size_t ofs = 0;
|
||||
int total_count = 0;
|
||||
while ((ofs = mg_json_next(json, ofs, &key, &val)) > 0) {
|
||||
struct mg_field_set *set = mg_dash_find_field_set(dash, trimq(key));
|
||||
int count = 0;
|
||||
if (set != NULL) {
|
||||
if (set != NULL && (set->write_level <= 0 || level >= set->write_level)) {
|
||||
size_t i;
|
||||
for (i = 0; set->fields[i].name != NULL; i++) {
|
||||
if (mg_dash_parse_field(val, &set->fields[i])) count++;
|
||||
@@ -327,7 +334,7 @@ static int mg_dash_apply(struct mg_connection *c, struct mg_dash *dash,
|
||||
mg_dash_send_change(c->mgr, set);
|
||||
total_count += count;
|
||||
}
|
||||
} else {
|
||||
} else if (set == NULL) {
|
||||
MG_ERROR(("UNKNOWN SET: [%.*s]", key.len, key.buf));
|
||||
}
|
||||
}
|
||||
@@ -339,11 +346,12 @@ static void mg_dash_process_msg(struct mg_connection *c,
|
||||
struct mg_dash *dash) {
|
||||
struct mg_str req = wm->data;
|
||||
struct mg_str method = trimq(mg_json_get_tok(req, "$.method"));
|
||||
int level = *(int *) c->data;
|
||||
if (mg_match(method, mg_str("get"), NULL)) {
|
||||
mg_dash_success(c, req, "%M", mg_dash_print, &req, dash);
|
||||
mg_dash_success(c, req, "%M", mg_dash_print, &req, dash, level);
|
||||
} else if (mg_match(method, mg_str("set"), NULL)) {
|
||||
struct mg_str params = trimq(mg_json_get_tok(req, "$.params"));
|
||||
int count = mg_dash_apply(c, dash, params);
|
||||
int count = mg_dash_apply(c, dash, params, level);
|
||||
mg_dash_success(c, req, "%d", count);
|
||||
} else {
|
||||
mg_dash_error(c, req, "%s", "unknown method");
|
||||
@@ -632,7 +640,8 @@ void mg_dash_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
|
||||
c->is_resp = 0;
|
||||
} else if (ev == MG_EV_HTTP_MSG && c->data[0] == '\0') {
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
// struct mg_dash_user *u = mg_dash_authenticate(hm, dash);
|
||||
struct mg_dash_user *u = mg_dash_authenticate(hm, dash);
|
||||
int level = u == NULL ? 0 : u->level;
|
||||
struct mg_str parts[5];
|
||||
memset(parts, 0, sizeof(parts));
|
||||
|
||||
@@ -643,6 +652,7 @@ void mg_dash_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
|
||||
mg_ws_printf(c, WEBSOCKET_OP_TEXT, "{%m:%m}", MG_ESC("method"),
|
||||
MG_ESC("logout"));
|
||||
} else if (mg_match(hm->uri, mg_str("/api/websocket"), NULL)) {
|
||||
*(int *) c->data = level;
|
||||
mg_ws_upgrade(c, hm, NULL);
|
||||
} else if (mg_match(hm->uri, mg_str("/fs/#"), NULL)) {
|
||||
struct mg_str name = mg_dash_file_name(hm);
|
||||
@@ -660,9 +670,9 @@ void mg_dash_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
|
||||
} else if (mg_match(hm->uri, mg_str("/api/get/#"), parts) ||
|
||||
mg_match(hm->uri, mg_str("/api/get"), NULL)) {
|
||||
mg_http_reply(c, 200, MG_JSON_HEADERS, "%M\n", mg_dash_print_name, dash,
|
||||
&parts[0]);
|
||||
&parts[0], level);
|
||||
} else if (mg_match(hm->uri, mg_str("/api/set"), NULL)) {
|
||||
int count = mg_dash_apply(c, dash, hm->body);
|
||||
int count = mg_dash_apply(c, dash, hm->body, level);
|
||||
mg_http_reply(c, 200, MG_JSON_HEADERS, "%d\n", count);
|
||||
} else if (mg_match(hm->uri, mg_str("/"), NULL)) {
|
||||
struct mg_http_serve_opts opts;
|
||||
@@ -686,7 +696,7 @@ void mg_dash_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
|
||||
for (fs = dash->sets; fs != NULL; fs = fs->next) {
|
||||
mg_dash_send_change(c->mgr, fs);
|
||||
}
|
||||
mg_dash_broadcast(c->mgr, "{%m:%m}", MG_ESC("method"), MG_ESC("ready"));
|
||||
mg_dash_broadcast(c->mgr, 0, "{%m:%m}", MG_ESC("method"), MG_ESC("ready"));
|
||||
} else if (ev == MG_EV_WS_MSG) {
|
||||
// Add this to automatically handle "get" and "set" JSON-RPC calls
|
||||
struct mg_ws_message *wm = (struct mg_ws_message *) ev_data;
|
||||
|
||||
+31
-21
@@ -29,19 +29,22 @@ static struct mg_str trimq(struct mg_str s) { // Trim double quotes
|
||||
return s;
|
||||
}
|
||||
|
||||
static void mg_dash_broadcast(struct mg_mgr *mgr, const char *fmt, ...) {
|
||||
static void mg_dash_broadcast(struct mg_mgr *mgr, int level, const char *fmt,
|
||||
...) {
|
||||
struct mg_connection *c;
|
||||
va_list ap;
|
||||
for (c = mgr->conns; c != NULL; c = c->next) {
|
||||
int user_level = *(int *) c->data;
|
||||
if (!c->is_websocket) continue;
|
||||
if (level > 0 && user_level < level) continue;
|
||||
if (c->send.len > MG_DASH_MAX_SEND_BUF_SIZE) {
|
||||
MG_ERROR(("%lu buffered data %lu > MG_DASH_MAX_SEND_BUF_SIZE, throttled",
|
||||
c->id, c->send.len));
|
||||
continue;
|
||||
mg_error(c, "%lu buffered data %lu > MG_DASH_MAX_SEND_BUF_SIZE", c->id,
|
||||
c->send.len);
|
||||
} else {
|
||||
va_start(ap, fmt);
|
||||
mg_ws_vprintf(c, WEBSOCKET_OP_TEXT, fmt, &ap);
|
||||
va_end(ap);
|
||||
}
|
||||
va_start(ap, fmt);
|
||||
mg_ws_vprintf(c, WEBSOCKET_OP_TEXT, fmt, &ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,6 +128,7 @@ static size_t mg_print_field_set(mg_pfn_t fn, void *arg, va_list *ap) {
|
||||
static size_t mg_dash_print_name(mg_pfn_t fn, void *arg, va_list *ap) {
|
||||
struct mg_dash *dash = va_arg(*ap, struct mg_dash *);
|
||||
struct mg_str *name = va_arg(*ap, struct mg_str *);
|
||||
int level = va_arg(*ap, int);
|
||||
struct mg_field_set *set = mg_dash_find_field_set(dash, *name);
|
||||
size_t n = 0;
|
||||
if (name->len == 0) {
|
||||
@@ -132,6 +136,7 @@ static size_t mg_dash_print_name(mg_pfn_t fn, void *arg, va_list *ap) {
|
||||
const char *comma = "";
|
||||
n += mg_xprintf(fn, arg, "{");
|
||||
for (fs = dash->sets; fs != NULL; fs = fs->next) {
|
||||
if (fs->read_level > 0 && level < fs->read_level) continue;
|
||||
if (fs->reader) fs->reader();
|
||||
n += mg_xprintf(fn, arg, comma);
|
||||
n += mg_xprintf(fn, arg, "%m:", MG_ESC(fs->name));
|
||||
@@ -139,7 +144,8 @@ static size_t mg_dash_print_name(mg_pfn_t fn, void *arg, va_list *ap) {
|
||||
comma = ",";
|
||||
}
|
||||
n += mg_xprintf(fn, arg, "}");
|
||||
} else if (set != NULL) {
|
||||
} else if (set != NULL &&
|
||||
(set->read_level <= 0 || level >= set->read_level)) {
|
||||
if (set->reader) set->reader();
|
||||
n += mg_xprintf(fn, arg, "%M", mg_print_field_set, set);
|
||||
} else {
|
||||
@@ -151,15 +157,16 @@ static size_t mg_dash_print_name(mg_pfn_t fn, void *arg, va_list *ap) {
|
||||
static size_t mg_dash_print(mg_pfn_t fn, void *arg, va_list *ap) {
|
||||
struct mg_str *req = va_arg(*ap, struct mg_str *);
|
||||
struct mg_dash *dash = va_arg(*ap, struct mg_dash *);
|
||||
int level = va_arg(*ap, int);
|
||||
struct mg_str name = trimq(mg_json_get_tok(*req, "$.params"));
|
||||
return mg_xprintf(fn, arg, "%M", mg_dash_print_name, dash, &name);
|
||||
return mg_xprintf(fn, arg, "%M", mg_dash_print_name, dash, &name, level);
|
||||
}
|
||||
|
||||
void mg_dash_send_change(struct mg_mgr *mgr, struct mg_field_set *set) {
|
||||
if (set->reader) set->reader();
|
||||
mg_dash_broadcast(mgr, "{%m:%m,%m:{%m:%M}}", MG_ESC("method"),
|
||||
MG_ESC("change"), MG_ESC("params"), MG_ESC(set->name),
|
||||
mg_print_field_set, set);
|
||||
mg_dash_broadcast(mgr, set->read_level, "{%m:%m,%m:{%m:%M}}",
|
||||
MG_ESC("method"), MG_ESC("change"), MG_ESC("params"),
|
||||
MG_ESC(set->name), mg_print_field_set, set);
|
||||
}
|
||||
|
||||
static int mg_dash_parse_field(struct mg_str json, struct mg_field *f) {
|
||||
@@ -189,14 +196,14 @@ static int mg_dash_parse_field(struct mg_str json, struct mg_field *f) {
|
||||
}
|
||||
|
||||
static int mg_dash_apply(struct mg_connection *c, struct mg_dash *dash,
|
||||
struct mg_str json) {
|
||||
struct mg_str json, int level) {
|
||||
struct mg_str key, val;
|
||||
size_t ofs = 0;
|
||||
int total_count = 0;
|
||||
while ((ofs = mg_json_next(json, ofs, &key, &val)) > 0) {
|
||||
struct mg_field_set *set = mg_dash_find_field_set(dash, trimq(key));
|
||||
int count = 0;
|
||||
if (set != NULL) {
|
||||
if (set != NULL && (set->write_level <= 0 || level >= set->write_level)) {
|
||||
size_t i;
|
||||
for (i = 0; set->fields[i].name != NULL; i++) {
|
||||
if (mg_dash_parse_field(val, &set->fields[i])) count++;
|
||||
@@ -206,7 +213,7 @@ static int mg_dash_apply(struct mg_connection *c, struct mg_dash *dash,
|
||||
mg_dash_send_change(c->mgr, set);
|
||||
total_count += count;
|
||||
}
|
||||
} else {
|
||||
} else if (set == NULL) {
|
||||
MG_ERROR(("UNKNOWN SET: [%.*s]", key.len, key.buf));
|
||||
}
|
||||
}
|
||||
@@ -218,11 +225,12 @@ static void mg_dash_process_msg(struct mg_connection *c,
|
||||
struct mg_dash *dash) {
|
||||
struct mg_str req = wm->data;
|
||||
struct mg_str method = trimq(mg_json_get_tok(req, "$.method"));
|
||||
int level = *(int *) c->data;
|
||||
if (mg_match(method, mg_str("get"), NULL)) {
|
||||
mg_dash_success(c, req, "%M", mg_dash_print, &req, dash);
|
||||
mg_dash_success(c, req, "%M", mg_dash_print, &req, dash, level);
|
||||
} else if (mg_match(method, mg_str("set"), NULL)) {
|
||||
struct mg_str params = trimq(mg_json_get_tok(req, "$.params"));
|
||||
int count = mg_dash_apply(c, dash, params);
|
||||
int count = mg_dash_apply(c, dash, params, level);
|
||||
mg_dash_success(c, req, "%d", count);
|
||||
} else {
|
||||
mg_dash_error(c, req, "%s", "unknown method");
|
||||
@@ -511,7 +519,8 @@ void mg_dash_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
|
||||
c->is_resp = 0;
|
||||
} else if (ev == MG_EV_HTTP_MSG && c->data[0] == '\0') {
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
// struct mg_dash_user *u = mg_dash_authenticate(hm, dash);
|
||||
struct mg_dash_user *u = mg_dash_authenticate(hm, dash);
|
||||
int level = u == NULL ? 0 : u->level;
|
||||
struct mg_str parts[5];
|
||||
memset(parts, 0, sizeof(parts));
|
||||
|
||||
@@ -522,6 +531,7 @@ void mg_dash_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
|
||||
mg_ws_printf(c, WEBSOCKET_OP_TEXT, "{%m:%m}", MG_ESC("method"),
|
||||
MG_ESC("logout"));
|
||||
} else if (mg_match(hm->uri, mg_str("/api/websocket"), NULL)) {
|
||||
*(int *) c->data = level;
|
||||
mg_ws_upgrade(c, hm, NULL);
|
||||
} else if (mg_match(hm->uri, mg_str("/fs/#"), NULL)) {
|
||||
struct mg_str name = mg_dash_file_name(hm);
|
||||
@@ -539,9 +549,9 @@ void mg_dash_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
|
||||
} else if (mg_match(hm->uri, mg_str("/api/get/#"), parts) ||
|
||||
mg_match(hm->uri, mg_str("/api/get"), NULL)) {
|
||||
mg_http_reply(c, 200, MG_JSON_HEADERS, "%M\n", mg_dash_print_name, dash,
|
||||
&parts[0]);
|
||||
&parts[0], level);
|
||||
} else if (mg_match(hm->uri, mg_str("/api/set"), NULL)) {
|
||||
int count = mg_dash_apply(c, dash, hm->body);
|
||||
int count = mg_dash_apply(c, dash, hm->body, level);
|
||||
mg_http_reply(c, 200, MG_JSON_HEADERS, "%d\n", count);
|
||||
} else if (mg_match(hm->uri, mg_str("/"), NULL)) {
|
||||
struct mg_http_serve_opts opts;
|
||||
@@ -565,7 +575,7 @@ void mg_dash_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
|
||||
for (fs = dash->sets; fs != NULL; fs = fs->next) {
|
||||
mg_dash_send_change(c->mgr, fs);
|
||||
}
|
||||
mg_dash_broadcast(c->mgr, "{%m:%m}", MG_ESC("method"), MG_ESC("ready"));
|
||||
mg_dash_broadcast(c->mgr, 0, "{%m:%m}", MG_ESC("method"), MG_ESC("ready"));
|
||||
} else if (ev == MG_EV_WS_MSG) {
|
||||
// Add this to automatically handle "get" and "set" JSON-RPC calls
|
||||
struct mg_ws_message *wm = (struct mg_ws_message *) ev_data;
|
||||
|
||||
+185
-2
@@ -4134,6 +4134,52 @@ static void dash_custom(struct mg_connection *c, int ev, void *ev_data) {
|
||||
(void) c, (void) ev, (void) ev_data;
|
||||
}
|
||||
|
||||
static int dash_authenticate(const char *user, const char *pass) {
|
||||
int level = 0;
|
||||
if (strcmp(pass, "admin") == 0) {
|
||||
level = 7;
|
||||
} else if (strcmp(pass, "user") == 0) {
|
||||
level = 3;
|
||||
}
|
||||
(void) user;
|
||||
return level;
|
||||
}
|
||||
|
||||
struct dash_ws_test {
|
||||
const char *req;
|
||||
int done;
|
||||
int result;
|
||||
int saw_set3;
|
||||
};
|
||||
|
||||
static void dash_ws_cb(struct mg_connection *c, int ev, void *ev_data) {
|
||||
struct dash_ws_test *d = (struct dash_ws_test *) c->fn_data;
|
||||
if (ev == MG_EV_WS_OPEN) {
|
||||
if (d->req != NULL) {
|
||||
mg_ws_send(c, d->req, strlen(d->req), WEBSOCKET_OP_TEXT);
|
||||
}
|
||||
} else if (ev == MG_EV_WS_MSG) {
|
||||
struct mg_ws_message *wm = (struct mg_ws_message *) ev_data;
|
||||
struct mg_str method = mg_json_get_tok(wm->data, "$.method");
|
||||
struct mg_str set3 = mg_json_get_tok(wm->data, "$.params.set3");
|
||||
double result = 0;
|
||||
if (mg_strcmp(method, mg_str("\"change\"")) == 0 && set3.buf != NULL) {
|
||||
d->saw_set3 = 1;
|
||||
}
|
||||
if (mg_json_get_num(wm->data, "$.result", &result)) {
|
||||
d->result = (int) result;
|
||||
d->done = 1;
|
||||
c->is_closing = 1;
|
||||
} else if (d->req == NULL &&
|
||||
mg_strcmp(method, mg_str("\"ready\"")) == 0) {
|
||||
d->done = 1;
|
||||
c->is_closing = 1;
|
||||
}
|
||||
} else if (ev == MG_EV_CLOSE && d->done == 0) {
|
||||
d->done = -1;
|
||||
}
|
||||
}
|
||||
|
||||
char three[10] = "hi";
|
||||
int one = 1;
|
||||
static void rfields1(void) {
|
||||
@@ -4143,9 +4189,13 @@ static void rfields1(void) {
|
||||
static void test_dash(void) {
|
||||
char buf[FETCH_BUF_SIZE];
|
||||
const char *url = "http://localhost:26352";
|
||||
const char *ws_url = "ws://localhost:26352/api/websocket";
|
||||
struct mg_mgr mgr;
|
||||
struct mg_dash dash;
|
||||
struct dash_ws_test ws_user, ws_admin, ws_user_notify;
|
||||
bool two = false;
|
||||
int admin = 7;
|
||||
int i;
|
||||
struct mg_field fields1[] = {
|
||||
{"one", MG_VAL_INT, &one, sizeof(one)},
|
||||
{"three", MG_VAL_STR, three, sizeof(three)},
|
||||
@@ -4155,14 +4205,44 @@ static void test_dash(void) {
|
||||
{"two", MG_VAL_BOOL, &two, 0}, // Size set to 0 - readonly
|
||||
{NULL, MG_VAL_INT, NULL, 0},
|
||||
};
|
||||
struct mg_field_set set1 = {"set1", fields1, rfields1, NULL, 0, 0, NULL};
|
||||
struct mg_field fields3[] = {
|
||||
{"admin", MG_VAL_INT, &admin, sizeof(admin)},
|
||||
{NULL, MG_VAL_INT, NULL, 0},
|
||||
};
|
||||
struct mg_field_set set1 = {"set1", fields1, rfields1, NULL, 3, 7, NULL};
|
||||
struct mg_field_set set2 = {"set2", fields2, NULL, NULL, 0, 0, NULL};
|
||||
struct mg_field_set set3 = {"set3", fields3, NULL, NULL, 7, 7, NULL};
|
||||
const char *get_all_expected =
|
||||
"{\"files\":{\"data\":[]},\"set2\":{\"two\":false},"
|
||||
"{\"files\":{\"data\":[]},\"set3\":{\"admin\":7},"
|
||||
"\"set2\":{\"two\":false},"
|
||||
"\"set1\":{\"one\":1,\"three\":\"t: 1\"}}\n";
|
||||
const char *set1_req = "POST /api/set HTTP/1.0\nContent-Length: 18\n\n"
|
||||
"{\"set1\":{\"one\":2}}";
|
||||
const char *set1_set3_req = "POST /api/set HTTP/1.0\n"
|
||||
"Authorization: Basic dXNlcjp1c2Vy\n"
|
||||
"Content-Length: 18\n\n"
|
||||
"{\"set1\":{\"one\":3}}";
|
||||
const char *set1_admin_set3_req = "POST /api/set HTTP/1.0\n"
|
||||
"Authorization: Basic YWRtaW46YWRtaW4=\n"
|
||||
"Content-Length: 18\n\n"
|
||||
"{\"set1\":{\"one\":3}}";
|
||||
const char *set3_user_req = "POST /api/set HTTP/1.0\n"
|
||||
"Authorization: Basic dXNlcjp1c2Vy\n"
|
||||
"Content-Length: 20\n\n"
|
||||
"{\"set3\":{\"admin\":8}}";
|
||||
const char *set3_admin_req = "POST /api/set HTTP/1.0\n"
|
||||
"Authorization: Basic YWRtaW46YWRtaW4=\n"
|
||||
"Content-Length: 20\n\n"
|
||||
"{\"set3\":{\"admin\":8}}";
|
||||
const char *set1_ws_set4_req =
|
||||
"{\"id\":1,\"method\":\"set\",\"params\":{\"set1\":{\"one\":4}}}";
|
||||
const char *set1_expected = "{\"one\":2,\"three\":\"t: 2\"}\n";
|
||||
const char *set1_expected3 = "{\"one\":3,\"three\":\"t: 3\"}\n";
|
||||
const char *set1_expected4 = "{\"one\":4,\"three\":\"t: 4\"}\n";
|
||||
const char *set3_expected = "{\"admin\":7}\n";
|
||||
const char *set3_expected8 = "{\"admin\":8}\n";
|
||||
const char *login_user_expected = "{\"user\":\"user\",\"level\":3}\n";
|
||||
const char *login_admin_expected = "{\"user\":\"admin\",\"level\":7}\n";
|
||||
const char *set2_req = "POST /api/set HTTP/1.0\nContent-Length: 21\n\n"
|
||||
"{\"set2\":{\"two\":true}}";
|
||||
const char *set2_expected = "{\"two\":false}\n";
|
||||
@@ -4178,6 +4258,10 @@ static void test_dash(void) {
|
||||
ASSERT(dash.sets == &set2);
|
||||
ASSERT(set2.next == &set1);
|
||||
|
||||
MG_DASH_ADD_FIELD_SET(&dash, &set3);
|
||||
ASSERT(dash.sets == &set3);
|
||||
ASSERT(set3.next == &set2);
|
||||
|
||||
MG_DASH_REGISTER_CUSTOM_HANDLER(&dash, "/api/custom", dash_custom, &marker);
|
||||
ASSERT(dash.custom_handlers != NULL);
|
||||
ASSERT(mg_strcmp(dash.custom_handlers->uri_pattern, mg_str("/api/custom")) ==
|
||||
@@ -4209,6 +4293,7 @@ static void test_dash(void) {
|
||||
mg_mem_files = mg_packed_files;
|
||||
ASSERT(mg_http_listen(&mgr, url, mg_dash_ev_handler, &dash) != NULL);
|
||||
|
||||
// Test general get / set functionality
|
||||
ASSERT(fetch(&mgr, buf, url, "GET /api/get HTTP/1.0\n\n") == 200);
|
||||
ASSERT(cmpbody(buf, get_all_expected) == 0);
|
||||
|
||||
@@ -4217,11 +4302,109 @@ static void test_dash(void) {
|
||||
ASSERT(fetch(&mgr, buf, url, "GET /api/get/set1 HTTP/1.0\n\n") == 200);
|
||||
ASSERT(cmpbody(buf, set1_expected) == 0);
|
||||
|
||||
// Setting a variable with zero size should fail
|
||||
ASSERT(fetch(&mgr, buf, url, set2_req) == 200);
|
||||
ASSERT(cmpbody(buf, "0\n") == 0);
|
||||
ASSERT(two == false);
|
||||
ASSERT(fetch(&mgr, buf, url, "GET /api/get/set2 HTTP/1.0\n\n") == 200);
|
||||
ASSERT(cmpbody(buf, set2_expected) == 0);
|
||||
|
||||
// Install auth function with two users - user, level 3 and admin, level 7
|
||||
dash.authenticate = dash_authenticate;
|
||||
ASSERT(fetch(&mgr, buf, url, "GET /api/get HTTP/1.0\n\n") == 403);
|
||||
ASSERT(cmpbody(buf, "Not Authorised\n") == 0);
|
||||
ASSERT(fetch(&mgr, buf, url,
|
||||
"GET /api/login HTTP/1.0\n"
|
||||
"Authorization: Basic dXNlcjpiYWQ=\n\n") == 403);
|
||||
ASSERT(fetch(&mgr, buf, url,
|
||||
"GET /api/login HTTP/1.0\n"
|
||||
"Authorization: Basic dXNlcjp1c2Vy\n\n") == 200);
|
||||
ASSERT(cmpbody(buf, login_user_expected) == 0);
|
||||
ASSERT(fetch(&mgr, buf, url,
|
||||
"GET /api/login HTTP/1.0\n"
|
||||
"Authorization: Basic YWRtaW46YWRtaW4=\n\n") == 200);
|
||||
ASSERT(cmpbody(buf, login_admin_expected) == 0);
|
||||
|
||||
// set3 is admin-only
|
||||
ASSERT(fetch(&mgr, buf, url,
|
||||
"GET /api/get/set3 HTTP/1.0\n"
|
||||
"Authorization: Basic dXNlcjp1c2Vy\n\n") == 200);
|
||||
ASSERT(cmpbody(buf, "null\n") == 0);
|
||||
ASSERT(fetch(&mgr, buf, url,
|
||||
"GET /api/get/set3 HTTP/1.0\n"
|
||||
"Authorization: Basic YWRtaW46YWRtaW4=\n\n") == 200);
|
||||
ASSERT(cmpbody(buf, set3_expected) == 0);
|
||||
ASSERT(fetch(&mgr, buf, url, set3_user_req) == 200);
|
||||
ASSERT(cmpbody(buf, "0\n") == 0);
|
||||
ASSERT(fetch(&mgr, buf, url,
|
||||
"GET /api/get/set3 HTTP/1.0\n"
|
||||
"Authorization: Basic YWRtaW46YWRtaW4=\n\n") == 200);
|
||||
ASSERT(cmpbody(buf, set3_expected) == 0);
|
||||
ASSERT(fetch(&mgr, buf, url, set3_admin_req) == 200);
|
||||
ASSERT(cmpbody(buf, "1\n") == 0);
|
||||
ASSERT(fetch(&mgr, buf, url,
|
||||
"GET /api/get/set3 HTTP/1.0\n"
|
||||
"Authorization: Basic YWRtaW46YWRtaW4=\n\n") == 200);
|
||||
ASSERT(cmpbody(buf, set3_expected8) == 0);
|
||||
|
||||
// set1 read level should be 3, write level 7
|
||||
ASSERT(fetch(&mgr, buf, url,
|
||||
"GET /api/get/set1 HTTP/1.0\n"
|
||||
"Authorization: Basic dXNlcjp1c2Vy\n\n") == 200);
|
||||
ASSERT(cmpbody(buf, set1_expected) == 0);
|
||||
ASSERT(fetch(&mgr, buf, url, set1_set3_req) == 200);
|
||||
ASSERT(cmpbody(buf, "0\n") == 0);
|
||||
ASSERT(fetch(&mgr, buf, url,
|
||||
"GET /api/get/set1 HTTP/1.0\n"
|
||||
"Authorization: Basic dXNlcjp1c2Vy\n\n") == 200);
|
||||
ASSERT(cmpbody(buf, set1_expected) == 0);
|
||||
ASSERT(fetch(&mgr, buf, url, set1_admin_set3_req) == 200);
|
||||
ASSERT(cmpbody(buf, "1\n") == 0);
|
||||
ASSERT(fetch(&mgr, buf, url,
|
||||
"GET /api/get/set1 HTTP/1.0\n"
|
||||
"Authorization: Basic YWRtaW46YWRtaW4=\n\n") == 200);
|
||||
ASSERT(cmpbody(buf, set1_expected3) == 0);
|
||||
|
||||
ws_user_notify.req = NULL;
|
||||
ws_user_notify.done = 0;
|
||||
ws_user_notify.result = -1;
|
||||
ws_user_notify.saw_set3 = 0;
|
||||
mg_ws_connect(&mgr, ws_url, dash_ws_cb, &ws_user_notify, "%s",
|
||||
"Authorization: Basic dXNlcjp1c2Vy\r\n");
|
||||
for (i = 0; i < 200 && ws_user_notify.done == 0; i++) mg_mgr_poll(&mgr, 1);
|
||||
ASSERT(ws_user_notify.done == 1);
|
||||
ASSERT(ws_user_notify.saw_set3 == 0);
|
||||
|
||||
ws_user.req = set1_ws_set4_req;
|
||||
ws_user.done = 0;
|
||||
ws_user.result = -1;
|
||||
ws_user.saw_set3 = 0;
|
||||
mg_ws_connect(&mgr, ws_url, dash_ws_cb, &ws_user, "%s",
|
||||
"Authorization: Basic dXNlcjp1c2Vy\r\n");
|
||||
for (i = 0; i < 200 && ws_user.done == 0; i++) mg_mgr_poll(&mgr, 1);
|
||||
ASSERT(ws_user.done == 1);
|
||||
ASSERT(ws_user.result == 0);
|
||||
ASSERT(ws_user.saw_set3 == 0);
|
||||
ASSERT(fetch(&mgr, buf, url,
|
||||
"GET /api/get/set1 HTTP/1.0\n"
|
||||
"Authorization: Basic dXNlcjp1c2Vy\n\n") == 200);
|
||||
ASSERT(cmpbody(buf, set1_expected3) == 0);
|
||||
|
||||
ws_admin.req = set1_ws_set4_req;
|
||||
ws_admin.done = 0;
|
||||
ws_admin.result = -1;
|
||||
ws_admin.saw_set3 = 0;
|
||||
mg_ws_connect(&mgr, ws_url, dash_ws_cb, &ws_admin, "%s",
|
||||
"Authorization: Basic YWRtaW46YWRtaW4=\r\n");
|
||||
for (i = 0; i < 200 && ws_admin.done == 0; i++) mg_mgr_poll(&mgr, 1);
|
||||
ASSERT(ws_admin.done == 1);
|
||||
ASSERT(ws_admin.result == 1);
|
||||
ASSERT(ws_admin.saw_set3 == 1);
|
||||
ASSERT(fetch(&mgr, buf, url,
|
||||
"GET /api/get/set1 HTTP/1.0\n"
|
||||
"Authorization: Basic YWRtaW46YWRtaW4=\n\n") == 200);
|
||||
ASSERT(cmpbody(buf, set1_expected4) == 0);
|
||||
|
||||
mg_mgr_free(&mgr);
|
||||
}
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ static struct mg_field fields_settings[] = {
|
||||
};
|
||||
|
||||
static struct mg_field_set set_settings = {
|
||||
"settings", fields_settings, read_settings, write_settings, 0, 0, NULL,
|
||||
"settings", fields_settings, read_settings, write_settings, 3, 7, NULL,
|
||||
};
|
||||
|
||||
#define NUM_POINTS_GRAPH1 7 // How many graph1 data points to send
|
||||
@@ -126,8 +126,8 @@ void read_graph1(void) {
|
||||
for (i = 0; i < NUM_POINTS_GRAPH1; i++) {
|
||||
struct point p;
|
||||
p.x = (uint16_t) i;
|
||||
p.y1 = 85 - (uint16_t) ((49 * i) / NUM_POINTS_GRAPH1) + (rand() % 9);
|
||||
p.y2 = 20 + (uint16_t) ((69 * i) / NUM_POINTS_GRAPH1) + (rand() % 5);
|
||||
p.y1 = (uint16_t) (85 - ((49 * i) / NUM_POINTS_GRAPH1) + (rand() % 9));
|
||||
p.y2 = (uint16_t) (20 + ((69 * i) / NUM_POINTS_GRAPH1) + (rand() % 5));
|
||||
len += mg_snprintf(s_graph1_data + len, sizeof(s_graph1_data) - len,
|
||||
"%s[%hu,%hu,%hu]", i > 0 ? "," : "", p.x, p.y1, p.y2);
|
||||
}
|
||||
@@ -156,8 +156,8 @@ void read_graph2(void) {
|
||||
for (i = 0; i < NUM_POINTS_GRAPH2; i++) {
|
||||
uint16_t x = (uint16_t) (i * 7 + t);
|
||||
uint16_t y = (uint16_t) (i * 3 - t / 2);
|
||||
uint8_t a = (x ^ (x >> 3)) & 255;
|
||||
uint8_t b = (y ^ (y >> 4)) & 255;
|
||||
uint8_t a = (uint8_t) (x ^ (x >> 3)) & 255;
|
||||
uint8_t b = (uint8_t) (y ^ (y >> 4)) & 255;
|
||||
int v =
|
||||
70 + ((a < 128 ? a : 255 - a) >> 1) + ((b < 128 ? b : 255 - b) >> 2);
|
||||
len += mg_snprintf(s_graph2_data + len, sizeof(s_graph2_data) - len,
|
||||
|
||||
@@ -327,7 +327,7 @@ a, a:visited, a:link { text-decoration: none; }
|
||||
</svg>
|
||||
Overview
|
||||
</a>
|
||||
<a href="#settings" id="tab-settings" class="nav-link" role="tab" aria-controls="settings" aria-selected="false" tabindex="-1">
|
||||
<a href="#settings" id="tab-settings" class="nav-link ${__status.userlevel > 0 && __status.userlevel < 7 ? 'hidden' : ''}" role="tab" aria-controls="settings" aria-selected="false" tabindex="-1">
|
||||
<svg viewBox="0 0 24 24" class="nav-icon" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<circle cx="12" cy="12" r="3" />
|
||||
<path d="M19.4 15a1.7 1.7 0 0 0 .34 1.87l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06A1.7 1.7 0 0 0 15 19.4a1.7 1.7 0 0 0-1 .6 1.7 1.7 0 0 0-.4 1.1V21a2 2 0 1 1-4 0v-.1a1.7 1.7 0 0 0-.4-1.1 1.7 1.7 0 0 0-1-.6 1.7 1.7 0 0 0-1.87.34l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06A1.7 1.7 0 0 0 4.6 15a1.7 1.7 0 0 0-.6-1 1.7 1.7 0 0 0-1.1-.4H2.8a2 2 0 1 1 0-4h.1a1.7 1.7 0 0 0 1.1-.4 1.7 1.7 0 0 0 .6-1 1.7 1.7 0 0 0-.34-1.87l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06A1.7 1.7 0 0 0 9 4.6c.38-.16.72-.4 1-.7.26-.3.4-.69.4-1.1V2.8a2 2 0 1 1 4 0v.1c0 .41.14.8.4 1.1.28.3.62.54 1 .7a1.7 1.7 0 0 0 1.87-.34l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06A1.7 1.7 0 0 0 19.4 9c.16.38.4.72.7 1 .3.26.69.4 1.1.4h.1a2 2 0 1 1 0 4h-.1a1.7 1.7 0 0 0-1.1.4 1.7 1.7 0 0 0-.7 1z" />
|
||||
@@ -363,7 +363,7 @@ a, a:visited, a:link { text-decoration: none; }
|
||||
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" />
|
||||
<circle cx="12" cy="7" r="4" />
|
||||
</svg>
|
||||
<span>${__status.username || 'admin'}</span>
|
||||
<span>${__status.userlevel == 3 ? 'user' : 'admin'}</span>
|
||||
<svg viewBox="0 0 24 24"
|
||||
onclick="Dashboard.logout().then(() => location.reload())"
|
||||
style="cursor: pointer;"
|
||||
|
||||
Reference in new issue
Block a user