DSNode *dslink_node_get_path(DSNode *root, const char *path) { if (!root) { return NULL; } else if (strcmp(path, "/") == 0) { return root; } else if (*path == '/') { path++; } DSNode *node = root; const char *end = strchr(path, '/'); if (end) { if (!node->children) { return NULL; } node = dslink_map_getl(node->children, (void *) path, end - path); return dslink_node_get_path(node, end); } else if (*path != '\0') { if (!node->children) { return NULL; } return dslink_map_get(node->children, (void *) path); } return node; }
int dslink_response_sub(DSLink *link, json_t *paths, json_t *rid) { if (dslink_response_send_closed(link, rid) != 0) { return DSLINK_ALLOC_ERR; } DSNode *root = link->responder->super_root; size_t index; json_t *value; json_array_foreach(paths, index, value) { const char *path = json_string_value(json_object_get(value, "path")); DSNode *node = dslink_node_get_path(root, path); if (!node) { continue; } uint32_t *sid = malloc(sizeof(uint32_t)); if (!sid) { return DSLINK_ALLOC_ERR; } *sid = (uint32_t) json_integer_value(json_object_get(value, "sid")); void *tmp = sid; if (dslink_map_set(link->responder->value_path_subs, (void *) node->path, &tmp) != 0) { free(sid); return 1; } if (tmp) { void *p = tmp; dslink_map_remove(link->responder->value_sid_subs, &p); free(tmp); } tmp = (void *) node->path; if (dslink_map_set(link->responder->value_sid_subs, sid, &tmp) != 0) { tmp = (void *) node->path; dslink_map_remove(link->responder->value_path_subs, &tmp); free(sid); return 1; } dslink_response_send_val(link, node, *sid); if (node->on_subscribe) { node->on_subscribe(link, node); } } return 0; }
int dslink_response_unsub(DSLink *link, json_t *sids, json_t *rid) { size_t index; json_t *value; json_array_foreach(sids, index, value) { uint32_t sid = (uint32_t) json_integer_value(value); void *p = &sid; char *path = dslink_map_remove(link->responder->value_sid_subs, &p); if (path) { DSNode *node = dslink_node_get_path(link->responder->super_root, path); if (node && node->on_unsubscribe) { node->on_unsubscribe(link, node); } void *tmp = path; dslink_map_remove(link->responder->value_path_subs, &tmp); free(p); } }
int dslink_request_handle(DSLink *link, json_t *req) { const char *method = json_string_value(json_object_get(req, "method")); if (!method) { return 1; } if (strcmp(method, "list") == 0) { const char *path = json_string_value(json_object_get(req, "path")); DSNode *node = dslink_node_get_path(link->responder->super_root, path); return dslink_response_list(link, req, node); } else if (strcmp(method, "subscribe") == 0) { json_t *paths = json_object_get(req, "paths"); json_t *rid = json_object_get(req, "rid"); return dslink_response_sub(link, paths, rid); } else if (strcmp(method, "unsubscribe") == 0) { json_t *sids = json_object_get(req, "sids"); json_t *rid = json_object_get(req, "rid"); return dslink_response_unsub(link, sids, rid); } else if (strcmp(method, "invoke") == 0) { const char *path = json_string_value(json_object_get(req, "path")); DSNode *node = dslink_node_get_path(link->responder->super_root, path); if (node && node->on_invocation) { Stream *stream = dslink_malloc(sizeof(Stream)); if (!stream) { return 1; } stream->type = INVOCATION_STREAM; stream->path = dslink_strdup(node->path); ref_t *stream_ref = dslink_ref(stream, free_stream); json_t *jsonRid = json_object_get(req, "rid"); json_t *params = json_object_get(req, "params"); node->on_invocation(link, node, jsonRid, params, stream_ref); if (stream->unused != 1) { dslink_decref(stream_ref); } else { ref_t *rid = dslink_ref(dslink_malloc(sizeof(uint32_t)), dslink_free); { uint32_t r = (uint32_t) json_integer_value(jsonRid); *((uint32_t *) rid->data) = r; } if (dslink_map_set(link->responder->open_streams, rid, stream_ref) != 0) { dslink_free(rid); dslink_free(stream_ref); free_stream(stream); return 1; } } } } else if (strcmp(method, "set") == 0) { const char *path = json_string_value(json_object_get(req, "path")); json_t *value = json_object_get(req, "value"); DSNode *node = dslink_node_get_path(link->responder->super_root, path); if (node) { ref_t *writable_ref = dslink_map_get(node->meta_data, "$writable"); if (writable_ref && json_is_string((json_t*) writable_ref->data)) { if (node->on_value_set) { node->on_value_set(link, node, value); } else { dslink_node_update_value(link, node, value); } } } } else if (strcmp(method, "close") == 0) { json_t *rid = json_object_get(req, "rid"); uint32_t ridi = (uint32_t) json_integer_value(rid); ref_t *stream_ref = dslink_map_remove_get(link->responder->open_streams, &ridi); if (stream_ref) { Stream *stream = stream_ref->data; DSNode *node = NULL; if (stream->path) { node = dslink_node_get_path(link->responder->super_root, stream->path); } if (stream->on_close != NULL) { stream->on_close(link, node, stream); } if (stream->type == LIST_STREAM) { dslink_map_remove(link->responder->list_subs, (void *) stream->path); } dslink_decref(stream_ref); } } else { log_warn("Unrecognized method: %s\n", method); } return 0; }