mirror of
https://github.com/cesanta/mongoose.git
synced 2026-10-30 12:50:58 +00:00
191 lines
7.2 KiB
C
191 lines
7.2 KiB
C
#include "mdash.h"
|
|
|
|
#if MG_ENABLE_MDASH
|
|
|
|
#include "base64.h"
|
|
#include "health.h"
|
|
#include "log.h"
|
|
#include "ota.h"
|
|
#include "printf.h"
|
|
#include "rpc.h"
|
|
#include "sntp.h"
|
|
#include "tls.h"
|
|
#include "url.h"
|
|
#include "ws.h"
|
|
|
|
static const char *mg_mdash_ca_pem =
|
|
"-----BEGIN CERTIFICATE-----\n"
|
|
"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\n"
|
|
"-----END CERTIFICATE-----\n";
|
|
|
|
static struct mg_connection *mg_mdash_conn = NULL;
|
|
// static struct mg_str mg_mdash_key;
|
|
// static void mg_connection *mg_mdash_conn = NULL;
|
|
|
|
static void mg_mdash_fn(struct mg_connection *c, int ev, void *ev_data) {
|
|
if (ev == MG_EV_CONNECT) {
|
|
// c->is_hexdumping = true;
|
|
if (mg_url_is_ssl(MG_MDASH_URL)) {
|
|
struct mg_str host = mg_url_host(MG_MDASH_URL);
|
|
struct mg_tls_opts opts;
|
|
memset(&opts, 0, sizeof(struct mg_tls_opts));
|
|
opts.ca = mg_str(mg_mdash_ca_pem);
|
|
opts.name = host;
|
|
mg_tls_init(c, &opts);
|
|
}
|
|
}
|
|
if (ev == MG_EV_WS_OPEN) {
|
|
MG_INFO(("Connected to %s", MG_MDASH_URL));
|
|
// s_mDashState = MDASH_STATE_CLOUD_CONNECTED;
|
|
// mDashTriggerEvent(s_mDashState, NULL);
|
|
} else if (ev == MG_EV_WS_MSG) {
|
|
struct mg_iobuf io = {0, 0, 0, 512};
|
|
struct mg_ws_message *wm = (struct mg_ws_message *) ev_data;
|
|
struct mg_str s = wm->data;
|
|
struct mg_rpc_req r;
|
|
while (s.len > 0 && isspace((uint8_t) s.buf[s.len - 1])) s.len--;
|
|
MG_INFO(("RPC: %.*s", (int) s.len, s.buf));
|
|
memset(&r, 0, sizeof(struct mg_rpc_req));
|
|
r.head = &c->mgr->rpcs;
|
|
r.rpc = NULL;
|
|
r.pfn = mg_pfn_iobuf;
|
|
r.pfn_data = &io;
|
|
r.req_data = NULL;
|
|
r.frame = s;
|
|
mg_rpc_process(&r);
|
|
if (io.buf != NULL) {
|
|
MG_INFO((" %s", io.buf));
|
|
mg_ws_send(c, (const char *) io.buf, io.len, WEBSOCKET_OP_TEXT);
|
|
} else {
|
|
MG_DEBUG(("%s", "RPC unhandled"));
|
|
}
|
|
mg_iobuf_free(&io);
|
|
} else if (ev == MG_EV_CLOSE) {
|
|
mg_mdash_conn = NULL;
|
|
MG_INFO(("disconnected, ram %lu", 0));
|
|
}
|
|
(void) c;
|
|
}
|
|
|
|
static void mg_mdash_rpc_get_info(struct mg_rpc_req *r) {
|
|
const char *reset_reason = mg_health_reason_str(mg_health_reason());
|
|
mg_rpc_ok(r, "{%m:%m,%m:%llu,%m:%m,%m:\"mws.%d\",%m:%M}", //
|
|
MG_ESC("fw_version"), MG_ESC(MG_FIRMWARE_VERSION), //
|
|
MG_ESC("uptime"), (uint64_t) (mg_millis() / 1000), //
|
|
MG_ESC("reboot_reason"), MG_ESC(reset_reason), //
|
|
MG_ESC("arch"), MG_ARCH, //
|
|
MG_ESC("crash"), mg_print_crash_record);
|
|
}
|
|
|
|
static void mg_mdash_rpc_ota_begin(struct mg_rpc_req *r) {
|
|
size_t total = (size_t) mg_json_get_long(r->frame, "$.params.size", -1);
|
|
if (mg_ota_begin(total)) {
|
|
mg_rpc_ok(r, "true");
|
|
} else {
|
|
mg_rpc_err(r, 500, "%m", MG_ESC("failed"));
|
|
}
|
|
}
|
|
|
|
static void mg_mdash_rpc_ota_write(struct mg_rpc_req *r) {
|
|
int len = 0, ofs = 0;
|
|
if ((ofs = mg_json_get(r->frame, "$.params.data", &len)) <= 0 ||
|
|
r->frame.buf[ofs] != '"') {
|
|
mg_rpc_err(r, 500, "%m", MG_ESC("data required"));
|
|
} else {
|
|
struct mg_str s = mg_str_n(&r->frame.buf[ofs] + 1, (size_t) (len - 2));
|
|
size_t n = mg_base64_decode(s.buf, s.len, s.buf, s.len); // Decode in-place
|
|
if (n == 0) {
|
|
mg_rpc_ok(r, "%m", MG_ESC("finished"));
|
|
mg_ota_end();
|
|
} else if (mg_ota_write(s.buf, n)) {
|
|
mg_rpc_ok(r, "{%m:%d}", MG_ESC("queued"), n);
|
|
} else {
|
|
mg_rpc_err(r, 500, "%m", MG_ESC("write failed"));
|
|
mg_ota_end();
|
|
}
|
|
// mDashNotify("State.Set", "{%m:{%m:%d}}", MG_ESC("ota"),
|
|
// MG_ESC("percent"), (int) (s_ota_written * 100 / s_ota_size));
|
|
}
|
|
}
|
|
|
|
static void mg_mdash_rpc_ota_end(struct mg_rpc_req *r) {
|
|
if (mg_ota_end()) {
|
|
mg_rpc_ok(r, "true");
|
|
} else {
|
|
mg_rpc_err(r, 500, "%m", MG_ESC("failed"));
|
|
}
|
|
// mDashNotify("State.Set", "{%m:{%m:null}}", MG_ESC("ota"),
|
|
// MG_ESC("percent"));
|
|
}
|
|
|
|
void mg_mdash_init(struct mg_mgr *mgr) {
|
|
MG_INFO(("Initialising mdash agent, key [%s]", MG_MDASH_KEY));
|
|
mg_rpc_add(&mgr->rpcs, mg_str("RPC.List"), mg_rpc_list, NULL);
|
|
mg_rpc_add(&mgr->rpcs, mg_str("Sys.GetInfo"), mg_mdash_rpc_get_info, NULL);
|
|
mg_rpc_add(&mgr->rpcs, mg_str("OTA.Begin"), mg_mdash_rpc_ota_begin, NULL);
|
|
mg_rpc_add(&mgr->rpcs, mg_str("OTA.Write"), mg_mdash_rpc_ota_write, NULL);
|
|
mg_rpc_add(&mgr->rpcs, mg_str("OTA.End"), mg_mdash_rpc_ota_end, NULL);
|
|
}
|
|
|
|
void mg_mdash_poll(struct mg_mgr *mgr) {
|
|
#if MG_TLS == MG_TLS_NONE
|
|
(void) mgr, (void) mg_mdash_fn; // mdash needs wss://, nothing to do
|
|
#else
|
|
static uint64_t timer = 0;
|
|
// No RPC handlers means mdash was never set up, or mg_mdash_free() ran.
|
|
// No key means mdash would reject us, so do not connect at all
|
|
if (mg_mdash_conn == NULL && mgr->rpcs != NULL && MG_MDASH_KEY[0] != '\0' &&
|
|
mg_timer_expired(&timer, 1000, mg_millis())) {
|
|
MG_INFO(("Connecting to %s", MG_MDASH_URL));
|
|
mg_mdash_conn = mg_ws_connect(mgr, MG_MDASH_URL, mg_mdash_fn, NULL,
|
|
"Origin: %s\r\n"
|
|
"Authorization: Bearer %s\r\n",
|
|
MG_MDASH_URL, MG_MDASH_KEY);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void mg_mdash_free(struct mg_mgr *mgr) {
|
|
mg_rpc_del(&mgr->rpcs, NULL);
|
|
}
|
|
|
|
#else
|
|
void mg_mdash_init(struct mg_mgr *mgr) {
|
|
(void) mgr;
|
|
}
|
|
void mg_mdash_poll(struct mg_mgr *mgr) {
|
|
(void) mgr;
|
|
}
|
|
void mg_mdash_free(struct mg_mgr *mgr) {
|
|
(void) mgr;
|
|
}
|
|
#endif
|