/* clock /root * Returns the current clock value for a watched root */ static void cmd_clock(struct watchman_client *client, json_t *args) { w_root_t *root; json_t *resp; /* resolve the root */ if (json_array_size(args) != 2) { send_error_response(client, "wrong number of arguments to 'clock'"); return; } root = resolve_root_or_err(client, args, 1, false); if (!root) { return; } resp = make_response(); w_root_lock(root); annotate_with_clock(root, resp); w_root_unlock(root); send_and_dispose_response(client, resp); w_root_delref(root); }
/* subscribe /root subname {query} * Subscribes the client connection to the specified root. */ void cmd_subscribe(struct watchman_client *client, json_t *args) { w_root_t *root; struct watchman_client_subscription *sub; json_t *resp; const char *name; json_t *jfield_list; w_query *query; json_t *query_spec; struct w_query_field_list field_list; char *errmsg; if (json_array_size(args) != 4) { send_error_response(client, "wrong number of arguments for subscribe"); return; } root = resolve_root_or_err(client, args, 1, true); if (!root) { return; } name = json_string_value(json_array_get(args, 2)); if (!name) { send_error_response(client, "expected 2nd parameter to be subscription name"); goto done; } query_spec = json_array_get(args, 3); jfield_list = json_object_get(query_spec, "fields"); if (!parse_field_list(jfield_list, &field_list, &errmsg)) { send_error_response(client, "invalid field list: %s", errmsg); free(errmsg); goto done; } query = w_query_parse(query_spec, &errmsg); if (!query) { send_error_response(client, "failed to parse query: %s", errmsg); free(errmsg); goto done; } sub = calloc(1, sizeof(*sub)); if (!sub) { send_error_response(client, "no memory!"); goto done; } sub->name = w_string_new(name); sub->query = query; memcpy(&sub->field_list, &field_list, sizeof(field_list)); sub->root = root; pthread_mutex_lock(&w_client_lock); w_ht_replace(client->subscriptions, w_ht_ptr_val(sub->name), w_ht_ptr_val(sub)); pthread_mutex_unlock(&w_client_lock); resp = make_response(); annotate_with_clock(root, resp); set_prop(resp, "subscribe", json_string(name)); send_and_dispose_response(client, resp); resp = build_subscription_results(sub, root); if (resp) { send_and_dispose_response(client, resp); } done: w_root_delref(root); }
/* subscribe /root subname {query} * Subscribes the client connection to the specified root. */ static void cmd_subscribe(struct watchman_client *client, json_t *args) { w_root_t *root; struct watchman_client_subscription *sub; json_t *resp; const char *name; json_t *jfield_list; w_query *query; json_t *query_spec; struct w_query_field_list field_list; char *errmsg; int defer = true; /* can't use bool because json_unpack requires int */ json_t *defer_list = NULL; json_t *drop_list = NULL; if (json_array_size(args) != 4) { send_error_response(client, "wrong number of arguments for subscribe"); return; } root = resolve_root_or_err(client, args, 1, true); if (!root) { return; } name = json_string_value(json_array_get(args, 2)); if (!name) { send_error_response(client, "expected 2nd parameter to be subscription name"); goto done; } query_spec = json_array_get(args, 3); jfield_list = json_object_get(query_spec, "fields"); if (!parse_field_list(jfield_list, &field_list, &errmsg)) { send_error_response(client, "invalid field list: %s", errmsg); free(errmsg); goto done; } query = w_query_parse(root, query_spec, &errmsg); if (!query) { send_error_response(client, "failed to parse query: %s", errmsg); free(errmsg); goto done; } json_unpack(query_spec, "{s?:o}", "defer", &defer_list); if (defer_list && !json_is_array(defer_list)) { send_error_response(client, "defer field must be an array of strings"); goto done; } json_unpack(query_spec, "{s?:o}", "drop", &drop_list); if (drop_list && !json_is_array(drop_list)) { send_error_response(client, "drop field must be an array of strings"); goto done; } sub = calloc(1, sizeof(*sub)); if (!sub) { send_error_response(client, "no memory!"); goto done; } sub->name = w_string_new(name); sub->query = query; json_unpack(query_spec, "{s?:b}", "defer_vcs", &defer); sub->vcs_defer = defer; if (drop_list || defer_list) { size_t i; sub->drop_or_defer = w_ht_new(2, &w_ht_string_funcs); if (defer_list) { for (i = 0; i < json_array_size(defer_list); i++) { w_ht_replace(sub->drop_or_defer, w_ht_ptr_val(w_string_new(json_string_value( json_array_get(defer_list, i)))), false); } } if (drop_list) { for (i = 0; i < json_array_size(drop_list); i++) { w_ht_replace(sub->drop_or_defer, w_ht_ptr_val(w_string_new(json_string_value( json_array_get(drop_list, i)))), true); } } } memcpy(&sub->field_list, &field_list, sizeof(field_list)); sub->root = root; pthread_mutex_lock(&w_client_lock); w_ht_replace(client->subscriptions, w_ht_ptr_val(sub->name), w_ht_ptr_val(sub)); pthread_mutex_unlock(&w_client_lock); resp = make_response(); annotate_with_clock(root, resp); set_prop(resp, "subscribe", json_string(name)); add_root_warnings_to_response(resp, root); send_and_dispose_response(client, resp); resp = build_subscription_results(sub, root); if (resp) { send_and_dispose_response(client, resp); } done: w_root_delref(root); }