83 lines
2.8 KiB
C

// 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;
}