/* * Publishes a message to a topic. * * Args: * - `topic`: topic, string. * - `message`: message, string. * * Only QOS 0 is implemented at the moment. */ enum v7_err MQTT_publish(struct v7 *v7, v7_val_t *res) { enum v7_err rcode = V7_OK; struct user_data *ud; struct mg_connection *nc; const char *topic; const char *message; size_t message_len; v7_val_t topicv = v7_arg(v7, 0), messagev = v7_arg(v7, 1); (void) res; topic = v7_get_cstring(v7, &topicv); if (topic == NULL || strlen(topic) == 0) { rcode = v7_throwf(v7, "TypeError", "invalid topic"); goto clean; } if (!v7_is_string(messagev)) { rcode = v7_throwf(v7, "TypeError", "invalid message"); goto clean; } message = v7_get_string(v7, &messagev, &message_len); nc = v7_get_ptr(v7, v7_get(v7, v7_get_this(v7), "_nc", ~0)); if (nc == NULL) { rcode = v7_throwf(v7, "Error", "invalid connection"); goto clean; } ud = (struct user_data *) nc->user_data; mg_mqtt_publish(nc, topic, ud->msgid++, MG_MQTT_QOS(0), message, message_len); clean: return rcode; }
/* * Usage: * * new UART("platform_specific_name") * */ static enum v7_err UART_ctor(struct v7 *v7, v7_val_t *res) { (void) res; enum v7_err rcode = V7_OK; v7_val_t this_obj = v7_get_this(v7); v7_val_t dev = v7_arg(v7, 0); struct user_data *ud; void *uart; const char *name; size_t len; if (!v7_is_string(dev)) { rcode = v7_throwf(v7, "Error", "device must be string"); goto clean; } ud = (struct user_data *) calloc(1, sizeof(struct user_data)); ud->v7 = v7; ud->want = 0; ud->cb = V7_UNDEFINED; v7_own(v7, &ud->cb); name = v7_get_string(v7, &dev, &len); uart = sj_hal_open_uart(name, (void *) ud); if (uart == NULL) { rcode = v7_throwf(v7, "Error", "cannot open uart"); goto clean; } v7_def(v7, this_obj, "_ud", ~0, _V7_DESC_HIDDEN(1), v7_mk_foreign(v7, ud)); v7_def(v7, this_obj, "_dev", ~0, _V7_DESC_HIDDEN(1), v7_mk_foreign(v7, uart)); clean: return rcode; }
SJ_PRIVATE enum v7_err sj_Wifi_setup(struct v7 *v7, v7_val_t *res) { enum v7_err rcode = V7_OK; v7_val_t ssidv = v7_arg(v7, 0); v7_val_t passv = v7_arg(v7, 1); v7_val_t extrasv = v7_arg(v7, 2); const char *ssid, *pass; size_t ssid_len, pass_len; int permanent = 1, ret = 0; if (!v7_is_string(ssidv) || !v7_is_string(passv)) { printf("ssid/pass are not strings\n"); *res = V7_UNDEFINED; goto clean; } if (v7_is_object(extrasv)) { permanent = v7_is_truthy(v7, v7_get(v7, extrasv, "permanent", ~0)); } ssid = v7_get_string(v7, &ssidv, &ssid_len); pass = v7_get_string(v7, &passv, &pass_len); struct sys_config_wifi_sta cfg; memset(&cfg, 0, sizeof(cfg)); cfg.ssid = (char *) ssid; cfg.pass = (char *) pass; LOG(LL_INFO, ("WiFi: connecting to '%s'", ssid)); ret = sj_wifi_setup_sta(&cfg); if (ret && permanent) { struct sys_config *cfg = get_cfg(); cfg->wifi.sta.enable = 1; sj_conf_set_str(&cfg->wifi.sta.ssid, ssid); sj_conf_set_str(&cfg->wifi.sta.pass, pass); } *res = v7_mk_boolean(v7, ret); goto clean; clean: return rcode; }
static enum v7_err UART_write(struct v7 *v7, v7_val_t *res) { v7_val_t this_obj = v7_get_this(v7); v7_val_t dev = v7_get(v7, this_obj, "_dev", ~0), data = v7_arg(v7, 0); size_t len; const char *d = v7_get_string(v7, &data, &len); (void) v7; (void) this_obj; sj_hal_write_uart(v7_get_ptr(v7, dev), d, len); *res = v7_mk_boolean(v7, 1); return V7_OK; }
static enum v7_err UART_send(struct v7 *v7, v7_val_t *res) { struct esp_sj_uart_state *us; enum v7_err ret = esp_sj_uart_get_state(v7, &us); if (ret != V7_OK) return ret; v7_val_t arg0 = v7_arg(v7, 0); if (!v7_is_string(arg0)) { return v7_throwf(v7, "Error", "String arg required"); } size_t len = 0; const char *data = v7_get_string(v7, &arg0, &len); if (data != NULL && len > 0) { cs_rbuf_t *txb = esp_uart_tx_buf(us->uart_no); len = MIN(len, txb->avail); cs_rbuf_append(txb, (uint8_t *) data, len); esp_sj_uart_schedule_dispatcher(us->uart_no); } *res = v7_mk_number(v7, len); return V7_OK; }
/* * Alternative implementation of JSON.parse(), needed when v7 parser is * disabled */ enum v7_err v7_alt_json_parse(struct v7 *v7, v7_val_t json_string, v7_val_t *res) { struct json_parse_ctx *ctx = (struct json_parse_ctx *) calloc(sizeof(struct json_parse_ctx), 1); size_t len; const char *str = v7_get_string(v7, &json_string, &len); int json_res; enum v7_err rcode = V7_OK; ctx->v7 = v7; ctx->result = V7_UNDEFINED; ctx->frame = NULL; v7_own(v7, &ctx->result); json_res = json_walk(str, len, frozen_cb, ctx); if (json_res >= 0) { /* Expression is parsed successfully */ *res = ctx->result; /* There should be no allocated frames */ assert(ctx->frame == NULL); } else { /* There was an error during parsing */ rcode = v7_throwf(v7, "SyntaxError", "Invalid JSON string"); /* There might be some allocated frames in case of malformed JSON */ while (ctx->frame != NULL) { ctx->frame = free_json_frame(ctx, ctx->frame); } } v7_disown(v7, &ctx->result); free(ctx); return rcode; }
int v7_example(void) { size_t n; const char *domain_str; struct v7 *v7 = v7_create(); v7_val_t domain, port0, config; /* Load JSON configuration */ if (v7_parse_json_file(v7, "config.json", &config) != V7_OK) { printf("%s\n", "Cannot load JSON config"); return 1; } /* Lookup values in JSON configuration object */ domain = v7_get(v7, config, "domain", 6); port0 = v7_array_get(v7, v7_get(v7, config, "ports", 5), 0); domain_str = v7_get_string(v7, &domain, &n); printf("Domain: [%.*s], port 0: [%d]\n", (int) n, domain_str, (int) v7_get_double(port0)); v7_destroy(v7); return 0; }
MG_PRIVATE enum v7_err Console_log(struct v7 *v7, v7_val_t *res) { int argc = v7_argc(v7); /* Put everything into one message */ for (int i = 0; i < argc; i++) { v7_val_t arg = v7_arg(v7, i); if (v7_is_string(arg)) { size_t len; const char *str = v7_get_string(v7, &arg, &len); miot_console_puts_n(str, len); } else { char buf[100], *p; p = v7_stringify(v7, arg, buf, sizeof(buf), V7_STRINGIFY_DEBUG); miot_console_puts_n(p, strlen(p)); if (p != buf) free(p); } if (i != argc - 1) { miot_console_putc(' '); } } miot_console_putc('\n'); *res = V7_UNDEFINED; /* like JS print */ return V7_OK; }
/* * Make a new MQTT client. * * Arguments: * url: url where to connect to * opts: option object * * Recognized option object properties: * * - clientId: string; mqtt client id. defaults to * Math.random().toString(16).substr(2, 10) * * Example: * * var client = MQTT.connect('mqtt://test.mosquitto.org'); * * client.on('connect', function () { * client.subscribe('presence'); * client.publish('presence', 'Hello mqtt'); * }); * * client.on('message', function (topic, message) { * console.log(message); * }); * * TLS can be enabled by choosing the `mqtts://` protocol. In that * case the default port is 8883 as defined by IANA. * * The API is modeled after https://www.npmjs.com/package/mqtt. * */ enum v7_err sj_mqtt_connect(struct v7 *v7, v7_val_t *res) { enum v7_err rcode = V7_OK; const char *url; size_t len; struct mg_str host, scheme; unsigned int port; struct mg_connection *nc; struct user_data *ud; char *url_with_port = NULL; int use_ssl = 0; v7_val_t urlv = v7_arg(v7, 0), opts = v7_arg(v7, 1); v7_val_t client_id; v7_val_t proto = v7_get(v7, v7_get(v7, v7_get_global(v7), "MQTT", ~0), "proto", ~0); if (!v7_is_string(urlv)) { rcode = v7_throwf(v7, "Error", "invalid url string"); goto clean; } url = v7_get_string(v7, &urlv, &len); if (mg_parse_uri(mg_mk_str(url), &scheme, NULL, &host, &port, NULL, NULL, NULL) < 0) { rcode = v7_throwf(v7, "Error", "invalid url string"); goto clean; } if (mg_vcmp(&scheme, "mqtt") == 0) { url += sizeof("mqtt://") - 1; } else if (mg_vcmp(&scheme, "mqtts") == 0) { url += sizeof("mqtts://") - 1; use_ssl = 1; } else { rcode = v7_throwf(v7, "Error", "unsupported protocol"); goto clean; } client_id = v7_get(v7, opts, "clientId", ~0); if (v7_is_undefined(client_id)) { rcode = v7_exec(v7, "Math.random().toString(16).substr(2,8)", &client_id); if (rcode != V7_OK) { goto clean; } } if (port == 0) { if (asprintf(&url_with_port, "%.*s%s", (int) host.len, host.p, (use_ssl ? ":8883" : ":1883")) < 0) { rcode = v7_throwf(v7, "Error", "Out of memory"); goto clean; } } nc = mg_connect(&sj_mgr, url_with_port ? url_with_port : url, mqtt_ev_handler); if (nc == NULL) { rcode = v7_throwf(v7, "Error", "cannot create connection"); goto clean; } if (use_ssl) { #ifdef MG_ENABLE_SSL mg_set_ssl(nc, NULL, NULL); #else rcode = v7_throwf(v7, "Error", "SSL not enabled"); goto clean; #endif } mg_set_protocol_mqtt(nc); *res = v7_mk_object(v7); v7_set_proto(v7, *res, proto); ud = calloc(1, sizeof(*ud)); if (ud == NULL) { rcode = v7_throwf(v7, "Error", "Out of memory"); goto clean; } ud->v7 = v7; ud->client = *res; ud->client_id = strdup(v7_get_cstring(v7, &client_id)); if (ud->client_id == NULL) { free(ud); rcode = v7_throwf(v7, "Error", "Out of memory"); goto clean; } nc->user_data = ud; v7_own(v7, &ud->client); v7_def(v7, *res, "_nc", ~0, _V7_DESC_HIDDEN(1), v7_mk_foreign(v7, nc)); clean: free(url_with_port); return rcode; }