static void send_heartbeat(noit_websocket_closure_t *wcl)
{
#ifdef HAVE_WSLAY
mtev_http_websocket_queue_msg(wcl->restc->http_ctx,
                              WSLAY_TEXT_FRAME,
                              (const unsigned char *)heartbeat_str, heartbeat_str_len);
#endif
}
예제 #2
0
static int my_websocket_msg_handler(mtev_http_rest_closure_t *restc,
                                    int opcode, const unsigned char *msg, size_t msg_len)
{
    /* simply echo back what was sent */
    mtev_boolean x = mtev_http_websocket_queue_msg(restc->http_ctx, opcode, msg, msg_len);
    if (debug == 1) {
        mtevL(mtev_debug, "Queue websocket message.. success == %d\n", x);
    }
    return !x;
}
static void
send_individual_metric(noit_websocket_closure_t *wcl, const char *metric_string, size_t len)
{
#ifdef HAVE_WSLAY
  noit_metric_message_t message;
  char *json = NULL;
  size_t json_len = 0;

  int rval = noit_message_decoder_parse_line(metric_string, len, &message.id.id, &message.id.name,
                                             &message.id.name_len, &message.value, mtev_false);
  if (rval < 0) {
    return;
  }

  message.type = metric_string[0];

  if (wcl->use_filter == mtev_true) {
    for (int i = 0; i < wcl->filter_count; i++) {
      if (message.id.name_len > 0 &&
        strncmp(wcl->filters[i], message.id.name, message.id.name_len) == 0) {
        noit_metric_to_json(&message, &json, &json_len, mtev_false);
        mtev_http_websocket_queue_msg(wcl->restc->http_ctx,
                                      WSLAY_TEXT_FRAME,
                                      (const unsigned char *)json, json_len);
        free(json);
        break;
      }
    }
  } else {
        noit_metric_to_json(&message, &json, &json_len, mtev_false);
        mtev_http_websocket_queue_msg(wcl->restc->http_ctx,
                                      WSLAY_TEXT_FRAME,
                                      (const unsigned char *)json, json_len);
        free(json);
  }
#endif
}
/**
 * The "noit_livestream" protocol requires a well formed request to come
 * in via websocket that resembles:
 *
 * {
 *   "period_ms": <milliseconds>,
 *   "check_uuid": "<uuid_string>",
 *   "metrics" : ["<metric_name1>", "<metric_name2>"]
 * }
 *
 * There can be only one active livestream request for a single websocket at one time.
 * However, you can send down a new livestream request at any time to alter the
 * stream based on new requirements.
 *
 * If the "metrics" member exists in the incoming request, then the metrics that are sent will be
 * filtered to those that match the strings in the array by exact match.  If you want to get
 * all metrics in the check, omit the "metrics" member from the request object.
 */
int
noit_websocket_msg_handler(mtev_http_rest_closure_t *restc, int opcode,
                           const unsigned char *msg, size_t msg_len)
{
#ifdef HAVE_WSLAY
  const char *error = NULL;
  noit_websocket_closure_t *handler_data = restc->call_closure;

  /* for now this message is JSON, that might change in the future */

  struct mtev_json_tokener *tok = mtev_json_tokener_new();
  struct mtev_json_object *request = mtev_json_tokener_parse_ex(tok, (const char *)msg, msg_len);
  enum mtev_json_tokener_error err = tok->err;
  mtev_json_tokener_free(tok);
  if (err != mtev_json_tokener_success) {
    error = "Unable to parse incoming json";
    goto websocket_handler_error;
  }

  uint64_t period_ms = mtev_json_object_get_uint64(mtev_json_object_object_get(request, "period_ms"));
  const char *check_uuid = mtev_json_object_get_string(mtev_json_object_object_get(request, "check_uuid"));
  struct mtev_json_object *metrics = mtev_json_object_object_get(request, "metrics");

  if (handler_data != NULL) {
    /* destroy old subscription */
    noit_websocket_closure_free(handler_data);
    handler_data = NULL;
  }

  handler_data = restc->call_closure = noit_websocket_closure_alloc();
  handler_data->use_filter = mtev_false;
  restc->call_closure_free = noit_websocket_closure_free;
  handler_data->period = period_ms;
  if (metrics != NULL) {
    handler_data->use_filter = mtev_true;
    handler_data->filter_count = mtev_json_object_array_length(metrics);
    handler_data->filters = calloc(sizeof(char *), handler_data->filter_count);
    jl_array_list* a = mtev_json_object_get_array(metrics);
    for (int i = 0; i < handler_data->filter_count; i++) {
      struct mtev_json_object *o = jl_array_list_get_idx(a, i);
      if (o != NULL) {
        handler_data->filters[i] = strdup(mtev_json_object_get_string(o));
      }
    }
  }

  handler_data->restc = restc;

  strncpy(handler_data->uuid_str, check_uuid, UUID_STR_LEN);
  handler_data->uuid_str[36] = '\0';
  if(uuid_parse(handler_data->uuid_str, handler_data->uuid)) {
    mtevL(noit_error, "bad uuid received in livestream websocket_handler '%s'\n", handler_data->uuid_str);
    error = "bad uuid received in livestream subscription request";
    goto websocket_handler_error;
  }
  mtev_json_object_put(request);

  /* setup subscription to noit_livestream */
  asprintf(&handler_data->feed, "websocket_livestream/%d", mtev_atomic_inc32(&ls_counter));
  handler_data->log_stream = mtev_log_stream_new(handler_data->feed, "noit_websocket_livestream", handler_data->feed,
                                                 handler_data, NULL);

  handler_data->check = noit_check_watch(handler_data->uuid, handler_data->period);
  if(!handler_data->check) {
    error = "Cannot locate check";
    goto websocket_handler_error;
  }

  /* This check must be watched from the livestream */
  noit_check_transient_add_feed(handler_data->check, handler_data->feed);

  /* Note the check */
  noit_check_log_check(handler_data->check);

  /* kick it off, if it isn't running already */
  if(!NOIT_CHECK_LIVE(handler_data->check)) noit_check_activate(handler_data->check);

  return 0;

 websocket_handler_error:
  {
    struct mtev_json_object *e = mtev_json_object_new_object();
    mtev_json_object_object_add(e, "success", mtev_json_object_new_int(0));
    struct mtev_json_object *errors = mtev_json_object_new_array();
    struct mtev_json_object *error_o = mtev_json_object_new_object();
    mtev_json_object_object_add(error_o, "error", mtev_json_object_new_string(error));
    mtev_json_object_array_add(errors, error_o);
    mtev_json_object_object_add(e, "errors", errors);

    const char *json_error = mtev_json_object_to_json_string(e);
    mtev_http_websocket_queue_msg(restc->http_ctx,
                                  WSLAY_TEXT_FRAME | WSLAY_CONNECTION_CLOSE,
                                  (const unsigned char *)json_error, strlen(json_error));
    mtev_json_object_put(e);
  }
#endif
  return -1;
}