Beispiel #1
0
/* 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;
}
/*
* Construct a new WebSocket object:
*
* url: url where to connect to
* protocol: websocket subprotocol
*
* Example:
* ws = new WebSocket('wss://localhost:1234');
* ws.onopen = function(ev) {
*     print("ON OPEN", ev);
* }
*
* ws.onclose = function(ev) {
*     print("ON CLOSE", ev);
* }
*
* ws.onmessage = function(ev) {
*     print("ON MESSAGE", ev);
* }
*
* ws.onerror = function(ev) {
*     print("ON ERROR", ev);
* }
*
*/
static v7_val_t sj_ws_ctor(struct v7 *v7, v7_val_t this_obj, v7_val_t args) {
  struct mg_connection *nc;
  struct user_data *ud;
  v7_val_t urlv = v7_array_get(v7, args, 0);
  v7_val_t subprotov = v7_array_get(v7, args, 1);
  (void) this_obj;
  (void) args;

  if (!v7_is_string(urlv)) {
    v7_throw(v7, "invalid ws url string");
  }

  if (v7_is_object(this_obj) && this_obj != v7_get_global_object(v7)) {
    int use_ssl = 0;
    size_t len;
    const char *url = v7_to_string(v7, &urlv, &len);

    if (strncmp(url, "ws://", 5) == 0) {
      url += 5;
    } else if (strncmp(url, "wss://", 6) == 0) {
      url += 6;
      use_ssl = 1;
    }

    nc = mg_connect(&sj_mgr, url, ws_ev_handler);
    if (nc == NULL) v7_throw(v7, "error creating the connection");
#ifdef NS_ENABLE_SSL
    if (use_ssl) {
      mg_set_ssl(nc, NULL, NULL);
    }
#endif

    (void) use_ssl;
    mg_set_protocol_http_websocket(nc);

    ud = calloc(1, sizeof(*ud));
    ud->v7 = v7;
    ud->ws = this_obj;
    nc->user_data = ud;
    v7_own(v7, &ud->ws);

    if (v7_is_string(subprotov)) {
      size_t len;
      const char *proto = v7_to_string(v7, &subprotov, &len);
      ud->proto = strdup(proto);
    }

  } else {
    v7_throw(v7, "WebSocket ctor called without new");
  }

  return v7_create_undefined();
}
Beispiel #3
0
clubby_handle_t console_get_current_clubby(struct v7 *v7) {
  v7_val_t clubby_v = v7_get(v7, v7_get_global(v7), s_clubby_prop, ~0);
  if (!v7_is_object(clubby_v)) {
    LOG(LL_ERROR, ("Clubby is not set"));
    return NULL;
  }

  clubby_handle_t ret = sj_clubby_get_handle(v7, clubby_v);
  LOG(LL_DEBUG, ("clubby handle: %p", ret));

  return ret;
}
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;
}
Beispiel #5
0
static void http_write_headers(struct v7 *v7, v7_val_t headers_obj,
                               struct mg_connection *c) {
  if (v7_is_object(headers_obj)) {
    void *h = NULL;
    v7_val_t name, value;
    v7_prop_attr_t attrs;
    while ((h = v7_next_prop(h, headers_obj, &name, &value, &attrs)) != NULL) {
      size_t n1, n2;
      const char *s1 = v7_get_string_data(v7, &name, &n1);
      const char *s2 = v7_get_string_data(v7, &value, &n2);
      mg_printf(c, "%.*s: %.*s\r\n", (int) n1, s1, (int) n2, s2);
    }
  }
}
Beispiel #6
0
V7_PRIVATE int is_cfunction_obj(struct v7 *v7, val_t v) {
  int ret = 0;
  if (v7_is_object(v)) {
    /* extract the hidden property from a cfunction_object */
    struct v7_property *p;
    p = v7_get_own_property2(v7, v, "", 0, _V7_PROPERTY_HIDDEN);
    if (p != NULL) {
      v = p->value;
    }

    ret = is_cfunction_lite(v);
  }
  return ret;
}
Beispiel #7
0
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;
}
Beispiel #8
0
V7_PRIVATE
val_t mk_js_function(struct v7 *v7, struct v7_generic_object *scope,
                     val_t proto) {
  struct v7_js_function *f;
  val_t fval = V7_NULL;
  struct gc_tmp_frame tf = new_tmp_frame(v7);
  tmp_stack_push(&tf, &proto);
  tmp_stack_push(&tf, &fval);

  f = new_function(v7);

  if (f == NULL) {
    /* fval is left `null` */
    goto cleanup;
  }

#if defined(V7_ENABLE_ENTITY_IDS)
  f->base.entity_id_base = V7_ENTITY_ID_PART_OBJ;
  f->base.entity_id_spec = V7_ENTITY_ID_PART_JS_FUNC;
#endif

  fval = js_function_to_value(f);

  f->base.properties = NULL;
  f->scope = scope;

  /*
   * Before setting a `V7_OBJ_FUNCTION` flag, make sure we don't have
   * `V7_OBJ_DENSE_ARRAY` flag set
   */
  assert(!(f->base.attributes & V7_OBJ_DENSE_ARRAY));
  f->base.attributes |= V7_OBJ_FUNCTION;

  /* TODO(mkm): lazily create these properties on first access */
  if (v7_is_object(proto)) {
    v7_def(v7, proto, "constructor", 11, V7_DESC_ENUMERABLE(0), fval);
    v7_def(v7, fval, "prototype", 9,
           V7_DESC_ENUMERABLE(0) | V7_DESC_CONFIGURABLE(0), proto);
  }

cleanup:
  tmp_frame_cleanup(&tf);
  return fval;
}
Beispiel #9
0
static enum v7_err UART_configure(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;

  struct esp_uart_config *cfg = esp_sj_uart_default_config(us->uart_no);
  v7_val_t cobj = v7_arg(v7, 0);
  if (v7_is_object(cobj)) {
    v7_val_t v;
#define NUM_PROP(p)             \
  v = v7_get(v7, cobj, #p, ~0); \
  if (v7_is_number(v)) cfg->p = v7_to_number(v);
#define BOOL_PROP(p)            \
  v = v7_get(v7, cobj, #p, ~0); \
  if (!v7_is_undefined(v)) cfg->p = v7_to_boolean(v);

    NUM_PROP(baud_rate);

    NUM_PROP(rx_buf_size);
    BOOL_PROP(rx_fc_ena);
    NUM_PROP(rx_fifo_full_thresh);
    NUM_PROP(rx_fifo_fc_thresh);
    NUM_PROP(rx_fifo_alarm);
    NUM_PROP(rx_linger_micros);

    NUM_PROP(tx_buf_size);
    BOOL_PROP(tx_fc_ena);
    NUM_PROP(tx_fifo_empty_thresh);
    NUM_PROP(tx_fifo_full_thresh);

    BOOL_PROP(swap_rxtx_ctsrts);

    NUM_PROP(status_interval_ms);
  }

  if (esp_uart_init(cfg)) {
    esp_sj_uart_schedule_dispatcher(cfg->uart_no);
    *res = v7_mk_boolean(1);
  } else {
    free(cfg);
    *res = v7_mk_boolean(0);
  }
  return V7_OK;
}
Beispiel #10
0
/*
 * 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;
}
Beispiel #11
0
/* 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);
}