Rename complete -> device-dashboard, remove multiple-logins and dashboard
Before Width: | Height: | Size: 134 KiB |
Before Width: | Height: | Size: 52 KiB |
Before Width: | Height: | Size: 122 KiB |
@ -1,10 +0,0 @@
|
||||
PROG ?= example
|
||||
|
||||
all: $(PROG)
|
||||
$(DEBUGGER) ./$(PROG)
|
||||
|
||||
$(PROG):
|
||||
$(CC) ../../mongoose.c -I../.. $(CFLAGS) $(EXTRA) -o $(PROG) main.c mjson.c
|
||||
|
||||
clean:
|
||||
rm -rf $(PROG) *.o *.dSYM *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb log.txt
|
@ -1,82 +0,0 @@
|
||||
// Copyright (c) 2020 Cesanta Software Limited
|
||||
// All rights reserved
|
||||
|
||||
#include "mjson.h" // JSON parsing and printing
|
||||
#include "mongoose.h"
|
||||
|
||||
// This is a configuration structure we're going to show on a dashboard
|
||||
static struct config {
|
||||
int value1;
|
||||
char *value2;
|
||||
} s_config = {123, NULL};
|
||||
|
||||
// Stringifies the config. A caller must free() it.
|
||||
static char *stringify_config(struct config *cfg) {
|
||||
char *s = NULL;
|
||||
mjson_printf(mjson_print_dynamic_buf, &s, "{%Q:%d,%Q:%Q}", "value1",
|
||||
cfg->value1, "value2", cfg->value2);
|
||||
return s;
|
||||
}
|
||||
|
||||
// Update config structure. Return true if changed, false otherwise
|
||||
static bool update_config(struct mg_http_message *hm, struct config *cfg) {
|
||||
bool changed = false;
|
||||
char buf[256];
|
||||
double dv;
|
||||
if (mjson_get_number(hm->body.ptr, hm->body.len, "$.value1", &dv)) {
|
||||
s_config.value1 = dv;
|
||||
changed = true;
|
||||
}
|
||||
if (mjson_get_string(hm->body.ptr, hm->body.len, "$.value2", buf,
|
||||
sizeof(buf)) > 0) {
|
||||
free(s_config.value2);
|
||||
s_config.value2 = strdup(buf);
|
||||
changed = true;
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
// Notify all config watchers about the config change
|
||||
static void notify_config_change(struct mg_mgr *mgr) {
|
||||
struct mg_connection *c;
|
||||
char *s = stringify_config(&s_config);
|
||||
for (c = mgr->conns; c != NULL; c = c->next) {
|
||||
if (c->label[0] == 'W') mg_http_printf_chunk(c, "%s\n", s);
|
||||
}
|
||||
free(s);
|
||||
}
|
||||
|
||||
// HTTP request handler function. It implements the following endpoints:
|
||||
// /api/config/get - returns current config
|
||||
// /api/config/set - updates current config
|
||||
// /api/config/watch - does not return. Sends config as it changes in
|
||||
// chunks all other URI - serves web_root/ directory
|
||||
static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||
if (ev == MG_EV_HTTP_MSG) {
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
if (mg_http_match_uri(hm, "/api/config/get")) {
|
||||
char *s = stringify_config(&s_config);
|
||||
mg_printf(c, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\n\r\n%s\n",
|
||||
(int) strlen(s) + 1, s);
|
||||
free(s);
|
||||
} else if (mg_http_match_uri(hm, "/api/config/set")) {
|
||||
if (update_config(hm, &s_config)) notify_config_change(fn_data);
|
||||
mg_printf(c, "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
|
||||
} else if (mg_http_match_uri(hm, "/api/config/watch")) {
|
||||
c->label[0] = 'W'; // Mark ourselves as a config watcher
|
||||
mg_printf(c, "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n");
|
||||
} else {
|
||||
struct mg_http_serve_opts opts = {.root_dir = "web_root"};
|
||||
mg_http_serve_dir(c, ev_data, &opts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
struct mg_mgr mgr;
|
||||
mg_mgr_init(&mgr);
|
||||
mg_http_listen(&mgr, "http://localhost:8000", cb, &mgr);
|
||||
for (;;) mg_mgr_poll(&mgr, 1000);
|
||||
mg_mgr_free(&mgr);
|
||||
return 0;
|
||||
}
|
@ -1,981 +0,0 @@
|
||||
// Copyright (c) 2018-2020 Cesanta Software Limited
|
||||
// All rights reserved
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#include "mjson.h"
|
||||
|
||||
#if !defined(_MSC_VER) || _MSC_VER >= 1700
|
||||
#else
|
||||
#define va_copy(x, y) (x) = (y)
|
||||
#define snprintf _snprintf
|
||||
#define alloca _alloca
|
||||
#endif
|
||||
|
||||
static int mjson_esc(int c, int esc) {
|
||||
const char *p, *esc1 = "\b\f\n\r\t\\\"", *esc2 = "bfnrt\\\"";
|
||||
for (p = esc ? esc1 : esc2; *p != '\0'; p++) {
|
||||
if (*p == c) return esc ? esc2[p - esc1] : esc1[p - esc2];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mjson_pass_string(const char *s, int len) {
|
||||
int i;
|
||||
for (i = 0; i < len; i++) {
|
||||
if (s[i] == '\\' && i + 1 < len && mjson_esc(s[i + 1], 1)) {
|
||||
i++;
|
||||
} else if (s[i] == '\0') {
|
||||
return MJSON_ERROR_INVALID_INPUT;
|
||||
} else if (s[i] == '"') {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return MJSON_ERROR_INVALID_INPUT;
|
||||
}
|
||||
|
||||
int mjson(const char *s, int len, mjson_cb_t cb, void *ud) {
|
||||
enum { S_VALUE, S_KEY, S_COLON, S_COMMA_OR_EOO } expecting = S_VALUE;
|
||||
unsigned char nesting[MJSON_MAX_DEPTH];
|
||||
int i, depth = 0;
|
||||
#define MJSONCALL(ev) \
|
||||
if (cb != NULL && cb(ev, s, start, i - start + 1, ud)) return i + 1;
|
||||
|
||||
// In the ascii table, the distance between `[` and `]` is 2.
|
||||
// Ditto for `{` and `}`. Hence +2 in the code below.
|
||||
#define MJSONEOO() \
|
||||
do { \
|
||||
if (c != nesting[depth - 1] + 2) return MJSON_ERROR_INVALID_INPUT; \
|
||||
depth--; \
|
||||
if (depth == 0) { \
|
||||
MJSONCALL(tok); \
|
||||
return i + 1; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
int start = i;
|
||||
unsigned char c = ((unsigned char *) s)[i];
|
||||
int tok = c;
|
||||
if (c == ' ' || c == '\t' || c == '\n' || c == '\r') continue;
|
||||
// printf("- %c [%.*s] %d %d\n", c, i, s, depth, expecting);
|
||||
switch (expecting) {
|
||||
case S_VALUE:
|
||||
if (c == '{') {
|
||||
if (depth >= (int) sizeof(nesting)) return MJSON_ERROR_TOO_DEEP;
|
||||
nesting[depth++] = c;
|
||||
expecting = S_KEY;
|
||||
break;
|
||||
} else if (c == '[') {
|
||||
if (depth >= (int) sizeof(nesting)) return MJSON_ERROR_TOO_DEEP;
|
||||
nesting[depth++] = c;
|
||||
break;
|
||||
} else if (c == ']' && depth > 0) { // Empty array
|
||||
MJSONEOO();
|
||||
} else if (c == 't' && i + 3 < len && memcmp(&s[i], "true", 4) == 0) {
|
||||
i += 3;
|
||||
tok = MJSON_TOK_TRUE;
|
||||
} else if (c == 'n' && i + 3 < len && memcmp(&s[i], "null", 4) == 0) {
|
||||
i += 3;
|
||||
tok = MJSON_TOK_NULL;
|
||||
} else if (c == 'f' && i + 4 < len && memcmp(&s[i], "false", 5) == 0) {
|
||||
i += 4;
|
||||
tok = MJSON_TOK_FALSE;
|
||||
} else if (c == '-' || ((c >= '0' && c <= '9'))) {
|
||||
char *end = NULL;
|
||||
strtod(&s[i], &end);
|
||||
if (end != NULL) i += end - &s[i] - 1;
|
||||
tok = MJSON_TOK_NUMBER;
|
||||
} else if (c == '"') {
|
||||
int n = mjson_pass_string(&s[i + 1], len - i - 1);
|
||||
if (n < 0) return n;
|
||||
i += n + 1;
|
||||
tok = MJSON_TOK_STRING;
|
||||
} else {
|
||||
return MJSON_ERROR_INVALID_INPUT;
|
||||
}
|
||||
if (depth == 0) {
|
||||
MJSONCALL(tok);
|
||||
return i + 1;
|
||||
}
|
||||
expecting = S_COMMA_OR_EOO;
|
||||
break;
|
||||
|
||||
case S_KEY:
|
||||
if (c == '"') {
|
||||
int n = mjson_pass_string(&s[i + 1], len - i - 1);
|
||||
if (n < 0) return n;
|
||||
i += n + 1;
|
||||
tok = MJSON_TOK_KEY;
|
||||
expecting = S_COLON;
|
||||
} else if (c == '}') { // Empty object
|
||||
MJSONEOO();
|
||||
expecting = S_COMMA_OR_EOO;
|
||||
} else {
|
||||
return MJSON_ERROR_INVALID_INPUT;
|
||||
}
|
||||
break;
|
||||
|
||||
case S_COLON:
|
||||
if (c == ':') {
|
||||
expecting = S_VALUE;
|
||||
} else {
|
||||
return MJSON_ERROR_INVALID_INPUT;
|
||||
}
|
||||
break;
|
||||
|
||||
case S_COMMA_OR_EOO:
|
||||
if (depth <= 0) return MJSON_ERROR_INVALID_INPUT;
|
||||
if (c == ',') {
|
||||
expecting = (nesting[depth - 1] == '{') ? S_KEY : S_VALUE;
|
||||
} else if (c == ']' || c == '}') {
|
||||
MJSONEOO();
|
||||
} else {
|
||||
return MJSON_ERROR_INVALID_INPUT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
MJSONCALL(tok);
|
||||
}
|
||||
return MJSON_ERROR_INVALID_INPUT;
|
||||
}
|
||||
|
||||
struct msjon_get_data {
|
||||
const char *path; // Lookup json path
|
||||
int pos; // Current path index
|
||||
int d1; // Current depth of traversal
|
||||
int d2; // Expected depth of traversal
|
||||
int i1; // Index in an array
|
||||
int i2; // Expected index in an array
|
||||
int obj; // If the value is array/object, offset where it starts
|
||||
const char **tokptr; // Destination
|
||||
int *toklen; // Destination length
|
||||
int tok; // Returned token
|
||||
};
|
||||
|
||||
static int mjson_plen(const char *s) {
|
||||
int i = 0;
|
||||
while (s[i] != '\0' && s[i] != '.' && s[i] != '[') i++;
|
||||
return i;
|
||||
}
|
||||
|
||||
static int mjson_get_cb(int tok, const char *s, int off, int len, void *ud) {
|
||||
struct msjon_get_data *data = (struct msjon_get_data *) ud;
|
||||
// printf("--> %2x %2d %2d %2d %2d\t'%s'\t'%.*s'\t\t'%.*s'\n", tok, data->d1,
|
||||
// data->d2, data->i1, data->i2, data->path + data->pos, off, s, len,
|
||||
// s + off);
|
||||
if (data->tok != MJSON_TOK_INVALID) return 1; // Found
|
||||
|
||||
if (tok == '{') {
|
||||
if (!data->path[data->pos] && data->d1 == data->d2) data->obj = off;
|
||||
data->d1++;
|
||||
} else if (tok == '[') {
|
||||
if (data->d1 == data->d2 && data->path[data->pos] == '[') {
|
||||
data->i1 = 0;
|
||||
data->i2 = (int) strtod(&data->path[data->pos + 1], NULL);
|
||||
if (data->i1 == data->i2) {
|
||||
data->d2++;
|
||||
data->pos += 3;
|
||||
}
|
||||
}
|
||||
if (!data->path[data->pos] && data->d1 == data->d2) data->obj = off;
|
||||
data->d1++;
|
||||
} else if (tok == ',') {
|
||||
if (data->d1 == data->d2 + 1) {
|
||||
data->i1++;
|
||||
if (data->i1 == data->i2) {
|
||||
while (data->path[data->pos] != ']') data->pos++;
|
||||
data->pos++;
|
||||
data->d2++;
|
||||
}
|
||||
}
|
||||
} else if (tok == MJSON_TOK_KEY && data->d1 == data->d2 + 1 &&
|
||||
data->path[data->pos] == '.' && s[off] == '"' &&
|
||||
s[off + len - 1] == '"' &&
|
||||
mjson_plen(&data->path[data->pos + 1]) == len - 2 &&
|
||||
!memcmp(s + off + 1, &data->path[data->pos + 1], len - 2)) {
|
||||
data->d2++;
|
||||
data->pos += len - 1;
|
||||
} else if (tok == MJSON_TOK_KEY && data->d1 == data->d2) {
|
||||
return 1; // Exhausted path, not found
|
||||
} else if (tok == '}' || tok == ']') {
|
||||
data->d1--;
|
||||
// data->d2--;
|
||||
if (!data->path[data->pos] && data->d1 == data->d2 && data->obj != -1) {
|
||||
data->tok = tok - 2;
|
||||
if (data->tokptr) *data->tokptr = s + data->obj;
|
||||
if (data->toklen) *data->toklen = off - data->obj + 1;
|
||||
return 1;
|
||||
}
|
||||
} else if (MJSON_TOK_IS_VALUE(tok)) {
|
||||
// printf("TOK --> %d\n", tok);
|
||||
if (data->d1 == data->d2 && !data->path[data->pos]) {
|
||||
data->tok = tok;
|
||||
if (data->tokptr) *data->tokptr = s + off;
|
||||
if (data->toklen) *data->toklen = len;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum mjson_tok mjson_find(const char *s, int len, const char *jp,
|
||||
const char **tokptr, int *toklen) {
|
||||
struct msjon_get_data data = {jp, 1, 0, 0, 0,
|
||||
0, -1, tokptr, toklen, MJSON_TOK_INVALID};
|
||||
if (jp[0] != '$') return MJSON_TOK_INVALID;
|
||||
if (mjson(s, len, mjson_get_cb, &data) < 0) return MJSON_TOK_INVALID;
|
||||
return (enum mjson_tok) data.tok;
|
||||
}
|
||||
|
||||
int mjson_get_number(const char *s, int len, const char *path, double *v) {
|
||||
const char *p;
|
||||
int tok, n;
|
||||
if ((tok = mjson_find(s, len, path, &p, &n)) == MJSON_TOK_NUMBER) {
|
||||
if (v != NULL) *v = strtod(p, NULL);
|
||||
}
|
||||
return tok == MJSON_TOK_NUMBER ? 1 : 0;
|
||||
}
|
||||
|
||||
int mjson_get_bool(const char *s, int len, const char *path, int *v) {
|
||||
int tok = mjson_find(s, len, path, NULL, NULL);
|
||||
if (tok == MJSON_TOK_TRUE && v != NULL) *v = 1;
|
||||
if (tok == MJSON_TOK_FALSE && v != NULL) *v = 0;
|
||||
return tok == MJSON_TOK_TRUE || tok == MJSON_TOK_FALSE ? 1 : 0;
|
||||
}
|
||||
|
||||
static int mjson_unescape(const char *s, int len, char *to, int n) {
|
||||
int i, j;
|
||||
for (i = 0, j = 0; i < len && j < n; i++, j++) {
|
||||
if (s[i] == '\\' && i + 1 < len) {
|
||||
int c = mjson_esc(s[i + 1], 0);
|
||||
if (c == 0) return -1;
|
||||
to[j] = c;
|
||||
i++;
|
||||
} else {
|
||||
to[j] = s[i];
|
||||
}
|
||||
}
|
||||
if (j >= n) return -1;
|
||||
if (n > 0) to[j] = '\0';
|
||||
return j;
|
||||
}
|
||||
|
||||
int mjson_get_string(const char *s, int len, const char *path, char *to,
|
||||
int n) {
|
||||
const char *p;
|
||||
int sz;
|
||||
if (mjson_find(s, len, path, &p, &sz) != MJSON_TOK_STRING) return -1;
|
||||
return mjson_unescape(p + 1, sz - 2, to, n);
|
||||
}
|
||||
|
||||
int mjson_get_hex(const char *s, int len, const char *x, char *to, int n) {
|
||||
const char *p;
|
||||
int i, j, sz;
|
||||
if (mjson_find(s, len, x, &p, &sz) != MJSON_TOK_STRING) return -1;
|
||||
for (i = j = 0; i < sz - 3 && j < n; i += 2, j++) {
|
||||
#define HEXTOI(x) (x >= '0' && x <= '9' ? x - '0' : x - 'W')
|
||||
unsigned char a = *(const unsigned char *) (p + i + 1);
|
||||
unsigned char b = *(const unsigned char *) (p + i + 2);
|
||||
((unsigned char *) to)[j] = (HEXTOI(a) << 4) | HEXTOI(b);
|
||||
}
|
||||
if (j < n) to[j] = '\0';
|
||||
return j;
|
||||
}
|
||||
|
||||
#if MJSON_ENABLE_BASE64
|
||||
static int mjson_base64rev(int c) {
|
||||
if (c >= 'A' && c <= 'Z') {
|
||||
return c - 'A';
|
||||
} else if (c >= 'a' && c <= 'z') {
|
||||
return c + 26 - 'a';
|
||||
} else if (c >= '0' && c <= '9') {
|
||||
return c + 52 - '0';
|
||||
} else if (c == '+') {
|
||||
return 62;
|
||||
} else if (c == '/') {
|
||||
return 63;
|
||||
} else {
|
||||
return 64;
|
||||
}
|
||||
}
|
||||
|
||||
int mjson_base64_dec(const char *src, int n, char *dst, int dlen) {
|
||||
const char *end = src + n;
|
||||
int len = 0;
|
||||
while (src + 3 < end && len < dlen) {
|
||||
int a = mjson_base64rev(src[0]), b = mjson_base64rev(src[1]),
|
||||
c = mjson_base64rev(src[2]), d = mjson_base64rev(src[3]);
|
||||
dst[len++] = (a << 2) | (b >> 4);
|
||||
if (src[2] != '=' && len < dlen) {
|
||||
dst[len++] = (b << 4) | (c >> 2);
|
||||
if (src[3] != '=' && len < dlen) {
|
||||
dst[len++] = (c << 6) | d;
|
||||
}
|
||||
}
|
||||
src += 4;
|
||||
}
|
||||
if (len < dlen) dst[len] = '\0';
|
||||
return len;
|
||||
}
|
||||
|
||||
int mjson_get_base64(const char *s, int len, const char *path, char *to,
|
||||
int n) {
|
||||
const char *p;
|
||||
int sz;
|
||||
if (mjson_find(s, len, path, &p, &sz) != MJSON_TOK_STRING) return 0;
|
||||
return mjson_base64_dec(p + 1, sz - 2, to, n);
|
||||
}
|
||||
#endif // MJSON_ENABLE_BASE64
|
||||
|
||||
#if MJSON_ENABLE_NEXT
|
||||
struct nextdata {
|
||||
int off, len, depth, t, vo, arrayindex;
|
||||
int *koff, *klen, *voff, *vlen, *vtype;
|
||||
};
|
||||
|
||||
static int next_cb(int tok, const char *s, int off, int len, void *ud) {
|
||||
struct nextdata *d = (struct nextdata *) ud;
|
||||
// int i;
|
||||
switch (tok) {
|
||||
case '{':
|
||||
case '[':
|
||||
if (d->depth == 0 && tok == '[') d->arrayindex = 0;
|
||||
if (d->depth == 1 && off > d->off) {
|
||||
d->vo = off;
|
||||
d->t = tok == '{' ? MJSON_TOK_OBJECT : MJSON_TOK_ARRAY;
|
||||
if (d->voff) *d->voff = off;
|
||||
if (d->vtype) *d->vtype = d->t;
|
||||
}
|
||||
d->depth++;
|
||||
break;
|
||||
case '}':
|
||||
case ']':
|
||||
d->depth--;
|
||||
if (d->depth == 1 && d->vo) {
|
||||
d->len = off + len;
|
||||
if (d->vlen) *d->vlen = d->len - d->vo;
|
||||
if (d->arrayindex >= 0) {
|
||||
if (d->koff) *d->koff = d->arrayindex; // koff holds array index
|
||||
if (d->klen) *d->klen = 0; // klen holds 0
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
if (d->depth == 1 && d->arrayindex >= 0) d->arrayindex++;
|
||||
break;
|
||||
case ',':
|
||||
case ':':
|
||||
break;
|
||||
case MJSON_TOK_KEY:
|
||||
if (d->depth == 1 && d->off < off) {
|
||||
if (d->koff) *d->koff = off; // And report back to the user
|
||||
if (d->klen) *d->klen = len; // If we have to
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (d->depth != 1) break;
|
||||
// If we're iterating over the array
|
||||
if (off > d->off) {
|
||||
d->len = off + len;
|
||||
if (d->vlen) *d->vlen = len; // value length
|
||||
if (d->voff) *d->voff = off; // value offset
|
||||
if (d->vtype) *d->vtype = tok; // value type
|
||||
if (d->arrayindex >= 0) {
|
||||
if (d->koff) *d->koff = d->arrayindex; // koff holds array index
|
||||
if (d->klen) *d->klen = 0; // klen holds 0
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
if (d->arrayindex >= 0) d->arrayindex++;
|
||||
break;
|
||||
}
|
||||
(void) s;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mjson_next(const char *s, int n, int off, int *koff, int *klen, int *voff,
|
||||
int *vlen, int *vtype) {
|
||||
struct nextdata d = {off, 0, 0, 0, 0, -1, koff, klen, voff, vlen, vtype};
|
||||
mjson(s, n, next_cb, &d);
|
||||
return d.len;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if MJSON_ENABLE_PRINT
|
||||
int mjson_print_fixed_buf(const char *ptr, int len, void *fndata) {
|
||||
struct mjson_fixedbuf *fb = (struct mjson_fixedbuf *) fndata;
|
||||
int i, left = fb->size - 1 - fb->len;
|
||||
if (left < len) len = left;
|
||||
for (i = 0; i < len; i++) fb->ptr[fb->len + i] = ptr[i];
|
||||
fb->len += len;
|
||||
fb->ptr[fb->len] = '\0';
|
||||
return len;
|
||||
}
|
||||
|
||||
int mjson_print_dynamic_buf(const char *ptr, int len, void *fndata) {
|
||||
char *s, *buf = *(char **) fndata;
|
||||
int curlen = buf == NULL ? 0 : strlen(buf);
|
||||
if ((s = (char *) realloc(buf, curlen + len + 1)) == NULL) {
|
||||
return 0;
|
||||
} else {
|
||||
memcpy(s + curlen, ptr, len);
|
||||
s[curlen + len] = '\0';
|
||||
*(char **) fndata = s;
|
||||
return len;
|
||||
}
|
||||
}
|
||||
|
||||
int mjson_print_null(const char *ptr, int len, void *userdata) {
|
||||
(void) ptr;
|
||||
(void) userdata;
|
||||
return len;
|
||||
}
|
||||
|
||||
int mjson_print_file(const char *ptr, int len, void *userdata) {
|
||||
return fwrite(ptr, 1, len, (FILE *) userdata);
|
||||
}
|
||||
|
||||
int mjson_print_buf(mjson_print_fn_t fn, void *fndata, const char *buf,
|
||||
int len) {
|
||||
return fn(buf, len, fndata);
|
||||
}
|
||||
|
||||
int mjson_print_int(mjson_print_fn_t fn, void *fndata, int value,
|
||||
int is_signed) {
|
||||
char buf[20];
|
||||
int len = snprintf(buf, sizeof(buf), is_signed ? "%d" : "%u", value);
|
||||
return fn(buf, len, fndata);
|
||||
}
|
||||
|
||||
int mjson_print_long(mjson_print_fn_t fn, void *fndata, long value,
|
||||
int is_signed) {
|
||||
char buf[20];
|
||||
const char *fmt = (is_signed ? "%ld" : "%lu");
|
||||
int len = snprintf(buf, sizeof(buf), fmt, value);
|
||||
return fn(buf, len, fndata);
|
||||
}
|
||||
|
||||
int mjson_print_dbl(mjson_print_fn_t fn, void *fndata, double d,
|
||||
const char *fmt) {
|
||||
char buf[40];
|
||||
int n = snprintf(buf, sizeof(buf), fmt, d);
|
||||
return fn(buf, n, fndata);
|
||||
}
|
||||
|
||||
int mjson_print_str(mjson_print_fn_t fn, void *fndata, const char *s, int len) {
|
||||
int i, n = fn("\"", 1, fndata);
|
||||
for (i = 0; i < len; i++) {
|
||||
char c = mjson_esc(s[i], 1);
|
||||
if (c) {
|
||||
n += fn("\\", 1, fndata);
|
||||
n += fn(&c, 1, fndata);
|
||||
} else {
|
||||
n += fn(&s[i], 1, fndata);
|
||||
}
|
||||
}
|
||||
return n + fn("\"", 1, fndata);
|
||||
}
|
||||
|
||||
#if MJSON_ENABLE_BASE64
|
||||
int mjson_print_b64(mjson_print_fn_t fn, void *fndata, const unsigned char *s,
|
||||
int n) {
|
||||
const char *t =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
int i, len = fn("\"", 1, fndata);
|
||||
for (i = 0; i < n; i += 3) {
|
||||
int a = s[i], b = i + 1 < n ? s[i + 1] : 0, c = i + 2 < n ? s[i + 2] : 0;
|
||||
char buf[4] = {t[a >> 2], t[(a & 3) << 4 | (b >> 4)], '=', '='};
|
||||
if (i + 1 < n) buf[2] = t[(b & 15) << 2 | (c >> 6)];
|
||||
if (i + 2 < n) buf[3] = t[c & 63];
|
||||
len += fn(buf, sizeof(buf), fndata);
|
||||
}
|
||||
return len + fn("\"", 1, fndata);
|
||||
}
|
||||
#endif /* MJSON_ENABLE_BASE64 */
|
||||
|
||||
int mjson_vprintf(mjson_print_fn_t fn, void *fndata, const char *fmt,
|
||||
va_list xap) {
|
||||
int i = 0, n = 0;
|
||||
va_list ap;
|
||||
va_copy(ap, xap);
|
||||
while (fmt[i] != '\0') {
|
||||
if (fmt[i] == '%') {
|
||||
char fc = fmt[++i];
|
||||
int is_long = 0;
|
||||
if (fc == 'l') {
|
||||
is_long = 1;
|
||||
fc = fmt[i + 1];
|
||||
}
|
||||
if (fc == 'Q') {
|
||||
char *buf = va_arg(ap, char *);
|
||||
n += mjson_print_str(fn, fndata, buf ? buf : "", buf ? strlen(buf) : 0);
|
||||
} else if (strncmp(&fmt[i], ".*Q", 3) == 0) {
|
||||
int len = va_arg(ap, int);
|
||||
char *buf = va_arg(ap, char *);
|
||||
n += mjson_print_str(fn, fndata, buf, len);
|
||||
i += 2;
|
||||
} else if (fc == 'd' || fc == 'u') {
|
||||
int is_signed = (fc == 'd');
|
||||
if (is_long) {
|
||||
long val = va_arg(ap, long);
|
||||
n += mjson_print_long(fn, fndata, val, is_signed);
|
||||
i++;
|
||||
} else {
|
||||
int val = va_arg(ap, int);
|
||||
n += mjson_print_int(fn, fndata, val, is_signed);
|
||||
}
|
||||
} else if (fc == 'B') {
|
||||
const char *s = va_arg(ap, int) ? "true" : "false";
|
||||
n += mjson_print_buf(fn, fndata, s, strlen(s));
|
||||
} else if (fc == 's') {
|
||||
char *buf = va_arg(ap, char *);
|
||||
n += mjson_print_buf(fn, fndata, buf, strlen(buf));
|
||||
} else if (strncmp(&fmt[i], ".*s", 3) == 0) {
|
||||
int len = va_arg(ap, int);
|
||||
char *buf = va_arg(ap, char *);
|
||||
n += mjson_print_buf(fn, fndata, buf, len);
|
||||
i += 2;
|
||||
} else if (fc == 'g') {
|
||||
n += mjson_print_dbl(fn, fndata, va_arg(ap, double), "%g");
|
||||
} else if (fc == 'f') {
|
||||
n += mjson_print_dbl(fn, fndata, va_arg(ap, double), "%f");
|
||||
#if MJSON_ENABLE_BASE64
|
||||
} else if (fc == 'V') {
|
||||
int len = va_arg(ap, int);
|
||||
const char *buf = va_arg(ap, const char *);
|
||||
n += mjson_print_b64(fn, fndata, (unsigned char *) buf, len);
|
||||
#endif
|
||||
} else if (fc == 'H') {
|
||||
const char *hex = "0123456789abcdef";
|
||||
int i, len = va_arg(ap, int);
|
||||
const unsigned char *p = va_arg(ap, const unsigned char *);
|
||||
n += fn("\"", 1, fndata);
|
||||
for (i = 0; i < len; i++) {
|
||||
n += fn(&hex[(p[i] >> 4) & 15], 1, fndata);
|
||||
n += fn(&hex[p[i] & 15], 1, fndata);
|
||||
}
|
||||
n += fn("\"", 1, fndata);
|
||||
} else if (fc == 'M') {
|
||||
mjson_vprint_fn_t vfn = va_arg(ap, mjson_vprint_fn_t);
|
||||
n += vfn(fn, fndata, &ap);
|
||||
}
|
||||
i++;
|
||||
} else {
|
||||
n += mjson_print_buf(fn, fndata, &fmt[i++], 1);
|
||||
}
|
||||
}
|
||||
va_end(xap);
|
||||
va_end(ap);
|
||||
return n;
|
||||
}
|
||||
|
||||
int mjson_printf(mjson_print_fn_t fn, void *fndata, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
int len;
|
||||
va_start(ap, fmt);
|
||||
len = mjson_vprintf(fn, fndata, fmt, ap);
|
||||
va_end(ap);
|
||||
return len;
|
||||
}
|
||||
#endif /* MJSON_ENABLE_PRINT */
|
||||
|
||||
#if MJSON_IMPLEMENT_STRTOD
|
||||
static inline int is_digit(int c) {
|
||||
return c >= '0' && c <= '9';
|
||||
}
|
||||
|
||||
/* NOTE: strtod() implementation by Yasuhiro Matsumoto. */
|
||||
double strtod(const char *str, char **end) {
|
||||
double d = 0.0;
|
||||
int sign = 1, n = 0;
|
||||
const char *p = str, *a = str;
|
||||
|
||||
/* decimal part */
|
||||
if (*p == '-') {
|
||||
sign = -1;
|
||||
++p;
|
||||
} else if (*p == '+')
|
||||
++p;
|
||||
if (is_digit(*p)) {
|
||||
d = (double) (*p++ - '0');
|
||||
while (*p && is_digit(*p)) {
|
||||
d = d * 10.0 + (double) (*p - '0');
|
||||
++p;
|
||||
++n;
|
||||
}
|
||||
a = p;
|
||||
} else if (*p != '.')
|
||||
goto done;
|
||||
d *= sign;
|
||||
|
||||
/* fraction part */
|
||||
if (*p == '.') {
|
||||
double f = 0.0;
|
||||
double base = 0.1;
|
||||
++p;
|
||||
|
||||
if (is_digit(*p)) {
|
||||
while (*p && is_digit(*p)) {
|
||||
f += base * (*p - '0');
|
||||
base /= 10.0;
|
||||
++p;
|
||||
++n;
|
||||
}
|
||||
}
|
||||
d += f * sign;
|
||||
a = p;
|
||||
}
|
||||
|
||||
/* exponential part */
|
||||
if ((*p == 'E') || (*p == 'e')) {
|
||||
int e = 0;
|
||||
++p;
|
||||
|
||||
sign = 1;
|
||||
if (*p == '-') {
|
||||
sign = -1;
|
||||
++p;
|
||||
} else if (*p == '+')
|
||||
++p;
|
||||
|
||||
if (is_digit(*p)) {
|
||||
while (*p == '0') ++p;
|
||||
e = (int) (*p++ - '0');
|
||||
while (*p && is_digit(*p)) {
|
||||
e = e * 10 + (int) (*p - '0');
|
||||
++p;
|
||||
}
|
||||
e *= sign;
|
||||
} else if (!is_digit(*(a - 1))) {
|
||||
a = str;
|
||||
goto done;
|
||||
} else if (*p == 0)
|
||||
goto done;
|
||||
|
||||
if (d == 2.2250738585072011 && e == -308) {
|
||||
d = 0.0;
|
||||
a = p;
|
||||
goto done;
|
||||
}
|
||||
if (d == 2.2250738585072012 && e <= -308) {
|
||||
d *= 1.0e-308;
|
||||
a = p;
|
||||
goto done;
|
||||
}
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 10; i++) d *= 10;
|
||||
}
|
||||
a = p;
|
||||
} else if (p > str && !is_digit(*(p - 1))) {
|
||||
a = str;
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
if (end) *end = (char *) a;
|
||||
return d;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if MJSON_ENABLE_MERGE
|
||||
int mjson_merge(const char *s, int n, const char *s2, int n2,
|
||||
mjson_print_fn_t fn, void *userdata) {
|
||||
int koff, klen, voff, vlen, t, t2, k, off = 0, len = 0, comma = 0;
|
||||
if (n < 2) return len;
|
||||
len += fn("{", 1, userdata);
|
||||
while ((off = mjson_next(s, n, off, &koff, &klen, &voff, &vlen, &t)) != 0) {
|
||||
#if !defined(_MSC_VER) || _MSC_VER >= 1700
|
||||
char path[klen + 1];
|
||||
#else
|
||||
char *path = (char *) alloca(klen + 1);
|
||||
#endif
|
||||
const char *val;
|
||||
memcpy(path, "$.", 2);
|
||||
memcpy(path + 2, s + koff + 1, klen - 2);
|
||||
path[klen] = '\0';
|
||||
if ((t2 = mjson_find(s2, n2, path, &val, &k)) != MJSON_TOK_INVALID) {
|
||||
if (t2 == MJSON_TOK_NULL) continue; // null deletes the key
|
||||
} else {
|
||||
val = s + voff; // Key is not found in the update. Copy the old value.
|
||||
}
|
||||
if (comma) len += fn(",", 1, userdata);
|
||||
len += fn(s + koff, klen, userdata);
|
||||
len += fn(":", 1, userdata);
|
||||
if (t == MJSON_TOK_OBJECT && t2 == MJSON_TOK_OBJECT) {
|
||||
len += mjson_merge(s + voff, vlen, val, k, fn, userdata);
|
||||
} else {
|
||||
if (t2 != MJSON_TOK_INVALID) vlen = k;
|
||||
len += fn(val, vlen, userdata);
|
||||
}
|
||||
comma = 1;
|
||||
}
|
||||
// Add missing keys
|
||||
off = 0;
|
||||
while ((off = mjson_next(s2, n2, off, &koff, &klen, &voff, &vlen, &t)) != 0) {
|
||||
#if !defined(_MSC_VER) || _MSC_VER >= 1700
|
||||
char path[klen + 1];
|
||||
#else
|
||||
char *path = (char *) alloca(klen + 1);
|
||||
#endif
|
||||
const char *val;
|
||||
if (t == MJSON_TOK_NULL) continue;
|
||||
memcpy(path, "$.", 2);
|
||||
memcpy(path + 2, s2 + koff + 1, klen - 2);
|
||||
path[klen] = '\0';
|
||||
if (mjson_find(s, n, path, &val, &vlen) != MJSON_TOK_INVALID) continue;
|
||||
if (comma) len += fn(",", 1, userdata);
|
||||
len += fn(s2 + koff, klen, userdata);
|
||||
len += fn(":", 1, userdata);
|
||||
len += fn(s2 + voff, vlen, userdata);
|
||||
comma = 1;
|
||||
}
|
||||
len += fn("}", 1, userdata);
|
||||
return len;
|
||||
}
|
||||
#endif // MJSON_ENABLE_MERGE
|
||||
|
||||
#if MJSON_ENABLE_PRETTY
|
||||
struct prettydata {
|
||||
int level;
|
||||
int len;
|
||||
int prev;
|
||||
const char *pad;
|
||||
int padlen;
|
||||
mjson_print_fn_t fn;
|
||||
void *userdata;
|
||||
};
|
||||
|
||||
static int pretty_cb(int ev, const char *s, int off, int len, void *ud) {
|
||||
struct prettydata *d = (struct prettydata *) ud;
|
||||
int i;
|
||||
switch (ev) {
|
||||
case '{':
|
||||
case '[':
|
||||
d->level++;
|
||||
d->len += d->fn(s + off, len, d->userdata);
|
||||
break;
|
||||
case '}':
|
||||
case ']':
|
||||
d->level--;
|
||||
if (d->prev != '[' && d->prev != '{' && d->padlen > 0) {
|
||||
d->len += d->fn("\n", 1, d->userdata);
|
||||
for (i = 0; i < d->level; i++)
|
||||
d->len += d->fn(d->pad, d->padlen, d->userdata);
|
||||
}
|
||||
d->len += d->fn(s + off, len, d->userdata);
|
||||
break;
|
||||
case ',':
|
||||
d->len += d->fn(s + off, len, d->userdata);
|
||||
if (d->padlen > 0) {
|
||||
d->len += d->fn("\n", 1, d->userdata);
|
||||
for (i = 0; i < d->level; i++)
|
||||
d->len += d->fn(d->pad, d->padlen, d->userdata);
|
||||
}
|
||||
break;
|
||||
case ':':
|
||||
d->len += d->fn(s + off, len, d->userdata);
|
||||
if (d->padlen > 0) d->len += d->fn(" ", 1, d->userdata);
|
||||
break;
|
||||
case MJSON_TOK_KEY:
|
||||
if (d->prev == '{' && d->padlen > 0) {
|
||||
d->len += d->fn("\n", 1, d->userdata);
|
||||
for (i = 0; i < d->level; i++)
|
||||
d->len += d->fn(d->pad, d->padlen, d->userdata);
|
||||
}
|
||||
d->len += d->fn(s + off, len, d->userdata);
|
||||
break;
|
||||
default:
|
||||
if (d->prev == '[' && d->padlen > 0) {
|
||||
d->len += d->fn("\n", 1, d->userdata);
|
||||
for (i = 0; i < d->level; i++)
|
||||
d->len += d->fn(d->pad, d->padlen, d->userdata);
|
||||
}
|
||||
d->len += d->fn(s + off, len, d->userdata);
|
||||
break;
|
||||
}
|
||||
d->prev = ev;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mjson_pretty(const char *s, int n, const char *pad, mjson_print_fn_t fn,
|
||||
void *userdata) {
|
||||
struct prettydata d = {0, 0, 0, pad, strlen(pad), fn, userdata};
|
||||
if (mjson(s, n, pretty_cb, &d) < 0) return -1;
|
||||
return d.len;
|
||||
}
|
||||
#endif // MJSON_ENABLE_PRETTY
|
||||
|
||||
#if MJSON_ENABLE_RPC
|
||||
struct jsonrpc_ctx jsonrpc_default_context;
|
||||
struct jsonrpc_userdata {
|
||||
mjson_print_fn_t fn;
|
||||
void *fndata;
|
||||
};
|
||||
|
||||
int mjson_globmatch(const char *s1, int n1, const char *s2, int n2) {
|
||||
int i = 0, j = 0, ni = 0, nj = 0;
|
||||
while (i < n1 || j < n2) {
|
||||
if (i < n1 && j < n2 && (s1[i] == '?' || s2[j] == s1[i])) {
|
||||
i++, j++;
|
||||
} else if (i < n1 && (s1[i] == '*' || s1[i] == '#')) {
|
||||
ni = i, nj = j + 1, i++;
|
||||
} else if (nj > 0 && nj <= n2 && (s1[i - 1] == '#' || s2[j] != '/')) {
|
||||
i = ni, j = nj;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int jsonrpc_printer(const char *buf, int len, void *userdata) {
|
||||
struct jsonrpc_userdata *u = (struct jsonrpc_userdata *) userdata;
|
||||
return u->fn(buf, len, u->fndata);
|
||||
}
|
||||
|
||||
void jsonrpc_return_errorv(struct jsonrpc_request *r, int code,
|
||||
const char *message, const char *data_fmt,
|
||||
va_list ap) {
|
||||
if (r->id_len == 0) return;
|
||||
mjson_printf(r->fn, r->fndata,
|
||||
"{\"id\":%.*s,\"error\":{\"code\":%d,\"message\":%Q", r->id_len,
|
||||
r->id, code, message == NULL ? "" : message);
|
||||
if (data_fmt != NULL) {
|
||||
mjson_printf(r->fn, r->fndata, ",\"data\":");
|
||||
mjson_vprintf(r->fn, r->fndata, data_fmt, ap);
|
||||
}
|
||||
mjson_printf(r->fn, r->fndata, "}}\n");
|
||||
}
|
||||
|
||||
void jsonrpc_return_error(struct jsonrpc_request *r, int code,
|
||||
const char *message, const char *data_fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, data_fmt);
|
||||
jsonrpc_return_errorv(r, code, message, data_fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void jsonrpc_return_successv(struct jsonrpc_request *r, const char *result_fmt,
|
||||
va_list ap) {
|
||||
if (r->id_len == 0) return;
|
||||
mjson_printf(r->fn, r->fndata, "{\"id\":%.*s,\"result\":", r->id_len, r->id);
|
||||
if (result_fmt != NULL) {
|
||||
mjson_vprintf(r->fn, r->fndata, result_fmt, ap);
|
||||
} else {
|
||||
mjson_printf(r->fn, r->fndata, "%s", "null");
|
||||
}
|
||||
mjson_printf(r->fn, r->fndata, "}\n");
|
||||
}
|
||||
|
||||
void jsonrpc_return_success(struct jsonrpc_request *r, const char *result_fmt,
|
||||
...) {
|
||||
va_list ap;
|
||||
va_start(ap, result_fmt);
|
||||
jsonrpc_return_successv(r, result_fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void jsonrpc_ctx_process(struct jsonrpc_ctx *ctx, const char *req, int req_sz,
|
||||
mjson_print_fn_t fn, void *fndata) {
|
||||
const char *result = NULL, *error = NULL;
|
||||
int result_sz = 0, error_sz = 0;
|
||||
struct jsonrpc_method *m = NULL;
|
||||
struct jsonrpc_userdata d;
|
||||
struct jsonrpc_request r = {req, req_sz, 0, 0, 0, 0, 0,
|
||||
0, &jsonrpc_printer, NULL, NULL};
|
||||
|
||||
d.fn = fn;
|
||||
d.fndata = fndata;
|
||||
r.fndata = &d;
|
||||
|
||||
// Is is a response frame?
|
||||
mjson_find(req, req_sz, "$.result", &result, &result_sz);
|
||||
if (result == NULL) mjson_find(req, req_sz, "$.error", &error, &error_sz);
|
||||
if (result_sz > 0 || error_sz > 0) {
|
||||
if (ctx->response_cb != NULL) ctx->response_cb(req, req_sz, ctx->userdata);
|
||||
return;
|
||||
}
|
||||
|
||||
// Method must exist and must be a string
|
||||
if (mjson_find(req, req_sz, "$.method", &r.method, &r.method_len) !=
|
||||
MJSON_TOK_STRING) {
|
||||
mjson_printf(fn, fndata, "{\"error\":{\"code\":-32700,\"message\":%.*Q}}\n",
|
||||
req_sz, req);
|
||||
ctx->in_len = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// id and params are optional
|
||||
mjson_find(req, req_sz, "$.id", &r.id, &r.id_len);
|
||||
mjson_find(req, req_sz, "$.params", &r.params, &r.params_len);
|
||||
|
||||
for (m = ctx->methods; m != NULL; m = m->next) {
|
||||
if (mjson_globmatch(m->method, m->method_sz, r.method + 1,
|
||||
r.method_len - 2) > 0) {
|
||||
if (r.params == NULL) r.params = "";
|
||||
r.userdata = m->cbdata;
|
||||
m->cb(&r);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (m == NULL) {
|
||||
jsonrpc_return_error(&r, JSONRPC_ERROR_NOT_FOUND, "method not found", NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static int jsonrpc_print_methods(mjson_print_fn_t fn, void *fndata,
|
||||
va_list *ap) {
|
||||
struct jsonrpc_ctx *ctx = va_arg(*ap, struct jsonrpc_ctx *);
|
||||
struct jsonrpc_method *m;
|
||||
int len = 0;
|
||||
for (m = ctx->methods; m != NULL; m = m->next) {
|
||||
if (m != ctx->methods) len += mjson_print_buf(fn, fndata, ",", 1);
|
||||
len += mjson_print_str(fn, fndata, m->method, strlen(m->method));
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
static void rpclist(struct jsonrpc_request *r) {
|
||||
jsonrpc_return_success(r, "[%M]", jsonrpc_print_methods, r->userdata);
|
||||
}
|
||||
|
||||
void jsonrpc_ctx_init(struct jsonrpc_ctx *ctx, mjson_print_fn_t response_cb,
|
||||
void *userdata) {
|
||||
ctx->response_cb = response_cb;
|
||||
ctx->userdata = userdata;
|
||||
jsonrpc_ctx_export(ctx, MJSON_RPC_LIST_NAME, rpclist, ctx);
|
||||
}
|
||||
|
||||
void jsonrpc_ctx_process_byte(struct jsonrpc_ctx *ctx, unsigned char ch,
|
||||
mjson_print_fn_t fn, void *p) {
|
||||
if (ctx->in_len >= (int) sizeof(ctx->in)) ctx->in_len = 0; // Overflow
|
||||
if (ch == '\n') { // If new line, parse frame
|
||||
if (ctx->in_len > 1) jsonrpc_ctx_process(ctx, ctx->in, ctx->in_len, fn, p);
|
||||
ctx->in_len = 0;
|
||||
} else {
|
||||
ctx->in[ctx->in_len] = ch; // Append to the buffer
|
||||
ctx->in_len++;
|
||||
}
|
||||
}
|
||||
|
||||
void jsonrpc_init(mjson_print_fn_t response_cb, void *userdata) {
|
||||
jsonrpc_ctx_init(&jsonrpc_default_context, response_cb, userdata);
|
||||
}
|
||||
#endif // MJSON_ENABLE_RPC
|
@ -1,220 +0,0 @@
|
||||
// Copyright (c) 2018-2020 Cesanta Software Limited
|
||||
// All rights reserved
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#ifndef MJSON_H
|
||||
#define MJSON_H
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef MJSON_ENABLE_PRINT
|
||||
#define MJSON_ENABLE_PRINT 1
|
||||
#endif
|
||||
|
||||
#ifndef MJSON_ENABLE_RPC
|
||||
#define MJSON_ENABLE_RPC 1
|
||||
#endif
|
||||
|
||||
#ifndef MJSON_ENABLE_BASE64
|
||||
#define MJSON_ENABLE_BASE64 1
|
||||
#endif
|
||||
|
||||
#ifndef MJSON_ENABLE_MERGE
|
||||
#define MJSON_ENABLE_MERGE 0
|
||||
#elif MJSON_ENABLE_MERGE
|
||||
#define MJSON_ENABLE_NEXT 1
|
||||
#endif
|
||||
|
||||
#ifndef MJSON_ENABLE_PRETTY
|
||||
#define MJSON_ENABLE_PRETTY 0
|
||||
#elif MJSON_ENABLE_PRETTY
|
||||
#define MJSON_ENABLE_NEXT 1
|
||||
#endif
|
||||
|
||||
#ifndef MJSON_ENABLE_NEXT
|
||||
#define MJSON_ENABLE_NEXT 0
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef MJSON_RPC_IN_BUF_SIZE
|
||||
#define MJSON_RPC_IN_BUF_SIZE 256
|
||||
#endif
|
||||
|
||||
#ifndef MJSON_RPC_LIST_NAME
|
||||
#define MJSON_RPC_LIST_NAME "rpc.list"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum {
|
||||
MJSON_ERROR_INVALID_INPUT = -1,
|
||||
MJSON_ERROR_TOO_DEEP = -2,
|
||||
};
|
||||
|
||||
enum mjson_tok {
|
||||
MJSON_TOK_INVALID = 0,
|
||||
MJSON_TOK_KEY = 1,
|
||||
MJSON_TOK_STRING = 11,
|
||||
MJSON_TOK_NUMBER = 12,
|
||||
MJSON_TOK_TRUE = 13,
|
||||
MJSON_TOK_FALSE = 14,
|
||||
MJSON_TOK_NULL = 15,
|
||||
MJSON_TOK_ARRAY = 91,
|
||||
MJSON_TOK_OBJECT = 123,
|
||||
};
|
||||
#define MJSON_TOK_IS_VALUE(t) ((t) > 10 && (t) < 20)
|
||||
|
||||
typedef int (*mjson_cb_t)(int ev, const char *s, int off, int len, void *ud);
|
||||
|
||||
#ifndef MJSON_MAX_DEPTH
|
||||
#define MJSON_MAX_DEPTH 20
|
||||
#endif
|
||||
|
||||
int mjson(const char *s, int len, mjson_cb_t cb, void *ud);
|
||||
enum mjson_tok mjson_find(const char *s, int len, const char *jp,
|
||||
const char **tokptr, int *toklen);
|
||||
int mjson_get_number(const char *s, int len, const char *path, double *v);
|
||||
int mjson_get_bool(const char *s, int len, const char *path, int *v);
|
||||
int mjson_get_string(const char *s, int len, const char *path, char *to, int n);
|
||||
int mjson_get_hex(const char *s, int len, const char *path, char *to, int n);
|
||||
|
||||
#if MJSON_ENABLE_NEXT
|
||||
int mjson_next(const char *s, int n, int off, int *koff, int *klen, int *voff,
|
||||
int *vlen, int *vtype);
|
||||
#endif
|
||||
|
||||
#if MJSON_ENABLE_BASE64
|
||||
int mjson_get_base64(const char *s, int len, const char *path, char *to, int n);
|
||||
int mjson_base64_dec(const char *src, int n, char *dst, int dlen);
|
||||
#endif
|
||||
|
||||
#if MJSON_ENABLE_PRINT
|
||||
typedef int (*mjson_print_fn_t)(const char *buf, int len, void *userdata);
|
||||
typedef int (*mjson_vprint_fn_t)(mjson_print_fn_t, void *, va_list *);
|
||||
|
||||
struct mjson_fixedbuf {
|
||||
char *ptr;
|
||||
int size, len;
|
||||
};
|
||||
|
||||
int mjson_printf(mjson_print_fn_t, void *, const char *fmt, ...);
|
||||
int mjson_vprintf(mjson_print_fn_t, void *, const char *fmt, va_list ap);
|
||||
int mjson_print_str(mjson_print_fn_t, void *, const char *s, int len);
|
||||
int mjson_print_int(mjson_print_fn_t, void *, int value, int is_signed);
|
||||
int mjson_print_long(mjson_print_fn_t, void *, long value, int is_signed);
|
||||
int mjson_print_buf(mjson_print_fn_t fn, void *, const char *buf, int len);
|
||||
|
||||
int mjson_print_null(const char *ptr, int len, void *userdata);
|
||||
int mjson_print_file(const char *ptr, int len, void *userdata);
|
||||
int mjson_print_fixed_buf(const char *ptr, int len, void *userdata);
|
||||
int mjson_print_dynamic_buf(const char *ptr, int len, void *userdata);
|
||||
|
||||
#if MJSON_ENABLE_PRETTY
|
||||
int mjson_pretty(const char *, int, const char *, mjson_print_fn_t, void *);
|
||||
#endif
|
||||
|
||||
#if MJSON_ENABLE_MERGE
|
||||
int mjson_merge(const char *, int, const char *, int, mjson_print_fn_t, void *);
|
||||
#endif
|
||||
|
||||
#endif // MJSON_ENABLE_PRINT
|
||||
|
||||
#if MJSON_ENABLE_RPC
|
||||
|
||||
void jsonrpc_init(mjson_print_fn_t, void *userdata);
|
||||
int mjson_globmatch(const char *s1, int n1, const char *s2, int n2);
|
||||
|
||||
struct jsonrpc_request {
|
||||
const char *frame; // Points to the whole frame
|
||||
int frame_len; // Frame length
|
||||
const char *params; // Points to the "params" in the request frame
|
||||
int params_len; // Length of the "params"
|
||||
const char *id; // Points to the "id" in the request frame
|
||||
int id_len; // Length of the "id"
|
||||
const char *method; // Points to the "method" in the request frame
|
||||
int method_len; // Length of the "method"
|
||||
mjson_print_fn_t fn; // Printer function
|
||||
void *fndata; // Printer function data
|
||||
void *userdata; // Callback's user data as specified at export time
|
||||
};
|
||||
|
||||
struct jsonrpc_method {
|
||||
const char *method;
|
||||
int method_sz;
|
||||
void (*cb)(struct jsonrpc_request *);
|
||||
void *cbdata;
|
||||
struct jsonrpc_method *next;
|
||||
};
|
||||
|
||||
// Main RPC context, stores current request information and a list of
|
||||
// exported RPC methods.
|
||||
struct jsonrpc_ctx {
|
||||
struct jsonrpc_method *methods;
|
||||
void *userdata;
|
||||
mjson_print_fn_t response_cb;
|
||||
int in_len;
|
||||
char in[MJSON_RPC_IN_BUF_SIZE];
|
||||
};
|
||||
|
||||
// Registers function fn under the given name within the given RPC context
|
||||
#define jsonrpc_ctx_export(ctx, name, fn, ud) \
|
||||
do { \
|
||||
static struct jsonrpc_method m = {(name), sizeof(name) - 1, (fn), 0, 0}; \
|
||||
m.cbdata = (ud); \
|
||||
m.next = (ctx)->methods; \
|
||||
(ctx)->methods = &m; \
|
||||
} while (0)
|
||||
|
||||
void jsonrpc_ctx_init(struct jsonrpc_ctx *ctx, mjson_print_fn_t, void *);
|
||||
void jsonrpc_return_error(struct jsonrpc_request *r, int code,
|
||||
const char *message, const char *data_fmt, ...);
|
||||
void jsonrpc_return_success(struct jsonrpc_request *r, const char *result_fmt,
|
||||
...);
|
||||
void jsonrpc_ctx_process(struct jsonrpc_ctx *ctx, const char *req, int req_sz,
|
||||
mjson_print_fn_t fn, void *fndata);
|
||||
void jsonrpc_ctx_process_byte(struct jsonrpc_ctx *ctx, unsigned char ch,
|
||||
mjson_print_fn_t fn, void *fndata);
|
||||
|
||||
extern struct jsonrpc_ctx jsonrpc_default_context;
|
||||
|
||||
#define jsonrpc_export(name, fn, ud) \
|
||||
jsonrpc_ctx_export(&jsonrpc_default_context, (name), (fn), (ud))
|
||||
|
||||
#define jsonrpc_process(buf, len, fn, data) \
|
||||
jsonrpc_ctx_process(&jsonrpc_default_context, (buf), (len), (fn), (data))
|
||||
|
||||
#define jsonrpc_process_byte(x, fn, data) \
|
||||
jsonrpc_ctx_process_byte(&jsonrpc_default_context, (x), (fn), (data))
|
||||
|
||||
#define JSONRPC_ERROR_INVALID -32700 /* Invalid JSON was received */
|
||||
#define JSONRPC_ERROR_NOT_FOUND -32601 /* The method does not exist */
|
||||
#define JSONRPC_ERROR_BAD_PARAMS -32602 /* Invalid params passed */
|
||||
#define JSONRPC_ERROR_INTERNAL -32603 /* Internal JSON-RPC error */
|
||||
|
||||
#endif // MJSON_ENABLE_RPC
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif // MJSON_H
|
@ -1,76 +0,0 @@
|
||||
const {h, render, Component} = preact;
|
||||
const html = htm.bind(h);
|
||||
|
||||
const Info = () => html`<div id="info">
|
||||
This dashboard shows values kept in server memory. Many clients
|
||||
can open this page. As soon as any client changes any value,
|
||||
all clients update automatically.
|
||||
<br/><br/>
|
||||
The JS code that watches state changes, reconnects on network failures.
|
||||
That means if server restarts, dashboard on all connected clients
|
||||
refresh automatically.
|
||||
<br/><br/>
|
||||
|
||||
You can use <code>curl</code> command-line utility:
|
||||
<br/><code>curl localhost:8000/api/config/get</code>
|
||||
<br/><code>curl localhost:8000/api/config/watch</code>
|
||||
<br/><code>curl localhost:8000/api/config/set -d '{"a":123}'</code>
|
||||
</div>`;
|
||||
|
||||
class Dashboard extends Component {
|
||||
state = {value1: null, value2: null};
|
||||
componentDidMount() {
|
||||
axios.get('/api/config/get')
|
||||
.then(r => this.setState(r.data))
|
||||
.catch(e => console.log(e));
|
||||
var self = this;
|
||||
var f = function(reader) {
|
||||
return reader.read().then(function(result) {
|
||||
var data = String.fromCharCode.apply(null, result.value);
|
||||
self.setState(JSON.parse(data));
|
||||
// console.log(JSON.parse(data));
|
||||
if (!result.done) return f(reader);
|
||||
});
|
||||
};
|
||||
fetch('/api/config/watch')
|
||||
.then(r => r.body.getReader())
|
||||
.then(f)
|
||||
.catch(e => setTimeout(x => self.componentDidMount(), 1000));
|
||||
}
|
||||
render(props, state) {
|
||||
return html
|
||||
`<div id="dashboard" style="display: flex; justify-content: flex-evenly;">
|
||||
<div style="width:50%;text-align:center;">Value 1 (number):
|
||||
<div style="font-size:140%;"><b>${state.value1}</b></div></div>
|
||||
<div style="width:50%;text-align:center;">Value 2 (string):
|
||||
<div style="font-size:140%;"><b>${state.value2}</b></div></div>
|
||||
</div>`
|
||||
}
|
||||
};
|
||||
|
||||
class Form extends Component {
|
||||
render(props, state) {
|
||||
const onclick = ev => axios.post(
|
||||
'/api/config/set', {value1: +state.value1, value2: state.value2});
|
||||
// alert(JSON.stringify(state));
|
||||
return html`<div id="form">
|
||||
<div><b>Change values</b></div>
|
||||
<table>
|
||||
<tr><td>Value 1 (number):</td><td><input value=${state.value1}
|
||||
onInput=${linkState(this, 'value1')} /></td></tr>
|
||||
<tr><td>Value 2 (string):</td><td><input value=${state.value2}
|
||||
onInput=${linkState(this, 'value2')}/></td></tr>
|
||||
<tr><td></td>
|
||||
<td><button onClick=${onclick}>Save values</button></td></tr>
|
||||
</table>
|
||||
</div>`
|
||||
}
|
||||
};
|
||||
|
||||
const App = () => html`<div id="container">
|
||||
<${Info} />
|
||||
<${Dashboard} />
|
||||
<${Form} />
|
||||
</div>`;
|
||||
|
||||
window.onload = () => render(h(App), document.body);
|
3
examples/dashboard/web_root/axios.min.js
vendored
1
examples/dashboard/web_root/htm.min.js
vendored
@ -1 +0,0 @@
|
||||
!function(){function n(n){var t=e.get(this);return t||(t=new Map,e.set(this,t)),1<(t=a(this,t.get(n)||(t.set(n,t=function(n){function t(n){1===u&&(n||(r=r.replace(/^\s*\n\s*|\s*\n\s*$/g,"")))?p.push(0,n,r):3===u&&(n||r)?(p.push(3,n,r),u=2):2===u&&"..."===r&&n?p.push(4,n,0):2===u&&r&&!n?p.push(5,0,!0,r):5<=u&&((r||!n&&5===u)&&(p.push(u,0,r,s),u=6),n&&(p.push(u,n,0,s),u=6)),r=""}for(var e,s,u=1,r="",h="",p=[0],a=0;a<n.length;a++){a&&(1===u&&t(),t(a));for(var o=0;o<n[a].length;o++)e=n[a][o],1===u?"<"===e?(t(),p=[p],u=3):r+=e:4===u?r="--"===r&&">"===e?(u=1,""):e+r[0]:h?e===h?h="":r+=e:'"'===e||"'"===e?h=e:">"===e?(t(),u=1):u&&("="===e?(u=5,s=r,r=""):"/"===e&&(u<5||">"===n[a][o+1])?(t(),3===u&&(p=p[0]),(p=(u=p)[0]).push(2,0,u),u=0):" "===e||"\t"===e||"\n"===e||"\r"===e?(t(),u=2):r+=e),3===u&&"!--"===r&&(u=4,p=p[0])}return t(),p}(n)),t),arguments,[])).length?t:t[0]}var a=function(n,t,e,s){var u;t[0]=0;for(var r=1;r<t.length;r++){var h=t[r++],p=t[r]?(t[0]|=h?1:2,e[t[r++]]):t[++r];3===h?s[0]=p:4===h?s[1]=Object.assign(s[1]||{},p):5===h?(s[1]=s[1]||{})[t[++r]]=p:6===h?s[1][t[++r]]+=p+"":h?(u=n.apply(p,a(n,p,e,["",null])),s.push(u),p[0]?t[0]|=2:(t[r-2]=0,t[r]=u)):s.push(p)}return s},e=new Map;"undefined"!=typeof module?module.exports=n:self.htm=n}();
|
@ -1,16 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>example</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="stylesheet" href="style.css" />
|
||||
<script src="preact.min.js"></script>
|
||||
<script src="htm.min.js"></script>
|
||||
<script src="linkstate.min.js"></script>
|
||||
<script src="axios.min.js"></script>
|
||||
<script src="app.js"></script>
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
18
examples/dashboard/web_root/linkstate.min.js
vendored
@ -1,18 +0,0 @@
|
||||
function linkState(component, key, eventPath) {
|
||||
let path = key.split('.'), cache = component.__lsc || (component.__lsc = {});
|
||||
|
||||
return cache[key + eventPath] || (cache[key + eventPath] = function(e) {
|
||||
let t = e && e.target || this, state = {}, obj = state,
|
||||
v = typeof eventPath === 'string' ?
|
||||
delve(e, eventPath) :
|
||||
t.nodeName ? (t.type.match(/^che|rad/) ? t.checked : t.value) :
|
||||
e,
|
||||
i = 0;
|
||||
for (; i < path.length - 1; i++) {
|
||||
obj = obj[path[i]] ||
|
||||
(obj[path[i]] = !i && component.state[path[i]] || {});
|
||||
}
|
||||
obj[path[i]] = v;
|
||||
component.setState(state);
|
||||
});
|
||||
}
|
2
examples/dashboard/web_root/preact.min.js
vendored
@ -1,6 +0,0 @@
|
||||
#container { margin-right: auto; margin-left: auto; max-width: 480px; }
|
||||
#info { background: #d0f0f0; border-radius: .5em; padding: 2em; }
|
||||
#dashboard { background: #f0f0f0; border-radius: .5em; padding: 0.5em; max-height: 10em; overflow: auto; height: 100%; margin-top: 1em; }
|
||||
#form { background: #d0c0f0; border-radius: .5em; padding: 0.5em; max-height: 10em; overflow: auto; height: 100%; margin-top: 1em; }
|
||||
button { width: 100%; }
|
||||
button, select, input, label::before, textarea { outline: none; box-shadow:none !important; border: 1px solid #ccc !important; }
|
@ -4,16 +4,14 @@ This example is a demonstration of how Mongoose Library could be integrated
|
||||
into an embedded device and provide a complete device dashboard with the
|
||||
following features:
|
||||
|
||||
- Authentication: login-protected dashboard
|
||||
- Multiple logins with different permissions (admin and user)
|
||||
- Login screen for non-authenticated connections
|
||||
- A [preact](https://preactjs.com/)-based dashboard with multiple pages
|
||||
- Web UI is fully embedded into the server/firmware binary, and does not
|
||||
need a filesystem to serve it
|
||||
need a filesystem to serve it. UI is resilient to FS problems
|
||||
- View and change server settings
|
||||
- All changes are propagates to all connected clients
|
||||
- Live interactive chat that demonstrates bi-directional data exchange
|
||||
|
||||
|
||||
# Screenshots
|
||||
|
||||
This is a login screen that prompts for user/password
|
||||
@ -22,10 +20,6 @@ This is a login screen that prompts for user/password
|
||||
|
||||
# Main dashboard
|
||||
|
||||
A main dashboard page shows internal data, live video stream, and a form
|
||||
A main dashboard page shows device settings form, and live chat
|
||||
|
||||
![](screenshots/dashboard.png)
|
||||
|
||||
A live log page shows live log stream coming from device
|
||||
|
||||
![](screenshots/logs.png)
|
@ -334,446 +334,455 @@ static const unsigned char v2[] = {
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, //
|
||||
32, 32, 125, 41, 46, 99, 97, 116, 99, 104, 40, 101, // }).catch(e
|
||||
114, 114, 32, 61, 62, 32, 101, 114, 114, 41, 59, 10, // rr => err);.
|
||||
32, 32, 114, 101, 116, 117, 114, 110, 32, 104, 116, 109, // return htm
|
||||
108, 96, 10, 60, 100, 105, 118, 32, 115, 116, 121, 108, // l`.<div styl
|
||||
101, 61, 34, 109, 97, 114, 103, 105, 110, 58, 32, 48, // e="margin: 0
|
||||
32, 48, 46, 51, 101, 109, 59, 34, 62, 10, 32, 32, // 0.3em;">.
|
||||
60, 104, 51, 32, 115, 116, 121, 108, 101, 61, 34, 98, // <h3 style="b
|
||||
97, 99, 107, 103, 114, 111, 117, 110, 100, 58, 32, 35, // ackground: #
|
||||
99, 48, 51, 52, 51, 52, 59, 32, 99, 111, 108, 111, // c03434; colo
|
||||
114, 58, 32, 35, 102, 102, 102, 59, 32, 112, 97, 100, // r: #fff; pad
|
||||
100, 105, 110, 103, 58, 32, 48, 46, 52, 101, 109, 59, // ding: 0.4em;
|
||||
34, 62, 10, 32, 32, 32, 32, 67, 104, 97, 110, 103, // ">. Chang
|
||||
101, 32, 99, 111, 110, 102, 105, 103, 117, 114, 97, 116, // e configurat
|
||||
105, 111, 110, 60, 47, 104, 51, 62, 10, 32, 32, 60, // ion</h3>. <
|
||||
100, 105, 118, 32, 115, 116, 121, 108, 101, 61, 34, 109, // div style="m
|
||||
97, 114, 103, 105, 110, 58, 32, 48, 46, 53, 101, 109, // argin: 0.5em
|
||||
32, 48, 59, 34, 62, 10, 32, 32, 32, 32, 60, 115, // 0;">. <s
|
||||
112, 97, 110, 32, 99, 108, 97, 115, 115, 61, 34, 97, // pan class="a
|
||||
100, 100, 111, 110, 34, 62, 118, 97, 108, 117, 101, 49, // ddon">value1
|
||||
58, 60, 47, 115, 112, 97, 110, 62, 10, 32, 32, 32, // :</span>.
|
||||
32, 60, 105, 110, 112, 117, 116, 32, 116, 121, 112, 101, // <input type
|
||||
61, 34, 116, 101, 120, 116, 34, 32, 118, 97, 108, 117, // ="text" valu
|
||||
101, 61, 36, 123, 118, 97, 108, 117, 101, 49, 125, 10, // e=${value1}.
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 111, 110, // on
|
||||
105, 110, 112, 117, 116, 61, 36, 123, 101, 118, 32, 61, // input=${ev =
|
||||
62, 32, 115, 101, 116, 86, 97, 108, 117, 101, 49, 40, // > setValue1(
|
||||
101, 118, 46, 116, 97, 114, 103, 101, 116, 46, 118, 97, // ev.target.va
|
||||
108, 117, 101, 41, 125, 32, 47, 62, 10, 32, 32, 32, // lue)} />.
|
||||
32, 60, 98, 117, 116, 116, 111, 110, 32, 99, 108, 97, // <button cla
|
||||
115, 115, 61, 34, 98, 116, 110, 34, 32, 100, 105, 115, // ss="btn" dis
|
||||
97, 98, 108, 101, 100, 61, 36, 123, 33, 118, 97, 108, // abled=${!val
|
||||
117, 101, 49, 125, 10, 32, 32, 32, 32, 32, 32, 111, // ue1}. o
|
||||
110, 99, 108, 105, 99, 107, 61, 36, 123, 101, 118, 32, // nclick=${ev
|
||||
61, 62, 32, 117, 112, 100, 97, 116, 101, 40, 39, 118, // => update('v
|
||||
97, 108, 117, 101, 49, 39, 44, 32, 118, 97, 108, 117, // alue1', valu
|
||||
101, 49, 41, 125, 10, 32, 32, 32, 32, 32, 32, 115, // e1)}. s
|
||||
116, 121, 108, 101, 61, 34, 109, 97, 114, 103, 105, 110, // tyle="margin
|
||||
45, 108, 101, 102, 116, 58, 32, 49, 101, 109, 59, 32, // -left: 1em;
|
||||
98, 97, 99, 107, 103, 114, 111, 117, 110, 100, 58, 32, // background:
|
||||
35, 56, 97, 97, 59, 34, 62, 85, 112, 100, 97, 116, // #8aa;">Updat
|
||||
101, 60, 47, 98, 117, 116, 116, 111, 110, 62, 10, 32, // e</button>.
|
||||
32, 60, 47, 100, 105, 118, 62, 10, 32, 32, 60, 100, // </div>. <d
|
||||
105, 118, 32, 115, 116, 121, 108, 101, 61, 34, 109, 97, // iv style="ma
|
||||
114, 103, 105, 110, 58, 32, 48, 46, 53, 101, 109, 32, // rgin: 0.5em
|
||||
48, 59, 34, 62, 10, 32, 32, 32, 32, 60, 115, 112, // 0;">. <sp
|
||||
97, 110, 32, 99, 108, 97, 115, 115, 61, 34, 97, 100, // an class="ad
|
||||
100, 111, 110, 34, 62, 118, 97, 108, 117, 101, 50, 58, // don">value2:
|
||||
60, 47, 115, 112, 97, 110, 62, 10, 32, 32, 32, 32, // </span>.
|
||||
60, 105, 110, 112, 117, 116, 32, 116, 121, 112, 101, 61, // <input type=
|
||||
34, 116, 101, 120, 116, 34, 32, 118, 97, 108, 117, 101, // "text" value
|
||||
61, 36, 123, 118, 97, 108, 117, 101, 50, 125, 10, 32, // =${value2}.
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 32, 111, 110, 105, // oni
|
||||
110, 112, 117, 116, 61, 36, 123, 101, 118, 32, 61, 62, // nput=${ev =>
|
||||
32, 115, 101, 116, 86, 97, 108, 117, 101, 50, 40, 101, // setValue2(e
|
||||
118, 46, 116, 97, 114, 103, 101, 116, 46, 118, 97, 108, // v.target.val
|
||||
117, 101, 41, 125, 32, 47, 62, 10, 32, 32, 32, 32, // ue)} />.
|
||||
60, 98, 117, 116, 116, 111, 110, 32, 99, 108, 97, 115, // <button clas
|
||||
115, 61, 34, 98, 116, 110, 34, 32, 100, 105, 115, 97, // s="btn" disa
|
||||
98, 108, 101, 100, 61, 36, 123, 33, 118, 97, 108, 117, // bled=${!valu
|
||||
101, 50, 125, 10, 32, 32, 32, 32, 32, 32, 111, 110, // e2}. on
|
||||
99, 108, 105, 99, 107, 61, 36, 123, 101, 118, 32, 61, // click=${ev =
|
||||
62, 32, 117, 112, 100, 97, 116, 101, 40, 39, 118, 97, // > update('va
|
||||
108, 117, 101, 50, 39, 44, 32, 118, 97, 108, 117, 101, // lue2', value
|
||||
50, 41, 125, 10, 32, 32, 32, 32, 32, 32, 115, 116, // 2)}. st
|
||||
121, 108, 101, 61, 34, 109, 97, 114, 103, 105, 110, 45, // yle="margin-
|
||||
108, 101, 102, 116, 58, 32, 49, 101, 109, 59, 32, 98, // left: 1em; b
|
||||
97, 99, 107, 103, 114, 111, 117, 110, 100, 58, 32, 35, // ackground: #
|
||||
56, 97, 97, 59, 34, 62, 85, 112, 100, 97, 116, 101, // 8aa;">Update
|
||||
60, 47, 98, 117, 116, 116, 111, 110, 62, 10, 32, 32, // </button>.
|
||||
60, 47, 100, 105, 118, 62, 10, 32, 32, 60, 100, 105, // </div>. <di
|
||||
118, 32, 99, 108, 97, 115, 115, 61, 34, 109, 115, 103, // v class="msg
|
||||
34, 62, 10, 32, 32, 32, 32, 65, 115, 32, 115, 111, // ">. As so
|
||||
111, 110, 32, 97, 115, 32, 97, 100, 109, 105, 110, 105, // on as admini
|
||||
115, 116, 114, 97, 116, 111, 114, 32, 117, 112, 100, 97, // strator upda
|
||||
116, 101, 115, 32, 99, 111, 110, 102, 105, 103, 117, 114, // tes configur
|
||||
97, 116, 105, 111, 110, 44, 32, 10, 32, 32, 32, 32, // ation, .
|
||||
115, 101, 114, 118, 101, 114, 32, 105, 116, 101, 114, 97, // server itera
|
||||
116, 101, 115, 32, 111, 118, 101, 114, 32, 97, 108, 108, // tes over all
|
||||
32, 99, 111, 110, 110, 101, 99, 116, 101, 100, 32, 99, // connected c
|
||||
108, 105, 101, 110, 116, 115, 32, 97, 110, 100, 32, 115, // lients and s
|
||||
101, 110, 100, 115, 32, 117, 112, 100, 97, 116, 101, 10, // ends update.
|
||||
32, 32, 32, 32, 110, 111, 116, 105, 102, 105, 99, 97, // notifica
|
||||
116, 105, 111, 110, 115, 32, 116, 111, 32, 97, 108, 108, // tions to all
|
||||
32, 111, 102, 32, 116, 104, 101, 109, 32, 45, 32, 115, // of them - s
|
||||
111, 32, 116, 104, 101, 121, 32, 117, 112, 100, 97, 116, // o they updat
|
||||
101, 32, 97, 117, 116, 111, 109, 97, 116, 105, 99, 97, // e automatica
|
||||
108, 108, 121, 46, 10, 32, 32, 60, 47, 100, 105, 118, // lly.. </div
|
||||
62, 10, 60, 47, 100, 105, 118, 62, 96, 59, 10, 125, // >.</div>`;.}
|
||||
59, 10, 10, 99, 111, 110, 115, 116, 32, 76, 111, 103, // ;..const Log
|
||||
105, 110, 32, 61, 32, 102, 117, 110, 99, 116, 105, 111, // in = functio
|
||||
110, 40, 112, 114, 111, 112, 115, 41, 32, 123, 10, 32, // n(props) {.
|
||||
32, 99, 111, 110, 115, 116, 32, 91, 117, 115, 101, 114, // const [user
|
||||
44, 32, 115, 101, 116, 85, 115, 101, 114, 93, 32, 61, // , setUser] =
|
||||
32, 117, 115, 101, 83, 116, 97, 116, 101, 40, 39, 39, // useState(''
|
||||
41, 59, 10, 32, 32, 99, 111, 110, 115, 116, 32, 91, // );. const [
|
||||
112, 97, 115, 115, 44, 32, 115, 101, 116, 80, 97, 115, // pass, setPas
|
||||
115, 93, 32, 61, 32, 117, 115, 101, 83, 116, 97, 116, // s] = useStat
|
||||
101, 40, 39, 39, 41, 59, 10, 32, 32, 99, 111, 110, // e('');. con
|
||||
115, 116, 32, 108, 111, 103, 105, 110, 32, 61, 32, 101, // st login = e
|
||||
118, 32, 61, 62, 10, 32, 32, 32, 32, 32, 32, 102, // v =>. f
|
||||
101, 116, 99, 104, 40, 10, 32, 32, 32, 32, 32, 32, // etch(.
|
||||
32, 32, 32, 32, 39, 47, 97, 112, 105, 47, 108, 111, // '/api/lo
|
||||
103, 105, 110, 39, 44, 10, 32, 32, 32, 32, 32, 32, // gin',.
|
||||
32, 32, 32, 32, 123, 104, 101, 97, 100, 101, 114, 115, // {headers
|
||||
58, 32, 123, 65, 117, 116, 104, 111, 114, 105, 122, 97, // : {Authoriza
|
||||
116, 105, 111, 110, 58, 32, 39, 66, 97, 115, 105, 99, // tion: 'Basic
|
||||
32, 39, 32, 43, 32, 98, 116, 111, 97, 40, 117, 115, // ' + btoa(us
|
||||
101, 114, 32, 43, 32, 39, 58, 39, 32, 43, 32, 112, // er + ':' + p
|
||||
97, 115, 115, 41, 125, 125, 41, 10, 32, 32, 32, 32, // ass)}}).
|
||||
32, 32, 32, 32, 32, 32, 46, 116, 104, 101, 110, 40, // .then(
|
||||
114, 32, 61, 62, 32, 114, 46, 106, 115, 111, 110, 40, // r => r.json(
|
||||
41, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, // )).
|
||||
32, 46, 116, 104, 101, 110, 40, 114, 32, 61, 62, 32, // .then(r =>
|
||||
114, 32, 38, 38, 32, 112, 114, 111, 112, 115, 46, 108, // r && props.l
|
||||
111, 103, 105, 110, 40, 114, 41, 41, 10, 32, 32, 32, // ogin(r)).
|
||||
32, 32, 32, 32, 32, 32, 32, 46, 99, 97, 116, 99, // .catc
|
||||
104, 40, 101, 114, 114, 32, 61, 62, 32, 101, 114, 114, // h(err => err
|
||||
41, 59, 10, 32, 32, 114, 101, 116, 117, 114, 110, 32, // );. return
|
||||
104, 116, 109, 108, 96, 10, 60, 100, 105, 118, 32, 99, // html`.<div c
|
||||
108, 97, 115, 115, 61, 34, 114, 111, 117, 110, 100, 101, // lass="rounde
|
||||
100, 32, 98, 111, 114, 100, 101, 114, 34, 32, 115, 116, // d border" st
|
||||
121, 108, 101, 61, 34, 109, 97, 120, 45, 119, 105, 100, // yle="max-wid
|
||||
116, 104, 58, 32, 52, 56, 48, 112, 120, 59, 32, 109, // th: 480px; m
|
||||
97, 114, 103, 105, 110, 58, 32, 48, 32, 97, 117, 116, // argin: 0 aut
|
||||
111, 59, 32, 109, 97, 114, 103, 105, 110, 45, 116, 111, // o; margin-to
|
||||
112, 58, 32, 53, 101, 109, 59, 32, 98, 97, 99, 107, // p: 5em; back
|
||||
103, 114, 111, 117, 110, 100, 58, 32, 35, 101, 101, 101, // ground: #eee
|
||||
59, 32, 34, 62, 10, 32, 32, 60, 100, 105, 118, 32, // ; ">. <div
|
||||
115, 116, 121, 108, 101, 61, 34, 112, 97, 100, 100, 105, // style="paddi
|
||||
110, 103, 58, 32, 50, 101, 109, 59, 32, 34, 62, 10, // ng: 2em; ">.
|
||||
32, 32, 32, 32, 60, 104, 49, 32, 115, 116, 121, 108, // <h1 styl
|
||||
101, 61, 34, 99, 111, 108, 111, 114, 58, 32, 35, 54, // e="color: #6
|
||||
54, 54, 59, 34, 62, 68, 101, 118, 105, 99, 101, 32, // 66;">Device
|
||||
68, 97, 115, 104, 98, 111, 97, 114, 100, 32, 76, 111, // Dashboard Lo
|
||||
103, 105, 110, 32, 60, 47, 104, 49, 62, 10, 32, 32, // gin </h1>.
|
||||
32, 32, 60, 100, 105, 118, 32, 115, 116, 121, 108, 101, // <div style
|
||||
61, 34, 109, 97, 114, 103, 105, 110, 58, 32, 48, 46, // ="margin: 0.
|
||||
53, 101, 109, 32, 48, 59, 34, 62, 10, 32, 32, 32, // 5em 0;">.
|
||||
32, 32, 32, 60, 105, 110, 112, 117, 116, 32, 116, 121, // <input ty
|
||||
112, 101, 61, 39, 116, 101, 120, 116, 39, 32, 112, 108, // pe='text' pl
|
||||
97, 99, 101, 104, 111, 108, 100, 101, 114, 61, 39, 78, // aceholder='N
|
||||
97, 109, 101, 39, 32, 115, 116, 121, 108, 101, 61, 34, // ame' style="
|
||||
119, 105, 100, 116, 104, 58, 32, 49, 48, 48, 37, 59, // width: 100%;
|
||||
34, 10, 32, 32, 32, 32, 32, 32, 32, 32, 111, 110, // ". on
|
||||
105, 110, 112, 117, 116, 61, 36, 123, 101, 118, 32, 61, // input=${ev =
|
||||
62, 32, 115, 101, 116, 85, 115, 101, 114, 40, 101, 118, // > setUser(ev
|
||||
46, 116, 97, 114, 103, 101, 116, 46, 118, 97, 108, 117, // .target.valu
|
||||
101, 41, 125, 32, 118, 97, 108, 117, 101, 61, 36, 123, // e)} value=${
|
||||
117, 115, 101, 114, 125, 32, 47, 62, 10, 32, 32, 32, // user} />.
|
||||
32, 60, 47, 100, 105, 118, 62, 10, 32, 32, 32, 32, // </div>.
|
||||
60, 100, 105, 118, 32, 115, 116, 121, 108, 101, 61, 34, // <div style="
|
||||
109, 97, 114, 103, 105, 110, 58, 32, 48, 46, 53, 101, // margin: 0.5e
|
||||
109, 32, 48, 59, 34, 62, 10, 32, 32, 32, 32, 32, // m 0;">.
|
||||
32, 60, 105, 110, 112, 117, 116, 32, 116, 121, 112, 101, // <input type
|
||||
61, 34, 112, 97, 115, 115, 119, 111, 114, 100, 34, 32, // ="password"
|
||||
112, 108, 97, 99, 101, 104, 111, 108, 100, 101, 114, 61, // placeholder=
|
||||
34, 80, 97, 115, 115, 119, 111, 114, 100, 34, 32, 115, // "Password" s
|
||||
116, 121, 108, 101, 61, 34, 119, 105, 100, 116, 104, 58, // tyle="width:
|
||||
32, 49, 48, 48, 37, 59, 34, 10, 32, 32, 32, 32, // 100%;".
|
||||
32, 32, 32, 32, 111, 110, 105, 110, 112, 117, 116, 61, // oninput=
|
||||
36, 123, 101, 118, 32, 61, 62, 32, 115, 101, 116, 80, // ${ev => setP
|
||||
97, 115, 115, 40, 101, 118, 46, 116, 97, 114, 103, 101, // ass(ev.targe
|
||||
116, 46, 118, 97, 108, 117, 101, 41, 125, 32, 118, 97, // t.value)} va
|
||||
108, 117, 101, 61, 36, 123, 112, 97, 115, 115, 125, 10, // lue=${pass}.
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 111, 110, 99, 104, // onch
|
||||
97, 110, 103, 101, 61, 36, 123, 108, 111, 103, 105, 110, // ange=${login
|
||||
125, 32, 47, 62, 10, 32, 32, 32, 32, 60, 47, 100, // } />. </d
|
||||
105, 118, 62, 10, 32, 32, 32, 32, 60, 100, 105, 118, // iv>. <div
|
||||
32, 115, 116, 121, 108, 101, 61, 34, 109, 97, 114, 103, // style="marg
|
||||
105, 110, 58, 32, 49, 101, 109, 32, 48, 59, 34, 62, // in: 1em 0;">
|
||||
10, 32, 32, 32, 32, 32, 32, 60, 98, 117, 116, 116, // . <butt
|
||||
111, 110, 32, 99, 108, 97, 115, 115, 61, 34, 98, 116, // on class="bt
|
||||
110, 34, 32, 115, 116, 121, 108, 101, 61, 34, 119, 105, // n" style="wi
|
||||
100, 116, 104, 58, 32, 49, 48, 48, 37, 59, 32, 98, // dth: 100%; b
|
||||
97, 99, 107, 103, 114, 111, 117, 110, 100, 58, 32, 35, // ackground: #
|
||||
56, 97, 97, 59, 34, 10, 32, 32, 32, 32, 32, 32, // 8aa;".
|
||||
32, 32, 100, 105, 115, 97, 98, 108, 101, 100, 61, 36, // disabled=$
|
||||
123, 33, 117, 115, 101, 114, 32, 124, 124, 32, 33, 112, // {!user || !p
|
||||
97, 115, 115, 125, 32, 111, 110, 99, 108, 105, 99, 107, // ass} onclick
|
||||
61, 36, 123, 108, 111, 103, 105, 110, 125, 62, 32, 76, // =${login}> L
|
||||
111, 103, 105, 110, 32, 60, 47, 98, 117, 116, 116, 111, // ogin </butto
|
||||
110, 62, 10, 32, 32, 32, 32, 60, 47, 100, 105, 118, // n>. </div
|
||||
62, 10, 32, 32, 32, 32, 60, 100, 105, 118, 32, 115, // >. <div s
|
||||
116, 121, 108, 101, 61, 34, 99, 111, 108, 111, 114, 58, // tyle="color:
|
||||
32, 35, 55, 55, 55, 59, 32, 109, 97, 114, 103, 105, // #777; margi
|
||||
110, 45, 116, 111, 112, 58, 32, 50, 101, 109, 59, 34, // n-top: 2em;"
|
||||
62, 10, 32, 32, 32, 32, 32, 32, 86, 97, 108, 105, // >. Vali
|
||||
100, 32, 108, 111, 103, 105, 110, 115, 58, 32, 97, 100, // d logins: ad
|
||||
109, 105, 110, 58, 112, 97, 115, 115, 48, 44, 32, 117, // min:pass0, u
|
||||
115, 101, 114, 49, 58, 112, 97, 115, 115, 49, 44, 32, // ser1:pass1,
|
||||
117, 115, 101, 114, 50, 58, 112, 97, 115, 115, 50, 10, // user2:pass2.
|
||||
32, 32, 32, 32, 60, 47, 100, 105, 118, 62, 10, 32, // </div>.
|
||||
32, 60, 47, 100, 105, 118, 62, 10, 60, 47, 100, 105, // </div>.</di
|
||||
118, 62, 96, 59, 10, 125, 59, 10, 10, 99, 111, 110, // v>`;.};..con
|
||||
115, 116, 32, 77, 101, 115, 115, 97, 103, 101, 32, 61, // st Message =
|
||||
32, 116, 101, 120, 116, 32, 61, 62, 32, 104, 116, 109, // text => htm
|
||||
108, 96, 60, 100, 105, 118, 32, 115, 116, 121, 108, 101, // l`<div style
|
||||
61, 34, 109, 97, 114, 103, 105, 110, 58, 32, 48, 46, // ="margin: 0.
|
||||
53, 101, 109, 32, 48, 59, 34, 62, 36, 123, 116, 101, // 5em 0;">${te
|
||||
120, 116, 125, 60, 47, 100, 105, 118, 62, 96, 59, 10, // xt}</div>`;.
|
||||
10, 99, 111, 110, 115, 116, 32, 67, 104, 97, 116, 32, // .const Chat
|
||||
61, 32, 102, 117, 110, 99, 116, 105, 111, 110, 40, 112, // = function(p
|
||||
114, 111, 112, 115, 41, 32, 123, 10, 32, 32, 99, 111, // rops) {. co
|
||||
110, 115, 116, 32, 91, 109, 101, 115, 115, 97, 103, 101, // nst [message
|
||||
44, 32, 115, 101, 116, 77, 101, 115, 115, 97, 103, 101, // , setMessage
|
||||
93, 32, 61, 32, 117, 115, 101, 83, 116, 97, 116, 101, // ] = useState
|
||||
40, 39, 39, 41, 59, 10, 32, 32, 99, 111, 110, 115, // ('');. cons
|
||||
116, 32, 115, 101, 110, 100, 109, 101, 115, 115, 97, 103, // t sendmessag
|
||||
101, 32, 61, 32, 101, 118, 32, 61, 62, 32, 102, 101, // e = ev => fe
|
||||
116, 99, 104, 40, 39, 47, 97, 112, 105, 47, 109, 101, // tch('/api/me
|
||||
115, 115, 97, 103, 101, 47, 115, 101, 110, 100, 39, 44, // ssage/send',
|
||||
32, 123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, // {.
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, //
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 32, 109, 101, 116, // met
|
||||
104, 111, 100, 58, 32, 39, 112, 111, 115, 116, 39, 44, // hod: 'post',
|
||||
10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, // .
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, //
|
||||
32, 32, 32, 32, 32, 32, 32, 98, 111, 100, 121, 58, // body:
|
||||
32, 96, 109, 101, 115, 115, 97, 103, 101, 61, 36, 123, // `message=${
|
||||
101, 110, 99, 111, 100, 101, 85, 82, 73, 67, 111, 109, // encodeURICom
|
||||
112, 111, 110, 101, 110, 116, 40, 109, 101, 115, 115, 97, // ponent(messa
|
||||
103, 101, 41, 125, 96, 10, 32, 32, 32, 32, 32, 32, // ge)}`.
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, //
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 125, 41, // })
|
||||
46, 116, 104, 101, 110, 40, 114, 32, 61, 62, 32, 115, // .then(r => s
|
||||
101, 116, 77, 101, 115, 115, 97, 103, 101, 40, 39, 39, // etMessage(''
|
||||
41, 41, 59, 10, 10, 32, 32, 99, 111, 110, 115, 116, // ));.. const
|
||||
32, 109, 101, 115, 115, 97, 103, 101, 115, 32, 61, 32, // messages =
|
||||
112, 114, 111, 112, 115, 46, 109, 101, 115, 115, 97, 103, // props.messag
|
||||
101, 115, 46, 109, 97, 112, 40, 10, 32, 32, 32, 32, // es.map(.
|
||||
32, 32, 116, 101, 120, 116, 32, 61, 62, 32, 104, 116, // text => ht
|
||||
109, 108, 96, 60, 100, 105, 118, 32, 115, 116, 121, 108, // ml`<div styl
|
||||
101, 61, 34, 109, 97, 114, 103, 105, 110, 58, 32, 48, // e="margin: 0
|
||||
46, 53, 101, 109, 32, 48, 59, 34, 62, 36, 123, 116, // .5em 0;">${t
|
||||
101, 120, 116, 125, 60, 47, 100, 105, 118, 62, 96, 41, // ext}</div>`)
|
||||
32, 32, 99, 111, 110, 115, 116, 32, 117, 112, 100, 97, // const upda
|
||||
116, 101, 118, 97, 108, 117, 101, 49, 32, 61, 32, 101, // tevalue1 = e
|
||||
118, 32, 61, 62, 32, 117, 112, 100, 97, 116, 101, 40, // v => update(
|
||||
39, 118, 97, 108, 117, 101, 49, 39, 44, 32, 118, 97, // 'value1', va
|
||||
108, 117, 101, 49, 41, 59, 10, 32, 32, 99, 111, 110, // lue1);. con
|
||||
115, 116, 32, 117, 112, 100, 97, 116, 101, 118, 97, 108, // st updateval
|
||||
117, 101, 50, 32, 61, 32, 101, 118, 32, 61, 62, 32, // ue2 = ev =>
|
||||
117, 112, 100, 97, 116, 101, 40, 39, 118, 97, 108, 117, // update('valu
|
||||
101, 50, 39, 44, 32, 118, 97, 108, 117, 101, 50, 41, // e2', value2)
|
||||
59, 10, 32, 32, 114, 101, 116, 117, 114, 110, 32, 104, // ;. return h
|
||||
116, 109, 108, 96, 10, 60, 100, 105, 118, 32, 115, 116, // tml`.<div st
|
||||
121, 108, 101, 61, 34, 109, 97, 114, 103, 105, 110, 58, // yle="margin:
|
||||
32, 48, 32, 48, 46, 51, 101, 109, 59, 34, 62, 10, // 0 0.3em;">.
|
||||
32, 32, 60, 104, 51, 32, 115, 116, 121, 108, 101, 61, // <h3 style=
|
||||
34, 98, 97, 99, 107, 103, 114, 111, 117, 110, 100, 58, // "background:
|
||||
32, 35, 51, 48, 99, 48, 52, 48, 59, 32, 99, 111, // #30c040; co
|
||||
32, 35, 99, 48, 51, 52, 51, 52, 59, 32, 99, 111, // #c03434; co
|
||||
108, 111, 114, 58, 32, 35, 102, 102, 102, 59, 32, 112, // lor: #fff; p
|
||||
97, 100, 100, 105, 110, 103, 58, 32, 48, 46, 52, 101, // adding: 0.4e
|
||||
109, 59, 34, 62, 85, 115, 101, 114, 32, 99, 104, 97, // m;">User cha
|
||||
116, 60, 47, 104, 51, 62, 10, 32, 32, 60, 100, 105, // t</h3>. <di
|
||||
118, 32, 115, 116, 121, 108, 101, 61, 34, 104, 101, 105, // v style="hei
|
||||
103, 104, 116, 58, 32, 49, 48, 101, 109, 59, 32, 111, // ght: 10em; o
|
||||
118, 101, 114, 102, 108, 111, 119, 58, 32, 97, 117, 116, // verflow: aut
|
||||
111, 59, 32, 112, 97, 100, 100, 105, 110, 103, 58, 32, // o; padding:
|
||||
48, 46, 53, 101, 109, 59, 32, 34, 32, 99, 108, 97, // 0.5em; " cla
|
||||
115, 115, 61, 34, 98, 111, 114, 100, 101, 114, 34, 62, // ss="border">
|
||||
10, 32, 32, 32, 32, 36, 123, 109, 101, 115, 115, 97, // . ${messa
|
||||
103, 101, 115, 125, 10, 32, 32, 60, 47, 100, 105, 118, // ges}. </div
|
||||
62, 10, 32, 32, 60, 100, 105, 118, 32, 115, 116, 121, // >. <div sty
|
||||
109, 59, 34, 62, 10, 32, 32, 32, 32, 67, 104, 97, // m;">. Cha
|
||||
110, 103, 101, 32, 99, 111, 110, 102, 105, 103, 117, 114, // nge configur
|
||||
97, 116, 105, 111, 110, 60, 47, 104, 51, 62, 10, 32, // ation</h3>.
|
||||
32, 60, 100, 105, 118, 32, 115, 116, 121, 108, 101, 61, // <div style=
|
||||
34, 109, 97, 114, 103, 105, 110, 58, 32, 48, 46, 53, // "margin: 0.5
|
||||
101, 109, 32, 48, 59, 34, 62, 10, 32, 32, 32, 32, // em 0;">.
|
||||
60, 115, 112, 97, 110, 32, 99, 108, 97, 115, 115, 61, // <span class=
|
||||
34, 97, 100, 100, 111, 110, 34, 62, 118, 97, 108, 117, // "addon">valu
|
||||
101, 49, 58, 60, 47, 115, 112, 97, 110, 62, 10, 32, // e1:</span>.
|
||||
32, 32, 32, 60, 105, 110, 112, 117, 116, 32, 116, 121, // <input ty
|
||||
112, 101, 61, 34, 116, 101, 120, 116, 34, 32, 118, 97, // pe="text" va
|
||||
108, 117, 101, 61, 36, 123, 118, 97, 108, 117, 101, 49, // lue=${value1
|
||||
125, 32, 111, 110, 99, 104, 97, 110, 103, 101, 61, 36, // } onchange=$
|
||||
123, 117, 112, 100, 97, 116, 101, 118, 97, 108, 117, 101, // {updatevalue
|
||||
49, 125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, // 1}.
|
||||
32, 111, 110, 105, 110, 112, 117, 116, 61, 36, 123, 101, // oninput=${e
|
||||
118, 32, 61, 62, 32, 115, 101, 116, 86, 97, 108, 117, // v => setValu
|
||||
101, 49, 40, 101, 118, 46, 116, 97, 114, 103, 101, 116, // e1(ev.target
|
||||
46, 118, 97, 108, 117, 101, 41, 125, 32, 47, 62, 10, // .value)} />.
|
||||
32, 32, 32, 32, 60, 98, 117, 116, 116, 111, 110, 32, // <button
|
||||
99, 108, 97, 115, 115, 61, 34, 98, 116, 110, 34, 32, // class="btn"
|
||||
100, 105, 115, 97, 98, 108, 101, 100, 61, 36, 123, 33, // disabled=${!
|
||||
118, 97, 108, 117, 101, 49, 125, 32, 111, 110, 99, 108, // value1} oncl
|
||||
105, 99, 107, 61, 36, 123, 117, 112, 100, 97, 116, 101, // ick=${update
|
||||
118, 97, 108, 117, 101, 49, 125, 10, 32, 32, 32, 32, // value1}.
|
||||
32, 32, 115, 116, 121, 108, 101, 61, 34, 109, 97, 114, // style="mar
|
||||
103, 105, 110, 45, 108, 101, 102, 116, 58, 32, 49, 101, // gin-left: 1e
|
||||
109, 59, 32, 98, 97, 99, 107, 103, 114, 111, 117, 110, // m; backgroun
|
||||
100, 58, 32, 35, 56, 97, 97, 59, 34, 62, 85, 112, // d: #8aa;">Up
|
||||
100, 97, 116, 101, 60, 47, 98, 117, 116, 116, 111, 110, // date</button
|
||||
62, 10, 32, 32, 60, 47, 100, 105, 118, 62, 10, 32, // >. </div>.
|
||||
32, 60, 100, 105, 118, 32, 115, 116, 121, 108, 101, 61, // <div style=
|
||||
34, 109, 97, 114, 103, 105, 110, 58, 32, 48, 46, 53, // "margin: 0.5
|
||||
101, 109, 32, 48, 59, 34, 62, 10, 32, 32, 32, 32, // em 0;">.
|
||||
60, 115, 112, 97, 110, 32, 99, 108, 97, 115, 115, 61, // <span class=
|
||||
34, 97, 100, 100, 111, 110, 34, 62, 118, 97, 108, 117, // "addon">valu
|
||||
101, 50, 58, 60, 47, 115, 112, 97, 110, 62, 10, 32, // e2:</span>.
|
||||
32, 32, 32, 60, 105, 110, 112, 117, 116, 32, 116, 121, // <input ty
|
||||
112, 101, 61, 34, 116, 101, 120, 116, 34, 32, 118, 97, // pe="text" va
|
||||
108, 117, 101, 61, 36, 123, 118, 97, 108, 117, 101, 50, // lue=${value2
|
||||
125, 32, 111, 110, 99, 104, 97, 110, 103, 101, 61, 36, // } onchange=$
|
||||
123, 117, 112, 100, 97, 116, 101, 118, 97, 108, 117, 101, // {updatevalue
|
||||
50, 125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, // 2}.
|
||||
32, 111, 110, 105, 110, 112, 117, 116, 61, 36, 123, 101, // oninput=${e
|
||||
118, 32, 61, 62, 32, 115, 101, 116, 86, 97, 108, 117, // v => setValu
|
||||
101, 50, 40, 101, 118, 46, 116, 97, 114, 103, 101, 116, // e2(ev.target
|
||||
46, 118, 97, 108, 117, 101, 41, 125, 32, 47, 62, 10, // .value)} />.
|
||||
32, 32, 32, 32, 60, 98, 117, 116, 116, 111, 110, 32, // <button
|
||||
99, 108, 97, 115, 115, 61, 34, 98, 116, 110, 34, 32, // class="btn"
|
||||
100, 105, 115, 97, 98, 108, 101, 100, 61, 36, 123, 33, // disabled=${!
|
||||
118, 97, 108, 117, 101, 50, 125, 32, 111, 110, 99, 108, // value2} oncl
|
||||
105, 99, 107, 61, 36, 123, 117, 112, 100, 97, 116, 101, // ick=${update
|
||||
118, 97, 108, 117, 101, 50, 125, 10, 32, 32, 32, 32, // value2}.
|
||||
32, 32, 115, 116, 121, 108, 101, 61, 34, 109, 97, 114, // style="mar
|
||||
103, 105, 110, 45, 108, 101, 102, 116, 58, 32, 49, 101, // gin-left: 1e
|
||||
109, 59, 32, 98, 97, 99, 107, 103, 114, 111, 117, 110, // m; backgroun
|
||||
100, 58, 32, 35, 56, 97, 97, 59, 34, 62, 85, 112, // d: #8aa;">Up
|
||||
100, 97, 116, 101, 60, 47, 98, 117, 116, 116, 111, 110, // date</button
|
||||
62, 10, 32, 32, 60, 47, 100, 105, 118, 62, 10, 32, // >. </div>.
|
||||
32, 60, 100, 105, 118, 32, 99, 108, 97, 115, 115, 61, // <div class=
|
||||
34, 109, 115, 103, 34, 62, 10, 32, 32, 32, 32, 65, // "msg">. A
|
||||
115, 32, 115, 111, 111, 110, 32, 97, 115, 32, 97, 100, // s soon as ad
|
||||
109, 105, 110, 105, 115, 116, 114, 97, 116, 111, 114, 32, // ministrator
|
||||
117, 112, 100, 97, 116, 101, 115, 32, 99, 111, 110, 102, // updates conf
|
||||
105, 103, 117, 114, 97, 116, 105, 111, 110, 44, 32, 10, // iguration, .
|
||||
32, 32, 32, 32, 115, 101, 114, 118, 101, 114, 32, 105, // server i
|
||||
116, 101, 114, 97, 116, 101, 115, 32, 111, 118, 101, 114, // terates over
|
||||
32, 97, 108, 108, 32, 99, 111, 110, 110, 101, 99, 116, // all connect
|
||||
101, 100, 32, 99, 108, 105, 101, 110, 116, 115, 32, 97, // ed clients a
|
||||
110, 100, 32, 115, 101, 110, 100, 115, 32, 117, 112, 100, // nd sends upd
|
||||
97, 116, 101, 10, 32, 32, 32, 32, 110, 111, 116, 105, // ate. noti
|
||||
102, 105, 99, 97, 116, 105, 111, 110, 115, 32, 116, 111, // fications to
|
||||
32, 97, 108, 108, 32, 111, 102, 32, 116, 104, 101, 109, // all of them
|
||||
32, 45, 32, 115, 111, 32, 116, 104, 101, 121, 32, 117, // - so they u
|
||||
112, 100, 97, 116, 101, 32, 97, 117, 116, 111, 109, 97, // pdate automa
|
||||
116, 105, 99, 97, 108, 108, 121, 46, 10, 32, 32, 60, // tically.. <
|
||||
47, 100, 105, 118, 62, 10, 60, 47, 100, 105, 118, 62, // /div>.</div>
|
||||
96, 59, 10, 125, 59, 10, 10, 99, 111, 110, 115, 116, // `;.};..const
|
||||
32, 76, 111, 103, 105, 110, 32, 61, 32, 102, 117, 110, // Login = fun
|
||||
99, 116, 105, 111, 110, 40, 112, 114, 111, 112, 115, 41, // ction(props)
|
||||
32, 123, 10, 32, 32, 99, 111, 110, 115, 116, 32, 91, // {. const [
|
||||
117, 115, 101, 114, 44, 32, 115, 101, 116, 85, 115, 101, // user, setUse
|
||||
114, 93, 32, 61, 32, 117, 115, 101, 83, 116, 97, 116, // r] = useStat
|
||||
101, 40, 39, 39, 41, 59, 10, 32, 32, 99, 111, 110, // e('');. con
|
||||
115, 116, 32, 91, 112, 97, 115, 115, 44, 32, 115, 101, // st [pass, se
|
||||
116, 80, 97, 115, 115, 93, 32, 61, 32, 117, 115, 101, // tPass] = use
|
||||
83, 116, 97, 116, 101, 40, 39, 39, 41, 59, 10, 32, // State('');.
|
||||
32, 99, 111, 110, 115, 116, 32, 108, 111, 103, 105, 110, // const login
|
||||
32, 61, 32, 101, 118, 32, 61, 62, 10, 32, 32, 32, // = ev =>.
|
||||
32, 32, 32, 102, 101, 116, 99, 104, 40, 10, 32, 32, // fetch(.
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 39, 47, 97, 112, // '/ap
|
||||
105, 47, 108, 111, 103, 105, 110, 39, 44, 10, 32, 32, // i/login',.
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 123, 104, 101, 97, // {hea
|
||||
100, 101, 114, 115, 58, 32, 123, 65, 117, 116, 104, 111, // ders: {Autho
|
||||
114, 105, 122, 97, 116, 105, 111, 110, 58, 32, 39, 66, // rization: 'B
|
||||
97, 115, 105, 99, 32, 39, 32, 43, 32, 98, 116, 111, // asic ' + bto
|
||||
97, 40, 117, 115, 101, 114, 32, 43, 32, 39, 58, 39, // a(user + ':'
|
||||
32, 43, 32, 112, 97, 115, 115, 41, 125, 125, 41, 10, // + pass)}}).
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 116, // .t
|
||||
104, 101, 110, 40, 114, 32, 61, 62, 32, 114, 46, 106, // hen(r => r.j
|
||||
115, 111, 110, 40, 41, 41, 10, 32, 32, 32, 32, 32, // son()).
|
||||
32, 32, 32, 32, 32, 46, 116, 104, 101, 110, 40, 114, // .then(r
|
||||
32, 61, 62, 32, 114, 32, 38, 38, 32, 112, 114, 111, // => r && pro
|
||||
112, 115, 46, 108, 111, 103, 105, 110, 40, 114, 41, 41, // ps.login(r))
|
||||
10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, // . .
|
||||
99, 97, 116, 99, 104, 40, 101, 114, 114, 32, 61, 62, // catch(err =>
|
||||
32, 101, 114, 114, 41, 59, 10, 32, 32, 114, 101, 116, // err);. ret
|
||||
117, 114, 110, 32, 104, 116, 109, 108, 96, 10, 60, 100, // urn html`.<d
|
||||
105, 118, 32, 99, 108, 97, 115, 115, 61, 34, 114, 111, // iv class="ro
|
||||
117, 110, 100, 101, 100, 32, 98, 111, 114, 100, 101, 114, // unded border
|
||||
34, 32, 115, 116, 121, 108, 101, 61, 34, 109, 97, 120, // " style="max
|
||||
45, 119, 105, 100, 116, 104, 58, 32, 52, 56, 48, 112, // -width: 480p
|
||||
120, 59, 32, 109, 97, 114, 103, 105, 110, 58, 32, 48, // x; margin: 0
|
||||
32, 97, 117, 116, 111, 59, 32, 109, 97, 114, 103, 105, // auto; margi
|
||||
110, 45, 116, 111, 112, 58, 32, 53, 101, 109, 59, 32, // n-top: 5em;
|
||||
98, 97, 99, 107, 103, 114, 111, 117, 110, 100, 58, 32, // background:
|
||||
35, 101, 101, 101, 59, 32, 34, 62, 10, 32, 32, 60, // #eee; ">. <
|
||||
100, 105, 118, 32, 115, 116, 121, 108, 101, 61, 34, 112, // div style="p
|
||||
97, 100, 100, 105, 110, 103, 58, 32, 50, 101, 109, 59, // adding: 2em;
|
||||
32, 34, 62, 10, 32, 32, 32, 32, 60, 104, 49, 32, // ">. <h1
|
||||
115, 116, 121, 108, 101, 61, 34, 99, 111, 108, 111, 114, // style="color
|
||||
58, 32, 35, 54, 54, 54, 59, 34, 62, 68, 101, 118, // : #666;">Dev
|
||||
105, 99, 101, 32, 68, 97, 115, 104, 98, 111, 97, 114, // ice Dashboar
|
||||
100, 32, 76, 111, 103, 105, 110, 32, 60, 47, 104, 49, // d Login </h1
|
||||
62, 10, 32, 32, 32, 32, 60, 100, 105, 118, 32, 115, // >. <div s
|
||||
116, 121, 108, 101, 61, 34, 109, 97, 114, 103, 105, 110, // tyle="margin
|
||||
58, 32, 48, 46, 53, 101, 109, 32, 48, 59, 34, 62, // : 0.5em 0;">
|
||||
10, 32, 32, 32, 32, 32, 32, 60, 105, 110, 112, 117, // . <inpu
|
||||
116, 32, 116, 121, 112, 101, 61, 39, 116, 101, 120, 116, // t type='text
|
||||
39, 32, 112, 108, 97, 99, 101, 104, 111, 108, 100, 101, // ' placeholde
|
||||
114, 61, 39, 78, 97, 109, 101, 39, 32, 115, 116, 121, // r='Name' sty
|
||||
108, 101, 61, 34, 119, 105, 100, 116, 104, 58, 32, 49, // le="width: 1
|
||||
48, 48, 37, 59, 34, 10, 32, 32, 32, 32, 32, 32, // 00%;".
|
||||
32, 32, 111, 110, 105, 110, 112, 117, 116, 61, 36, 123, // oninput=${
|
||||
101, 118, 32, 61, 62, 32, 115, 101, 116, 85, 115, 101, // ev => setUse
|
||||
114, 40, 101, 118, 46, 116, 97, 114, 103, 101, 116, 46, // r(ev.target.
|
||||
118, 97, 108, 117, 101, 41, 125, 32, 118, 97, 108, 117, // value)} valu
|
||||
101, 61, 36, 123, 117, 115, 101, 114, 125, 32, 47, 62, // e=${user} />
|
||||
10, 32, 32, 32, 32, 60, 47, 100, 105, 118, 62, 10, // . </div>.
|
||||
32, 32, 32, 32, 60, 100, 105, 118, 32, 115, 116, 121, // <div sty
|
||||
108, 101, 61, 34, 109, 97, 114, 103, 105, 110, 58, 32, // le="margin:
|
||||
48, 46, 53, 101, 109, 32, 48, 59, 34, 62, 10, 32, // 0.5em 0;">.
|
||||
32, 32, 32, 60, 105, 110, 112, 117, 116, 32, 112, 108, // <input pl
|
||||
97, 99, 101, 104, 111, 108, 100, 101, 114, 61, 34, 116, // aceholder="t
|
||||
121, 112, 101, 32, 109, 101, 115, 115, 97, 103, 101, 46, // ype message.
|
||||
46, 46, 34, 32, 115, 116, 121, 108, 101, 61, 34, 119, // .." style="w
|
||||
105, 100, 116, 104, 58, 32, 49, 48, 48, 37, 34, 32, // idth: 100%"
|
||||
118, 97, 108, 117, 101, 61, 36, 123, 109, 101, 115, 115, // value=${mess
|
||||
97, 103, 101, 125, 10, 32, 32, 32, 32, 32, 32, 111, // age}. o
|
||||
110, 99, 104, 97, 110, 103, 101, 61, 36, 123, 115, 101, // nchange=${se
|
||||
110, 100, 109, 101, 115, 115, 97, 103, 101, 125, 10, 32, // ndmessage}.
|
||||
32, 32, 32, 32, 32, 111, 110, 105, 110, 112, 117, 116, // oninput
|
||||
61, 36, 123, 101, 118, 32, 61, 62, 32, 115, 101, 116, // =${ev => set
|
||||
77, 101, 115, 115, 97, 103, 101, 40, 101, 118, 46, 116, // Message(ev.t
|
||||
32, 32, 32, 32, 32, 60, 105, 110, 112, 117, 116, 32, // <input
|
||||
116, 121, 112, 101, 61, 34, 112, 97, 115, 115, 119, 111, // type="passwo
|
||||
114, 100, 34, 32, 112, 108, 97, 99, 101, 104, 111, 108, // rd" placehol
|
||||
100, 101, 114, 61, 34, 80, 97, 115, 115, 119, 111, 114, // der="Passwor
|
||||
100, 34, 32, 115, 116, 121, 108, 101, 61, 34, 119, 105, // d" style="wi
|
||||
100, 116, 104, 58, 32, 49, 48, 48, 37, 59, 34, 10, // dth: 100%;".
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 111, 110, 105, 110, // onin
|
||||
112, 117, 116, 61, 36, 123, 101, 118, 32, 61, 62, 32, // put=${ev =>
|
||||
115, 101, 116, 80, 97, 115, 115, 40, 101, 118, 46, 116, // setPass(ev.t
|
||||
97, 114, 103, 101, 116, 46, 118, 97, 108, 117, 101, 41, // arget.value)
|
||||
125, 32, 47, 62, 10, 32, 32, 60, 47, 100, 105, 118, // } />. </div
|
||||
62, 10, 32, 32, 60, 100, 105, 118, 32, 99, 108, 97, // >. <div cla
|
||||
115, 115, 61, 34, 109, 115, 103, 34, 62, 10, 32, 32, // ss="msg">.
|
||||
32, 32, 67, 104, 97, 116, 32, 100, 101, 109, 111, 110, // Chat demon
|
||||
115, 114, 97, 116, 101, 115, 10, 32, 32, 32, 32, 114, // srates. r
|
||||
101, 97, 108, 45, 116, 105, 109, 101, 32, 98, 105, 100, // eal-time bid
|
||||
105, 114, 101, 99, 116, 105, 111, 110, 97, 108, 32, 100, // irectional d
|
||||
97, 116, 97, 32, 101, 120, 99, 104, 97, 110, 103, 101, // ata exchange
|
||||
32, 98, 101, 116, 119, 101, 101, 110, 32, 109, 97, 110, // between man
|
||||
121, 32, 99, 108, 105, 101, 110, 116, 115, 32, 97, 110, // y clients an
|
||||
100, 32, 97, 32, 115, 101, 114, 118, 101, 114, 46, 10, // d a server..
|
||||
32, 32, 60, 47, 100, 105, 118, 62, 10, 60, 47, 100, // </div>.</d
|
||||
105, 118, 62, 96, 59, 10, 125, 59, 10, 10, 99, 111, // iv>`;.};..co
|
||||
110, 115, 116, 32, 65, 112, 112, 32, 61, 32, 102, 117, // nst App = fu
|
||||
110, 99, 116, 105, 111, 110, 40, 112, 114, 111, 112, 115, // nction(props
|
||||
41, 32, 123, 10, 32, 32, 99, 111, 110, 115, 116, 32, // ) {. const
|
||||
91, 109, 101, 115, 115, 97, 103, 101, 115, 44, 32, 115, // [messages, s
|
||||
101, 116, 77, 101, 115, 115, 97, 103, 101, 115, 93, 32, // etMessages]
|
||||
61, 32, 117, 115, 101, 83, 116, 97, 116, 101, 40, 91, // = useState([
|
||||
93, 41, 59, 10, 32, 32, 99, 111, 110, 115, 116, 32, // ]);. const
|
||||
91, 117, 115, 101, 114, 44, 32, 115, 101, 116, 85, 115, // [user, setUs
|
||||
101, 114, 93, 32, 61, 32, 117, 115, 101, 83, 116, 97, // er] = useSta
|
||||
116, 101, 40, 39, 39, 41, 59, 10, 32, 32, 99, 111, // te('');. co
|
||||
110, 115, 116, 32, 91, 99, 111, 110, 102, 105, 103, 44, // nst [config,
|
||||
32, 115, 101, 116, 67, 111, 110, 102, 105, 103, 93, 32, // setConfig]
|
||||
61, 32, 117, 115, 101, 83, 116, 97, 116, 101, 40, 123, // = useState({
|
||||
125, 41, 59, 10, 10, 32, 32, 99, 111, 110, 115, 116, // });.. const
|
||||
32, 114, 101, 102, 114, 101, 115, 104, 32, 61, 32, 40, // refresh = (
|
||||
41, 32, 61, 62, 10, 32, 32, 32, 32, 32, 32, 102, // ) =>. f
|
||||
101, 116, 99, 104, 40, 39, 47, 97, 112, 105, 47, 99, // etch('/api/c
|
||||
111, 110, 102, 105, 103, 47, 103, 101, 116, 39, 41, 46, // onfig/get').
|
||||
116, 104, 101, 110, 40, 114, 32, 61, 62, 32, 114, 46, // then(r => r.
|
||||
106, 115, 111, 110, 40, 41, 41, 46, 116, 104, 101, 110, // json()).then
|
||||
40, 114, 32, 61, 62, 32, 115, 101, 116, 67, 111, 110, // (r => setCon
|
||||
102, 105, 103, 40, 114, 41, 41, 59, 10, 10, 32, 32, // fig(r));..
|
||||
99, 111, 110, 115, 116, 32, 108, 111, 103, 105, 110, 32, // const login
|
||||
61, 32, 102, 117, 110, 99, 116, 105, 111, 110, 40, 117, // = function(u
|
||||
41, 32, 123, 10, 32, 32, 32, 32, 100, 111, 99, 117, // ) {. docu
|
||||
109, 101, 110, 116, 46, 99, 111, 111, 107, 105, 101, 32, // ment.cookie
|
||||
61, 32, 96, 97, 99, 99, 101, 115, 115, 95, 116, 111, // = `access_to
|
||||
107, 101, 110, 61, 36, 123, 117, 46, 116, 111, 107, 101, // ken=${u.toke
|
||||
110, 125, 59, 112, 97, 116, 104, 61, 47, 59, 109, 97, // n};path=/;ma
|
||||
120, 45, 97, 103, 101, 61, 51, 54, 48, 48, 96, 59, // x-age=3600`;
|
||||
10, 32, 32, 32, 32, 115, 101, 116, 85, 115, 101, 114, // . setUser
|
||||
40, 117, 46, 117, 115, 101, 114, 41, 59, 10, 32, 32, // (u.user);.
|
||||
32, 32, 114, 101, 102, 114, 101, 115, 104, 40, 41, 59, // refresh();
|
||||
10, 32, 32, 125, 59, 10, 10, 32, 32, 99, 111, 110, // . };.. con
|
||||
115, 116, 32, 108, 111, 103, 111, 117, 116, 32, 61, 32, // st logout =
|
||||
101, 118, 32, 61, 62, 32, 123, 10, 32, 32, 32, 32, // ev => {.
|
||||
125, 32, 118, 97, 108, 117, 101, 61, 36, 123, 112, 97, // } value=${pa
|
||||
115, 115, 125, 10, 32, 32, 32, 32, 32, 32, 32, 32, // ss}.
|
||||
111, 110, 99, 104, 97, 110, 103, 101, 61, 36, 123, 108, // onchange=${l
|
||||
111, 103, 105, 110, 125, 32, 47, 62, 10, 32, 32, 32, // ogin} />.
|
||||
32, 60, 47, 100, 105, 118, 62, 10, 32, 32, 32, 32, // </div>.
|
||||
60, 100, 105, 118, 32, 115, 116, 121, 108, 101, 61, 34, // <div style="
|
||||
109, 97, 114, 103, 105, 110, 58, 32, 49, 101, 109, 32, // margin: 1em
|
||||
48, 59, 34, 62, 10, 32, 32, 32, 32, 32, 32, 60, // 0;">. <
|
||||
98, 117, 116, 116, 111, 110, 32, 99, 108, 97, 115, 115, // button class
|
||||
61, 34, 98, 116, 110, 34, 32, 115, 116, 121, 108, 101, // ="btn" style
|
||||
61, 34, 119, 105, 100, 116, 104, 58, 32, 49, 48, 48, // ="width: 100
|
||||
37, 59, 32, 98, 97, 99, 107, 103, 114, 111, 117, 110, // %; backgroun
|
||||
100, 58, 32, 35, 56, 97, 97, 59, 34, 10, 32, 32, // d: #8aa;".
|
||||
32, 32, 32, 32, 32, 32, 100, 105, 115, 97, 98, 108, // disabl
|
||||
101, 100, 61, 36, 123, 33, 117, 115, 101, 114, 32, 124, // ed=${!user |
|
||||
124, 32, 33, 112, 97, 115, 115, 125, 32, 111, 110, 99, // | !pass} onc
|
||||
108, 105, 99, 107, 61, 36, 123, 108, 111, 103, 105, 110, // lick=${login
|
||||
125, 62, 32, 76, 111, 103, 105, 110, 32, 60, 47, 98, // }> Login </b
|
||||
117, 116, 116, 111, 110, 62, 10, 32, 32, 32, 32, 60, // utton>. <
|
||||
47, 100, 105, 118, 62, 10, 32, 32, 32, 32, 60, 100, // /div>. <d
|
||||
105, 118, 32, 115, 116, 121, 108, 101, 61, 34, 99, 111, // iv style="co
|
||||
108, 111, 114, 58, 32, 35, 55, 55, 55, 59, 32, 109, // lor: #777; m
|
||||
97, 114, 103, 105, 110, 45, 116, 111, 112, 58, 32, 50, // argin-top: 2
|
||||
101, 109, 59, 34, 62, 10, 32, 32, 32, 32, 32, 32, // em;">.
|
||||
86, 97, 108, 105, 100, 32, 108, 111, 103, 105, 110, 115, // Valid logins
|
||||
58, 32, 97, 100, 109, 105, 110, 58, 112, 97, 115, 115, // : admin:pass
|
||||
48, 44, 32, 117, 115, 101, 114, 49, 58, 112, 97, 115, // 0, user1:pas
|
||||
115, 49, 44, 32, 117, 115, 101, 114, 50, 58, 112, 97, // s1, user2:pa
|
||||
115, 115, 50, 10, 32, 32, 32, 32, 60, 47, 100, 105, // ss2. </di
|
||||
118, 62, 10, 32, 32, 60, 47, 100, 105, 118, 62, 10, // v>. </div>.
|
||||
60, 47, 100, 105, 118, 62, 96, 59, 10, 125, 59, 10, // </div>`;.};.
|
||||
10, 99, 111, 110, 115, 116, 32, 77, 101, 115, 115, 97, // .const Messa
|
||||
103, 101, 32, 61, 32, 116, 101, 120, 116, 32, 61, 62, // ge = text =>
|
||||
32, 104, 116, 109, 108, 96, 60, 100, 105, 118, 32, 115, // html`<div s
|
||||
116, 121, 108, 101, 61, 34, 109, 97, 114, 103, 105, 110, // tyle="margin
|
||||
58, 32, 48, 46, 53, 101, 109, 32, 48, 59, 34, 62, // : 0.5em 0;">
|
||||
36, 123, 116, 101, 120, 116, 125, 60, 47, 100, 105, 118, // ${text}</div
|
||||
62, 96, 59, 10, 10, 99, 111, 110, 115, 116, 32, 67, // >`;..const C
|
||||
104, 97, 116, 32, 61, 32, 102, 117, 110, 99, 116, 105, // hat = functi
|
||||
111, 110, 40, 112, 114, 111, 112, 115, 41, 32, 123, 10, // on(props) {.
|
||||
32, 32, 99, 111, 110, 115, 116, 32, 91, 109, 101, 115, // const [mes
|
||||
115, 97, 103, 101, 44, 32, 115, 101, 116, 77, 101, 115, // sage, setMes
|
||||
115, 97, 103, 101, 93, 32, 61, 32, 117, 115, 101, 83, // sage] = useS
|
||||
116, 97, 116, 101, 40, 39, 39, 41, 59, 10, 32, 32, // tate('');.
|
||||
99, 111, 110, 115, 116, 32, 115, 101, 110, 100, 109, 101, // const sendme
|
||||
115, 115, 97, 103, 101, 32, 61, 32, 101, 118, 32, 61, // ssage = ev =
|
||||
62, 32, 102, 101, 116, 99, 104, 40, 39, 47, 97, 112, // > fetch('/ap
|
||||
105, 47, 109, 101, 115, 115, 97, 103, 101, 47, 115, 101, // i/message/se
|
||||
110, 100, 39, 44, 32, 123, 10, 32, 32, 32, 32, 32, // nd', {.
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, //
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, //
|
||||
32, 109, 101, 116, 104, 111, 100, 58, 32, 39, 112, 111, // method: 'po
|
||||
115, 116, 39, 44, 10, 32, 32, 32, 32, 32, 32, 32, // st',.
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, //
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 98, // b
|
||||
111, 100, 121, 58, 32, 96, 109, 101, 115, 115, 97, 103, // ody: `messag
|
||||
101, 61, 36, 123, 101, 110, 99, 111, 100, 101, 85, 82, // e=${encodeUR
|
||||
73, 67, 111, 109, 112, 111, 110, 101, 110, 116, 40, 109, // IComponent(m
|
||||
101, 115, 115, 97, 103, 101, 41, 125, 96, 10, 32, 32, // essage)}`.
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, //
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, //
|
||||
32, 32, 125, 41, 46, 116, 104, 101, 110, 40, 114, 32, // }).then(r
|
||||
61, 62, 32, 115, 101, 116, 77, 101, 115, 115, 97, 103, // => setMessag
|
||||
101, 40, 39, 39, 41, 41, 59, 10, 10, 32, 32, 99, // e(''));.. c
|
||||
111, 110, 115, 116, 32, 109, 101, 115, 115, 97, 103, 101, // onst message
|
||||
115, 32, 61, 32, 112, 114, 111, 112, 115, 46, 109, 101, // s = props.me
|
||||
115, 115, 97, 103, 101, 115, 46, 109, 97, 112, 40, 10, // ssages.map(.
|
||||
32, 32, 32, 32, 32, 32, 116, 101, 120, 116, 32, 61, // text =
|
||||
62, 32, 104, 116, 109, 108, 96, 60, 100, 105, 118, 32, // > html`<div
|
||||
115, 116, 121, 108, 101, 61, 34, 109, 97, 114, 103, 105, // style="margi
|
||||
110, 58, 32, 48, 46, 53, 101, 109, 32, 48, 59, 34, // n: 0.5em 0;"
|
||||
62, 36, 123, 116, 101, 120, 116, 125, 60, 47, 100, 105, // >${text}</di
|
||||
118, 62, 96, 41, 59, 10, 32, 32, 114, 101, 116, 117, // v>`);. retu
|
||||
114, 110, 32, 104, 116, 109, 108, 96, 10, 60, 100, 105, // rn html`.<di
|
||||
118, 32, 115, 116, 121, 108, 101, 61, 34, 109, 97, 114, // v style="mar
|
||||
103, 105, 110, 58, 32, 48, 32, 48, 46, 51, 101, 109, // gin: 0 0.3em
|
||||
59, 34, 62, 10, 32, 32, 60, 104, 51, 32, 115, 116, // ;">. <h3 st
|
||||
121, 108, 101, 61, 34, 98, 97, 99, 107, 103, 114, 111, // yle="backgro
|
||||
117, 110, 100, 58, 32, 35, 51, 48, 99, 48, 52, 48, // und: #30c040
|
||||
59, 32, 99, 111, 108, 111, 114, 58, 32, 35, 102, 102, // ; color: #ff
|
||||
102, 59, 32, 112, 97, 100, 100, 105, 110, 103, 58, 32, // f; padding:
|
||||
48, 46, 52, 101, 109, 59, 34, 62, 85, 115, 101, 114, // 0.4em;">User
|
||||
32, 99, 104, 97, 116, 60, 47, 104, 51, 62, 10, 32, // chat</h3>.
|
||||
32, 60, 100, 105, 118, 32, 115, 116, 121, 108, 101, 61, // <div style=
|
||||
34, 104, 101, 105, 103, 104, 116, 58, 32, 49, 48, 101, // "height: 10e
|
||||
109, 59, 32, 111, 118, 101, 114, 102, 108, 111, 119, 58, // m; overflow:
|
||||
32, 97, 117, 116, 111, 59, 32, 112, 97, 100, 100, 105, // auto; paddi
|
||||
110, 103, 58, 32, 48, 46, 53, 101, 109, 59, 32, 34, // ng: 0.5em; "
|
||||
32, 99, 108, 97, 115, 115, 61, 34, 98, 111, 114, 100, // class="bord
|
||||
101, 114, 34, 62, 10, 32, 32, 32, 32, 36, 123, 109, // er">. ${m
|
||||
101, 115, 115, 97, 103, 101, 115, 125, 10, 32, 32, 60, // essages}. <
|
||||
47, 100, 105, 118, 62, 10, 32, 32, 60, 100, 105, 118, // /div>. <div
|
||||
32, 115, 116, 121, 108, 101, 61, 34, 109, 97, 114, 103, // style="marg
|
||||
105, 110, 58, 32, 48, 46, 53, 101, 109, 32, 48, 59, // in: 0.5em 0;
|
||||
34, 62, 10, 32, 32, 32, 32, 60, 105, 110, 112, 117, // ">. <inpu
|
||||
116, 32, 112, 108, 97, 99, 101, 104, 111, 108, 100, 101, // t placeholde
|
||||
114, 61, 34, 116, 121, 112, 101, 32, 109, 101, 115, 115, // r="type mess
|
||||
97, 103, 101, 46, 46, 46, 34, 32, 115, 116, 121, 108, // age..." styl
|
||||
101, 61, 34, 119, 105, 100, 116, 104, 58, 32, 49, 48, // e="width: 10
|
||||
48, 37, 34, 32, 118, 97, 108, 117, 101, 61, 36, 123, // 0%" value=${
|
||||
109, 101, 115, 115, 97, 103, 101, 125, 10, 32, 32, 32, // message}.
|
||||
32, 32, 32, 111, 110, 99, 104, 97, 110, 103, 101, 61, // onchange=
|
||||
36, 123, 115, 101, 110, 100, 109, 101, 115, 115, 97, 103, // ${sendmessag
|
||||
101, 125, 10, 32, 32, 32, 32, 32, 32, 111, 110, 105, // e}. oni
|
||||
110, 112, 117, 116, 61, 36, 123, 101, 118, 32, 61, 62, // nput=${ev =>
|
||||
32, 115, 101, 116, 77, 101, 115, 115, 97, 103, 101, 40, // setMessage(
|
||||
101, 118, 46, 116, 97, 114, 103, 101, 116, 46, 118, 97, // ev.target.va
|
||||
108, 117, 101, 41, 125, 32, 47, 62, 10, 32, 32, 60, // lue)} />. <
|
||||
47, 100, 105, 118, 62, 10, 32, 32, 60, 100, 105, 118, // /div>. <div
|
||||
32, 99, 108, 97, 115, 115, 61, 34, 109, 115, 103, 34, // class="msg"
|
||||
62, 10, 32, 32, 32, 32, 67, 104, 97, 116, 32, 100, // >. Chat d
|
||||
101, 109, 111, 110, 115, 114, 97, 116, 101, 115, 10, 32, // emonsrates.
|
||||
32, 32, 32, 114, 101, 97, 108, 45, 116, 105, 109, 101, // real-time
|
||||
32, 98, 105, 100, 105, 114, 101, 99, 116, 105, 111, 110, // bidirection
|
||||
97, 108, 32, 100, 97, 116, 97, 32, 101, 120, 99, 104, // al data exch
|
||||
97, 110, 103, 101, 32, 98, 101, 116, 119, 101, 101, 110, // ange between
|
||||
32, 109, 97, 110, 121, 32, 99, 108, 105, 101, 110, 116, // many client
|
||||
115, 32, 97, 110, 100, 32, 97, 32, 115, 101, 114, 118, // s and a serv
|
||||
101, 114, 46, 10, 32, 32, 60, 47, 100, 105, 118, 62, // er.. </div>
|
||||
10, 60, 47, 100, 105, 118, 62, 96, 59, 10, 125, 59, // .</div>`;.};
|
||||
10, 10, 99, 111, 110, 115, 116, 32, 65, 112, 112, 32, // ..const App
|
||||
61, 32, 102, 117, 110, 99, 116, 105, 111, 110, 40, 112, // = function(p
|
||||
114, 111, 112, 115, 41, 32, 123, 10, 32, 32, 99, 111, // rops) {. co
|
||||
110, 115, 116, 32, 91, 109, 101, 115, 115, 97, 103, 101, // nst [message
|
||||
115, 44, 32, 115, 101, 116, 77, 101, 115, 115, 97, 103, // s, setMessag
|
||||
101, 115, 93, 32, 61, 32, 117, 115, 101, 83, 116, 97, // es] = useSta
|
||||
116, 101, 40, 91, 93, 41, 59, 10, 32, 32, 99, 111, // te([]);. co
|
||||
110, 115, 116, 32, 91, 117, 115, 101, 114, 44, 32, 115, // nst [user, s
|
||||
101, 116, 85, 115, 101, 114, 93, 32, 61, 32, 117, 115, // etUser] = us
|
||||
101, 83, 116, 97, 116, 101, 40, 39, 39, 41, 59, 10, // eState('');.
|
||||
32, 32, 99, 111, 110, 115, 116, 32, 91, 99, 111, 110, // const [con
|
||||
102, 105, 103, 44, 32, 115, 101, 116, 67, 111, 110, 102, // fig, setConf
|
||||
105, 103, 93, 32, 61, 32, 117, 115, 101, 83, 116, 97, // ig] = useSta
|
||||
116, 101, 40, 123, 125, 41, 59, 10, 10, 32, 32, 99, // te({});.. c
|
||||
111, 110, 115, 116, 32, 114, 101, 102, 114, 101, 115, 104, // onst refresh
|
||||
32, 61, 32, 40, 41, 32, 61, 62, 10, 32, 32, 32, // = () =>.
|
||||
32, 32, 32, 102, 101, 116, 99, 104, 40, 39, 47, 97, // fetch('/a
|
||||
112, 105, 47, 99, 111, 110, 102, 105, 103, 47, 103, 101, // pi/config/ge
|
||||
116, 39, 41, 46, 116, 104, 101, 110, 40, 114, 32, 61, // t').then(r =
|
||||
62, 32, 114, 46, 106, 115, 111, 110, 40, 41, 41, 46, // > r.json()).
|
||||
116, 104, 101, 110, 40, 114, 32, 61, 62, 32, 115, 101, // then(r => se
|
||||
116, 67, 111, 110, 102, 105, 103, 40, 114, 41, 41, 59, // tConfig(r));
|
||||
10, 10, 32, 32, 99, 111, 110, 115, 116, 32, 108, 111, // .. const lo
|
||||
103, 105, 110, 32, 61, 32, 102, 117, 110, 99, 116, 105, // gin = functi
|
||||
111, 110, 40, 117, 41, 32, 123, 10, 32, 32, 32, 32, // on(u) {.
|
||||
100, 111, 99, 117, 109, 101, 110, 116, 46, 99, 111, 111, // document.coo
|
||||
107, 105, 101, 32, 61, 32, 96, 97, 99, 99, 101, 115, // kie = `acces
|
||||
115, 95, 116, 111, 107, 101, 110, 61, 59, 112, 97, 116, // s_token=;pat
|
||||
104, 61, 47, 59, 109, 97, 120, 45, 97, 103, 101, 61, // h=/;max-age=
|
||||
48, 96, 59, 10, 32, 32, 32, 32, 115, 101, 116, 85, // 0`;. setU
|
||||
115, 101, 114, 40, 39, 39, 41, 59, 10, 32, 32, 125, // ser('');. }
|
||||
59, 10, 10, 32, 32, 99, 111, 110, 115, 116, 32, 119, // ;.. const w
|
||||
97, 116, 99, 104, 32, 61, 32, 102, 117, 110, 99, 116, // atch = funct
|
||||
105, 111, 110, 40, 41, 32, 123, 10, 32, 32, 32, 32, // ion() {.
|
||||
118, 97, 114, 32, 102, 32, 61, 32, 102, 117, 110, 99, // var f = func
|
||||
116, 105, 111, 110, 40, 114, 101, 97, 100, 101, 114, 41, // tion(reader)
|
||||
32, 123, 10, 32, 32, 32, 32, 32, 32, 114, 101, 116, // {. ret
|
||||
117, 114, 110, 32, 114, 101, 97, 100, 101, 114, 46, 114, // urn reader.r
|
||||
101, 97, 100, 40, 41, 46, 116, 104, 101, 110, 40, 102, // ead().then(f
|
||||
117, 110, 99, 116, 105, 111, 110, 40, 114, 101, 115, 117, // unction(resu
|
||||
108, 116, 41, 32, 123, 10, 32, 32, 32, 32, 32, 32, // lt) {.
|
||||
32, 32, 118, 97, 114, 32, 100, 97, 116, 97, 32, 61, // var data =
|
||||
32, 83, 116, 114, 105, 110, 103, 46, 102, 114, 111, 109, // String.from
|
||||
67, 104, 97, 114, 67, 111, 100, 101, 46, 97, 112, 112, // CharCode.app
|
||||
108, 121, 40, 110, 117, 108, 108, 44, 32, 114, 101, 115, // ly(null, res
|
||||
117, 108, 116, 46, 118, 97, 108, 117, 101, 41, 59, 10, // ult.value);.
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 118, 97, 114, 32, // var
|
||||
115, 95, 116, 111, 107, 101, 110, 61, 36, 123, 117, 46, // s_token=${u.
|
||||
116, 111, 107, 101, 110, 125, 59, 112, 97, 116, 104, 61, // token};path=
|
||||
47, 59, 109, 97, 120, 45, 97, 103, 101, 61, 51, 54, // /;max-age=36
|
||||
48, 48, 96, 59, 10, 32, 32, 32, 32, 115, 101, 116, // 00`;. set
|
||||
85, 115, 101, 114, 40, 117, 46, 117, 115, 101, 114, 41, // User(u.user)
|
||||
59, 10, 32, 32, 32, 32, 114, 101, 102, 114, 101, 115, // ;. refres
|
||||
104, 40, 41, 59, 10, 32, 32, 125, 59, 10, 10, 32, // h();. };..
|
||||
32, 99, 111, 110, 115, 116, 32, 108, 111, 103, 111, 117, // const logou
|
||||
116, 32, 61, 32, 101, 118, 32, 61, 62, 32, 123, 10, // t = ev => {.
|
||||
32, 32, 32, 32, 100, 111, 99, 117, 109, 101, 110, 116, // document
|
||||
46, 99, 111, 111, 107, 105, 101, 32, 61, 32, 96, 97, // .cookie = `a
|
||||
99, 99, 101, 115, 115, 95, 116, 111, 107, 101, 110, 61, // ccess_token=
|
||||
59, 112, 97, 116, 104, 61, 47, 59, 109, 97, 120, 45, // ;path=/;max-
|
||||
97, 103, 101, 61, 48, 96, 59, 10, 32, 32, 32, 32, // age=0`;.
|
||||
115, 101, 116, 85, 115, 101, 114, 40, 39, 39, 41, 59, // setUser('');
|
||||
10, 32, 32, 125, 59, 10, 10, 32, 32, 99, 111, 110, // . };.. con
|
||||
115, 116, 32, 119, 97, 116, 99, 104, 32, 61, 32, 102, // st watch = f
|
||||
117, 110, 99, 116, 105, 111, 110, 40, 41, 32, 123, 10, // unction() {.
|
||||
32, 32, 32, 32, 118, 97, 114, 32, 102, 32, 61, 32, // var f =
|
||||
102, 117, 110, 99, 116, 105, 111, 110, 40, 114, 101, 97, // function(rea
|
||||
100, 101, 114, 41, 32, 123, 10, 32, 32, 32, 32, 32, // der) {.
|
||||
32, 114, 101, 116, 117, 114, 110, 32, 114, 101, 97, 100, // return read
|
||||
101, 114, 46, 114, 101, 97, 100, 40, 41, 46, 116, 104, // er.read().th
|
||||
101, 110, 40, 102, 117, 110, 99, 116, 105, 111, 110, 40, // en(function(
|
||||
114, 101, 115, 117, 108, 116, 41, 32, 123, 10, 32, 32, // result) {.
|
||||
32, 32, 32, 32, 32, 32, 118, 97, 114, 32, 100, 97, // var da
|
||||
116, 97, 32, 61, 32, 83, 116, 114, 105, 110, 103, 46, // ta = String.
|
||||
102, 114, 111, 109, 67, 104, 97, 114, 67, 111, 100, 101, // fromCharCode
|
||||
46, 97, 112, 112, 108, 121, 40, 110, 117, 108, 108, 44, // .apply(null,
|
||||
32, 114, 101, 115, 117, 108, 116, 46, 118, 97, 108, 117, // result.valu
|
||||
101, 41, 59, 10, 32, 32, 32, 32, 32, 32, 32, 32, // e);.
|
||||
118, 97, 114, 32, 110, 111, 116, 105, 102, 105, 99, 97, // var notifica
|
||||
116, 105, 111, 110, 32, 61, 32, 74, 83, 79, 78, 46, // tion = JSON.
|
||||
112, 97, 114, 115, 101, 40, 100, 97, 116, 97, 41, 59, // parse(data);
|
||||
10, 32, 32, 32, 32, 32, 32, 32, 32, 105, 102, 32, // . if
|
||||
40, 110, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, // (notificatio
|
||||
110, 46, 110, 97, 109, 101, 32, 61, 61, 32, 39, 99, // n.name == 'c
|
||||
111, 110, 102, 105, 103, 39, 41, 32, 114, 101, 102, 114, // onfig') refr
|
||||
101, 115, 104, 40, 41, 59, 10, 32, 32, 32, 32, 32, // esh();.
|
||||
32, 32, 32, 105, 102, 32, 40, 110, 111, 116, 105, 102, // if (notif
|
||||
105, 99, 97, 116, 105, 111, 110, 46, 110, 97, 109, 101, // ication.name
|
||||
32, 61, 61, 32, 39, 109, 101, 115, 115, 97, 103, 101, // == 'message
|
||||
39, 41, 32, 123, 10, 32, 32, 32, 32, 32, 32, 32, // ') {.
|
||||
32, 32, 32, 115, 101, 116, 77, 101, 115, 115, 97, 103, // setMessag
|
||||
101, 115, 40, 109, 32, 61, 62, 32, 109, 46, 99, 111, // es(m => m.co
|
||||
110, 99, 97, 116, 40, 91, 110, 111, 116, 105, 102, 105, // ncat([notifi
|
||||
99, 97, 116, 105, 111, 110, 46, 100, 97, 116, 97, 93, // cation.data]
|
||||
41, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 125, // )). }
|
||||
10, 32, 32, 32, 32, 32, 32, 32, 32, 47, 47, 32, // . //
|
||||
99, 111, 110, 115, 111, 108, 101, 46, 108, 111, 103, 40, // console.log(
|
||||
110, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, // notification
|
||||
32, 61, 32, 74, 83, 79, 78, 46, 112, 97, 114, 115, // = JSON.pars
|
||||
101, 40, 100, 97, 116, 97, 41, 59, 10, 32, 32, 32, // e(data);.
|
||||
32, 32, 32, 32, 32, 105, 102, 32, 40, 110, 111, 116, // if (not
|
||||
105, 102, 105, 99, 97, 116, 105, 111, 110, 46, 110, 97, // ification.na
|
||||
109, 101, 32, 61, 61, 32, 39, 99, 111, 110, 102, 105, // me == 'confi
|
||||
103, 39, 41, 32, 114, 101, 102, 114, 101, 115, 104, 40, // g') refresh(
|
||||
41, 59, 10, 32, 32, 32, 32, 32, 32, 32, 32, 105, // );. i
|
||||
102, 32, 40, 110, 111, 116, 105, 102, 105, 99, 97, 116, // f (notificat
|
||||
105, 111, 110, 46, 110, 97, 109, 101, 32, 61, 61, 32, // ion.name ==
|
||||
39, 109, 101, 115, 115, 97, 103, 101, 39, 41, 32, 123, // 'message') {
|
||||
10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 115, // . s
|
||||
101, 116, 77, 101, 115, 115, 97, 103, 101, 115, 40, 109, // etMessages(m
|
||||
32, 61, 62, 32, 109, 46, 99, 111, 110, 99, 97, 116, // => m.concat
|
||||
40, 91, 110, 111, 116, 105, 102, 105, 99, 97, 116, 105, // ([notificati
|
||||
111, 110, 46, 100, 97, 116, 97, 93, 41, 41, 10, 32, // on.data])).
|
||||
32, 32, 32, 32, 32, 32, 32, 125, 10, 32, 32, 32, // }.
|
||||
32, 32, 32, 32, 32, 47, 47, 32, 99, 111, 110, 115, // // cons
|
||||
111, 108, 101, 46, 108, 111, 103, 40, 110, 111, 116, 105, // ole.log(noti
|
||||
102, 105, 99, 97, 116, 105, 111, 110, 41, 59, 10, 32, // fication);.
|
||||
32, 32, 32, 32, 32, 32, 32, 105, 102, 32, 40, 33, // if (!
|
||||
114, 101, 115, 117, 108, 116, 46, 100, 111, 110, 101, 41, // result.done)
|
||||
32, 114, 101, 116, 117, 114, 110, 32, 102, 40, 114, 101, // return f(re
|
||||
97, 100, 101, 114, 41, 59, 10, 32, 32, 32, 32, 32, // ader);.
|
||||
32, 125, 41, 59, 10, 32, 32, 32, 32, 125, 59, 10, // });. };.
|
||||
102, 32, 40, 33, 114, 101, 115, 117, 108, 116, 46, 100, // f (!result.d
|
||||
111, 110, 101, 41, 32, 114, 101, 116, 117, 114, 110, 32, // one) return
|
||||
102, 40, 114, 101, 97, 100, 101, 114, 41, 59, 10, 32, // f(reader);.
|
||||
32, 32, 32, 32, 32, 125, 41, 59, 10, 32, 32, 32, // });.
|
||||
32, 125, 59, 10, 32, 32, 32, 32, 102, 101, 116, 99, // };. fetc
|
||||
104, 40, 39, 47, 97, 112, 105, 47, 119, 97, 116, 99, // h('/api/watc
|
||||
104, 39, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, // h').
|
||||
46, 116, 104, 101, 110, 40, 114, 32, 61, 62, 32, 114, // .then(r => r
|
||||
46, 98, 111, 100, 121, 46, 103, 101, 116, 82, 101, 97, // .body.getRea
|
||||
100, 101, 114, 40, 41, 41, 10, 32, 32, 32, 32, 32, // der()).
|
||||
32, 32, 32, 46, 116, 104, 101, 110, 40, 102, 41, 10, // .then(f).
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 46, 99, 97, 116, // .cat
|
||||
99, 104, 40, 101, 32, 61, 62, 32, 115, 101, 116, 84, // ch(e => setT
|
||||
105, 109, 101, 111, 117, 116, 40, 119, 97, 116, 99, 104, // imeout(watch
|
||||
44, 32, 49, 48, 48, 48, 41, 41, 59, 10, 32, 32, // , 1000));.
|
||||
125, 59, 10, 10, 32, 32, 117, 115, 101, 69, 102, 102, // };.. useEff
|
||||
101, 99, 116, 40, 40, 41, 32, 61, 62, 32, 123, 10, // ect(() => {.
|
||||
32, 32, 32, 32, 102, 101, 116, 99, 104, 40, 39, 47, // fetch('/
|
||||
97, 112, 105, 47, 119, 97, 116, 99, 104, 39, 41, 10, // api/watch').
|
||||
97, 112, 105, 47, 108, 111, 103, 105, 110, 39, 41, 10, // api/login').
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 46, 116, 104, 101, // .the
|
||||
110, 40, 114, 32, 61, 62, 32, 114, 46, 98, 111, 100, // n(r => r.bod
|
||||
121, 46, 103, 101, 116, 82, 101, 97, 100, 101, 114, 40, // y.getReader(
|
||||
41, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 46, // )). .
|
||||
116, 104, 101, 110, 40, 102, 41, 10, 32, 32, 32, 32, // then(f).
|
||||
32, 32, 32, 32, 46, 99, 97, 116, 99, 104, 40, 101, // .catch(e
|
||||
32, 61, 62, 32, 115, 101, 116, 84, 105, 109, 101, 111, // => setTimeo
|
||||
117, 116, 40, 119, 97, 116, 99, 104, 44, 32, 49, 48, // ut(watch, 10
|
||||
48, 48, 41, 41, 59, 10, 32, 32, 125, 59, 10, 10, // 00));. };..
|
||||
32, 32, 117, 115, 101, 69, 102, 102, 101, 99, 116, 40, // useEffect(
|
||||
40, 41, 32, 61, 62, 32, 123, 10, 32, 32, 32, 32, // () => {.
|
||||
102, 101, 116, 99, 104, 40, 39, 47, 97, 112, 105, 47, // fetch('/api/
|
||||
108, 111, 103, 105, 110, 39, 41, 10, 32, 32, 32, 32, // login').
|
||||
32, 32, 32, 32, 46, 116, 104, 101, 110, 40, 114, 32, // .then(r
|
||||
61, 62, 32, 114, 46, 106, 115, 111, 110, 40, 41, 41, // => r.json())
|
||||
10, 32, 32, 32, 32, 32, 32, 32, 32, 46, 116, 104, // . .th
|
||||
101, 110, 40, 114, 32, 61, 62, 32, 108, 111, 103, 105, // en(r => logi
|
||||
110, 40, 114, 41, 41, 10, 32, 32, 32, 32, 32, 32, // n(r)).
|
||||
32, 32, 46, 99, 97, 116, 99, 104, 40, 101, 114, 114, // .catch(err
|
||||
32, 61, 62, 32, 115, 101, 116, 85, 115, 101, 114, 40, // => setUser(
|
||||
39, 39, 41, 41, 59, 10, 32, 32, 32, 32, 114, 101, // ''));. re
|
||||
102, 114, 101, 115, 104, 40, 41, 59, 10, 32, 32, 32, // fresh();.
|
||||
32, 119, 97, 116, 99, 104, 40, 41, 59, 10, 32, 32, // watch();.
|
||||
125, 44, 32, 91, 93, 41, 59, 10, 10, 32, 32, 105, // }, []);.. i
|
||||
102, 32, 40, 33, 117, 115, 101, 114, 41, 32, 114, 101, // f (!user) re
|
||||
116, 117, 114, 110, 32, 104, 116, 109, 108, 96, 60, 36, // turn html`<$
|
||||
123, 76, 111, 103, 105, 110, 125, 32, 108, 111, 103, 105, // {Login} logi
|
||||
110, 61, 36, 123, 108, 111, 103, 105, 110, 125, 32, 47, // n=${login} /
|
||||
62, 96, 59, 10, 32, 32, 99, 111, 110, 115, 116, 32, // >`;. const
|
||||
97, 100, 109, 105, 110, 32, 61, 32, 117, 115, 101, 114, // admin = user
|
||||
32, 61, 61, 32, 39, 97, 100, 109, 105, 110, 39, 59, // == 'admin';
|
||||
10, 32, 32, 99, 111, 110, 115, 116, 32, 99, 111, 108, // . const col
|
||||
115, 105, 122, 101, 32, 61, 32, 97, 100, 109, 105, 110, // size = admin
|
||||
32, 63, 32, 39, 99, 52, 39, 32, 58, 32, 39, 99, // ? 'c4' : 'c
|
||||
54, 39, 59, 10, 32, 32, 99, 111, 110, 115, 116, 32, // 6';. const
|
||||
99, 115, 32, 61, 32, 97, 100, 109, 105, 110, 32, 63, // cs = admin ?
|
||||
32, 104, 116, 109, 108, 96, 60, 36, 123, 67, 104, 97, // html`<${Cha
|
||||
110, 103, 101, 83, 101, 116, 116, 105, 110, 103, 115, 125, // ngeSettings}
|
||||
32, 99, 111, 110, 102, 105, 103, 61, 36, 123, 99, 111, // config=${co
|
||||
110, 102, 105, 103, 125, 32, 47, 62, 96, 32, 58, 32, // nfig} />` :
|
||||
39, 39, 59, 10, 32, 32, 114, 101, 116, 117, 114, 110, // '';. return
|
||||
32, 104, 116, 109, 108, 96, 10, 60, 36, 123, 78, 97, // html`.<${Na
|
||||
118, 125, 32, 117, 115, 101, 114, 61, 36, 123, 117, 115, // v} user=${us
|
||||
101, 114, 125, 32, 108, 111, 103, 111, 117, 116, 61, 36, // er} logout=$
|
||||
123, 108, 111, 103, 111, 117, 116, 125, 32, 47, 62, 10, // {logout} />.
|
||||
60, 100, 105, 118, 32, 99, 108, 97, 115, 115, 61, 34, // <div class="
|
||||
99, 111, 110, 116, 97, 105, 110, 101, 114, 34, 62, 10, // container">.
|
||||
32, 32, 60, 36, 123, 72, 101, 114, 111, 125, 32, 47, // <${Hero} /
|
||||
62, 10, 32, 32, 60, 100, 105, 118, 32, 99, 108, 97, // >. <div cla
|
||||
115, 115, 61, 34, 114, 111, 119, 34, 62, 10, 32, 32, // ss="row">.
|
||||
32, 32, 60, 100, 105, 118, 32, 99, 108, 97, 115, 115, // <div class
|
||||
61, 34, 99, 111, 108, 32, 36, 123, 99, 111, 108, 115, // ="col ${cols
|
||||
105, 122, 101, 125, 34, 62, 60, 36, 123, 83, 104, 111, // ize}"><${Sho
|
||||
119, 83, 101, 116, 116, 105, 110, 103, 115, 125, 32, 99, // wSettings} c
|
||||
111, 110, 102, 105, 103, 61, 36, 123, 99, 111, 110, 102, // onfig=${conf
|
||||
105, 103, 125, 32, 47, 62, 60, 47, 100, 105, 118, 62, // ig} /></div>
|
||||
110, 40, 114, 32, 61, 62, 32, 114, 46, 106, 115, 111, // n(r => r.jso
|
||||
110, 40, 41, 41, 10, 32, 32, 32, 32, 32, 32, 32, // n()).
|
||||
32, 46, 116, 104, 101, 110, 40, 114, 32, 61, 62, 32, // .then(r =>
|
||||
108, 111, 103, 105, 110, 40, 114, 41, 41, 10, 32, 32, // login(r)).
|
||||
32, 32, 32, 32, 32, 32, 46, 99, 97, 116, 99, 104, // .catch
|
||||
40, 101, 114, 114, 32, 61, 62, 32, 115, 101, 116, 85, // (err => setU
|
||||
115, 101, 114, 40, 39, 39, 41, 41, 59, 10, 32, 32, // ser(''));.
|
||||
32, 32, 114, 101, 102, 114, 101, 115, 104, 40, 41, 59, // refresh();
|
||||
10, 32, 32, 32, 32, 119, 97, 116, 99, 104, 40, 41, // . watch()
|
||||
59, 10, 32, 32, 125, 44, 32, 91, 93, 41, 59, 10, // ;. }, []);.
|
||||
10, 32, 32, 105, 102, 32, 40, 33, 117, 115, 101, 114, // . if (!user
|
||||
41, 32, 114, 101, 116, 117, 114, 110, 32, 104, 116, 109, // ) return htm
|
||||
108, 96, 60, 36, 123, 76, 111, 103, 105, 110, 125, 32, // l`<${Login}
|
||||
108, 111, 103, 105, 110, 61, 36, 123, 108, 111, 103, 105, // login=${logi
|
||||
110, 125, 32, 47, 62, 96, 59, 10, 32, 32, 99, 111, // n} />`;. co
|
||||
110, 115, 116, 32, 97, 100, 109, 105, 110, 32, 61, 32, // nst admin =
|
||||
117, 115, 101, 114, 32, 61, 61, 32, 39, 97, 100, 109, // user == 'adm
|
||||
105, 110, 39, 59, 10, 32, 32, 99, 111, 110, 115, 116, // in';. const
|
||||
32, 99, 111, 108, 115, 105, 122, 101, 32, 61, 32, 97, // colsize = a
|
||||
100, 109, 105, 110, 32, 63, 32, 39, 99, 52, 39, 32, // dmin ? 'c4'
|
||||
58, 32, 39, 99, 54, 39, 59, 10, 32, 32, 99, 111, // : 'c6';. co
|
||||
110, 115, 116, 32, 99, 115, 32, 61, 32, 97, 100, 109, // nst cs = adm
|
||||
105, 110, 32, 63, 32, 104, 116, 109, 108, 96, 60, 36, // in ? html`<$
|
||||
123, 67, 104, 97, 110, 103, 101, 83, 101, 116, 116, 105, // {ChangeSetti
|
||||
110, 103, 115, 125, 32, 99, 111, 110, 102, 105, 103, 61, // ngs} config=
|
||||
36, 123, 99, 111, 110, 102, 105, 103, 125, 32, 47, 62, // ${config} />
|
||||
96, 32, 58, 32, 39, 39, 59, 10, 32, 32, 114, 101, // ` : '';. re
|
||||
116, 117, 114, 110, 32, 104, 116, 109, 108, 96, 10, 60, // turn html`.<
|
||||
36, 123, 78, 97, 118, 125, 32, 117, 115, 101, 114, 61, // ${Nav} user=
|
||||
36, 123, 117, 115, 101, 114, 125, 32, 108, 111, 103, 111, // ${user} logo
|
||||
117, 116, 61, 36, 123, 108, 111, 103, 111, 117, 116, 125, // ut=${logout}
|
||||
32, 47, 62, 10, 60, 100, 105, 118, 32, 99, 108, 97, // />.<div cla
|
||||
115, 115, 61, 34, 99, 111, 110, 116, 97, 105, 110, 101, // ss="containe
|
||||
114, 34, 62, 10, 32, 32, 60, 36, 123, 72, 101, 114, // r">. <${Her
|
||||
111, 125, 32, 47, 62, 10, 32, 32, 60, 100, 105, 118, // o} />. <div
|
||||
32, 99, 108, 97, 115, 115, 61, 34, 114, 111, 119, 34, // class="row"
|
||||
62, 10, 32, 32, 32, 32, 60, 100, 105, 118, 32, 99, // >. <div c
|
||||
108, 97, 115, 115, 61, 34, 99, 111, 108, 32, 36, 123, // lass="col ${
|
||||
99, 111, 108, 115, 105, 122, 101, 125, 34, 62, 60, 36, // colsize}"><$
|
||||
123, 83, 104, 111, 119, 83, 101, 116, 116, 105, 110, 103, // {ShowSetting
|
||||
115, 125, 32, 99, 111, 110, 102, 105, 103, 61, 36, 123, // s} config=${
|
||||
99, 111, 110, 102, 105, 103, 125, 32, 47, 62, 60, 47, // config} /></
|
||||
100, 105, 118, 62, 10, 32, 32, 32, 32, 60, 100, 105, // div>. <di
|
||||
118, 32, 99, 108, 97, 115, 115, 61, 34, 99, 111, 108, // v class="col
|
||||
32, 36, 123, 99, 111, 108, 115, 105, 122, 101, 125, 34, // ${colsize}"
|
||||
62, 36, 123, 99, 115, 125, 60, 47, 100, 105, 118, 62, // >${cs}</div>
|
||||
10, 32, 32, 32, 32, 60, 100, 105, 118, 32, 99, 108, // . <div cl
|
||||
97, 115, 115, 61, 34, 99, 111, 108, 32, 36, 123, 99, // ass="col ${c
|
||||
111, 108, 115, 105, 122, 101, 125, 34, 62, 36, 123, 99, // olsize}">${c
|
||||
115, 125, 60, 47, 100, 105, 118, 62, 10, 32, 32, 32, // s}</div>.
|
||||
32, 60, 100, 105, 118, 32, 99, 108, 97, 115, 115, 61, // <div class=
|
||||
34, 99, 111, 108, 32, 36, 123, 99, 111, 108, 115, 105, // "col ${colsi
|
||||
122, 101, 125, 34, 62, 60, 36, 123, 67, 104, 97, 116, // ze}"><${Chat
|
||||
125, 32, 109, 101, 115, 115, 97, 103, 101, 115, 61, 36, // } messages=$
|
||||
123, 109, 101, 115, 115, 97, 103, 101, 115, 125, 32, 47, // {messages} /
|
||||
62, 60, 47, 100, 105, 118, 62, 10, 32, 32, 60, 47, // ></div>. </
|
||||
100, 105, 118, 62, 10, 32, 32, 60, 36, 123, 70, 111, // div>. <${Fo
|
||||
111, 116, 101, 114, 125, 32, 47, 62, 10, 60, 47, 100, // oter} />.</d
|
||||
105, 118, 62, 96, 59, 10, 125, 59, 10, 10, 119, 105, // iv>`;.};..wi
|
||||
110, 100, 111, 119, 46, 111, 110, 108, 111, 97, 100, 32, // ndow.onload
|
||||
61, 32, 40, 41, 32, 61, 62, 32, 114, 101, 110, 100, // = () => rend
|
||||
101, 114, 40, 104, 40, 65, 112, 112, 41, 44, 32, 100, // er(h(App), d
|
||||
111, 99, 117, 109, 101, 110, 116, 46, 98, 111, 100, 121, // ocument.body
|
||||
41, 59, 10, 0 // );.
|
||||
111, 108, 115, 105, 122, 101, 125, 34, 62, 60, 36, 123, // olsize}"><${
|
||||
67, 104, 97, 116, 125, 32, 109, 101, 115, 115, 97, 103, // Chat} messag
|
||||
101, 115, 61, 36, 123, 109, 101, 115, 115, 97, 103, 101, // es=${message
|
||||
115, 125, 32, 47, 62, 60, 47, 100, 105, 118, 62, 10, // s} /></div>.
|
||||
32, 32, 60, 47, 100, 105, 118, 62, 10, 32, 32, 60, // </div>. <
|
||||
36, 123, 70, 111, 111, 116, 101, 114, 125, 32, 47, 62, // ${Footer} />
|
||||
10, 60, 47, 100, 105, 118, 62, 96, 59, 10, 125, 59, // .</div>`;.};
|
||||
10, 10, 119, 105, 110, 100, 111, 119, 46, 111, 110, 108, // ..window.onl
|
||||
111, 97, 100, 32, 61, 32, 40, 41, 32, 61, 62, 32, // oad = () =>
|
||||
114, 101, 110, 100, 101, 114, 40, 104, 40, 65, 112, 112, // render(h(App
|
||||
41, 44, 32, 100, 111, 99, 117, 109, 101, 110, 116, 46, // ), document.
|
||||
98, 111, 100, 121, 41, 59, 10, 0 // body);.
|
||||
};
|
||||
static const unsigned char v3[] = {
|
||||
118, 97, 114, 32, 101, 44, 110, 44, 95, 44, 116, 44, // var e,n,_,t,
|
||||
@ -2336,7 +2345,7 @@ static const struct packed_file {
|
||||
time_t mtime;
|
||||
} packed_files[] = {
|
||||
{"/web_root/index.html", v1, sizeof(v1), 1652432837},
|
||||
{"/web_root/main.js", v2, sizeof(v2), 1652468289},
|
||||
{"/web_root/main.js", v2, sizeof(v2), 1652514584},
|
||||
{"/web_root/preact.min.js", v3, sizeof(v3), 1652374364},
|
||||
{"/web_root/style.css", v4, sizeof(v4), 1652467860},
|
||||
{"/web_root/user.png", v5, sizeof(v5), 1626172939},
|
BIN
examples/device-dashboard/screenshots/dashboard.png
Normal file
After Width: | Height: | Size: 309 KiB |
BIN
examples/device-dashboard/screenshots/login.png
Normal file
After Width: | Height: | Size: 64 KiB |
@ -91,24 +91,24 @@ const ChangeSettings = function(props) {
|
||||
method: 'post',
|
||||
body: `${name}=${encodeURIComponent(val)}`
|
||||
}).catch(err => err);
|
||||
const updatevalue1 = ev => update('value1', value1);
|
||||
const updatevalue2 = ev => update('value2', value2);
|
||||
return html`
|
||||
<div style="margin: 0 0.3em;">
|
||||
<h3 style="background: #c03434; color: #fff; padding: 0.4em;">
|
||||
Change configuration</h3>
|
||||
<div style="margin: 0.5em 0;">
|
||||
<span class="addon">value1:</span>
|
||||
<input type="text" value=${value1}
|
||||
<input type="text" value=${value1} onchange=${updatevalue1}
|
||||
oninput=${ev => setValue1(ev.target.value)} />
|
||||
<button class="btn" disabled=${!value1}
|
||||
onclick=${ev => update('value1', value1)}
|
||||
<button class="btn" disabled=${!value1} onclick=${updatevalue1}
|
||||
style="margin-left: 1em; background: #8aa;">Update</button>
|
||||
</div>
|
||||
<div style="margin: 0.5em 0;">
|
||||
<span class="addon">value2:</span>
|
||||
<input type="text" value=${value2}
|
||||
<input type="text" value=${value2} onchange=${updatevalue2}
|
||||
oninput=${ev => setValue2(ev.target.value)} />
|
||||
<button class="btn" disabled=${!value2}
|
||||
onclick=${ev => update('value2', value2)}
|
||||
<button class="btn" disabled=${!value2} onclick=${updatevalue2}
|
||||
style="margin-left: 1em; background: #8aa;">Update</button>
|
||||
</div>
|
||||
<div class="msg">
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
@ -1,10 +0,0 @@
|
||||
PROG ?= example
|
||||
|
||||
all: $(PROG)
|
||||
$(DEBUGGER) ./$(PROG)
|
||||
|
||||
$(PROG):
|
||||
$(CC) ../../mongoose.c -I../.. $(CFLAGS) $(EXTRA) -o $(PROG) main.c
|
||||
|
||||
clean:
|
||||
rm -rf $(PROG) *.o *.dSYM *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb
|
@ -1,90 +0,0 @@
|
||||
// Copyright (c) 2020 Cesanta Software Limited
|
||||
// All rights reserved
|
||||
|
||||
#include "mongoose.h"
|
||||
|
||||
// Authenticated user.
|
||||
// A user can be authenticated by:
|
||||
// - a name:pass pair
|
||||
// - a token
|
||||
// When a user is shown a login screen, she enters a user:pass. If successful,
|
||||
// a server returns user info which includes token. From that point on,
|
||||
// client can use token for authentication. Tokens could be refreshed/changed
|
||||
// on a server side, forcing clients to re-login.
|
||||
struct user {
|
||||
const char *name, *pass, *token;
|
||||
};
|
||||
|
||||
// Parse HTTP requests, return authenticated user or NULL
|
||||
static struct user *getuser(struct mg_http_message *hm) {
|
||||
// In production, make passwords strong and tokens randomly generated
|
||||
// In this example, user list is kept in RAM. In production, it can
|
||||
// be backed by file, database, or some other method.
|
||||
static struct user users[] = {
|
||||
{"admin", "admin", "admin_token"},
|
||||
{"user1", "pass1", "user1_token"},
|
||||
{"user2", "pass2", "user2_token"},
|
||||
{NULL, NULL, NULL},
|
||||
};
|
||||
char user[256], pass[256];
|
||||
struct user *u;
|
||||
mg_http_creds(hm, user, sizeof(user), pass, sizeof(pass));
|
||||
if (user[0] != '\0' && pass[0] != '\0') {
|
||||
// Both user and password is set, search by user/password
|
||||
for (u = users; u->name != NULL; u++)
|
||||
if (strcmp(user, u->name) == 0 && strcmp(pass, u->pass) == 0) return u;
|
||||
} else if (user[0] == '\0') {
|
||||
// Only password is set, search by token
|
||||
for (u = users; u->name != NULL; u++)
|
||||
if (strcmp(pass, u->token) == 0) return u;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// HTTP request handler function
|
||||
static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||
if (ev == MG_EV_HTTP_MSG) {
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
struct user *u = getuser(hm);
|
||||
// MG_INFO(("[%.*s] auth %s", (int) hm->uri.len, hm->uri.ptr,
|
||||
// u ? u->name : "NULL"));
|
||||
if (u == NULL && mg_http_match_uri(hm, "/api/#")) {
|
||||
// All URIs starting with /api/ must be authenticated
|
||||
mg_printf(c, "%s", "HTTP/1.1 403 Denied\r\nContent-Length: 0\r\n\r\n");
|
||||
} else if (mg_http_match_uri(hm, "/api/user/data")) {
|
||||
// Data visible to both users and administrators
|
||||
mg_printf(c, "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n");
|
||||
mg_http_printf_chunk(c, "{\"data\":\"%s\"}\n", "this is user data");
|
||||
mg_http_printf_chunk(c, "");
|
||||
} else if (mg_http_match_uri(hm, "/api/admin/data")) {
|
||||
// Data visible only to administrators
|
||||
if (strcmp(u->name, "admin") == 0) {
|
||||
mg_printf(c, "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n");
|
||||
mg_http_printf_chunk(c, "{\"data\":\"%s\"}\n", "this is admin data");
|
||||
mg_http_printf_chunk(c, "");
|
||||
} else {
|
||||
mg_printf(c, "%s", "HTTP/1.1 403 Denied\r\nContent-Length: 0\r\n\r\n");
|
||||
}
|
||||
} else if (mg_http_match_uri(hm, "/api/login")) {
|
||||
mg_printf(c, "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n");
|
||||
mg_http_printf_chunk(c, "{\"user\":\"%s\",\"token\":\"%s\"}\n", u->name,
|
||||
u->token);
|
||||
mg_http_printf_chunk(c, "");
|
||||
} else {
|
||||
struct mg_http_serve_opts opts = {.root_dir = "web_root"};
|
||||
mg_http_serve_dir(c, ev_data, &opts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
struct mg_mgr mgr;
|
||||
|
||||
mg_mgr_init(&mgr);
|
||||
mg_http_listen(&mgr, "http://localhost:8000", cb, NULL);
|
||||
|
||||
for (;;) mg_mgr_poll(&mgr, 1000);
|
||||
mg_mgr_free(&mgr);
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,178 +0,0 @@
|
||||
const {h, render, Component} = preact;
|
||||
const html = htm.bind(h);
|
||||
|
||||
class Login extends Component {
|
||||
state = {user: '', pass: ''};
|
||||
onclick = (app) => {
|
||||
const authhdr = 'Basic ' + btoa(this.state.user + ':' + this.state.pass);
|
||||
const headers = {Authorization: authhdr};
|
||||
return axios.get('/api/login', {headers})
|
||||
.then(res => app.setUser(res.data.token))
|
||||
.catch(err => alert('Login failed'));
|
||||
};
|
||||
onpassinput = (ev) => this.setState({pass: ev.target.value});
|
||||
onuserinput = (ev) => this.setState({user: ev.target.value});
|
||||
render({app}, {user, pass, signup}) {
|
||||
return html`
|
||||
<div class='mx-auto bg-light rounded border my-5' style='max-width: 480px;'>
|
||||
<div class='form p-5 rounded form-sm'>
|
||||
<h4 class="text-muted mb-4">Login </h4>
|
||||
<input type='email' placeholder='Email' class='my-2 form-control'
|
||||
oninput=${this.onuserinput} value=${user} />
|
||||
<input type="password" placeholder="Password" class="my-2 form-control"
|
||||
oninput=${this.onpassinput} value=${pass}
|
||||
onchange=${ev => this.onclick(app)} />
|
||||
<div class="mb-4">
|
||||
<button class="btn btn-info btn-block"
|
||||
disabled=${!user || !pass} onclick="${ev => this.onclick(app)}"
|
||||
> Login </button>
|
||||
</div>
|
||||
<div class="text-muted small">
|
||||
Valid logins: admin:admin, user1:pass1, user2:pass2
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
};
|
||||
|
||||
class Dropdown extends Component {
|
||||
state = {show: false};
|
||||
render(props, state) {
|
||||
const onclick = x => this.setState({show: x});
|
||||
const show = state.show ? 'show' : '';
|
||||
return html`
|
||||
<div class="dropdown autoexpand ${props.cls}">
|
||||
<div type="buttonx" onclick=${() => onclick(!state.show)}
|
||||
class="dropdown-toggle my-0 ${props.bcls}"
|
||||
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
${props.title}
|
||||
</div>
|
||||
<div onclick=${() => onclick(false)} style=${props.dstyle}
|
||||
class="dropdown-menu ${props.dcls} ${show}">
|
||||
${props.children}
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
};
|
||||
|
||||
const NavLink = ({href, title, url}) => html`<a class="nav-item nav-link
|
||||
${url == href ? 'active' : ''}"
|
||||
target=${href.match(/^http/) ? '_blank' : ''}
|
||||
href="${href.match(/^http/) ? '' : '#'}${href}">${title}</a>`;
|
||||
|
||||
class Header extends Component {
|
||||
state = {expanded: false};
|
||||
ontoggle = () => this.setState({expanded: !this.state.expanded});
|
||||
render(props, state) {
|
||||
const u = props.app.state.user || {};
|
||||
return html`
|
||||
<nav class="navbar navbar-expand-md navbar-dark bg-dark">
|
||||
<a class="navbar-brand" href="#">
|
||||
<img src="images/logo.png" width="26" height="26" alt="" class="mr-2" />
|
||||
MyProduct
|
||||
</a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation"
|
||||
onclick=${() => this.ontoggle()} >
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="navbar-collapse ${state.expanded ? '' : 'collapse'}"
|
||||
id="navbarNav">
|
||||
<div class="nav navbar-nav mr-auto">
|
||||
<${NavLink} href="/" title="Dashboard" url=${props.url} />
|
||||
<${NavLink} href="/settings" title="Settings" url=${props.url} />
|
||||
</div>
|
||||
</div>
|
||||
<form class="form-inline">
|
||||
<${Dropdown} title="${u.user}" cls="mr-2"
|
||||
bcls="btn btn-sm btn-outline-light pointer" dcls="m-0 dropdown-menu-right">
|
||||
<div onclick=${() => props.app.setUser('')}
|
||||
class="dropdown-item small pointer text-center">logout</div>
|
||||
</${Dropdown}>
|
||||
<img src="images/user.png" class="rounded-circle nav-item mr-2" width="30" />
|
||||
</form>
|
||||
</nav>
|
||||
`
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class AdminDashboard extends Component {
|
||||
state = {udata: '', adata: ''};
|
||||
componentDidMount() {
|
||||
axios.get('/api/user/data').then(r => this.setState({udata: r.data}));
|
||||
axios.get('/api/admin/data').then(r => this.setState({adata: r.data}));
|
||||
}
|
||||
render(props, state) {
|
||||
console.log('-->', state);
|
||||
return html`<div class="container-fluid">
|
||||
this is admin page
|
||||
<div>admin data, returned by server:
|
||||
<code class="mx-2">${JSON.stringify(state.adata)}</code></div>
|
||||
<div>user data, returned by server:
|
||||
<code class="mx-2">${JSON.stringify(state.udata)}</code></div>
|
||||
</div>`
|
||||
}
|
||||
}
|
||||
|
||||
class UserDashboard extends Component {
|
||||
state = {udata: ''};
|
||||
componentDidMount() {
|
||||
axios.get('/api/user/data').then(r => this.setState({udata: r.data}));
|
||||
axios.get('/api/admin/data').then(r => this.setState({adata: r.data}));
|
||||
}
|
||||
render(props, state) {
|
||||
return html`<div class="container-fluid">
|
||||
<div>admin data, returned by server (must be empty and dev tools should show 403):
|
||||
<code class="mx-2">${JSON.stringify(state.adata)}</code></div>
|
||||
<div>user data, returned by server:
|
||||
<code class="mx-2">${JSON.stringify(state.udata)}</code></div>
|
||||
</div>`
|
||||
}
|
||||
}
|
||||
|
||||
class Settings extends Component {
|
||||
state = {};
|
||||
render(props, state) {
|
||||
return html`<div class="container-fluid">settings page</div>`
|
||||
}
|
||||
}
|
||||
|
||||
class App extends Component {
|
||||
state = {user: null, url: '/'};
|
||||
setUser(token) {
|
||||
const maxAge = token ? 86400 : 0;
|
||||
document.cookie = `access_token=${token};path=/;max-age=${maxAge}`;
|
||||
// this.setState({token});
|
||||
return axios.get('/api/login')
|
||||
.then(res => this.setState({user: res.data}))
|
||||
.catch(err => this.setState({user: {}}));
|
||||
}
|
||||
componentDidMount() {
|
||||
const getCookie = name => {
|
||||
var v = document.cookie.match('(^|;) ?' + name + '=([^;]*)(;|$)');
|
||||
return v ? v[2] : '';
|
||||
};
|
||||
this.setUser(getCookie('access_token')); // Move from state1 to 2 or 3
|
||||
}
|
||||
render(props, state) {
|
||||
// We have three states:
|
||||
// 1. Beginning. We don't know if we have a valid auth token or not
|
||||
// 2. We sent an /api/login request, and failed to login
|
||||
// 3. We sent an /api/login request, and succeeded to login
|
||||
|
||||
if (!state.user) return ''; // State 1
|
||||
if (!state.user.user) return h(Login, {app: this}); // State 2
|
||||
return h( // State 3
|
||||
'div', {}, h(Header, {url: state.url, app: this}),
|
||||
h(preactRouter.Router, {
|
||||
history: History.createHashHistory(),
|
||||
onChange: ev => this.setState({url: ev.url}),
|
||||
},
|
||||
h(state.user.user == 'admin' ? AdminDashboard : UserDashboard,
|
||||
{default: true, app: this}),
|
||||
h(Settings, {path: 'settings', app: this})));
|
||||
}
|
||||
};
|
||||
|
||||
window.onload = () => render(h(App), document.body);
|
1
examples/multiple-logins/web_root/htm.min.js
vendored
@ -1 +0,0 @@
|
||||
!function(){function n(n){var t=e.get(this);return t||(t=new Map,e.set(this,t)),1<(t=a(this,t.get(n)||(t.set(n,t=function(n){function t(n){1===u&&(n||(r=r.replace(/^\s*\n\s*|\s*\n\s*$/g,"")))?p.push(0,n,r):3===u&&(n||r)?(p.push(3,n,r),u=2):2===u&&"..."===r&&n?p.push(4,n,0):2===u&&r&&!n?p.push(5,0,!0,r):5<=u&&((r||!n&&5===u)&&(p.push(u,0,r,s),u=6),n&&(p.push(u,n,0,s),u=6)),r=""}for(var e,s,u=1,r="",h="",p=[0],a=0;a<n.length;a++){a&&(1===u&&t(),t(a));for(var o=0;o<n[a].length;o++)e=n[a][o],1===u?"<"===e?(t(),p=[p],u=3):r+=e:4===u?r="--"===r&&">"===e?(u=1,""):e+r[0]:h?e===h?h="":r+=e:'"'===e||"'"===e?h=e:">"===e?(t(),u=1):u&&("="===e?(u=5,s=r,r=""):"/"===e&&(u<5||">"===n[a][o+1])?(t(),3===u&&(p=p[0]),(p=(u=p)[0]).push(2,0,u),u=0):" "===e||"\t"===e||"\n"===e||"\r"===e?(t(),u=2):r+=e),3===u&&"!--"===r&&(u=4,p=p[0])}return t(),p}(n)),t),arguments,[])).length?t:t[0]}var a=function(n,t,e,s){var u;t[0]=0;for(var r=1;r<t.length;r++){var h=t[r++],p=t[r]?(t[0]|=h?1:2,e[t[r++]]):t[++r];3===h?s[0]=p:4===h?s[1]=Object.assign(s[1]||{},p):5===h?(s[1]=s[1]||{})[t[++r]]=p:6===h?s[1][t[++r]]+=p+"":h?(u=n.apply(p,a(n,p,e,["",null])),s.push(u),p[0]?t[0]|=2:(t[r-2]=0,t[r]=u)):s.push(p)}return s},e=new Map;"undefined"!=typeof module?module.exports=n:self.htm=n}();
|
Before Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 3.8 KiB |
@ -1,18 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>example</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="stylesheet" href="bootstrap.min.css" />
|
||||
<link rel="stylesheet" href="style.css" />
|
||||
<script src="preact.min.js"></script>
|
||||
<script src="preact-router.min.js"></script>
|
||||
<script src="htm.min.js"></script>
|
||||
<script src="history.min.js"></script>
|
||||
<script src="axios.min.js"></script>
|
||||
<script src="app.js"></script>
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
@ -1 +0,0 @@
|
||||
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e(require("preact")):"function"==typeof define&&define.amd?define(["preact"],e):t.preactRouter=e(t.preact)}(this,function(p){function i(t,e){for(var n in e)t[n]=e[n];return t}function u(t,e,n){var r,o=/(?:\?([^#]*))?(#.*)?$/,i=t.match(o),u={};if(i&&i[1])for(var a=i[1].split("&"),p=0;p<a.length;p++){var c=a[p].split("=");u[decodeURIComponent(c[0])]=decodeURIComponent(c.slice(1).join("="))}t=y(t.replace(o,"")),e=y(e||"");for(var f=Math.max(t.length,e.length),l=0;l<f;l++)if(e[l]&&":"===e[l].charAt(0)){var s=e[l].replace(/(^:|[+*?]+$)/g,""),h=(e[l].match(/[+*?]+$/)||v)[0]||"",d=~h.indexOf("+"),g=~h.indexOf("*"),m=t[l]||"";if(!m&&!g&&(h.indexOf("?")<0||d)){r=!1;break}if(u[s]=decodeURIComponent(m),d||g){u[s]=t.slice(l).map(decodeURIComponent).join("/");break}}else if(e[l]!==t[l]){r=!1;break}return(!0===n.default||!1!==r)&&u}function e(t,e){return t.rank<e.rank?1:t.rank>e.rank?-1:t.index-e.index}function n(t,e){return t.index=e,t.rank=(n=t).props.default?0:function(t){return y(t).map(r).join("")}(n.props.path),t.props;var n}function y(t){return t.replace(/(^\/+|\/+$)/g,"").split("/")}function r(t){return":"==t.charAt(0)?1+"*+?".indexOf(t.charAt(t.length-1))||4:5}function o(){var t;return""+((t=g&&g.location?g.location:g&&g.getCurrentLocation?g.getCurrentLocation():"undefined"!=typeof location?location:b).pathname||"")+(t.search||"")}function a(t,e){return void 0===e&&(e=!1),"string"!=typeof t&&t.url&&(e=t.replace,t=t.url),function(t){for(var e=m.length;e--;)if(m[e].canRoute(t))return 1;return}(t)&&(n=t,void 0===(r=e?"replace":"push")&&(r="push"),g&&g[r]?g[r](n):"undefined"!=typeof history&&history[r+"State"]&&history[r+"State"](null,null,n)),c(t);var n,r}function c(t){for(var e=!1,n=0;n<m.length;n++)!0===m[n].routeTo(t)&&(e=!0);for(var r=C.length;r--;)C[r](t);return e}function f(t){if(t&&t.getAttribute){var e=t.getAttribute("href"),n=t.getAttribute("target");if(e&&e.match(/^\//g)&&(!n||n.match(/^_?self$/i)))return a(e)}}function l(t){if(!(t.ctrlKey||t.metaKey||t.altKey||t.shiftKey||0!==t.button))return f(t.currentTarget||t.target||this),s(t)}function s(t){return t&&(t.stopImmediatePropagation&&t.stopImmediatePropagation(),t.stopPropagation&&t.stopPropagation(),t.preventDefault()),!1}function h(t){if(!(t.ctrlKey||t.metaKey||t.altKey||t.shiftKey||0!==t.button)){var e=t.target;do{if("A"===(e.nodeName+"").toUpperCase()&&e.getAttribute("href")){if(e.hasAttribute("native"))return;if(f(e))return s(t)}}while(e=e.parentNode)}}var d,v={},g=null,m=[],C=[],b={},U=!1,t=((d=p.Component)&&(k.__proto__=d),((k.prototype=Object.create(d&&d.prototype)).constructor=k).prototype.shouldComponentUpdate=function(t){return!0!==t.static||t.url!==this.props.url||t.onChange!==this.props.onChange},k.prototype.canRoute=function(t){return 0<this.getMatchingChildren(p.toChildArray(this.props.children),t,!1).length},k.prototype.routeTo=function(t){this.setState({url:t});var e=this.canRoute(t);return this.updating||this.forceUpdate(),e},k.prototype.componentWillMount=function(){m.push(this),this.updating=!0},k.prototype.componentDidMount=function(){var e=this;g&&(this.unlisten=g.listen(function(t){e.routeTo(""+(t.pathname||"")+(t.search||""))})),this.updating=!1},k.prototype.componentWillUnmount=function(){"function"==typeof this.unlisten&&this.unlisten(),m.splice(m.indexOf(this),1)},k.prototype.componentWillUpdate=function(){this.updating=!0},k.prototype.componentDidUpdate=function(){this.updating=!1},k.prototype.getMatchingChildren=function(t,r,o){return t.filter(n).sort(e).map(function(t){var e=u(r,t.props.path,t.props);if(e){if(!1===o)return t;var n={url:r,matches:e};return i(n,e),delete n.ref,delete n.key,p.cloneElement(t,n)}}).filter(Boolean)},k.prototype.render=function(t,e){var n=t.children,r=t.onChange,o=e.url,i=this.getMatchingChildren(p.toChildArray(n),o,!0),u=i[0]||null,a=this.previousUrl;return o!==a&&(this.previousUrl=o,"function"==typeof r&&r({router:this,url:o,previous:a,active:i,current:u})),u},k);function k(t){d.call(this,t),t.history&&(g=t.history),this.state={url:t.url||o()},U||("function"==typeof addEventListener&&(g||addEventListener("popstate",function(){c(o())}),addEventListener("click",h)),U=!0)}return t.subscribers=C,t.getCurrentUrl=o,t.route=a,(t.Router=t).Route=function(t){return p.createElement(t.component,t)},t.Link=function(t){return p.createElement("a",i({onClick:l},t))},t.exec=u,t});
|
@ -1,6 +0,0 @@
|
||||
html, body { margin: 0; padding: 0; height: 100%; }
|
||||
select, input, label::before, textarea { outline: none; box-shadow:none !important; border: 1px solid #ccc !important; }
|
||||
.btn:focus,.btn:active:focus,.btn.active:focus,
|
||||
.btn.focus,.btn:active.focus,.btn.active.focus { outline: none; box-shadow:none !important; }
|
||||
.dropdown.autoexpand:hover>.dropdown-menu { display: block; }
|
||||
.pointer { cursor: pointer; }
|