static void invoke_cb(struct user_data *ud, const char *name, v7_val_t ev) { struct v7 *v7 = ud->v7; v7_val_t met = v7_get(v7, ud->ws, name, ~0); if (!v7_is_undefined(met)) { sj_invoke_cb1(v7, met, ev); } }
static enum v7_err jsBotSay(struct v7 *v7, v7_val_t *res) { long argc = v7_argc(v7); if (argc == 0) { return V7_OK; } v7_val_t v = v7_arg(v7, 0); if (!v7_is_string(v)) { return V7_OK; } TString str = (const char*)v7_to_cstring(v7, &v); TString font; if (argc >= 2) { v7_val_t fontt = v7_arg(v7, 1); if (!v7_is_null(fontt) && !v7_is_undefined(fontt)) font = (const char*)v7_to_cstring(v7, &fontt); } int size = 0; if (argc >= 3) { v7_val_t sizee = v7_arg(v7, 2); if (v7_is_number(sizee)) size = floor(v7_to_number(sizee)); if (size < 10) size = 10; } TString col; if (argc >= 4) { v7_val_t coll = v7_arg(v7, 3); if (v7_is_string(coll)) col = (const char*)v7_to_cstring(v7, &coll); if (col.GetAt(0) != L'#' || col.GetLength() != 7) col = L""; } _activeBot->say(str, font, size, col); return V7_OK; }
void sj_print_exception(struct v7 *v7, v7_val_t exc, const char *msg) { /* * TOD(mkm) add some API to hal to fetch the current debug mode * and avoid logging to stdout if according no error messages should go * there (e.g. because it's used to implement a serial protocol). */ FILE *fs[] = {stdout, stderr}; size_t i; v7_val_t msg_v = V7_UNDEFINED; /* * own because the exception could be a string, * and if not owned here, print_stack_trace could get * an unrelocated argument an ASN violation. */ v7_own(v7, &exc); v7_own(v7, &msg_v); msg_v = v7_get(v7, exc, "message", ~0); for (i = 0; i < sizeof(fs) / sizeof(fs[0]); i++) { fprintf(fs[i], "%s: ", msg); if (!v7_is_undefined(msg_v)) { v7_fprintln(fs[i], v7, msg_v); } else { v7_fprintln(fs[i], v7, exc); } v7_fprint_stack_trace(fs[i], v7, exc); } v7_disown(v7, &msg_v); v7_disown(v7, &exc); }
static v7_val_t WebSocket_readyState(struct v7 *v7, v7_val_t this_obj, v7_val_t args) { v7_val_t ncv = v7_get(v7, this_obj, "_nc", ~0); if (v7_is_undefined(ncv)) { return WEBSOCKET_CLOSED; } else { return WEBSOCKET_OPEN; } }
static void Http_write_data(struct v7 *v7, struct mg_connection *c) { v7_val_t arg0 = v7_arg(v7, 0); if (!v7_is_undefined(arg0)) { char buf[50], *p = buf; p = v7_stringify(v7, arg0, buf, sizeof(buf), 0); mg_send_http_chunk(c, p, strlen(p)); if (p != buf) { free(p); } } }
static void invoke_cb(struct user_data *ud, const char *name, v7_val_t ev) { struct v7 *v7 = ud->v7; v7_val_t met = v7_get(v7, ud->ws, name, ~0); if (!v7_is_undefined(met)) { v7_val_t res, args = v7_create_array(v7); v7_array_set(v7, args, 0, ev); if (v7_apply(v7, &res, met, v7_create_undefined(), args) != V7_OK) { /* TODO(mkm): make it print stack trace */ fprintf(stderr, "cb threw an exception\n"); } } }
enum v7_err fill_ssl_connect_opts(struct v7 *v7, v7_val_t opts, int force_ssl, struct mg_connect_opts *copts) { enum v7_err rcode = V7_OK; v7_val_t v_use_ssl = v7_get(v7, opts, "use_ssl", ~0); v7_val_t v_ca_cert = v7_get(v7, opts, "ssl_ca_cert", ~0); v7_val_t v_cert = v7_get(v7, opts, "ssl_cert", ~0); v7_val_t v_server_name = v7_get(v7, opts, "ssl_server_name", ~0); if (!v7_is_undefined(v_ca_cert) && !v7_is_string(v_ca_cert)) { rcode = v7_throwf(v7, "TypeError", "ssl_ca_cert must be a string"); goto clean; } if (!v7_is_undefined(v_cert) && !v7_is_string(v_cert)) { rcode = v7_throwf(v7, "TypeError", "ssl_cert must be a string"); goto clean; } if (!v7_is_undefined(v_server_name) && !v7_is_string(v_server_name)) { rcode = v7_throwf(v7, "TypeError", "ssl_server_name must be a string"); goto clean; } copts->ssl_ca_cert = v7_get_cstring(v7, &v_ca_cert); copts->ssl_cert = v7_get_cstring(v7, &v_cert); copts->ssl_server_name = v7_get_cstring(v7, &v_server_name); if ((force_ssl || (v7_is_boolean(v_use_ssl) && v7_get_bool(v7, v_use_ssl) != 0)) && copts->ssl_ca_cert == NULL) { /* Defaults to configuration */ copts->ssl_ca_cert = get_cfg()->tls.ca_file; } clean: return rcode; }
size_t sj_uart_recv_cb(void *ctx, const char *d, size_t len) { struct user_data *ud = (struct user_data *) ctx; v7_val_t s, cb = ud->cb; size_t want = ud->want; if (len < want || v7_is_undefined(ud->cb)) return 0; ud->cb = v7_create_undefined(); ud->want = 0; s = v7_create_string(ud->v7, d, want, 1); sj_invoke_cb1(ud->v7, cb, s); return want; }
/* JS signature: listen(addr, [options]) */ SJ_PRIVATE enum v7_err Http_Server_listen(struct v7 *v7, v7_val_t *res) { enum v7_err rcode = V7_OK; char buf[50], *p = buf; const char *ca_cert = NULL, *cert = NULL; v7_val_t this_obj = v7_get_this(v7); v7_val_t arg0 = v7_arg(v7, 0); v7_val_t opts = v7_arg(v7, 1); if (!v7_is_number(arg0) && !v7_is_string(arg0)) { rcode = v7_throwf(v7, "TypeError", "Function expected"); goto clean; } if (!v7_is_undefined(opts) && !v7_is_object(opts)) { rcode = v7_throwf(v7, "TypeError", "Options must be an object"); goto clean; } if (!v7_is_undefined(opts)) { v7_val_t ca_cert_v = v7_get(v7, opts, "ssl_ca_cert", ~0); v7_val_t cert_v = v7_get(v7, opts, "ssl_cert", ~0); if (!v7_is_undefined(ca_cert_v) && !v7_is_string(ca_cert_v)) { rcode = v7_throwf(v7, "TypeError", "ca_cert must be a string"); goto clean; } if (!v7_is_undefined(cert_v) && !v7_is_string(cert_v)) { rcode = v7_throwf(v7, "TypeError", "cert must be a string"); goto clean; } if (!v7_is_undefined(ca_cert_v)) { ca_cert = v7_to_cstring(v7, &ca_cert_v); } if (!v7_is_undefined(cert_v)) { cert = v7_to_cstring(v7, &cert_v); } } p = v7_stringify(v7, arg0, buf, sizeof(buf), 0); rcode = start_http_server(v7, p, this_obj, ca_cert, cert); if (rcode != V7_OK) { goto clean; } *res = this_obj; clean: if (p != buf) { free(p); } return rcode; }
static int notify_js(enum js_update_status us, const char *info) { #ifndef CS_DISABLE_JS if (!v7_is_undefined(s_updater_notify_cb)) { if (info == NULL) { sj_invoke_cb1(s_v7, s_updater_notify_cb, v7_mk_number(s_v7, us)); } else { sj_invoke_cb2(s_v7, s_updater_notify_cb, v7_mk_number(s_v7, us), v7_mk_string(s_v7, info, ~0, 1)); }; return 1; } #else (void) us; (void) info; #endif return 0; }
int update_sysconf(struct v7 *v7, const char *path, v7_val_t val) { v7_val_t sys = v7_get(v7, v7_get_global(v7), "Sys", ~0); if (!v7_is_object(sys)) { return 1; } v7_val_t conf = v7_get(v7, sys, "conf", ~0); if (!v7_is_object(conf)) { return 1; } v7_val_t prev_obj, curr_obj; prev_obj = curr_obj = conf; const char *prev_tok, *curr_tok; prev_tok = curr_tok = path; for (;;) { while (*curr_tok != 0 && *curr_tok != '.') { curr_tok++; } curr_obj = v7_get(v7, prev_obj, prev_tok, (curr_tok - prev_tok)); if (v7_is_undefined(curr_obj)) { return 1; } else if (!v7_is_object(curr_obj)) { v7_set(v7, prev_obj, prev_tok, (curr_tok - prev_tok), val); return 0; } if (*curr_tok == 0) { return 1; } curr_tok++; prev_tok = curr_tok; prev_obj = curr_obj; } return 1; }
static void _WebSocket_send_blob(struct v7 *v7, struct mg_connection *nc, v7_val_t blob) { const char *data; size_t len; unsigned long alen, i; v7_val_t chunks, chunk; chunks = v7_get(v7, blob, "a", ~0); alen = v7_array_length(v7, chunks); for (i = 0; i < alen; i++) { int op = i == 0 ? WEBSOCKET_OP_BINARY : WEBSOCKET_OP_CONTINUE; int flag = i == alen - 1 ? 0 : WEBSOCKET_DONT_FIN; chunk = v7_array_get(v7, chunks, i); /* * This hack allows us to skip the first or the last frame * while sending blobs. The effect of it is that it's possible to * concatenate more blobs into a single WS message composed of * several fragments. * * WebSocket.send(new Blob(["123", undefined])); * WebSocket.send(new Blob([undefined, "456"])); * * If the last blob component is undefined, the current message is thus * left open. In order to continue sending fragments of the same message * the next send call should have it's first component undefined. * * TODO(mkm): find a better API. */ if (!v7_is_undefined(chunk)) { data = v7_to_string(v7, &chunk, &len); mg_send_websocket_frame(nc, op | flag, data, len); } } }
/* * Create request object, used by `Http.request()` and `Http.get()` */ WARN_UNUSED_RESULT static enum v7_err sj_http_request_common(struct v7 *v7, v7_val_t opts, v7_val_t cb, v7_val_t *res) { enum v7_err rcode = V7_OK; char addr[200]; struct mg_connection *c; struct user_data *ud; struct mg_connect_opts copts; #ifdef MG_ENABLE_SSL int force_ssl; #endif memset(&copts, 0, sizeof(copts)); /* * Determine type of provided `opts`, and if it's a string, then parse * it to object */ if (v7_is_string(opts)) { rcode = sj_url_parse(v7, opts, &opts); if (rcode != V7_OK) { goto clean; } } else if (!v7_is_object(opts)) { rcode = v7_throwf(v7, "Error", "opts must be an object or a string URL"); goto clean; } /* * Now, `opts` is guaranteed to be an object. * Let's retrieve needed properties */ v7_val_t v_h = v7_get(v7, opts, "hostname", ~0); if (v7_is_undefined(v_h)) { v_h = v7_get(v7, opts, "host", ~0); } v7_val_t v_p = v7_get(v7, opts, "port", ~0); v7_val_t v_uri = v7_get(v7, opts, "path", ~0); v7_val_t v_m = v7_get(v7, opts, "method", ~0); v7_val_t v_hdrs = v7_get(v7, opts, "headers", ~0); /* Perform options validation and set defaults if needed */ int port = v7_is_number(v_p) ? v7_to_number(v_p) : 80; const char *host = v7_is_string(v_h) ? v7_to_cstring(v7, &v_h) : ""; const char *uri = v7_is_string(v_uri) ? v7_to_cstring(v7, &v_uri) : "/"; const char *method = v7_is_string(v_m) ? v7_to_cstring(v7, &v_m) : "GET"; #ifdef MG_ENABLE_SSL v7_val_t v_pr = v7_get(v7, opts, "protocol", ~0); const char *protocol = v7_is_string(v_pr) ? v7_to_cstring(v7, &v_pr) : ""; force_ssl = (strcasecmp(protocol, "https") == 0); if ((rcode = fill_ssl_connect_opts(v7, opts, force_ssl, &copts)) != V7_OK) { goto clean; } #endif /* Compose address like host:port */ snprintf(addr, sizeof(addr), "%s:%d", host, port); /* * Try to connect, passing `http_ev_handler` as the callback, which will * call provided JavaScript function (we'll set it in user data below). * TODO(alashkin): change mg_connect_opt to mg_connect_http_opt */ if ((c = mg_connect_opt(&sj_mgr, addr, http_ev_handler, copts)) == NULL) { rcode = v7_throwf(v7, "Error", "Cannot connect"); goto clean; } /* * Attach mongoose's built-in HTTP event handler to the connection, and send * necessary headers */ mg_set_protocol_http_websocket(c); mg_printf(c, "%s %s HTTP/1.1\r\n", method, uri); mg_printf(c, "Host: %s\r\n", host); http_write_headers(v7, v_hdrs, c); http_write_chunked_encoding_header(c); mg_printf(c, "%s", "\r\n"); /* * Allocate and initialize user data structure that is used by the JS HTTP * interface. Create the request object (which will have the request * prototype `sj_http_request_proto`), and set provided callback function. */ c->user_data = ud = (struct user_data *) calloc(1, sizeof(*ud)); ud->v7 = v7; ud->obj = v7_mk_object(v7); ud->handler = cb; v7_own(v7, &ud->obj); v7_set_proto(v7, ud->obj, sj_http_request_proto); /* internal property: mongoose connection */ v7_set(v7, ud->obj, "_c", ~0, v7_mk_foreign(c)); /* internal property: callback function that was passed as an argument */ v7_set(v7, ud->obj, "_cb", ~0, ud->handler); *res = ud->obj; clean: return rcode; }
static void mqtt_ev_handler(struct mg_connection *nc, int ev, void *ev_data) { struct mg_mqtt_message *msg = (struct mg_mqtt_message *) ev_data; struct user_data *ud = (struct user_data *) nc->user_data; struct v7 *v7 = ud->v7; v7_val_t cb; (void) nc; (void) ev_data; switch (ev) { case MG_EV_CONNECT: if (*(int *) ev_data == 0) { mg_send_mqtt_handshake(nc, ud->client_id); } else { cb = v7_get(v7, ud->client, SJ_MQTT_ERROR_CB, ~0); if (!v7_is_undefined(cb)) { sj_invoke_cb0(v7, cb); } } break; case MG_EV_MQTT_CONNACK: { /* * Call connect or error cb if they were registered. */ const char *key; if (msg->connack_ret_code == MG_EV_MQTT_CONNACK_ACCEPTED) { key = SJ_MQTT_CONNECT_CB; } else { key = SJ_MQTT_ERROR_CB; } cb = v7_get(v7, ud->client, key, ~0); if (!v7_is_undefined(cb)) { sj_invoke_cb0(v7, cb); } break; } case MG_EV_MQTT_PUBLISH: cb = v7_get(v7, ud->client, SJ_MQTT_MESSAGE_CB, ~0); if (!v7_is_undefined(cb)) { v7_val_t topic = v7_mk_string(v7, msg->topic, strlen(msg->topic), 1); v7_val_t payload = v7_mk_string(v7, msg->payload.p, msg->payload.len, 1); sj_invoke_cb2(v7, cb, topic, payload); } break; case MG_EV_CLOSE: /* * Invoke close cb and then destroys all mg state. */ cb = v7_get(v7, ud->client, SJ_MQTT_CLOSE_CB, ~0); if (!v7_is_undefined(cb)) { sj_invoke_cb0(v7, cb); } v7_def(v7, ud->client, "_nc", ~0, _V7_DESC_HIDDEN(1), V7_UNDEFINED); v7_disown(v7, &ud->client); free(ud->client_id); free(ud); break; } }
/* * 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; }
/* * SmartJS initialization, called as an SDK timer callback (`os_timer_...()`). */ void sjs_init(void *dummy) { /* * In order to see debug output (at least errors) during boot we have to * initialize debug in this point. But default we put debug to UART0 with * level=LL_ERROR, then configuration is loaded this settings are overridden */ { struct esp_uart_config *u0cfg = esp_sj_uart_default_config(0); #if ESP_DEBUG_UART == 0 u0cfg->baud_rate = ESP_DEBUG_UART_BAUD_RATE; #endif esp_uart_init(u0cfg); struct esp_uart_config *u1cfg = esp_sj_uart_default_config(1); /* UART1 has no RX pin, no point in allocating a buffer. */ u1cfg->rx_buf_size = 0; #if ESP_DEBUG_UART == 1 u1cfg->baud_rate = ESP_DEBUG_UART_BAUD_RATE; #endif esp_uart_init(u1cfg); fs_set_stdout_uart(0); fs_set_stderr_uart(ESP_DEBUG_UART); setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); cs_log_set_level(LL_DEBUG); os_install_putc1(dbg_putc); system_set_os_print(1); #ifdef ESP_ENABLE_HEAP_LOG uart_initialized = 1; #endif } init_v7(&dummy); /* disable GC during further initialization */ v7_set_gc_enabled(v7, 0); esp_sj_uart_init(v7); #ifndef V7_NO_FS #ifndef DISABLE_OTA fs_init(get_fs_addr(get_current_rom()), get_fs_size(get_current_rom())); finish_update(); #else fs_init(FS_ADDR, FS_SIZE); #endif #endif sj_common_api_setup(v7); sj_common_init(v7); sj_init_sys(v7); mongoose_init(); /* NOTE(lsm): must be done after mongoose_init(). */ if (!init_device(v7)) { LOG(LL_ERROR, ("init_device failed")); abort(); } esp_print_reset_info(); #ifndef DISABLE_OTA init_updater(v7); #endif LOG(LL_INFO, ("Sys init done, SDK %s", system_get_sdk_version())); if (!sj_app_init(v7)) { LOG(LL_ERROR, ("App init failed")); abort(); } LOG(LL_INFO, ("App init done")); /* SJS initialized, enable GC back, and trigger it */ v7_set_gc_enabled(v7, 1); v7_gc(v7, 1); #ifndef V7_NO_FS run_init_script(); #endif /* Install prompt if enabled in the config and user's app has not installed * a custom RX handler. */ if (get_cfg()->debug.enable_prompt && v7_is_undefined(esp_sj_uart_get_recv_handler(0))) { sj_prompt_init(v7); esp_sj_uart_set_prompt(0); } #ifdef ESP_UMM_ENABLE /* * We want to use our own heap functions instead of the ones provided by the * SDK. * * We have marked `pvPortMalloc` and friends weak, so that we can override * them with our own implementations, but to actually make it work, we have * to reference any function from the file with our implementation, so that * linker will not garbage-collect the whole compilation unit. * * So, we have a call to the no-op `esp_umm_init()` here. */ esp_umm_init(); #endif }
void wifi_changed_cb(System_Event_t *evt) { enum sj_wifi_status sj_ev = -1; /* TODO(rojer): Share this logic between platforms. */ if (wifi_setting_up && #ifndef RTOS_SDK evt->event == EVENT_STAMODE_GOT_IP #else evt->event_id == EVENT_STAMODE_GOT_IP #endif ) { struct station_config config; v7_val_t res; v7_val_t conf = v7_get(v7, v7_get_global_object(v7), "conf", ~0); v7_val_t known, wifi; if (v7_is_undefined(conf)) { fprintf(stderr, "cannot save conf, no conf object\n"); return; } wifi = v7_get(v7, conf, "wifi", ~0); if (v7_is_undefined(wifi)) { wifi = v7_create_object(v7); v7_set(v7, conf, "wifi", ~0, 0, wifi); } known = v7_get(v7, conf, "known", ~0); if (v7_is_undefined(known)) { known = v7_create_object(v7); v7_set(v7, wifi, "known", ~0, 0, known); } wifi_station_get_config(&config); v7_set(v7, known, (const char *) config.ssid, ~0, 0, v7_create_string(v7, (const char *) config.password, strlen((const char *) config.password), 1)); v7_exec(v7, "conf.save()", &res); wifi_setting_up = 0; } #ifndef RTOS_SDK switch (evt->event) { #else switch (evt->event_id) { #endif case EVENT_STAMODE_DISCONNECTED: sj_ev = SJ_WIFI_DISCONNECTED; break; case EVENT_STAMODE_CONNECTED: sj_ev = SJ_WIFI_CONNECTED; break; case EVENT_STAMODE_GOT_IP: sj_ev = SJ_WIFI_IP_ACQUIRED; break; } if (sj_ev >= 0) sj_wifi_on_change_callback(sj_ev); } char *sj_wifi_get_connected_ssid() { struct station_config conf; if (!wifi_station_get_config(&conf)) return NULL; return strdup((const char *) conf.ssid); } char *sj_wifi_get_sta_ip() { struct ip_info info; char *ip; if (!wifi_get_ip_info(0, &info) || info.ip.addr == 0) return NULL; if (asprintf(&ip, IPSTR, IP2STR(&info.ip)) < 0) { return NULL; } return ip; } void wifi_scan_done(void *arg, STATUS status) { if (status == OK) { STAILQ_HEAD(, bss_info) *info = arg; struct bss_info *p; const char **ssids; int n = 0; STAILQ_FOREACH(p, info, next) n++; ssids = calloc(n + 1, sizeof(*ssids)); n = 0; STAILQ_FOREACH(p, info, next) { ssids[n++] = (const char *) p->ssid; } wifi_scan_cb(ssids); free(ssids); } else {
/* Callback for json_walk() */ static void frozen_cb(void *data, const char *name, size_t name_len, const char *path, const struct json_token *token) { struct json_parse_ctx *ctx = (struct json_parse_ctx *) data; v7_val_t v = V7_UNDEFINED; (void) path; v7_own(ctx->v7, &v); switch (token->type) { case JSON_TYPE_STRING: v = v7_mk_string(ctx->v7, token->ptr, token->len, 1 /* copy */); break; case JSON_TYPE_NUMBER: v = v7_mk_number(ctx->v7, cs_strtod(token->ptr, NULL)); break; case JSON_TYPE_TRUE: v = v7_mk_boolean(ctx->v7, 1); break; case JSON_TYPE_FALSE: v = v7_mk_boolean(ctx->v7, 0); break; case JSON_TYPE_NULL: v = V7_NULL; break; case JSON_TYPE_OBJECT_START: v = v7_mk_object(ctx->v7); break; case JSON_TYPE_ARRAY_START: v = v7_mk_array(ctx->v7); break; case JSON_TYPE_OBJECT_END: case JSON_TYPE_ARRAY_END: { /* Object or array has finished: deallocate its frame */ ctx->frame = free_json_frame(ctx, ctx->frame); } break; default: LOG(LL_ERROR, ("Wrong token type %d\n", token->type)); break; } if (!v7_is_undefined(v)) { if (name != NULL && name_len != 0) { /* Need to define a property on the current object/array */ if (v7_is_object(ctx->frame->val)) { v7_set(ctx->v7, ctx->frame->val, name, name_len, v); } else if (v7_is_array(ctx->v7, ctx->frame->val)) { /* * TODO(dfrank): consult name_len. Currently it's not a problem due to * the implementation details of frozen, but it might change */ int idx = (int) cs_strtod(name, NULL); v7_array_set(ctx->v7, ctx->frame->val, idx, v); } else { LOG(LL_ERROR, ("Current value is neither object nor array\n")); } } else { /* This is a root value */ assert(ctx->frame == NULL); /* * This value will also be the overall result of JSON parsing * (it's already owned by the `v7_alt_json_parse()`) */ ctx->result = v; } if (token->type == JSON_TYPE_OBJECT_START || token->type == JSON_TYPE_ARRAY_START) { /* New object or array has just started, so we need to allocate a frame * for it */ struct json_parse_frame *new_frame = alloc_json_frame(ctx, v); new_frame->up = ctx->frame; ctx->frame = new_frame; } } v7_disown(ctx->v7, &v); }
void sj_wifi_on_change_callback(enum sj_wifi_status event) { struct v7 *v7 = s_v7; v7_val_t cb = v7_get(v7, s_wifi, "_ccb", ~0); if (v7_is_undefined(cb) || v7_is_null(cb)) return; sj_invoke_cb1(s_v7, cb, v7_create_number(event)); }