From 076a9adbf64c13034100cf1aac8e87599f14cd05 Mon Sep 17 00:00:00 2001 From: Shane Bryldt Date: Mon, 5 Jun 2017 15:29:19 -0600 Subject: [PATCH] FS-10167: Preliminary support for blade.execute, tested with a basic test.echo across 3 nodes with a common master. Multitier routing is not yet fully supported --- libs/libblade/libblade.vcxproj | 4 +- libs/libblade/libblade.vcxproj.filters | 12 +- libs/libblade/src/blade_jsonrpc.c | 432 ------------ libs/libblade/src/blade_rpc.c | 465 +++++++++++++ libs/libblade/src/blade_session.c | 110 ++- libs/libblade/src/blade_stack.c | 782 +++++++++++++++------- libs/libblade/src/blade_transport_wss.c | 24 +- libs/libblade/src/include/blade.h | 2 +- libs/libblade/src/include/blade_jsonrpc.h | 87 --- libs/libblade/src/include/blade_rpc.h | 92 +++ libs/libblade/src/include/blade_session.h | 2 +- libs/libblade/src/include/blade_stack.h | 27 +- libs/libblade/src/include/blade_types.h | 10 +- libs/libblade/test/bladec.c | 232 +++---- libs/libblade/test/blades.c | 434 ++---------- 15 files changed, 1350 insertions(+), 1365 deletions(-) delete mode 100644 libs/libblade/src/blade_jsonrpc.c create mode 100644 libs/libblade/src/blade_rpc.c delete mode 100644 libs/libblade/src/include/blade_jsonrpc.h create mode 100644 libs/libblade/src/include/blade_rpc.h diff --git a/libs/libblade/libblade.vcxproj b/libs/libblade/libblade.vcxproj index 46d225ef4b..b559f7f670 100644 --- a/libs/libblade/libblade.vcxproj +++ b/libs/libblade/libblade.vcxproj @@ -190,7 +190,7 @@ - + @@ -202,7 +202,7 @@ - + diff --git a/libs/libblade/libblade.vcxproj.filters b/libs/libblade/libblade.vcxproj.filters index 6aa19daafd..429764f066 100644 --- a/libs/libblade/libblade.vcxproj.filters +++ b/libs/libblade/libblade.vcxproj.filters @@ -36,15 +36,15 @@ Source Files - - Source Files - Source Files Source Files + + Source Files + @@ -71,14 +71,14 @@ Header Files - - Header Files - Header Files Header Files + + Header Files + \ No newline at end of file diff --git a/libs/libblade/src/blade_jsonrpc.c b/libs/libblade/src/blade_jsonrpc.c deleted file mode 100644 index c0127d1027..0000000000 --- a/libs/libblade/src/blade_jsonrpc.c +++ /dev/null @@ -1,432 +0,0 @@ -/* - * Copyright (c) 2017, Shane Bryldt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name of the original author; nor the names of any contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "blade.h" - -struct blade_jsonrpc_s { - blade_handle_t *handle; - ks_pool_t *pool; - - const char *method; - - blade_jsonrpc_request_callback_t callback; - void *callback_data; -}; - -struct blade_jsonrpc_request_s { - blade_handle_t *handle; - ks_pool_t *pool; - - const char *session_id; - - cJSON *message; - const char *message_id; // pulled from message for easier keying - blade_jsonrpc_response_callback_t callback; - // @todo ttl to wait for response before injecting an error response locally -}; - -struct blade_jsonrpc_response_s { - blade_handle_t *handle; - ks_pool_t *pool; - - const char *session_id; - - blade_jsonrpc_request_t *request; - - cJSON *message; -}; - - -static void blade_jsonrpc_cleanup(ks_pool_t *pool, void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type) -{ - //blade_jsonrpc_t *bjsonrpc = (blade_jsonrpc_t *)ptr; - - //ks_assert(bjsonrpc); - - switch (action) { - case KS_MPCL_ANNOUNCE: - break; - case KS_MPCL_TEARDOWN: - break; - case KS_MPCL_DESTROY: - break; - } -} - -KS_DECLARE(ks_status_t) blade_jsonrpc_create(blade_jsonrpc_t **bjsonrpcP, blade_handle_t *bh, const char *method, blade_jsonrpc_request_callback_t callback, void *callback_data) -{ - blade_jsonrpc_t *bjsonrpc = NULL; - ks_pool_t *pool = NULL; - - ks_assert(bjsonrpcP); - ks_assert(bh); - ks_assert(method); - ks_assert(callback); - - ks_pool_open(&pool); - ks_assert(pool); - - bjsonrpc = ks_pool_alloc(pool, sizeof(blade_jsonrpc_t)); - bjsonrpc->handle = bh; - bjsonrpc->pool = pool; - bjsonrpc->method = ks_pstrdup(pool, method); - bjsonrpc->callback = callback; - bjsonrpc->callback_data = callback_data; - - ks_pool_set_cleanup(pool, bjsonrpc, NULL, blade_jsonrpc_cleanup); - - *bjsonrpcP = bjsonrpc; - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_jsonrpc_destroy(blade_jsonrpc_t **bjsonrpcP) -{ - blade_jsonrpc_t *bjsonrpc = NULL; - ks_pool_t *pool = NULL; - - ks_assert(bjsonrpcP); - ks_assert(*bjsonrpcP); - - bjsonrpc = *bjsonrpcP; - - pool = bjsonrpc->pool; - - ks_pool_close(&pool); - - *bjsonrpcP = NULL; - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(blade_handle_t *) blade_jsonrpc_handle_get(blade_jsonrpc_t *bjsonrpc) -{ - ks_assert(bjsonrpc); - - return bjsonrpc->handle; -} - -KS_DECLARE(const char *) blade_jsonrpc_method_get(blade_jsonrpc_t *bjsonrpc) -{ - ks_assert(bjsonrpc); - - return bjsonrpc->method; -} - -KS_DECLARE(blade_jsonrpc_request_callback_t) blade_jsonrpc_callback_get(blade_jsonrpc_t *bjsonrpc) -{ - ks_assert(bjsonrpc); - - return bjsonrpc->callback; -} - -KS_DECLARE(void *) blade_jsonrpc_callback_data_get(blade_jsonrpc_t *bjsonrpc) -{ - ks_assert(bjsonrpc); - - return bjsonrpc->callback_data; -} - - -static void blade_jsonrpc_request_cleanup(ks_pool_t *pool, void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type) -{ - blade_jsonrpc_request_t *bjsonrpcreq = (blade_jsonrpc_request_t *)ptr; - - ks_assert(bjsonrpcreq); - - switch (action) { - case KS_MPCL_ANNOUNCE: - break; - case KS_MPCL_TEARDOWN: - ks_pool_free(bjsonrpcreq->pool, (void **)&bjsonrpcreq->session_id); - cJSON_Delete(bjsonrpcreq->message); - break; - case KS_MPCL_DESTROY: - break; - } -} - -KS_DECLARE(ks_status_t) blade_jsonrpc_request_create(blade_jsonrpc_request_t **bjsonrpcreqP, - blade_handle_t *bh, - ks_pool_t *pool, - const char *session_id, - cJSON *json, - blade_jsonrpc_response_callback_t callback) -{ - blade_jsonrpc_request_t *bjsonrpcreq = NULL; - - ks_assert(bjsonrpcreqP); - ks_assert(bh); - ks_assert(pool); - ks_assert(session_id); - ks_assert(json); - - bjsonrpcreq = ks_pool_alloc(pool, sizeof(blade_jsonrpc_request_t)); - bjsonrpcreq->handle = bh; - bjsonrpcreq->pool = pool; - bjsonrpcreq->session_id = ks_pstrdup(pool, session_id); - bjsonrpcreq->message = cJSON_Duplicate(json, 1); - bjsonrpcreq->message_id = cJSON_GetObjectCstr(bjsonrpcreq->message, "id"); - bjsonrpcreq->callback = callback; - - ks_pool_set_cleanup(pool, bjsonrpcreq, NULL, blade_jsonrpc_request_cleanup); - - *bjsonrpcreqP = bjsonrpcreq; - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_jsonrpc_request_destroy(blade_jsonrpc_request_t **bjsonrpcreqP) -{ - blade_jsonrpc_request_t *bjsonrpcreq = NULL; - - ks_assert(bjsonrpcreqP); - ks_assert(*bjsonrpcreqP); - - bjsonrpcreq = *bjsonrpcreqP; - - ks_pool_free(bjsonrpcreq->pool, bjsonrpcreqP); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(blade_handle_t *) blade_jsonrpc_request_handle_get(blade_jsonrpc_request_t *bjsonrpcreq) -{ - ks_assert(bjsonrpcreq); - return bjsonrpcreq->handle; -} - -KS_DECLARE(const char *) blade_jsonrpc_request_sessionid_get(blade_jsonrpc_request_t *bjsonrpcreq) -{ - ks_assert(bjsonrpcreq); - return bjsonrpcreq->session_id; -} - -KS_DECLARE(cJSON *) blade_jsonrpc_request_message_get(blade_jsonrpc_request_t *bjsonrpcreq) -{ - ks_assert(bjsonrpcreq); - return bjsonrpcreq->message; -} - -KS_DECLARE(const char *) blade_jsonrpc_request_messageid_get(blade_jsonrpc_request_t *bjsonrpcreq) -{ - ks_assert(bjsonrpcreq); - return bjsonrpcreq->message_id; -} - -KS_DECLARE(blade_jsonrpc_response_callback_t) blade_jsonrpc_request_callback_get(blade_jsonrpc_request_t *bjsonrpcreq) -{ - ks_assert(bjsonrpcreq); - return bjsonrpcreq->callback; -} - -KS_DECLARE(ks_status_t) blade_jsonrpc_request_raw_create(ks_pool_t *pool, cJSON **json, cJSON **params, const char **id, const char *method) -{ - cJSON *root = NULL; - cJSON *p = NULL; - uuid_t msgid; - const char *mid = NULL; - - ks_assert(pool); - ks_assert(json); - ks_assert(method); - - root = cJSON_CreateObject(); - - cJSON_AddStringToObject(root, "jsonrpc", "2.0"); - - ks_uuid(&msgid); - mid = ks_uuid_str(pool, &msgid); - cJSON_AddStringToObject(root, "id", mid); - ks_pool_free(pool, &mid); - - cJSON_AddStringToObject(root, "method", method); - - p = cJSON_CreateObject(); - cJSON_AddItemToObject(root, "params", p); - - *json = root; - if (params) *params = p; - if (id) *id = cJSON_GetObjectCstr(root, "id"); - - return KS_STATUS_SUCCESS; -} - - -static void blade_jsonrpc_response_cleanup(ks_pool_t *pool, void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type) -{ - blade_jsonrpc_response_t *bjsonrpcres = (blade_jsonrpc_response_t *)ptr; - - ks_assert(bjsonrpcres); - - switch (action) { - case KS_MPCL_ANNOUNCE: - break; - case KS_MPCL_TEARDOWN: - ks_pool_free(bjsonrpcres->pool, (void **)&bjsonrpcres->session_id); - blade_jsonrpc_request_destroy(&bjsonrpcres->request); - cJSON_Delete(bjsonrpcres->message); - break; - case KS_MPCL_DESTROY: - break; - } -} - -KS_DECLARE(ks_status_t) blade_jsonrpc_response_create(blade_jsonrpc_response_t **bjsonrpcresP, - blade_handle_t *bh, - ks_pool_t *pool, - const char *session_id, - blade_jsonrpc_request_t *bjsonrpcreq, - cJSON *json) -{ - blade_jsonrpc_response_t *bjsonrpcres = NULL; - - ks_assert(bjsonrpcresP); - ks_assert(bh); - ks_assert(pool); - ks_assert(session_id); - ks_assert(bjsonrpcreq); - ks_assert(json); - - bjsonrpcres = ks_pool_alloc(pool, sizeof(blade_jsonrpc_response_t)); - bjsonrpcres->handle = bh; - bjsonrpcres->pool = pool; - bjsonrpcres->session_id = ks_pstrdup(pool, session_id); - bjsonrpcres->request = bjsonrpcreq; - bjsonrpcres->message = cJSON_Duplicate(json, 1); - - ks_pool_set_cleanup(pool, bjsonrpcres, NULL, blade_jsonrpc_response_cleanup); - - *bjsonrpcresP = bjsonrpcres; - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_jsonrpc_response_destroy(blade_jsonrpc_response_t **bjsonrpcresP) -{ - blade_jsonrpc_response_t *bjsonrpcres = NULL; - - ks_assert(bjsonrpcresP); - ks_assert(*bjsonrpcresP); - - bjsonrpcres = *bjsonrpcresP; - - ks_pool_free(bjsonrpcres->pool, bjsonrpcresP); - - return KS_STATUS_SUCCESS; -} - - -KS_DECLARE(ks_status_t) blade_jsonrpc_response_raw_create(cJSON **json, cJSON **result, const char *id) -{ - cJSON *root = NULL; - cJSON *r = NULL; - - ks_assert(json); - ks_assert(id); - - root = cJSON_CreateObject(); - - cJSON_AddStringToObject(root, "jsonrpc", "2.0"); - - cJSON_AddStringToObject(root, "id", id); - - r = cJSON_CreateObject(); - cJSON_AddItemToObject(root, "result", r); - - *json = root; - if (result) *result = r; - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(blade_handle_t *) blade_jsonrpc_response_handle_get(blade_jsonrpc_response_t *bjsonrpcres) -{ - ks_assert(bjsonrpcres); - return bjsonrpcres->handle; -} - -KS_DECLARE(const char *) blade_jsonrpc_response_sessionid_get(blade_jsonrpc_response_t *bjsonrpcres) -{ - ks_assert(bjsonrpcres); - return bjsonrpcres->session_id; -} - -KS_DECLARE(blade_jsonrpc_request_t *) blade_jsonrpc_response_request_get(blade_jsonrpc_response_t *bjsonrpcres) -{ - ks_assert(bjsonrpcres); - return bjsonrpcres->request; -} - -KS_DECLARE(cJSON *) blade_jsonrpc_response_message_get(blade_jsonrpc_response_t *bjsonrpcres) -{ - ks_assert(bjsonrpcres); - return bjsonrpcres->message; -} - -KS_DECLARE(ks_status_t) blade_jsonrpc_error_raw_create(cJSON **json, cJSON **error, const char *id, int32_t code, const char *message) -{ - cJSON *root = NULL; - cJSON *e = NULL; - - ks_assert(json); - //ks_assert(id); - ks_assert(message); - - root = cJSON_CreateObject(); - - cJSON_AddStringToObject(root, "jsonrpc", "2.0"); - - if (id) cJSON_AddStringToObject(root, "id", id); - - e = cJSON_CreateObject(); - cJSON_AddNumberToObject(e, "code", code); - cJSON_AddStringToObject(e, "message", message); - cJSON_AddItemToObject(root, "error", e); - - *json = root; - if (error) *error = e; - - return KS_STATUS_SUCCESS; -} - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/blade_rpc.c b/libs/libblade/src/blade_rpc.c new file mode 100644 index 0000000000..7c881028e7 --- /dev/null +++ b/libs/libblade/src/blade_rpc.c @@ -0,0 +1,465 @@ +/* + * Copyright (c) 2017, Shane Bryldt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of the original author; nor the names of any contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "blade.h" + +struct blade_rpc_s { + blade_handle_t *handle; + ks_pool_t *pool; + + const char *method; + const char *protocol; + const char *realm; + + blade_rpc_request_callback_t callback; + void *callback_data; +}; + +struct blade_rpc_request_s { + blade_handle_t *handle; + ks_pool_t *pool; + + const char *session_id; + + cJSON *message; + const char *message_id; // pulled from message for easier keying + blade_rpc_response_callback_t callback; + void *callback_data; + // @todo ttl to wait for response before injecting an error response locally +}; + +struct blade_rpc_response_s { + blade_handle_t *handle; + ks_pool_t *pool; + + const char *session_id; + + blade_rpc_request_t *request; + + cJSON *message; +}; + + +static void blade_rpc_cleanup(ks_pool_t *pool, void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type) +{ + //blade_rpc_t *brpc = (blade_rpc_t *)ptr; + + //ks_assert(brpc); + + switch (action) { + case KS_MPCL_ANNOUNCE: + break; + case KS_MPCL_TEARDOWN: + break; + case KS_MPCL_DESTROY: + break; + } +} + +KS_DECLARE(ks_status_t) blade_rpc_create(blade_rpc_t **brpcP, blade_handle_t *bh, const char *method, const char *protocol, const char *realm, blade_rpc_request_callback_t callback, void *callback_data) +{ + blade_rpc_t *brpc = NULL; + ks_pool_t *pool = NULL; + + ks_assert(brpcP); + ks_assert(bh); + ks_assert(method); + ks_assert(callback); + + ks_pool_open(&pool); + ks_assert(pool); + + brpc = ks_pool_alloc(pool, sizeof(blade_rpc_t)); + brpc->handle = bh; + brpc->pool = pool; + brpc->method = ks_pstrdup(pool, method); + if (protocol) brpc->protocol = ks_pstrdup(pool, protocol); + if (realm) brpc->realm = ks_pstrdup(pool, realm); + brpc->callback = callback; + brpc->callback_data = callback_data; + + ks_pool_set_cleanup(pool, brpc, NULL, blade_rpc_cleanup); + + *brpcP = brpc; + + return KS_STATUS_SUCCESS; +} + +KS_DECLARE(ks_status_t) blade_rpc_destroy(blade_rpc_t **brpcP) +{ + blade_rpc_t *brpc = NULL; + ks_pool_t *pool = NULL; + + ks_assert(brpcP); + ks_assert(*brpcP); + + brpc = *brpcP; + + pool = brpc->pool; + + ks_pool_close(&pool); + + *brpcP = NULL; + + return KS_STATUS_SUCCESS; +} + +KS_DECLARE(blade_handle_t *) blade_rpc_handle_get(blade_rpc_t *brpc) +{ + ks_assert(brpc); + + return brpc->handle; +} + +KS_DECLARE(const char *) blade_rpc_method_get(blade_rpc_t *brpc) +{ + ks_assert(brpc); + + return brpc->method; +} + +KS_DECLARE(const char *) blade_rpc_protocol_get(blade_rpc_t *brpc) +{ + ks_assert(brpc); + + return brpc->protocol; +} + +KS_DECLARE(const char *) blade_rpc_realm_get(blade_rpc_t *brpc) +{ + ks_assert(brpc); + + return brpc->realm; +} + +KS_DECLARE(blade_rpc_request_callback_t) blade_rpc_callback_get(blade_rpc_t *brpc) +{ + ks_assert(brpc); + + return brpc->callback; +} + +KS_DECLARE(void *) blade_rpc_callback_data_get(blade_rpc_t *brpc) +{ + ks_assert(brpc); + + return brpc->callback_data; +} + + +static void blade_rpc_request_cleanup(ks_pool_t *pool, void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type) +{ + blade_rpc_request_t *brpcreq = (blade_rpc_request_t *)ptr; + + ks_assert(brpcreq); + + switch (action) { + case KS_MPCL_ANNOUNCE: + break; + case KS_MPCL_TEARDOWN: + ks_pool_free(brpcreq->pool, (void **)&brpcreq->session_id); + cJSON_Delete(brpcreq->message); + break; + case KS_MPCL_DESTROY: + break; + } +} + +KS_DECLARE(ks_status_t) blade_rpc_request_create(blade_rpc_request_t **brpcreqP, + blade_handle_t *bh, + ks_pool_t *pool, + const char *session_id, + cJSON *json, + blade_rpc_response_callback_t callback, + void *data) +{ + blade_rpc_request_t *brpcreq = NULL; + + ks_assert(brpcreqP); + ks_assert(bh); + ks_assert(pool); + ks_assert(session_id); + ks_assert(json); + + brpcreq = ks_pool_alloc(pool, sizeof(blade_rpc_request_t)); + brpcreq->handle = bh; + brpcreq->pool = pool; + brpcreq->session_id = ks_pstrdup(pool, session_id); + brpcreq->message = cJSON_Duplicate(json, 1); + brpcreq->message_id = cJSON_GetObjectCstr(brpcreq->message, "id"); + brpcreq->callback = callback; + brpcreq->callback_data = data; + + ks_pool_set_cleanup(pool, brpcreq, NULL, blade_rpc_request_cleanup); + + *brpcreqP = brpcreq; + + return KS_STATUS_SUCCESS; +} + +KS_DECLARE(ks_status_t) blade_rpc_request_destroy(blade_rpc_request_t **brpcreqP) +{ + blade_rpc_request_t *brpcreq = NULL; + + ks_assert(brpcreqP); + ks_assert(*brpcreqP); + + brpcreq = *brpcreqP; + + ks_pool_free(brpcreq->pool, brpcreqP); + + return KS_STATUS_SUCCESS; +} + +KS_DECLARE(ks_status_t) blade_rpc_request_duplicate(blade_rpc_request_t **brpcreqP, blade_rpc_request_t *brpcreq) +{ + return blade_rpc_request_create(brpcreqP, brpcreq->handle, brpcreq->pool, brpcreq->session_id, brpcreq->message, brpcreq->callback, brpcreq->callback_data); +} + +KS_DECLARE(blade_handle_t *) blade_rpc_request_handle_get(blade_rpc_request_t *brpcreq) +{ + ks_assert(brpcreq); + return brpcreq->handle; +} + +KS_DECLARE(const char *) blade_rpc_request_sessionid_get(blade_rpc_request_t *brpcreq) +{ + ks_assert(brpcreq); + return brpcreq->session_id; +} + +KS_DECLARE(cJSON *) blade_rpc_request_message_get(blade_rpc_request_t *brpcreq) +{ + ks_assert(brpcreq); + return brpcreq->message; +} + +KS_DECLARE(const char *) blade_rpc_request_messageid_get(blade_rpc_request_t *brpcreq) +{ + ks_assert(brpcreq); + return brpcreq->message_id; +} + +KS_DECLARE(blade_rpc_response_callback_t) blade_rpc_request_callback_get(blade_rpc_request_t *brpcreq) +{ + ks_assert(brpcreq); + return brpcreq->callback; +} + +KS_DECLARE(void *) blade_rpc_request_callback_data_get(blade_rpc_request_t *brpcreq) +{ + ks_assert(brpcreq); + + return brpcreq->callback_data; +} + +KS_DECLARE(ks_status_t) blade_rpc_request_raw_create(ks_pool_t *pool, cJSON **json, cJSON **params, const char **id, const char *method) +{ + cJSON *root = NULL; + cJSON *p = NULL; + uuid_t msgid; + const char *mid = NULL; + + ks_assert(pool); + ks_assert(json); + ks_assert(method); + + root = cJSON_CreateObject(); + + cJSON_AddStringToObject(root, "jsonrpc", "2.0"); + + ks_uuid(&msgid); + mid = ks_uuid_str(pool, &msgid); + cJSON_AddStringToObject(root, "id", mid); + ks_pool_free(pool, &mid); + + cJSON_AddStringToObject(root, "method", method); + + p = cJSON_CreateObject(); + cJSON_AddItemToObject(root, "params", p); + + *json = root; + if (params) *params = p; + if (id) *id = cJSON_GetObjectCstr(root, "id"); + + return KS_STATUS_SUCCESS; +} + + +static void blade_rpc_response_cleanup(ks_pool_t *pool, void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type) +{ + blade_rpc_response_t *brpcres = (blade_rpc_response_t *)ptr; + + ks_assert(brpcres); + + switch (action) { + case KS_MPCL_ANNOUNCE: + break; + case KS_MPCL_TEARDOWN: + ks_pool_free(brpcres->pool, (void **)&brpcres->session_id); + blade_rpc_request_destroy(&brpcres->request); + cJSON_Delete(brpcres->message); + break; + case KS_MPCL_DESTROY: + break; + } +} + +KS_DECLARE(ks_status_t) blade_rpc_response_create(blade_rpc_response_t **brpcresP, + blade_handle_t *bh, + ks_pool_t *pool, + const char *session_id, + blade_rpc_request_t *brpcreq, + cJSON *json) +{ + blade_rpc_response_t *brpcres = NULL; + + ks_assert(brpcresP); + ks_assert(bh); + ks_assert(pool); + ks_assert(session_id); + ks_assert(brpcreq); + ks_assert(json); + + brpcres = ks_pool_alloc(pool, sizeof(blade_rpc_response_t)); + brpcres->handle = bh; + brpcres->pool = pool; + brpcres->session_id = ks_pstrdup(pool, session_id); + brpcres->request = brpcreq; + brpcres->message = cJSON_Duplicate(json, 1); + + ks_pool_set_cleanup(pool, brpcres, NULL, blade_rpc_response_cleanup); + + *brpcresP = brpcres; + + return KS_STATUS_SUCCESS; +} + +KS_DECLARE(ks_status_t) blade_rpc_response_destroy(blade_rpc_response_t **brpcresP) +{ + blade_rpc_response_t *brpcres = NULL; + + ks_assert(brpcresP); + ks_assert(*brpcresP); + + brpcres = *brpcresP; + + ks_pool_free(brpcres->pool, brpcresP); + + return KS_STATUS_SUCCESS; +} + + +KS_DECLARE(ks_status_t) blade_rpc_response_raw_create(cJSON **json, cJSON **result, const char *id) +{ + cJSON *root = NULL; + cJSON *r = NULL; + + ks_assert(json); + ks_assert(id); + + root = cJSON_CreateObject(); + + cJSON_AddStringToObject(root, "jsonrpc", "2.0"); + + cJSON_AddStringToObject(root, "id", id); + + r = cJSON_CreateObject(); + cJSON_AddItemToObject(root, "result", r); + + *json = root; + if (result) *result = r; + + return KS_STATUS_SUCCESS; +} + +KS_DECLARE(blade_handle_t *) blade_rpc_response_handle_get(blade_rpc_response_t *brpcres) +{ + ks_assert(brpcres); + return brpcres->handle; +} + +KS_DECLARE(const char *) blade_rpc_response_sessionid_get(blade_rpc_response_t *brpcres) +{ + ks_assert(brpcres); + return brpcres->session_id; +} + +KS_DECLARE(blade_rpc_request_t *) blade_rpc_response_request_get(blade_rpc_response_t *brpcres) +{ + ks_assert(brpcres); + return brpcres->request; +} + +KS_DECLARE(cJSON *) blade_rpc_response_message_get(blade_rpc_response_t *brpcres) +{ + ks_assert(brpcres); + return brpcres->message; +} + +KS_DECLARE(ks_status_t) blade_rpc_error_raw_create(cJSON **json, cJSON **error, const char *id, int32_t code, const char *message) +{ + cJSON *root = NULL; + cJSON *e = NULL; + + ks_assert(json); + //ks_assert(id); + ks_assert(message); + + root = cJSON_CreateObject(); + + cJSON_AddStringToObject(root, "jsonrpc", "2.0"); + + if (id) cJSON_AddStringToObject(root, "id", id); + + e = cJSON_CreateObject(); + cJSON_AddNumberToObject(e, "code", code); + cJSON_AddStringToObject(e, "message", message); + cJSON_AddItemToObject(root, "error", e); + + *json = root; + if (error) *error = e; + + return KS_STATUS_SUCCESS; +} + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: + */ diff --git a/libs/libblade/src/blade_session.c b/libs/libblade/src/blade_session.c index 955e058557..41333a2bb9 100644 --- a/libs/libblade/src/blade_session.c +++ b/libs/libblade/src/blade_session.c @@ -76,23 +76,9 @@ static void blade_session_cleanup(ks_pool_t *pool, void *ptr, void *arg, ks_pool blade_session_shutdown(bs); break; case KS_MPCL_DESTROY: - // @todo consider looking at supporting externally allocated memory entries that can have cleanup callbacks associated, but the memory is not freed from the pool, only linked as an external allocation for auto cleanup // which would allow calling something like ks_pool_set_cleanup(bs->properties, ...) and when the pool is destroyed, it can call a callback which handles calling cJSON_Delete, which is allocated externally cJSON_Delete(bs->properties); - bs->properties = NULL; - - // @todo remove this, it's just for posterity in debugging - //bs->state_thread = NULL; - bs->properties_lock = NULL; - bs->receiving = NULL; - bs->sending = NULL; - bs->connection = NULL; - bs->cond = NULL; - bs->lock = NULL; - - //ks_pool_free(bs->pool, &bs->id); - bs->id = NULL; break; } } @@ -508,6 +494,8 @@ void *blade_session_state_thread(ks_thread_t *thread, void *data) // we can start stuffing any messages queued for output on the session straight to the connection right away, may need to only // do this when in session ready state but there may be implications of other states sending messages through the session while (blade_session_sending_pop(bs, &json) == KS_STATUS_SUCCESS && json) { + // @todo short-circuit with blade_session_receiving_push on the same session if the message has responder-nodeid == requester-nodeid == local_nodeid + // which would allow a system to send messages to itself, such as calling a protocolrpc immediately without bouncing upstream first blade_connection_sending_push(bc, json); cJSON_Delete(json); } @@ -520,9 +508,7 @@ void *blade_session_state_thread(ks_thread_t *thread, void *data) switch (state) { case BLADE_SESSION_STATE_STARTUP: - // @todo this may occur from a reconnect, should have some way to identify it is a reconnected session until we hit RUN state at least - ks_log(KS_LOG_DEBUG, "Session (%s) state startup\n", bs->id); - blade_session_state_set(bs, BLADE_SESSION_STATE_RUN); + blade_session_onstate_startup(bs); break; case BLADE_SESSION_STATE_SHUTDOWN: blade_session_onstate_shutdown(bs); @@ -549,12 +535,21 @@ void *blade_session_state_thread(ks_thread_t *thread, void *data) return NULL; } +ks_status_t blade_session_onstate_startup(blade_session_t *bs) +{ + ks_assert(bs); + + ks_log(KS_LOG_DEBUG, "Session (%s) state startup\n", bs->id); + blade_session_state_set(bs, BLADE_SESSION_STATE_RUN); + + return KS_STATUS_SUCCESS; +} + ks_status_t blade_session_onstate_shutdown(blade_session_t *bs) { ks_assert(bs); ks_log(KS_LOG_DEBUG, "Session (%s) state shutdown\n", bs->id); - blade_session_state_set(bs, BLADE_SESSION_STATE_CLEANUP); if (bs->connection) { @@ -565,7 +560,7 @@ ks_status_t blade_session_onstate_shutdown(blade_session_t *bs) } } - // @note wait for the connection to disconnect before we resume session cleanup + // wait for the connection to disconnect before we resume session cleanup while (bs->connection) ks_sleep(100); return KS_STATUS_SUCCESS; @@ -577,28 +572,18 @@ ks_status_t blade_session_onstate_run(blade_session_t *bs) ks_assert(bs); - //ks_log(KS_LOG_DEBUG, "Session (%s) state run\n", bs->id); - - // @todo for now only process messages if there is a connection available - if (bs->connection) { - // @todo may only want to pop once per call to give sending a chance to keep up - while (blade_session_receiving_pop(bs, &json) == KS_STATUS_SUCCESS && json) { - // @todo all messages will pass through the local jsonrpc method handlers, but each needs to determine if the - // message is destined for the local node, and if not then each handler can determine how routing occurs as - // they differ, especially when it comes to the announcing of identities and propagation of multicast events - blade_session_process(bs, json); - cJSON_Delete(json); - } + while (bs->connection && blade_session_receiving_pop(bs, &json) == KS_STATUS_SUCCESS && json) { + blade_session_process(bs, json); + cJSON_Delete(json); } - //ks_sleep_ms(1); return KS_STATUS_SUCCESS; } -KS_DECLARE(ks_status_t) blade_session_send(blade_session_t *bs, cJSON *json, blade_jsonrpc_response_callback_t callback) +KS_DECLARE(ks_status_t) blade_session_send(blade_session_t *bs, cJSON *json, blade_rpc_response_callback_t callback, void *data) { - blade_jsonrpc_request_t *bjsonrpcreq = NULL; + blade_rpc_request_t *brpcreq = NULL; const char *method = NULL; const char *id = NULL; @@ -615,17 +600,18 @@ KS_DECLARE(ks_status_t) blade_session_send(blade_session_t *bs, cJSON *json, bla // 1) Sending a request (client: method caller or consumer) ks_log(KS_LOG_DEBUG, "Session (%s) sending request (%s) for %s\n", bs->id, id, method); - blade_jsonrpc_request_create(&bjsonrpcreq, bs->handle, blade_handle_pool_get(bs->handle), bs->id, json, callback); - ks_assert(bjsonrpcreq); + blade_rpc_request_create(&brpcreq, bs->handle, blade_handle_pool_get(bs->handle), bs->id, json, callback, data); + ks_assert(brpcreq); // @todo set request TTL and figure out when requests are checked for expiration (separate thread in the handle?) - blade_handle_requests_add(bjsonrpcreq); + blade_handle_requests_add(brpcreq); } else { // @note This is scenario 3 // 3) Sending a response or error (server: method callee or provider) ks_log(KS_LOG_DEBUG, "Session (%s) sending response (%s)\n", bs->id, id); } + //blade_session_sending_push(bs, json); if (!bs->connection) { blade_session_sending_push(bs, json); } else { @@ -644,8 +630,8 @@ KS_DECLARE(ks_status_t) blade_session_send(blade_session_t *bs, cJSON *json, bla ks_status_t blade_session_process(blade_session_t *bs, cJSON *json) { blade_handle_t *bh = NULL; - blade_jsonrpc_request_t *bjsonrpcreq = NULL; - blade_jsonrpc_response_t *bjsonrpcres = NULL; + blade_rpc_request_t *brpcreq = NULL; + blade_rpc_response_t *brpcres = NULL; const char *jsonrpc = NULL; const char *id = NULL; const char *method = NULL; @@ -680,8 +666,8 @@ ks_status_t blade_session_process(blade_session_t *bs, cJSON *json) if (method) { // @note This is scenario 2 // 2) Receiving a request (server: method callee or provider) - blade_jsonrpc_t *bjsonrpc = NULL; - blade_jsonrpc_request_callback_t callback = NULL; + blade_rpc_t *brpc = NULL; + blade_rpc_request_callback_t callback = NULL; cJSON *params = NULL; ks_log(KS_LOG_DEBUG, "Session (%s) receiving request (%s) for %s\n", bs->id, id, method); @@ -700,13 +686,13 @@ ks_status_t blade_session_process(blade_session_t *bs, cJSON *json) cJSON *res_error = NULL; ks_log(KS_LOG_DEBUG, "Session (%s) request (%s => %s) but upstream session unavailable\n", blade_session_id_get(bs), params_requester_nodeid, params_responder_nodeid); - blade_jsonrpc_error_raw_create(&res, &res_error, id, -32603, "Upstream session unavailable"); + blade_rpc_error_raw_create(&res, &res_error, id, -32603, "Upstream session unavailable"); // needed in case this error must propagate further than the session which sent it cJSON_AddStringToObject(res_error, "requester-nodeid", params_requester_nodeid); cJSON_AddStringToObject(res_error, "responder-nodeid", params_responder_nodeid); // @todo responder-nodeid should become the local_nodeid to inform of which node actually responded - blade_session_send(bs, res, NULL); + blade_session_send(bs, res, NULL, NULL); return KS_STATUS_DISCONNECTED; } } @@ -716,7 +702,7 @@ ks_status_t blade_session_process(blade_session_t *bs, cJSON *json) } ks_log(KS_LOG_DEBUG, "Session (%s) request (%s => %s) routing (%s)\n", blade_session_id_get(bs), params_requester_nodeid, params_responder_nodeid, blade_session_id_get(bs_router)); - blade_session_send(bs_router, json, NULL); + blade_session_send(bs_router, json, NULL, NULL); blade_session_read_unlock(bs_router); return KS_STATUS_SUCCESS; @@ -724,26 +710,26 @@ ks_status_t blade_session_process(blade_session_t *bs, cJSON *json) } // reach here if the request was not captured for routing, this SHOULD always mean the message is to be processed by local handlers - bjsonrpc = blade_handle_jsonrpc_lookup(bs->handle, method); + brpc = blade_handle_corerpc_lookup(bs->handle, method); - if (!bjsonrpc) { - ks_log(KS_LOG_DEBUG, "Received unknown jsonrpc method %s\n", method); + if (!brpc) { + ks_log(KS_LOG_DEBUG, "Received unknown rpc method %s\n", method); // @todo send error response, code = -32601 (method not found) return KS_STATUS_FAIL; } - callback = blade_jsonrpc_callback_get(bjsonrpc); + callback = blade_rpc_callback_get(brpc); ks_assert(callback); - blade_jsonrpc_request_create(&bjsonrpcreq, bs->handle, blade_handle_pool_get(bs->handle), bs->id, json, NULL); - ks_assert(bjsonrpcreq); + blade_rpc_request_create(&brpcreq, bs->handle, blade_handle_pool_get(bs->handle), bs->id, json, NULL, NULL); + ks_assert(brpcreq); - disconnect = callback(bjsonrpcreq, blade_jsonrpc_callback_data_get(bjsonrpc)); + disconnect = callback(brpcreq, blade_rpc_callback_data_get(brpc)); - blade_jsonrpc_request_destroy(&bjsonrpcreq); + blade_rpc_request_destroy(&brpcreq); } else { // @note This is scenario 4 // 4) Receiving a response or error (client: method caller or consumer) - blade_jsonrpc_response_callback_t callback = NULL; + blade_rpc_response_callback_t callback = NULL; cJSON *error = NULL; cJSON *result = NULL; cJSON *object = NULL; @@ -773,29 +759,29 @@ ks_status_t blade_session_process(blade_session_t *bs, cJSON *json) } ks_log(KS_LOG_DEBUG, "Session (%s) response (%s <= %s) routing (%s)\n", blade_session_id_get(bs), object_requester_nodeid, object_responder_nodeid, blade_session_id_get(bs_router)); - blade_session_send(bs_router, json, NULL); + blade_session_send(bs_router, json, NULL, NULL); blade_session_read_unlock(bs_router); return KS_STATUS_SUCCESS; } } - bjsonrpcreq = blade_handle_requests_lookup(bs->handle, id); - if (!bjsonrpcreq) { + brpcreq = blade_handle_requests_lookup(bs->handle, id); + if (!brpcreq) { // @todo hangup session entirely? return KS_STATUS_FAIL; } - blade_handle_requests_remove(bjsonrpcreq); + blade_handle_requests_remove(brpcreq); - callback = blade_jsonrpc_request_callback_get(bjsonrpcreq); + callback = blade_rpc_request_callback_get(brpcreq); ks_assert(callback); - blade_jsonrpc_response_create(&bjsonrpcres, bs->handle, bs->pool, bs->id, bjsonrpcreq, json); - ks_assert(bjsonrpcres); + blade_rpc_response_create(&brpcres, bs->handle, bs->pool, bs->id, brpcreq, json); + ks_assert(brpcres); - disconnect = callback(bjsonrpcres); + disconnect = callback(brpcres, blade_rpc_request_callback_data_get(brpcreq)); - blade_jsonrpc_response_destroy(&bjsonrpcres); + blade_rpc_response_destroy(&brpcres); } if (disconnect) { diff --git a/libs/libblade/src/blade_stack.c b/libs/libblade/src/blade_stack.c index 5d141fa1bd..dda42e3233 100644 --- a/libs/libblade/src/blade_stack.c +++ b/libs/libblade/src/blade_stack.c @@ -60,8 +60,10 @@ struct blade_handle_s { ks_hash_t *transports; // registered blade_transport_t blade_transport_t *default_transport; // default wss transport - ks_hash_t *jsonrpcs; // registered blade_jsonrpc_t, for locally processing messages, keyed by the rpc method - ks_hash_t *requests; // outgoing jsonrpc requests waiting for a response, keyed by the message id + ks_hash_t *corerpcs; // registered blade_rpc_t, for locally processing core blade.xxxx messages, keyed by the rpc method + ks_hash_t *requests; // outgoing corerpc requests waiting for a response, keyed by the message id + + ks_hash_t *protocolrpcs; // registered blade_rpc_t, for locally processing protocol messages, keyed by the rpc method ks_hash_t *connections; // active connections keyed by connection id @@ -80,16 +82,14 @@ struct blade_handle_s { // create blade_protocol_method_t to represent a method that is executed with blade.execute, and is part of a protocol made available through blade.publish, registered locally by the protocol and method name (protocol.methodname?), // with a callback handler which should also have the realm available when executed so a single provider can easily provide a protocol for multiple realms with the same method callbacks ks_hash_t *protocols; // master only: protocols that have been published with blade.publish, and the details to locate a protocol provider with blade.locate - ks_hash_t *protocols_cleanup; // master only: keyed by the nodeid, each value should be a list_t* of which contains string values matching the "protocol@realm" keys to remove each nodeid from as a provider during cleanup + ks_hash_t *protocols_cleanup; // master only: keyed by the nodeid, each value is a hash_t* of which contains string keys matching the "protocol@realm" keys to remove each nodeid from as a provider during cleanup }; -ks_bool_t blade_protocol_publish_request_handler(blade_jsonrpc_request_t *breq, void *data); -ks_bool_t blade_protocol_publish_response_handler(blade_jsonrpc_response_t *bres); - -ks_bool_t blade_protocol_locate_request_handler(blade_jsonrpc_request_t *breq, void *data); -ks_bool_t blade_protocol_locate_response_handler(blade_jsonrpc_response_t *bres); +ks_bool_t blade_protocol_publish_request_handler(blade_rpc_request_t *brpcreq, void *data); +ks_bool_t blade_protocol_locate_request_handler(blade_rpc_request_t *brpcreq, void *data); +ks_bool_t blade_protocol_execute_request_handler(blade_rpc_request_t *brpcreq, void *data); typedef struct blade_handle_session_state_callback_registration_s blade_handle_session_state_callback_registration_t; @@ -165,14 +165,23 @@ static void blade_handle_cleanup(ks_pool_t *pool, void *ptr, void *arg, ks_pool_ blade_transport_destroy(&value); // must call destroy to close the transport pool, using FREE_VALUE on the hash would attempt to free the transport from the wrong pool } - while ((it = ks_hash_first(bh->jsonrpcs, KS_UNLOCKED)) != NULL) { + while ((it = ks_hash_first(bh->corerpcs, KS_UNLOCKED)) != NULL) { void *key = NULL; - blade_jsonrpc_t *value = NULL; + blade_rpc_t *value = NULL; ks_hash_this(it, (const void **)&key, NULL, (void **)&value); - ks_hash_remove(bh->jsonrpcs, key); + ks_hash_remove(bh->corerpcs, key); - blade_jsonrpc_destroy(&value); // must call destroy to close the jsonrpc pool, using FREE_VALUE on the hash would attempt to free the jsonrpc from the wrong pool + blade_rpc_destroy(&value); // must call destroy to close the rpc pool, using FREE_VALUE on the hash would attempt to free the rpc from the wrong pool + } + while ((it = ks_hash_first(bh->protocolrpcs, KS_UNLOCKED)) != NULL) { + void *key = NULL; + blade_rpc_t *value = NULL; + + ks_hash_this(it, (const void **)&key, NULL, (void **)&value); + ks_hash_remove(bh->protocolrpcs, key); + + blade_rpc_destroy(&value); // must call destroy to close the rpc pool, using FREE_VALUE on the hash would attempt to free the rpc from the wrong pool } ks_thread_pool_destroy(&bh->tpool); @@ -218,12 +227,15 @@ KS_DECLARE(ks_status_t) blade_handle_create(blade_handle_t **bhP) ks_hash_create(&bh->transports, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_RWLOCK | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_FREE_KEY, bh->pool); ks_assert(bh->transports); - ks_hash_create(&bh->jsonrpcs, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_RWLOCK | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_FREE_KEY, bh->pool); - ks_assert(bh->jsonrpcs); + ks_hash_create(&bh->corerpcs, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_RWLOCK | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_FREE_KEY, bh->pool); + ks_assert(bh->corerpcs); ks_hash_create(&bh->requests, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_RWLOCK | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_FREE_KEY, bh->pool); ks_assert(bh->requests); + ks_hash_create(&bh->protocolrpcs, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_RWLOCK | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_FREE_KEY, bh->pool); + ks_assert(bh->protocolrpcs); + ks_hash_create(&bh->connections, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_RWLOCK | KS_HASH_FLAG_DUP_CHECK, bh->pool); ks_assert(bh->connections); @@ -316,7 +328,7 @@ ks_status_t blade_handle_config(blade_handle_t *bh, config_setting_t *config) KS_DECLARE(ks_status_t) blade_handle_startup(blade_handle_t *bh, config_setting_t *config) { - blade_jsonrpc_t *bjsonrpc = NULL; + blade_rpc_t *brpc = NULL; blade_transport_t *bt = NULL; ks_hash_iterator_t *it = NULL; @@ -327,13 +339,17 @@ KS_DECLARE(ks_status_t) blade_handle_startup(blade_handle_t *bh, config_setting_ return KS_STATUS_FAIL; } - // register internals - blade_jsonrpc_create(&bjsonrpc, bh, "blade.publish", blade_protocol_publish_request_handler, NULL); - blade_handle_jsonrpc_register(bjsonrpc); + // register internal core rpcs for blade.xxx + blade_rpc_create(&brpc, bh, "blade.publish", NULL, NULL, blade_protocol_publish_request_handler, NULL); + blade_handle_corerpc_register(brpc); - blade_jsonrpc_create(&bjsonrpc, bh, "blade.locate", blade_protocol_locate_request_handler, NULL); - blade_handle_jsonrpc_register(bjsonrpc); + blade_rpc_create(&brpc, bh, "blade.locate", NULL, NULL, blade_protocol_locate_request_handler, NULL); + blade_handle_corerpc_register(brpc); + blade_rpc_create(&brpc, bh, "blade.execute", NULL, NULL, blade_protocol_execute_request_handler, NULL); + blade_handle_corerpc_register(brpc); + + // register internal transport for secure websockets blade_transport_wss_create(&bt, bh); ks_assert(bt); bh->default_transport = bt; @@ -663,89 +679,89 @@ KS_DECLARE(ks_status_t) blade_handle_transport_unregister(blade_transport_t *bt) } -KS_DECLARE(ks_status_t) blade_handle_jsonrpc_register(blade_jsonrpc_t *bjsonrpc) +KS_DECLARE(ks_status_t) blade_handle_corerpc_register(blade_rpc_t *brpc) { blade_handle_t *bh = NULL; char *key = NULL; - ks_assert(bjsonrpc); + ks_assert(brpc); - bh = blade_jsonrpc_handle_get(bjsonrpc); + bh = blade_rpc_handle_get(brpc); ks_assert(bh); - key = ks_pstrdup(bh->pool, blade_jsonrpc_method_get(bjsonrpc)); + key = ks_pstrdup(bh->pool, blade_rpc_method_get(brpc)); ks_assert(key); - ks_hash_insert(bh->jsonrpcs, (void *)key, bjsonrpc); + ks_hash_insert(bh->corerpcs, (void *)key, brpc); - ks_log(KS_LOG_DEBUG, "JSONRPC Registered: %s\n", key); + ks_log(KS_LOG_DEBUG, "CoreRPC Registered: %s\n", key); return KS_STATUS_SUCCESS; } -KS_DECLARE(ks_status_t) blade_handle_jsonrpc_unregister(blade_jsonrpc_t *bjsonrpc) +KS_DECLARE(ks_status_t) blade_handle_corerpc_unregister(blade_rpc_t *brpc) { blade_handle_t *bh = NULL; const char *method = NULL; - ks_assert(bjsonrpc); + ks_assert(brpc); - bh = blade_jsonrpc_handle_get(bjsonrpc); + bh = blade_rpc_handle_get(brpc); ks_assert(bh); - method = blade_jsonrpc_method_get(bjsonrpc); + method = blade_rpc_method_get(brpc); ks_assert(method); - ks_log(KS_LOG_DEBUG, "JSONRPC Unregistered: %s\n", method); + ks_log(KS_LOG_DEBUG, "CoreRPC Unregistered: %s\n", method); - ks_hash_remove(bh->jsonrpcs, (void *)method); + ks_hash_remove(bh->corerpcs, (void *)method); return KS_STATUS_SUCCESS; } -KS_DECLARE(blade_jsonrpc_t *) blade_handle_jsonrpc_lookup(blade_handle_t *bh, const char *method) +KS_DECLARE(blade_rpc_t *) blade_handle_corerpc_lookup(blade_handle_t *bh, const char *method) { - blade_jsonrpc_t *bjsonrpc = NULL; + blade_rpc_t *brpc = NULL; ks_assert(bh); ks_assert(method); - bjsonrpc = ks_hash_search(bh->jsonrpcs, (void *)method, KS_READLOCKED); - ks_hash_read_unlock(bh->jsonrpcs); + brpc = ks_hash_search(bh->corerpcs, (void *)method, KS_READLOCKED); + ks_hash_read_unlock(bh->corerpcs); - return bjsonrpc; + return brpc; } -KS_DECLARE(ks_status_t) blade_handle_requests_add(blade_jsonrpc_request_t *bjsonrpcreq) +KS_DECLARE(ks_status_t) blade_handle_requests_add(blade_rpc_request_t *brpcreq) { blade_handle_t *bh = NULL; const char *key = NULL; - ks_assert(bjsonrpcreq); + ks_assert(brpcreq); - bh = blade_jsonrpc_request_handle_get(bjsonrpcreq); + bh = blade_rpc_request_handle_get(brpcreq); ks_assert(bh); - key = ks_pstrdup(bh->pool, blade_jsonrpc_request_messageid_get(bjsonrpcreq)); + key = ks_pstrdup(bh->pool, blade_rpc_request_messageid_get(brpcreq)); ks_assert(key); - ks_hash_insert(bh->requests, (void *)key, bjsonrpcreq); + ks_hash_insert(bh->requests, (void *)key, brpcreq); return KS_STATUS_SUCCESS; } -KS_DECLARE(ks_status_t) blade_handle_requests_remove(blade_jsonrpc_request_t *bjsonrpcreq) +KS_DECLARE(ks_status_t) blade_handle_requests_remove(blade_rpc_request_t *brpcreq) { blade_handle_t *bh = NULL; const char *id = NULL; - ks_assert(bjsonrpcreq); + ks_assert(brpcreq); - bh = blade_jsonrpc_request_handle_get(bjsonrpcreq); + bh = blade_rpc_request_handle_get(brpcreq); ks_assert(bh); - id = blade_jsonrpc_request_messageid_get(bjsonrpcreq); + id = blade_rpc_request_messageid_get(brpcreq); ks_assert(id); ks_hash_remove(bh->requests, (void *)id); @@ -753,17 +769,103 @@ KS_DECLARE(ks_status_t) blade_handle_requests_remove(blade_jsonrpc_request_t *bj return KS_STATUS_SUCCESS; } -KS_DECLARE(blade_jsonrpc_request_t *) blade_handle_requests_lookup(blade_handle_t *bh, const char *id) +KS_DECLARE(blade_rpc_request_t *) blade_handle_requests_lookup(blade_handle_t *bh, const char *id) { - blade_jsonrpc_request_t *bjsonrpcreq = NULL; + blade_rpc_request_t *brpcreq = NULL; ks_assert(bh); ks_assert(id); - bjsonrpcreq = ks_hash_search(bh->requests, (void *)id, KS_READLOCKED); + brpcreq = ks_hash_search(bh->requests, (void *)id, KS_READLOCKED); ks_hash_read_unlock(bh->requests); - return bjsonrpcreq; + return brpcreq; +} + + +KS_DECLARE(ks_status_t) blade_handle_protocolrpc_register(blade_rpc_t *brpc) +{ + blade_handle_t *bh = NULL; + const char *method = NULL; + const char *protocol = NULL; + const char *realm = NULL; + char *key = NULL; + + ks_assert(brpc); + + bh = blade_rpc_handle_get(brpc); + ks_assert(bh); + + method = blade_rpc_method_get(brpc); + ks_assert(method); + + protocol = blade_rpc_protocol_get(brpc); + ks_assert(protocol); + + realm = blade_rpc_realm_get(brpc); + ks_assert(realm); + + key = ks_psprintf(bh->pool, "%s@%s/%s", protocol, realm, method); + ks_assert(key); + + ks_hash_insert(bh->protocolrpcs, (void *)key, brpc); + + ks_log(KS_LOG_DEBUG, "ProtocolRPC Registered: %s\n", key); + + return KS_STATUS_SUCCESS; +} + +KS_DECLARE(ks_status_t) blade_handle_protocolrpc_unregister(blade_rpc_t *brpc) +{ + blade_handle_t *bh = NULL; + const char *method = NULL; + const char *protocol = NULL; + const char *realm = NULL; + char *key = NULL; + + ks_assert(brpc); + + bh = blade_rpc_handle_get(brpc); + ks_assert(bh); + + method = blade_rpc_method_get(brpc); + ks_assert(method); + + protocol = blade_rpc_protocol_get(brpc); + ks_assert(protocol); + + realm = blade_rpc_realm_get(brpc); + ks_assert(realm); + + key = ks_psprintf(bh->pool, "%s@%s/%s", protocol, realm, method); + ks_assert(key); + + ks_log(KS_LOG_DEBUG, "ProtocolRPC Unregistered: %s\n", key); + + ks_hash_remove(bh->protocolrpcs, (void *)key); + + ks_pool_free(bh->pool, &key); + + return KS_STATUS_SUCCESS; +} + +KS_DECLARE(blade_rpc_t *) blade_handle_protocolrpc_lookup(blade_handle_t *bh, const char *method, const char *protocol, const char *realm) +{ + blade_rpc_t *brpc = NULL; + char *key = NULL; + + ks_assert(bh); + ks_assert(method); + ks_assert(protocol); + ks_assert(realm); + + key = ks_psprintf(bh->pool, "%s@%s/%s", protocol, realm, method); + brpc = ks_hash_search(bh->protocolrpcs, (void *)key, KS_READLOCKED); + ks_hash_read_unlock(bh->protocolrpcs); + + ks_pool_free(bh->pool, &key); + + return brpc; } @@ -921,13 +1023,6 @@ KS_DECLARE(blade_session_t *) blade_handle_sessions_lookup(blade_handle_t *bh, c ks_assert(bh); ks_assert(id); - // @todo consider using blade_session_t via reference counting, rather than locking a mutex to simulate a reference count to halt cleanups while in use - // using actual reference counting would mean that mutexes would not need to be held locked when looking up a session by id just to prevent cleanup, - // instead cleanup would automatically occur when the last reference is actually removed (which SHOULD be at the end of the state machine thread), - // which is safer than another thread potentially waiting on the write lock to release while it's being destroyed, or external code forgetting to unlock - // then use short lived mutex or rwl for accessing the content of the session while it is referenced - // this approach should also be used for blade_connection_t, which has a similar threaded state machine - ks_hash_read_lock(bh->sessions); bs = ks_hash_search(bh->sessions, (void *)id, KS_UNLOCKED); if (bs && blade_session_read_lock(bs, KS_FALSE) != KS_STATUS_SUCCESS) bs = NULL; @@ -966,7 +1061,7 @@ KS_DECLARE(void) blade_handle_sessions_send(blade_handle_t *bh, ks_list_t *sessi ks_log(KS_LOG_DEBUG, "This should not happen\n"); continue; } - blade_session_send(bs, json, NULL); + blade_session_send(bs, json, NULL, NULL); blade_session_read_unlock(bs); } ks_list_iterator_stop(sessions); @@ -1026,35 +1121,19 @@ KS_DECLARE(void) blade_handle_session_state_callbacks_execute(blade_session_t *b // BLADE PROTOCOL HANDLERS -// This is where the real work happens for the blade protocol, where routing is done based on the specific intent of the given message, these exist here to simplify -// access to the internals of the blade_handle_t where all the relevant data is stored -// Each jsonrpc method for the blade protocol will require 3 functions: a request generator, a request handler, and a response handler -// Responses can be generated internally and are not required for an isolated entry point, in the case of further external layers like blade.execute, they will be -// handled within the blade protocol handlers to dispatch further execution callbacks, however each jsonrpc exposed to support the blade protocols may deal with -// routing in their own ways as they have different requirements for different blade layer messages. - - -// blade.publish notes -// This jsonrpc is used to notify the master of a new protocol being made available, the purpose of which is to make such protocols able to be located by other nodes with -// only minimal information about the protocol, particularly it's registered name, which is most often the main/only namespace for the protocols methods, however it is -// possible that additional namespaces could be included in this publish as well if the namespaces are defined separately from the protocol name, and the protocol name could -// result in an implicitly created namespace in addition to any others provided. -// Routing Notes: -// When routing a publish request, it only needs to travel upstream to the master node for processing, however in order to receive a publish response the original request -// and response must carry a nodeid for the requesting node (requester-nodeid), technically the master does not need to be provided, but for posterity and consistency -// the master nodeid can be provided in whatever is used for the responder of a request (responder-nodeid). -// By using requester-nodeid and responder-nodeid, these do not need to be swapped in the response, they can simply be copied over, and the routing looks at the -// appropriate field depending on whether it is handling a request or a response to determine the appropriate downstream nodeid +// @todo revisit all error sending. JSONRPC "error" should only be used for json parsing errors, change the rest to internal errors for each of the corerpcs +// @todo all higher level errors should be handled by each of the calls internally so that a normal result response can be sent with an error block inside the result +// which is important for implementation of blade.execute where errors can be relayed back to the requester properly // blade.publish request generator -// @todo add additional async callback to be called upon a publish response to inform caller of the result from the publish response handler -KS_DECLARE(ks_status_t) blade_protocol_publish(blade_handle_t *bh, const char *name, const char *realm) +KS_DECLARE(ks_status_t) blade_protocol_publish(blade_handle_t *bh, const char *name, const char *realm, blade_rpc_response_callback_t callback, void *data) { ks_status_t ret = KS_STATUS_SUCCESS; + blade_session_t *bs = NULL; + ks_pool_t *pool = NULL; cJSON *req = NULL; cJSON *req_params = NULL; - blade_session_t *bs = NULL; ks_assert(bh); ks_assert(name); @@ -1065,7 +1144,10 @@ KS_DECLARE(ks_status_t) blade_protocol_publish(blade_handle_t *bh, const char *n goto done; } - blade_jsonrpc_request_raw_create(blade_handle_pool_get(bh), &req, &req_params, NULL, "blade.publish"); + pool = blade_handle_pool_get(bh); + ks_assert(pool); + + blade_rpc_request_raw_create(pool, &req, &req_params, NULL, "blade.publish"); // fill in the req_params cJSON_AddStringToObject(req_params, "protocol", name); @@ -1082,7 +1164,8 @@ KS_DECLARE(ks_status_t) blade_protocol_publish(blade_handle_t *bh, const char *n // @todo add a parameter containing a block of json for schema definitions for each of the methods being published ks_log(KS_LOG_DEBUG, "Session (%s) publish request started\n", blade_session_id_get(bs)); - ret = blade_session_send(bs, req, blade_protocol_publish_response_handler); // @todo add another callback to parameters so caller can be informed of blade.publish response + + ret = blade_session_send(bs, req, callback, data); // @todo upon return, a provider should register the methods for this protocol to be locally available // prior to receiving a response, if the response is an error then unregister, but if it is successful @@ -1096,7 +1179,7 @@ done: } // blade.publish request handler -ks_bool_t blade_protocol_publish_request_handler(blade_jsonrpc_request_t *breq, void *data) +ks_bool_t blade_protocol_publish_request_handler(blade_rpc_request_t *brpcreq, void *data) { blade_handle_t *bh = NULL; blade_session_t *bs = NULL; @@ -1112,38 +1195,38 @@ ks_bool_t blade_protocol_publish_request_handler(blade_jsonrpc_request_t *breq, const char *bp_key = NULL; ks_hash_t *bp_cleanup = NULL; - ks_assert(breq); + ks_assert(brpcreq); - bh = blade_jsonrpc_request_handle_get(breq); + bh = blade_rpc_request_handle_get(brpcreq); ks_assert(bh); - bs = blade_handle_sessions_lookup(bh, blade_jsonrpc_request_sessionid_get(breq)); + bs = blade_handle_sessions_lookup(bh, blade_rpc_request_sessionid_get(brpcreq)); ks_assert(bs); - req = blade_jsonrpc_request_message_get(breq); + req = blade_rpc_request_message_get(brpcreq); ks_assert(req); req_params = cJSON_GetObjectItem(req, "params"); if (!req_params) { ks_log(KS_LOG_DEBUG, "Session (%s) publish request missing 'params' object\n", blade_session_id_get(bs)); - blade_jsonrpc_error_raw_create(&res, NULL, blade_jsonrpc_request_messageid_get(breq), -32602, "Missing params object"); - blade_session_send(bs, res, NULL); + blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params object"); + blade_session_send(bs, res, NULL, NULL); goto done; } req_params_protocol = cJSON_GetObjectCstr(req_params, "protocol"); if (!req_params_protocol) { ks_log(KS_LOG_DEBUG, "Session (%s) publish request missing 'protocol'\n", blade_session_id_get(bs)); - blade_jsonrpc_error_raw_create(&res, NULL, blade_jsonrpc_request_messageid_get(breq), -32602, "Missing params protocol"); - blade_session_send(bs, res, NULL); + blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params protocol"); + blade_session_send(bs, res, NULL, NULL); goto done; } req_params_realm = cJSON_GetObjectCstr(req_params, "realm"); if (!req_params_realm) { ks_log(KS_LOG_DEBUG, "Session (%s) publish request missing 'realm'\n", blade_session_id_get(bs)); - blade_jsonrpc_error_raw_create(&res, NULL, blade_jsonrpc_request_messageid_get(breq), -32602, "Missing params realm"); - blade_session_send(bs, res, NULL); + blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params realm"); + blade_session_send(bs, res, NULL, NULL); goto done; } @@ -1152,23 +1235,23 @@ ks_bool_t blade_protocol_publish_request_handler(blade_jsonrpc_request_t *breq, req_params_requester_nodeid = cJSON_GetObjectCstr(req_params, "requester-nodeid"); if (!req_params_requester_nodeid) { ks_log(KS_LOG_DEBUG, "Session (%s) publish request missing 'requester-nodeid'\n", blade_session_id_get(bs)); - blade_jsonrpc_error_raw_create(&res, NULL, blade_jsonrpc_request_messageid_get(breq), -32602, "Missing params requester-nodeid"); - blade_session_send(bs, res, NULL); + blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params requester-nodeid"); + blade_session_send(bs, res, NULL, NULL); goto done; } req_params_responder_nodeid = cJSON_GetObjectCstr(req_params, "responder-nodeid"); if (!req_params_responder_nodeid) { ks_log(KS_LOG_DEBUG, "Session (%s) publish request missing 'responder-nodeid'\n", blade_session_id_get(bs)); - blade_jsonrpc_error_raw_create(&res, NULL, blade_jsonrpc_request_messageid_get(breq), -32602, "Missing params responder-nodeid"); - blade_session_send(bs, res, NULL); + blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params responder-nodeid"); + blade_session_send(bs, res, NULL, NULL); goto done; } if (!blade_handle_master_nodeid_compare(bh, req_params_responder_nodeid)) { ks_log(KS_LOG_DEBUG, "Session (%s) publish request invalid 'responder-nodeid' (%s)\n", blade_session_id_get(bs), req_params_responder_nodeid); - blade_jsonrpc_error_raw_create(&res, NULL, blade_jsonrpc_request_messageid_get(breq), -32602, "Invalid params responder-nodeid"); - blade_session_send(bs, res, NULL); + blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Invalid params responder-nodeid"); + blade_session_send(bs, res, NULL, NULL); goto done; } @@ -1206,7 +1289,7 @@ ks_bool_t blade_protocol_publish_request_handler(blade_jsonrpc_request_t *breq, // build the actual response finally - blade_jsonrpc_response_raw_create(&res, &res_result, blade_jsonrpc_request_messageid_get(breq)); + blade_rpc_response_raw_create(&res, &res_result, blade_rpc_request_messageid_get(brpcreq)); cJSON_AddStringToObject(res_result, "protocol", req_params_protocol); cJSON_AddStringToObject(res_result, "realm", req_params_realm); @@ -1214,7 +1297,7 @@ ks_bool_t blade_protocol_publish_request_handler(blade_jsonrpc_request_t *breq, cJSON_AddStringToObject(res_result, "responder-nodeid", req_params_responder_nodeid); // request was just received on a session that is already read locked, so we can assume the response goes back on the same session without further lookup - blade_session_send(bs, res, NULL); + blade_session_send(bs, res, NULL, NULL); done: @@ -1224,66 +1307,15 @@ done: return KS_FALSE; } -// blade.publish response handler -ks_bool_t blade_protocol_publish_response_handler(blade_jsonrpc_response_t *bres) -{ - blade_handle_t *bh = NULL; - blade_session_t *bs = NULL; - cJSON *res = NULL; - cJSON *res_error = NULL; - cJSON *res_result = NULL; - cJSON *res_object = NULL; - //const char *requester_nodeid = NULL; - //const char *responder_nodeid = NULL; - - ks_assert(bres); - - bh = blade_jsonrpc_response_handle_get(bres); - ks_assert(bh); - - bs = blade_handle_sessions_lookup(bh, blade_jsonrpc_response_sessionid_get(bres)); - ks_assert(bs); - - res = blade_jsonrpc_response_message_get(bres); - ks_assert(res); - - res_error = cJSON_GetObjectItem(res, "error"); - res_result = cJSON_GetObjectItem(res, "result"); - - if (!res_error && !res_result) { - ks_log(KS_LOG_DEBUG, "Session (%s) publish response missing 'error' or 'result' object\n", blade_session_id_get(bs)); - goto done; - } - res_object = res_error ? res_error : res_result; - - //requester_nodeid = cJSON_GetObjectCstr(res_object, "requester-nodeid"); - //responder_nodeid = cJSON_GetObjectCstr(res_object, "responder-nodeid"); - - ks_log(KS_LOG_DEBUG, "Session (%s) publish response processing\n", blade_session_id_get(bs)); - - if (res_error) { - // @todo process error response - ks_log(KS_LOG_DEBUG, "Session (%s) publish response error... add details\n", blade_session_id_get(bs)); - goto done; - } - - // @todo process result response - -done: - if (bs) blade_session_read_unlock(bs); - - return KS_FALSE; -} - // blade.locate request generator -// @todo add additional async callback to be called upon a locate response to inform caller of the result from the locate response handler -KS_DECLARE(ks_status_t) blade_protocol_locate(blade_handle_t *bh, const char *name, const char *realm) +KS_DECLARE(ks_status_t) blade_protocol_locate(blade_handle_t *bh, const char *name, const char *realm, blade_rpc_response_callback_t callback, void *data) { ks_status_t ret = KS_STATUS_SUCCESS; + blade_session_t *bs = NULL; + ks_pool_t *pool = NULL; cJSON *req = NULL; cJSON *req_params = NULL; - blade_session_t *bs = NULL; ks_assert(bh); ks_assert(name); @@ -1294,7 +1326,10 @@ KS_DECLARE(ks_status_t) blade_protocol_locate(blade_handle_t *bh, const char *na goto done; } - blade_jsonrpc_request_raw_create(blade_handle_pool_get(bh), &req, &req_params, NULL, "blade.locate"); + pool = blade_handle_pool_get(bh); + ks_assert(pool); + + blade_rpc_request_raw_create(pool, &req, &req_params, NULL, "blade.locate"); // fill in the req_params cJSON_AddStringToObject(req_params, "protocol", name); @@ -1309,11 +1344,8 @@ KS_DECLARE(ks_status_t) blade_protocol_locate(blade_handle_t *bh, const char *na ks_rwl_read_unlock(bh->master_nodeid_rwl); ks_log(KS_LOG_DEBUG, "Session (%s) locate request started\n", blade_session_id_get(bs)); - ret = blade_session_send(bs, req, blade_protocol_locate_response_handler); // @todo add another callback to parameters so caller can be informed of blade.publish response - // @todo upon return, a provider should register the methods for this protocol to be locally available - // prior to receiving a response, if the response is an error then unregister, but if it is successful - // then the node is already primed to receive any immediate requests + ret = blade_session_send(bs, req, callback, data); done: if (req) cJSON_Delete(req); @@ -1323,7 +1355,7 @@ done: } // blade.locate request handler -ks_bool_t blade_protocol_locate_request_handler(blade_jsonrpc_request_t *breq, void *data) +ks_bool_t blade_protocol_locate_request_handler(blade_rpc_request_t *brpcreq, void *data) { blade_handle_t *bh = NULL; blade_session_t *bs = NULL; @@ -1339,38 +1371,38 @@ ks_bool_t blade_protocol_locate_request_handler(blade_jsonrpc_request_t *breq, v blade_protocol_t *bp = NULL; const char *bp_key = NULL; - ks_assert(breq); + ks_assert(brpcreq); - bh = blade_jsonrpc_request_handle_get(breq); + bh = blade_rpc_request_handle_get(brpcreq); ks_assert(bh); - bs = blade_handle_sessions_lookup(bh, blade_jsonrpc_request_sessionid_get(breq)); + bs = blade_handle_sessions_lookup(bh, blade_rpc_request_sessionid_get(brpcreq)); ks_assert(bs); - req = blade_jsonrpc_request_message_get(breq); + req = blade_rpc_request_message_get(brpcreq); ks_assert(req); req_params = cJSON_GetObjectItem(req, "params"); if (!req_params) { ks_log(KS_LOG_DEBUG, "Session (%s) locate request missing 'params' object\n", blade_session_id_get(bs)); - blade_jsonrpc_error_raw_create(&res, NULL, blade_jsonrpc_request_messageid_get(breq), -32602, "Missing params object"); - blade_session_send(bs, res, NULL); + blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params object"); + blade_session_send(bs, res, NULL, NULL); goto done; } req_params_protocol = cJSON_GetObjectCstr(req_params, "protocol"); if (!req_params_protocol) { ks_log(KS_LOG_DEBUG, "Session (%s) locate request missing 'protocol'\n", blade_session_id_get(bs)); - blade_jsonrpc_error_raw_create(&res, NULL, blade_jsonrpc_request_messageid_get(breq), -32602, "Missing params protocol"); - blade_session_send(bs, res, NULL); + blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params protocol"); + blade_session_send(bs, res, NULL, NULL); goto done; } req_params_realm = cJSON_GetObjectCstr(req_params, "realm"); if (!req_params_realm) { ks_log(KS_LOG_DEBUG, "Session (%s) locate request missing 'realm'\n", blade_session_id_get(bs)); - blade_jsonrpc_error_raw_create(&res, NULL, blade_jsonrpc_request_messageid_get(breq), -32602, "Missing params realm"); - blade_session_send(bs, res, NULL); + blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params realm"); + blade_session_send(bs, res, NULL, NULL); goto done; } @@ -1379,23 +1411,23 @@ ks_bool_t blade_protocol_locate_request_handler(blade_jsonrpc_request_t *breq, v req_params_requester_nodeid = cJSON_GetObjectCstr(req_params, "requester-nodeid"); if (!req_params_requester_nodeid) { ks_log(KS_LOG_DEBUG, "Session (%s) locate request missing 'requester-nodeid'\n", blade_session_id_get(bs)); - blade_jsonrpc_error_raw_create(&res, NULL, blade_jsonrpc_request_messageid_get(breq), -32602, "Missing params requester-nodeid"); - blade_session_send(bs, res, NULL); + blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params requester-nodeid"); + blade_session_send(bs, res, NULL, NULL); goto done; } req_params_responder_nodeid = cJSON_GetObjectCstr(req_params, "responder-nodeid"); if (!req_params_responder_nodeid) { ks_log(KS_LOG_DEBUG, "Session (%s) locate request missing 'responder-nodeid'\n", blade_session_id_get(bs)); - blade_jsonrpc_error_raw_create(&res, NULL, blade_jsonrpc_request_messageid_get(breq), -32602, "Missing params responder-nodeid"); - blade_session_send(bs, res, NULL); + blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params responder-nodeid"); + blade_session_send(bs, res, NULL, NULL); goto done; } if (!blade_handle_master_nodeid_compare(bh, req_params_responder_nodeid)) { ks_log(KS_LOG_DEBUG, "Session (%s) locate request invalid 'responder-nodeid' (%s)\n", blade_session_id_get(bs), req_params_responder_nodeid); - blade_jsonrpc_error_raw_create(&res, NULL, blade_jsonrpc_request_messageid_get(breq), -32602, "Invalid params responder-nodeid"); - blade_session_send(bs, res, NULL); + blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Invalid params responder-nodeid"); + blade_session_send(bs, res, NULL, NULL); goto done; } @@ -1424,7 +1456,7 @@ ks_bool_t blade_protocol_locate_request_handler(blade_jsonrpc_request_t *breq, v // build the actual response finally - blade_jsonrpc_response_raw_create(&res, &res_result, blade_jsonrpc_request_messageid_get(breq)); + blade_rpc_response_raw_create(&res, &res_result, blade_rpc_request_messageid_get(brpcreq)); cJSON_AddStringToObject(res_result, "protocol", req_params_protocol); cJSON_AddStringToObject(res_result, "realm", req_params_realm); @@ -1433,7 +1465,7 @@ ks_bool_t blade_protocol_locate_request_handler(blade_jsonrpc_request_t *breq, v cJSON_AddItemToObject(res_result, "providers", res_result_providers); // request was just received on a session that is already read locked, so we can assume the response goes back on the same session without further lookup - blade_session_send(bs, res, NULL); + blade_session_send(bs, res, NULL, NULL); done: @@ -1443,85 +1475,345 @@ done: return KS_FALSE; } -// blade.locate response handler -ks_bool_t blade_protocol_locate_response_handler(blade_jsonrpc_response_t *bres) + +// blade.execute request generator +KS_DECLARE(ks_status_t) blade_protocol_execute(blade_handle_t *bh, const char *nodeid, const char *method, const char *protocol, const char *realm, cJSON *params, blade_rpc_response_callback_t callback, void *data) { - blade_handle_t *bh = NULL; + ks_status_t ret = KS_STATUS_SUCCESS; blade_session_t *bs = NULL; - cJSON *res = NULL; - cJSON *res_error = NULL; - cJSON *res_result = NULL; - cJSON *res_object = NULL; - cJSON *res_result_providers = NULL; - const char *requester_nodeid = NULL; - const char *responder_nodeid = NULL; - const char *res_result_protocol = NULL; - const char *res_result_realm = NULL; + ks_pool_t *pool = NULL; + cJSON *req = NULL; + cJSON *req_params = NULL; - ks_assert(bres); - - bh = blade_jsonrpc_response_handle_get(bres); ks_assert(bh); + ks_assert(nodeid); + ks_assert(method); + ks_assert(protocol); + ks_assert(realm); - bs = blade_handle_sessions_lookup(bh, blade_jsonrpc_response_sessionid_get(bres)); - ks_assert(bs); - - res = blade_jsonrpc_response_message_get(bres); - ks_assert(res); - - res_error = cJSON_GetObjectItem(res, "error"); - res_result = cJSON_GetObjectItem(res, "result"); - - if (!res_error && !res_result) { - ks_log(KS_LOG_DEBUG, "Session (%s) locate response missing 'error' or 'result' object\n", blade_session_id_get(bs)); - goto done; - } - res_object = res_error ? res_error : res_result; - - requester_nodeid = cJSON_GetObjectCstr(res_object, "requester-nodeid"); - responder_nodeid = cJSON_GetObjectCstr(res_object, "responder-nodeid"); - - ks_log(KS_LOG_DEBUG, "Session (%s) locate response processing\n", blade_session_id_get(bs)); - - if (res_error) { - // @todo process error response - ks_log(KS_LOG_DEBUG, "Session (%s) locate response error... add details\n", blade_session_id_get(bs)); - goto done; - } - - // process result response - - res_result_protocol = cJSON_GetObjectCstr(res_result, "protocol"); - if (!res_result_protocol) { - ks_log(KS_LOG_DEBUG, "Session (%s) locate response missing 'protocol'\n", blade_session_id_get(bs)); - goto done; - } - - res_result_realm = cJSON_GetObjectCstr(res_result, "realm"); - if (!res_result_realm) { - ks_log(KS_LOG_DEBUG, "Session (%s) locate response missing 'realm'\n", blade_session_id_get(bs)); - goto done; - } - - res_result_providers = cJSON_GetObjectItem(res_result, "providers"); - if (!res_result_providers) { - ks_log(KS_LOG_DEBUG, "Session (%s) locate response missing 'providers'\n", blade_session_id_get(bs)); - goto done; - } - - for (int index = 0; index < cJSON_GetArraySize(res_result_providers); ++index) { - cJSON *elem = cJSON_GetArrayItem(res_result_providers, index); - if (elem->type == cJSON_String) { - ks_log(KS_LOG_DEBUG, "Session (%s) locate (%s@%s) provider (%s)\n", blade_session_id_get(bs), res_result_protocol, res_result_realm, elem->valuestring); + if (!(bs = blade_handle_route_lookup(bh, nodeid))) { + if (!(bs = blade_handle_sessions_upstream(bh))) { + ret = KS_STATUS_DISCONNECTED; + goto done; } } + pool = blade_handle_pool_get(bh); + ks_assert(pool); + + blade_rpc_request_raw_create(pool, &req, &req_params, NULL, "blade.execute"); + + // fill in the req_params + cJSON_AddStringToObject(req_params, "method", method); + cJSON_AddStringToObject(req_params, "protocol", protocol); + cJSON_AddStringToObject(req_params, "realm", realm); + + ks_rwl_read_lock(bh->local_nodeid_rwl); + cJSON_AddStringToObject(req_params, "requester-nodeid", bh->local_nodeid); + ks_rwl_read_unlock(bh->local_nodeid_rwl); + + ks_rwl_read_lock(bh->master_nodeid_rwl); + cJSON_AddStringToObject(req_params, "responder-nodeid", nodeid); + ks_rwl_read_unlock(bh->master_nodeid_rwl); + + if (params) cJSON_AddItemToObject(req_params, "params", cJSON_Duplicate(params, 1)); + + ks_log(KS_LOG_DEBUG, "Session (%s) execute request started\n", blade_session_id_get(bs)); + + ret = blade_session_send(bs, req, callback, data); + done: + if (req) cJSON_Delete(req); if (bs) blade_session_read_unlock(bs); - return KS_FALSE; + return ret; } +// blade.execute request handler +ks_bool_t blade_protocol_execute_request_handler(blade_rpc_request_t *brpcreq, void *data) +{ + ks_bool_t ret = KS_FALSE; + blade_handle_t *bh = NULL; + blade_session_t *bs = NULL; + cJSON *req = NULL; + cJSON *req_params = NULL; + const char *req_params_method = NULL; + const char *req_params_protocol = NULL; + const char *req_params_realm = NULL; + const char *req_params_requester_nodeid = NULL; + const char *req_params_responder_nodeid = NULL; + blade_rpc_t *brpc = NULL; + blade_rpc_request_callback_t callback = NULL; + cJSON *res = NULL; + + ks_assert(brpcreq); + + bh = blade_rpc_request_handle_get(brpcreq); + ks_assert(bh); + + bs = blade_handle_sessions_lookup(bh, blade_rpc_request_sessionid_get(brpcreq)); + ks_assert(bs); + + req = blade_rpc_request_message_get(brpcreq); + ks_assert(req); + + req_params = cJSON_GetObjectItem(req, "params"); + if (!req_params) { + ks_log(KS_LOG_DEBUG, "Session (%s) execute request missing 'params' object\n", blade_session_id_get(bs)); + blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params object"); + blade_session_send(bs, res, NULL, NULL); + goto done; + } + + req_params_method = cJSON_GetObjectCstr(req_params, "method"); + if (!req_params_method) { + ks_log(KS_LOG_DEBUG, "Session (%s) execute request missing 'method'\n", blade_session_id_get(bs)); + blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params method"); + blade_session_send(bs, res, NULL, NULL); + goto done; + } + + req_params_protocol = cJSON_GetObjectCstr(req_params, "protocol"); + if (!req_params_protocol) { + ks_log(KS_LOG_DEBUG, "Session (%s) execute request missing 'protocol'\n", blade_session_id_get(bs)); + blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params protocol"); + blade_session_send(bs, res, NULL, NULL); + goto done; + } + + req_params_realm = cJSON_GetObjectCstr(req_params, "realm"); + if (!req_params_realm) { + ks_log(KS_LOG_DEBUG, "Session (%s) execute request missing 'realm'\n", blade_session_id_get(bs)); + blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params realm"); + blade_session_send(bs, res, NULL, NULL); + goto done; + } + + // @todo confirm the realm is permitted for the session, this gets complicated with subdomains, skipping for now + + req_params_requester_nodeid = cJSON_GetObjectCstr(req_params, "requester-nodeid"); + if (!req_params_requester_nodeid) { + ks_log(KS_LOG_DEBUG, "Session (%s) execute request missing 'requester-nodeid'\n", blade_session_id_get(bs)); + blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params requester-nodeid"); + blade_session_send(bs, res, NULL, NULL); + goto done; + } + + req_params_responder_nodeid = cJSON_GetObjectCstr(req_params, "responder-nodeid"); + if (!req_params_responder_nodeid) { + ks_log(KS_LOG_DEBUG, "Session (%s) execute request missing 'responder-nodeid'\n", blade_session_id_get(bs)); + blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params responder-nodeid"); + blade_session_send(bs, res, NULL, NULL); + goto done; + } + + ks_log(KS_LOG_DEBUG, "Session (%s) execute request (%s to %s) processing\n", blade_session_id_get(bs), req_params_requester_nodeid, req_params_responder_nodeid); + + // @todo pull out nested params block if it exists and check against schema later, so blade_rpc_t should be able to carry a schema with it, even though blade.xxx may not associate one + + brpc = blade_handle_protocolrpc_lookup(bh, req_params_method, req_params_protocol, req_params_realm); + if (!brpc) { + ks_log(KS_LOG_DEBUG, "Session (%s) execute request unknown method\n", blade_session_id_get(bs)); + blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Unknown params method"); + blade_session_send(bs, res, NULL, NULL); + goto done; + } + + callback = blade_rpc_callback_get(brpc); + if (callback) ret = callback(brpcreq, blade_rpc_callback_data_get(brpc)); + +done: + + if (res) cJSON_Delete(res); + if (bs) blade_session_read_unlock(bs); + + return ret; +} + +KS_DECLARE(cJSON *) blade_protocol_execute_request_params_get(blade_rpc_request_t *brpcreq) +{ + cJSON *req = NULL; + cJSON *req_params = NULL; + cJSON *req_params_params = NULL; + + ks_assert(brpcreq); + + req = blade_rpc_request_message_get(brpcreq); + ks_assert(req); + + req_params = cJSON_GetObjectItem(req, "params"); + if (req_params) req_params_params = cJSON_GetObjectItem(req_params, "params"); + + return req_params_params; +} + +KS_DECLARE(cJSON *) blade_protocol_execute_response_result_get(blade_rpc_response_t *brpcres) +{ + cJSON *res = NULL; + cJSON *res_result = NULL; + cJSON *res_result_result = NULL; + + ks_assert(brpcres); + + res = blade_rpc_response_message_get(brpcres); + ks_assert(res); + + res_result = cJSON_GetObjectItem(res, "result"); + if (res_result) res_result_result = cJSON_GetObjectItem(res_result, "result"); + + return res_result_result; +} + +// @note added blade_rpc_request_duplicate() to support async responding where the callbacks return immediately and the blade_rpc_request_t will be destroyed, +// in such cases duplicate the request to retain a copy for passing to blade_protocol_execute_response_send when sending the response as it contains everything +// needed to produce a response except the inner result block for blade.execute and call blade_rpc_request_destroy() to clean up the duplicate when finished +KS_DECLARE(void) blade_protocol_execute_response_send(blade_rpc_request_t *brpcreq, cJSON *result) +{ + blade_handle_t *bh = NULL; + blade_session_t *bs = NULL; + cJSON *req = NULL; + cJSON *req_params = NULL; + //const char *req_params_method = NULL; + const char *req_params_protocol = NULL; + const char *req_params_realm = NULL; + const char *req_params_requester_nodeid = NULL; + const char *req_params_responder_nodeid = NULL; + cJSON *res = NULL; + cJSON *res_result = NULL; + + ks_assert(brpcreq); + + bh = blade_rpc_request_handle_get(brpcreq); + ks_assert(bh); + + bs = blade_handle_sessions_lookup(bh, blade_rpc_request_sessionid_get(brpcreq)); + ks_assert(bs); + + req = blade_rpc_request_message_get(brpcreq); + ks_assert(req); + + req_params = cJSON_GetObjectItem(req, "params"); + ks_assert(req_params); + + req_params_protocol = cJSON_GetObjectCstr(req_params, "protocol"); + ks_assert(req_params_protocol); + + req_params_realm = cJSON_GetObjectCstr(req_params, "realm"); + ks_assert(req_params_realm); + + req_params_requester_nodeid = cJSON_GetObjectCstr(req_params, "requester-nodeid"); + ks_assert(req_params_requester_nodeid); + + req_params_responder_nodeid = cJSON_GetObjectCstr(req_params, "responder-nodeid"); + ks_assert(req_params_responder_nodeid); + + // build the actual response finally, wrap this into blade_protocol_execute_response_send() + blade_rpc_response_raw_create(&res, &res_result, blade_rpc_request_messageid_get(brpcreq)); + + cJSON_AddStringToObject(res_result, "protocol", req_params_protocol); + cJSON_AddStringToObject(res_result, "realm", req_params_realm); + cJSON_AddStringToObject(res_result, "requester-nodeid", req_params_requester_nodeid); + cJSON_AddStringToObject(res_result, "responder-nodeid", req_params_responder_nodeid); + if (result) cJSON_AddItemToObject(res_result, "result", cJSON_Duplicate(result, 1)); + + // request was just received on a session that is already read locked, so we can assume the response goes back on the same session without further lookup + blade_session_send(bs, res, NULL, NULL); + + cJSON_Delete(res); + + blade_session_read_unlock(bs); +} + +// blade.locate response handler +//ks_bool_t blade_protocol_locate_response_handler(blade_rpc_response_t *brpcres, void *data) +//{ +// ks_bool_t ret = KS_FALSE; +// blade_handle_t *bh = NULL; +// blade_session_t *bs = NULL; +// blade_rpc_response_callback_wrapper_t *wrapper = NULL; +// blade_rpc_response_callback_t callback = NULL; +// cJSON *res = NULL; +// cJSON *res_error = NULL; +// cJSON *res_result = NULL; +// cJSON *res_object = NULL; +// //cJSON *res_result_providers = NULL; +// const char *requester_nodeid = NULL; +// const char *responder_nodeid = NULL; +// //const char *res_result_protocol = NULL; +// //const char *res_result_realm = NULL; +// +// ks_assert(brpcres); +// ks_assert(data); +// +// wrapper = (blade_rpc_response_callback_wrapper_t *)data; +// callback = wrapper->callback; +// data = wrapper->data; +// ks_pool_free(wrapper->pool, &wrapper); +// +// bh = blade_rpc_response_handle_get(brpcres); +// ks_assert(bh); +// +// bs = blade_handle_sessions_lookup(bh, blade_rpc_response_sessionid_get(brpcres)); +// ks_assert(bs); +// +// res = blade_rpc_response_message_get(brpcres); +// ks_assert(res); +// +// res_error = cJSON_GetObjectItem(res, "error"); +// res_result = cJSON_GetObjectItem(res, "result"); +// +// if (!res_error && !res_result) { +// ks_log(KS_LOG_DEBUG, "Session (%s) locate response missing 'error' or 'result' object\n", blade_session_id_get(bs)); +// goto done; +// } +// res_object = res_error ? res_error : res_result; +// +// requester_nodeid = cJSON_GetObjectCstr(res_object, "requester-nodeid"); +// responder_nodeid = cJSON_GetObjectCstr(res_object, "responder-nodeid"); +// +// ks_log(KS_LOG_DEBUG, "Session (%s) locate response processing\n", blade_session_id_get(bs)); +// +// if (callback) ret = callback(brpcres, data); +// +// //if (res_error) { +// // // @todo process error response +// // ks_log(KS_LOG_DEBUG, "Session (%s) locate response error... add details\n", blade_session_id_get(bs)); +// // goto done; +// //} +// +// // process result response +// +// //res_result_protocol = cJSON_GetObjectCstr(res_result, "protocol"); +// //if (!res_result_protocol) { +// // ks_log(KS_LOG_DEBUG, "Session (%s) locate response missing 'protocol'\n", blade_session_id_get(bs)); +// // goto done; +// //} +// +// //res_result_realm = cJSON_GetObjectCstr(res_result, "realm"); +// //if (!res_result_realm) { +// // ks_log(KS_LOG_DEBUG, "Session (%s) locate response missing 'realm'\n", blade_session_id_get(bs)); +// // goto done; +// //} +// +// //res_result_providers = cJSON_GetObjectItem(res_result, "providers"); +// //if (!res_result_providers) { +// // ks_log(KS_LOG_DEBUG, "Session (%s) locate response missing 'providers'\n", blade_session_id_get(bs)); +// // goto done; +// //} +// +// //for (int index = 0; index < cJSON_GetArraySize(res_result_providers); ++index) { +// // cJSON *elem = cJSON_GetArrayItem(res_result_providers, index); +// // if (elem->type == cJSON_String) { +// // ks_log(KS_LOG_DEBUG, "Session (%s) locate (%s@%s) provider (%s)\n", blade_session_id_get(bs), res_result_protocol, res_result_realm, elem->valuestring); +// // } +// //} +// +//done: +// if (bs) blade_session_read_unlock(bs); +// +// return ret; +//} + /* For Emacs: * Local Variables: * mode:c diff --git a/libs/libblade/src/blade_transport_wss.c b/libs/libblade/src/blade_transport_wss.c index ddf7e7be99..52c0b31b22 100644 --- a/libs/libblade/src/blade_transport_wss.c +++ b/libs/libblade/src/blade_transport_wss.c @@ -687,7 +687,7 @@ ks_status_t blade_transport_wss_onreceive(blade_connection_t *bc, cJSON **json) return blade_transport_wss_link_read(btwssl, json); } -ks_status_t blade_transport_wss_jsonrpc_error_send(blade_connection_t *bc, const char *id, int32_t code, const char *message) +ks_status_t blade_transport_wss_rpc_error_send(blade_connection_t *bc, const char *id, int32_t code, const char *message) { ks_status_t ret = KS_STATUS_SUCCESS; blade_transport_wss_link_t *btwssl = NULL; @@ -699,7 +699,7 @@ ks_status_t blade_transport_wss_jsonrpc_error_send(blade_connection_t *bc, const btwssl = (blade_transport_wss_link_t *)blade_connection_transport_get(bc); - blade_jsonrpc_error_raw_create(&json, NULL, id, code, message); + blade_rpc_error_raw_create(&json, NULL, id, code, message); if (blade_transport_wss_link_write(btwssl, json) != KS_STATUS_SUCCESS) { ks_log(KS_LOG_DEBUG, "Failed to write error message\n"); @@ -761,18 +761,18 @@ blade_connection_state_hook_t blade_transport_wss_onstate_startup_inbound(blade_ if (!json_req) { ks_log(KS_LOG_DEBUG, "Failed to receive message before timeout\n"); - blade_transport_wss_jsonrpc_error_send(bc, NULL, -32600, "Timeout while expecting request"); + blade_transport_wss_rpc_error_send(bc, NULL, -32600, "Timeout while expecting request"); ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT; goto done; } - // @todo start here for a reusable handler for "blade.connect" request jsonrpc method within transport implementations, + // @todo start here for a reusable handler for "blade.connect" request rpc method within transport implementations, // output 2 parameters for response and error, if an error occurs, send it, otherwise send the response jsonrpc = cJSON_GetObjectCstr(json_req, "jsonrpc"); // @todo check for definitions of these keys and fixed values if (!jsonrpc || strcmp(jsonrpc, "2.0")) { ks_log(KS_LOG_DEBUG, "Received message is not the expected protocol\n"); - blade_transport_wss_jsonrpc_error_send(bc, NULL, -32600, "Invalid request, missing 'jsonrpc' field"); + blade_transport_wss_rpc_error_send(bc, NULL, -32600, "Invalid request, missing 'jsonrpc' field"); ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT; goto done; } @@ -780,7 +780,7 @@ blade_connection_state_hook_t blade_transport_wss_onstate_startup_inbound(blade_ id = cJSON_GetObjectCstr(json_req, "id"); if (!id) { ks_log(KS_LOG_DEBUG, "Received message is missing 'id'\n"); - blade_transport_wss_jsonrpc_error_send(bc, NULL, -32600, "Invalid request, missing 'id' field"); + blade_transport_wss_rpc_error_send(bc, NULL, -32600, "Invalid request, missing 'id' field"); ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT; goto done; } @@ -788,7 +788,7 @@ blade_connection_state_hook_t blade_transport_wss_onstate_startup_inbound(blade_ method = cJSON_GetObjectCstr(json_req, "method"); if (!method || strcasecmp(method, "blade.connect")) { ks_log(KS_LOG_DEBUG, "Received message is missing 'method' or is an unexpected method\n"); - blade_transport_wss_jsonrpc_error_send(bc, id, -32601, "Missing or unexpected 'method' field"); + blade_transport_wss_rpc_error_send(bc, id, -32601, "Missing or unexpected 'method' field"); ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT; goto done; } @@ -826,7 +826,7 @@ blade_connection_state_hook_t blade_transport_wss_onstate_startup_inbound(blade_ if (blade_session_startup(bs) != KS_STATUS_SUCCESS) { ks_log(KS_LOG_DEBUG, "Session (%s) startup failed\n", nodeid); - blade_transport_wss_jsonrpc_error_send(bc, id, -32603, "Internal error, session could not be started"); + blade_transport_wss_rpc_error_send(bc, id, -32603, "Internal error, session could not be started"); blade_session_read_unlock(bs); blade_session_destroy(&bs); ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT; @@ -863,7 +863,7 @@ blade_connection_state_hook_t blade_transport_wss_onstate_startup_inbound(blade_ ks_hash_read_unlock(realms); } - blade_jsonrpc_response_raw_create(&json_res, &json_result, id); + blade_rpc_response_raw_create(&json_res, &json_result, id); ks_assert(json_res); cJSON_AddStringToObject(json_result, "nodeid", nodeid); @@ -872,7 +872,7 @@ blade_connection_state_hook_t blade_transport_wss_onstate_startup_inbound(blade_ master_nodeid = blade_handle_master_nodeid_copy(bh, pool); if (!master_nodeid) { ks_log(KS_LOG_DEBUG, "Master nodeid unavailable\n"); - blade_transport_wss_jsonrpc_error_send(bc, id, -32602, "Master nodeid unavailable"); + blade_transport_wss_rpc_error_send(bc, id, -32602, "Master nodeid unavailable"); ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT; goto done; } @@ -961,7 +961,7 @@ blade_connection_state_hook_t blade_transport_wss_onstate_startup_outbound(blade goto done; } - blade_jsonrpc_request_raw_create(pool, &json_req, &json_params, &mid, "blade.connect"); + blade_rpc_request_raw_create(pool, &json_req, &json_params, &mid, "blade.connect"); ks_assert(json_req); if (btwssl->session_id) cJSON_AddStringToObject(json_params, "session-id", btwssl->session_id); @@ -988,7 +988,7 @@ blade_connection_state_hook_t blade_transport_wss_onstate_startup_outbound(blade goto done; } - // @todo start here for a reusable handler for "blade.connect" response jsonrpc method within transport implementations + // @todo start here for a reusable handler for "blade.connect" response rpc method within transport implementations jsonrpc = cJSON_GetObjectCstr(json_res, "jsonrpc"); // @todo check for definitions of these keys and fixed values if (!jsonrpc || strcmp(jsonrpc, "2.0")) { diff --git a/libs/libblade/src/include/blade.h b/libs/libblade/src/include/blade.h index cc8ecb6ae7..6e889b6808 100644 --- a/libs/libblade/src/include/blade.h +++ b/libs/libblade/src/include/blade.h @@ -41,7 +41,7 @@ #include "blade_stack.h" #include "blade_identity.h" #include "blade_transport.h" -#include "blade_jsonrpc.h" +#include "blade_rpc.h" #include "blade_connection.h" #include "blade_session.h" #include "blade_protocol.h" diff --git a/libs/libblade/src/include/blade_jsonrpc.h b/libs/libblade/src/include/blade_jsonrpc.h deleted file mode 100644 index a988c6f691..0000000000 --- a/libs/libblade/src/include/blade_jsonrpc.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2017, Shane Bryldt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name of the original author; nor the names of any contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _BLADE_JSONRPC_H_ -#define _BLADE_JSONRPC_H_ -#include - -KS_BEGIN_EXTERN_C -KS_DECLARE(ks_status_t) blade_jsonrpc_create(blade_jsonrpc_t **bjsonrpcP, blade_handle_t *bh, const char *method, blade_jsonrpc_request_callback_t callback, void *callback_data); -KS_DECLARE(ks_status_t) blade_jsonrpc_destroy(blade_jsonrpc_t **bjsonrpcP); -KS_DECLARE(blade_handle_t *) blade_jsonrpc_handle_get(blade_jsonrpc_t *bjsonrpc); -KS_DECLARE(const char *) blade_jsonrpc_method_get(blade_jsonrpc_t *bjsonrpc); -KS_DECLARE(blade_jsonrpc_request_callback_t) blade_jsonrpc_callback_get(blade_jsonrpc_t *bjsonrpc); -KS_DECLARE(void *) blade_jsonrpc_callback_data_get(blade_jsonrpc_t *bjsonrpc); - -KS_DECLARE(ks_status_t) blade_jsonrpc_request_create(blade_jsonrpc_request_t **bjsonrpcreqP, - blade_handle_t *bh, - ks_pool_t *pool, - const char *session_id, - cJSON *json, - blade_jsonrpc_response_callback_t callback); -KS_DECLARE(ks_status_t) blade_jsonrpc_request_destroy(blade_jsonrpc_request_t **bjsonrpcreqP); -KS_DECLARE(blade_handle_t *) blade_jsonrpc_request_handle_get(blade_jsonrpc_request_t *bjsonrpcreq); -KS_DECLARE(const char *) blade_jsonrpc_request_sessionid_get(blade_jsonrpc_request_t *bjsonrpcreq); -KS_DECLARE(cJSON *) blade_jsonrpc_request_message_get(blade_jsonrpc_request_t *bjsonrpcreq); -KS_DECLARE(const char *) blade_jsonrpc_request_messageid_get(blade_jsonrpc_request_t *bjsonrpcreq); -KS_DECLARE(blade_jsonrpc_response_callback_t) blade_jsonrpc_request_callback_get(blade_jsonrpc_request_t *bjsonrpcreq); -KS_DECLARE(ks_status_t) blade_jsonrpc_request_raw_create(ks_pool_t *pool, cJSON **json, cJSON **params, const char **id, const char *method); - -KS_DECLARE(ks_status_t) blade_jsonrpc_response_create(blade_jsonrpc_response_t **bjsonrpcresP, - blade_handle_t *bh, - ks_pool_t *pool, - const char *session_id, - blade_jsonrpc_request_t *bjsonrpcreq, - cJSON *json); -KS_DECLARE(ks_status_t) blade_jsonrpc_response_destroy(blade_jsonrpc_response_t **bjsonrpcresP); -KS_DECLARE(ks_status_t) blade_jsonrpc_response_raw_create(cJSON **json, cJSON **result, const char *id); -KS_DECLARE(blade_handle_t *) blade_jsonrpc_response_handle_get(blade_jsonrpc_response_t *bjsonrpcres); -KS_DECLARE(const char *) blade_jsonrpc_response_sessionid_get(blade_jsonrpc_response_t *bjsonrpcres); -KS_DECLARE(blade_jsonrpc_request_t *) blade_jsonrpc_response_request_get(blade_jsonrpc_response_t *bjsonrpcres); -KS_DECLARE(cJSON *) blade_jsonrpc_response_message_get(blade_jsonrpc_response_t *bjsonrpcres); - -KS_DECLARE(ks_status_t) blade_jsonrpc_error_raw_create(cJSON **json, cJSON **error, const char *id, int32_t code, const char *message); -KS_END_EXTERN_C - -#endif - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/include/blade_rpc.h b/libs/libblade/src/include/blade_rpc.h new file mode 100644 index 0000000000..cebd691267 --- /dev/null +++ b/libs/libblade/src/include/blade_rpc.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2017, Shane Bryldt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of the original author; nor the names of any contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _BLADE_RPC_H_ +#define _BLADE_RPC_H_ +#include + +KS_BEGIN_EXTERN_C +KS_DECLARE(ks_status_t) blade_rpc_create(blade_rpc_t **brpcP, blade_handle_t *bh, const char *method, const char *protocol, const char *realm, blade_rpc_request_callback_t callback, void *callback_data); +KS_DECLARE(ks_status_t) blade_rpc_destroy(blade_rpc_t **brpcP); +KS_DECLARE(blade_handle_t *) blade_rpc_handle_get(blade_rpc_t *brpc); +KS_DECLARE(const char *) blade_rpc_method_get(blade_rpc_t *brpc); +KS_DECLARE(const char *) blade_rpc_protocol_get(blade_rpc_t *brpc); +KS_DECLARE(const char *) blade_rpc_realm_get(blade_rpc_t *brpc); +KS_DECLARE(blade_rpc_request_callback_t) blade_rpc_callback_get(blade_rpc_t *brpc); +KS_DECLARE(void *) blade_rpc_callback_data_get(blade_rpc_t *brpc); + +KS_DECLARE(ks_status_t) blade_rpc_request_create(blade_rpc_request_t **brpcreqP, + blade_handle_t *bh, + ks_pool_t *pool, + const char *session_id, + cJSON *json, + blade_rpc_response_callback_t callback, + void *data); +KS_DECLARE(ks_status_t) blade_rpc_request_destroy(blade_rpc_request_t **brpcreqP); +KS_DECLARE(blade_handle_t *) blade_rpc_request_handle_get(blade_rpc_request_t *brpcreq); +KS_DECLARE(const char *) blade_rpc_request_sessionid_get(blade_rpc_request_t *brpcreq); +KS_DECLARE(cJSON *) blade_rpc_request_message_get(blade_rpc_request_t *brpcreq); +KS_DECLARE(const char *) blade_rpc_request_messageid_get(blade_rpc_request_t *brpcreq); +KS_DECLARE(blade_rpc_response_callback_t) blade_rpc_request_callback_get(blade_rpc_request_t *brpcreq); +KS_DECLARE(void *) blade_rpc_request_callback_data_get(blade_rpc_request_t *brpcreq); + +KS_DECLARE(ks_status_t) blade_rpc_request_raw_create(ks_pool_t *pool, cJSON **json, cJSON **params, const char **id, const char *method); + +KS_DECLARE(ks_status_t) blade_rpc_response_create(blade_rpc_response_t **brpcresP, + blade_handle_t *bh, + ks_pool_t *pool, + const char *session_id, + blade_rpc_request_t *brpcreq, + cJSON *json); +KS_DECLARE(ks_status_t) blade_rpc_response_destroy(blade_rpc_response_t **brpcresP); +KS_DECLARE(ks_status_t) blade_rpc_response_raw_create(cJSON **json, cJSON **result, const char *id); +KS_DECLARE(blade_handle_t *) blade_rpc_response_handle_get(blade_rpc_response_t *brpcres); +KS_DECLARE(const char *) blade_rpc_response_sessionid_get(blade_rpc_response_t *brpcres); +KS_DECLARE(blade_rpc_request_t *) blade_rpc_response_request_get(blade_rpc_response_t *brpcres); +KS_DECLARE(cJSON *) blade_rpc_response_message_get(blade_rpc_response_t *brpcres); + +KS_DECLARE(ks_status_t) blade_rpc_error_raw_create(cJSON **json, cJSON **error, const char *id, int32_t code, const char *message); +KS_END_EXTERN_C + +#endif + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: + */ diff --git a/libs/libblade/src/include/blade_session.h b/libs/libblade/src/include/blade_session.h index 01cda3d34f..612fdbccea 100644 --- a/libs/libblade/src/include/blade_session.h +++ b/libs/libblade/src/include/blade_session.h @@ -62,7 +62,7 @@ KS_DECLARE(void) blade_session_hangup(blade_session_t *bs); KS_DECLARE(ks_bool_t) blade_session_terminating(blade_session_t *bs); KS_DECLARE(const char *) blade_session_connection_get(blade_session_t *bs); KS_DECLARE(ks_status_t) blade_session_connection_set(blade_session_t *bs, const char *id); -KS_DECLARE(ks_status_t) blade_session_send(blade_session_t *bs, cJSON *json, blade_jsonrpc_response_callback_t callback); +KS_DECLARE(ks_status_t) blade_session_send(blade_session_t *bs, cJSON *json, blade_rpc_response_callback_t callback, void *data); KS_DECLARE(ks_status_t) blade_session_sending_push(blade_session_t *bs, cJSON *json); KS_DECLARE(ks_status_t) blade_session_sending_pop(blade_session_t *bs, cJSON **json); KS_DECLARE(ks_status_t) blade_session_receiving_push(blade_session_t *bs, cJSON *json); diff --git a/libs/libblade/src/include/blade_stack.h b/libs/libblade/src/include/blade_stack.h index 05c47acf0f..7095ecb192 100644 --- a/libs/libblade/src/include/blade_stack.h +++ b/libs/libblade/src/include/blade_stack.h @@ -66,13 +66,17 @@ KS_DECLARE(blade_session_t *) blade_handle_route_lookup(blade_handle_t *bh, cons KS_DECLARE(ks_status_t) blade_handle_transport_register(blade_transport_t *bt); KS_DECLARE(ks_status_t) blade_handle_transport_unregister(blade_transport_t *bt); -KS_DECLARE(ks_status_t) blade_handle_jsonrpc_register(blade_jsonrpc_t *bjsonrpc); -KS_DECLARE(ks_status_t) blade_handle_jsonrpc_unregister(blade_jsonrpc_t *bjsonrpc); -KS_DECLARE(blade_jsonrpc_t *) blade_handle_jsonrpc_lookup(blade_handle_t *bh, const char *method); +KS_DECLARE(ks_status_t) blade_handle_corerpc_register(blade_rpc_t *brpc); +KS_DECLARE(ks_status_t) blade_handle_corerpc_unregister(blade_rpc_t *brpc); +KS_DECLARE(blade_rpc_t *) blade_handle_corerpc_lookup(blade_handle_t *bh, const char *method); -KS_DECLARE(ks_status_t) blade_handle_requests_add(blade_jsonrpc_request_t *bjsonrpcreq); -KS_DECLARE(ks_status_t) blade_handle_requests_remove(blade_jsonrpc_request_t *bjsonrpcreq); -KS_DECLARE(blade_jsonrpc_request_t *) blade_handle_requests_lookup(blade_handle_t *bh, const char *id); +KS_DECLARE(ks_status_t) blade_handle_requests_add(blade_rpc_request_t *brpcreq); +KS_DECLARE(ks_status_t) blade_handle_requests_remove(blade_rpc_request_t *brpcreq); +KS_DECLARE(blade_rpc_request_t *) blade_handle_requests_lookup(blade_handle_t *bh, const char *id); + +KS_DECLARE(ks_status_t) blade_handle_protocolrpc_register(blade_rpc_t *brpc); +KS_DECLARE(ks_status_t) blade_handle_protocolrpc_unregister(blade_rpc_t *brpc); +KS_DECLARE(blade_rpc_t *) blade_handle_protocolrpc_lookup(blade_handle_t *bh, const char *method, const char *protocol, const char *realm); KS_DECLARE(ks_status_t) blade_handle_connect(blade_handle_t *bh, blade_connection_t **bcP, blade_identity_t *target, const char *session_id); @@ -91,8 +95,15 @@ KS_DECLARE(ks_status_t) blade_handle_session_state_callback_register(blade_handl KS_DECLARE(ks_status_t) blade_handle_session_state_callback_unregister(blade_handle_t *bh, const char *id); KS_DECLARE(void) blade_handle_session_state_callbacks_execute(blade_session_t *bs, blade_session_state_condition_t condition); -KS_DECLARE(ks_status_t) blade_protocol_publish(blade_handle_t *bh, const char *name, const char *realm); -KS_DECLARE(ks_status_t) blade_protocol_locate(blade_handle_t *bh, const char *name, const char *realm); +KS_DECLARE(ks_status_t) blade_protocol_publish(blade_handle_t *bh, const char *name, const char *realm, blade_rpc_response_callback_t callback, void *data); + +KS_DECLARE(ks_status_t) blade_protocol_locate(blade_handle_t *bh, const char *name, const char *realm, blade_rpc_response_callback_t callback, void *data); + +KS_DECLARE(ks_status_t) blade_protocol_execute(blade_handle_t *bh, const char *nodeid, const char *method, const char *protocol, const char *realm, cJSON *params, blade_rpc_response_callback_t callback, void *data); +KS_DECLARE(cJSON *) blade_protocol_execute_request_params_get(blade_rpc_request_t *brpcreq); +KS_DECLARE(cJSON *) blade_protocol_execute_response_result_get(blade_rpc_response_t *brpcres); +KS_DECLARE(void) blade_protocol_execute_response_send(blade_rpc_request_t *brpcreq, cJSON *result); + KS_END_EXTERN_C #endif diff --git a/libs/libblade/src/include/blade_types.h b/libs/libblade/src/include/blade_types.h index be269844e4..ed7433cd57 100644 --- a/libs/libblade/src/include/blade_types.h +++ b/libs/libblade/src/include/blade_types.h @@ -42,9 +42,9 @@ typedef struct blade_handle_s blade_handle_t; typedef struct blade_identity_s blade_identity_t; typedef struct blade_transport_s blade_transport_t; typedef struct blade_transport_callbacks_s blade_transport_callbacks_t; -typedef struct blade_jsonrpc_s blade_jsonrpc_t; -typedef struct blade_jsonrpc_request_s blade_jsonrpc_request_t; -typedef struct blade_jsonrpc_response_s blade_jsonrpc_response_t; +typedef struct blade_rpc_s blade_rpc_t; +typedef struct blade_rpc_request_s blade_rpc_request_t; +typedef struct blade_rpc_response_s blade_rpc_response_t; typedef struct blade_connection_s blade_connection_t; typedef struct blade_session_s blade_session_t; typedef struct blade_session_callbacks_s blade_session_callbacks_t; @@ -53,8 +53,8 @@ typedef struct blade_protocol_realm_s blade_protocol_realm_t; typedef struct blade_protocol_method_s blade_protocol_method_t; -typedef ks_bool_t (*blade_jsonrpc_request_callback_t)(blade_jsonrpc_request_t *breq, void *data); -typedef ks_bool_t (*blade_jsonrpc_response_callback_t)(blade_jsonrpc_response_t *bres); +typedef ks_bool_t (*blade_rpc_request_callback_t)(blade_rpc_request_t *brpcreq, void *data); +typedef ks_bool_t (*blade_rpc_response_callback_t)(blade_rpc_response_t *brpcres, void *data); typedef enum { diff --git a/libs/libblade/test/bladec.c b/libs/libblade/test/bladec.c index d7f1d95a8d..b3b7c9dfd8 100644 --- a/libs/libblade/test/bladec.c +++ b/libs/libblade/test/bladec.c @@ -16,20 +16,98 @@ struct command_def_s { }; void command_quit(blade_handle_t *bh, char *args); -void command_connect(blade_handle_t *bh, char *args); -//void command_chat(blade_handle_t *bh, char *args); +void command_execute(blade_handle_t *bh, char *args); static const struct command_def_s command_defs[] = { { "quit", command_quit }, - { "connect", command_connect }, -// { "chat", command_chat }, + { "execute", command_execute }, { NULL, NULL } }; -//ks_bool_t on_blade_chat_join_response(blade_response_t *bres); -//ks_bool_t on_blade_chat_message_event(blade_event_t *bev); -//void on_blade_session_state_callback(blade_session_t *bs, blade_session_state_condition_t condition, void *data); +ks_bool_t test_echo_response_handler(blade_rpc_response_t *brpcres, void *data) +{ + blade_handle_t *bh = NULL; + blade_session_t *bs = NULL; + cJSON *result = NULL; + const char *text = NULL; + + ks_assert(brpcres); + + bh = blade_rpc_response_handle_get(brpcres); + ks_assert(bh); + + bs = blade_handle_sessions_lookup(bh, blade_rpc_response_sessionid_get(brpcres)); + ks_assert(bs); + + result = blade_protocol_execute_response_result_get(brpcres); + ks_assert(result); + + text = cJSON_GetObjectCstr(result, "text"); + ks_assert(text); + + ks_log(KS_LOG_DEBUG, "Session (%s) test.echo response processing\n", blade_session_id_get(bs)); + + blade_session_read_unlock(bs); + + ks_log(KS_LOG_DEBUG, "Session (%s) test.echo: %s\n", blade_session_id_get(bs), text); + + return KS_FALSE; +} + +ks_bool_t blade_locate_response_handler(blade_rpc_response_t *brpcres, void *data) +{ + blade_handle_t *bh = NULL; + blade_session_t *bs = NULL; + const char *nodeid = NULL; + cJSON *res = NULL; + cJSON *res_result = NULL; + cJSON *res_result_providers = NULL; + const char *res_result_protocol = NULL; + const char *res_result_realm = NULL; + cJSON *params = NULL; + + ks_assert(brpcres); + + bh = blade_rpc_response_handle_get(brpcres); + ks_assert(bh); + + bs = blade_handle_sessions_lookup(bh, blade_rpc_response_sessionid_get(brpcres)); + ks_assert(bs); + + res = blade_rpc_response_message_get(brpcres); + ks_assert(res); + + res_result = cJSON_GetObjectItem(res, "result"); + ks_assert(res_result); + + res_result_protocol = cJSON_GetObjectCstr(res_result, "protocol"); + ks_assert(res_result_protocol); + + res_result_realm = cJSON_GetObjectCstr(res_result, "realm"); + ks_assert(res_result_realm); + + res_result_providers = cJSON_GetObjectItem(res_result, "providers"); + ks_assert(res_result_providers); + + ks_log(KS_LOG_DEBUG, "Session (%s) blade.locate response processing\n", blade_session_id_get(bs)); + + for (int index = 0; index < cJSON_GetArraySize(res_result_providers); ++index) { + cJSON *elem = cJSON_GetArrayItem(res_result_providers, index); + if (elem->type == cJSON_String) { + ks_log(KS_LOG_DEBUG, "Session (%s) blade.locate (%s@%s) provider (%s)\n", blade_session_id_get(bs), res_result_protocol, res_result_realm, elem->valuestring); + nodeid = elem->valuestring; + } + } + + blade_session_read_unlock(bs); + + params = cJSON_CreateObject(); + cJSON_AddStringToObject(params, "text", "hello world!"); + blade_protocol_execute(bh, nodeid, "test.echo", res_result_protocol, res_result_realm, params, test_echo_response_handler, NULL); + + return KS_FALSE; +} int main(int argc, char **argv) { @@ -71,9 +149,6 @@ int main(int argc, char **argv) return EXIT_FAILURE; } - //blade_handle_event_register(bh, "blade.chat.message", on_blade_chat_message_event); - //blade_handle_session_state_callback_register(bh, NULL, on_blade_session_state_callback, &session_state_callback_id); - if (autoconnect) { blade_connection_t *bc = NULL; blade_identity_t *target = NULL; @@ -85,13 +160,9 @@ int main(int argc, char **argv) blade_identity_destroy(&target); ks_sleep_ms(5000); - - blade_protocol_publish(bh, "test", "mydomain.com"); - - ks_sleep_ms(5000); - } else loop(bh); - - //blade_handle_session_state_callback_unregister(bh, session_state_callback_id); + } + + loop(bh); blade_handle_destroy(&bh); @@ -102,38 +173,6 @@ int main(int argc, char **argv) return 0; } -//ks_bool_t on_blade_chat_message_event(blade_event_t *bev) -//{ -// cJSON *res = NULL; -// const char *from = NULL; -// const char *message = NULL; -// -// ks_assert(bev); -// -// res = cJSON_GetObjectItem(bev->message, "result"); -// from = cJSON_GetObjectCstr(res, "from"); -// message = cJSON_GetObjectCstr(res, "message"); -// -// ks_log(KS_LOG_DEBUG, "Received Chat Message Event: (%s) %s\n", from, message); -// -// return KS_FALSE; -//} -// -//void on_blade_session_state_callback(blade_session_t *bs, blade_session_state_condition_t condition, void *data) -//{ -// blade_session_state_t state = blade_session_state_get(bs); -// -// if (condition == BLADE_SESSION_STATE_CONDITION_PRE) { -// ks_log(KS_LOG_DEBUG, "Blade Session State Changed: %s, %d\n", blade_session_id_get(bs), state); -// if (state == BLADE_SESSION_STATE_READY) { -// cJSON *req = NULL; -// blade_jsonrpc_request_raw_create(blade_handle_pool_get(blade_session_handle_get(bs)), &req, NULL, NULL, "blade.chat.join"); -// blade_session_send(bs, req, on_blade_chat_join_response); -// cJSON_Delete(req); -// } -// } -//} - void loop(blade_handle_t *bh) { char buf[CONSOLE_INPUT_MAX]; @@ -199,92 +238,21 @@ void command_quit(blade_handle_t *bh, char *args) g_shutdown = KS_TRUE; } -void command_connect(blade_handle_t *bh, char *args) +void command_execute(blade_handle_t *bh, char *args) { - blade_connection_t *bc = NULL; - blade_identity_t *target = NULL; - ks_assert(bh); ks_assert(args); - blade_identity_create(&target, blade_handle_pool_get(bh)); - - if (blade_identity_parse(target, args) == KS_STATUS_SUCCESS) blade_handle_connect(bh, &bc, target, NULL); - - blade_identity_destroy(&target); + blade_protocol_locate(bh, "test", "mydomain.com", blade_locate_response_handler, NULL); } -//ks_bool_t on_blade_chat_send_response(blade_response_t *bres); -// -//ks_bool_t on_blade_chat_join_response(blade_response_t *bres) // @todo this should get userdata passed in from when the callback is registered -//{ -// blade_session_t *bs = NULL; -// cJSON *req = NULL; -// cJSON *params = NULL; -// -// ks_log(KS_LOG_DEBUG, "Received Chat Join Response!\n"); -// -// bs = blade_handle_sessions_get(bres->handle, bres->session_id); -// if (!bs) { -// ks_log(KS_LOG_DEBUG, "Unknown Session: %s\n", bres->session_id); -// return KS_FALSE; -// } -// -// blade_jsonrpc_request_raw_create(blade_handle_pool_get(bres->handle), &req, ¶ms, NULL, "blade.chat.send"); -// ks_assert(req); -// ks_assert(params); -// -// cJSON_AddStringToObject(params, "message", "Hello World!"); -// -// blade_session_send(bs, req, on_blade_chat_send_response); -// -// blade_session_read_unlock(bs); -// -// return KS_FALSE; -//} -// -//ks_bool_t on_blade_chat_send_response(blade_response_t *bres) // @todo this should get userdata passed in from when the callback is registered -//{ -// ks_log(KS_LOG_DEBUG, "Received Chat Send Response!\n"); -// return KS_FALSE; -//} -// -//void command_chat(blade_handle_t *bh, char *args) -//{ -// char *cmd = NULL; -// -// ks_assert(bh); -// ks_assert(args); -// -// parse_argument(&args, &cmd, ' '); -// ks_log(KS_LOG_DEBUG, "Chat Command: %s, Args: %s\n", cmd, args); -// -// if (!strcmp(cmd, "leave")) { -// } else if (!strcmp(cmd, "send")) { -// char *sid = NULL; -// blade_session_t *bs = NULL; -// cJSON *req = NULL; -// cJSON *params = NULL; -// -// parse_argument(&args, &sid, ' '); -// -// bs = blade_handle_sessions_get(bh, sid); -// if (!bs) { -// ks_log(KS_LOG_DEBUG, "Unknown Session: %s\n", sid); -// return; -// } -// blade_jsonrpc_request_raw_create(blade_handle_pool_get(bh), &req, ¶ms, NULL, "blade.chat.send"); -// ks_assert(req); -// ks_assert(params); -// -// cJSON_AddStringToObject(params, "message", args); -// -// blade_session_send(bs, req, on_blade_chat_send_response); -// -// blade_session_read_unlock(bs); -// -// cJSON_Delete(req); -// } else { -// ks_log(KS_LOG_DEBUG, "Unknown Chat Command: %s\n", cmd); -// } -//} +/* For Emacs: +* Local Variables: +* mode:c +* indent-tabs-mode:t +* tab-width:4 +* c-basic-offset:4 +* End: +* For VIM: +* vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: +*/ diff --git a/libs/libblade/test/blades.c b/libs/libblade/test/blades.c index 6402ecfe81..15eaa2b017 100644 --- a/libs/libblade/test/blades.c +++ b/libs/libblade/test/blades.c @@ -16,45 +16,70 @@ struct command_def_s { }; void command_quit(blade_handle_t *bh, char *args); -void command_locate(blade_handle_t *bh, char *args); static const struct command_def_s command_defs[] = { { "quit", command_quit }, - { "locate", command_locate }, { NULL, NULL } }; -//ks_status_t blade_module_chat_create(blade_module_t **bmP, blade_handle_t *bh); -//ks_status_t blade_module_chat_on_startup(blade_module_t *bm, config_setting_t *config); -//ks_status_t blade_module_chat_on_shutdown(blade_module_t *bm); -// -//typedef struct blade_module_chat_s blade_module_chat_t; -//struct blade_module_chat_s { -// blade_handle_t *handle; -// ks_pool_t *pool; -// ks_thread_pool_t *tpool; -// blade_module_t *module; -// //blade_module_callbacks_t *module_callbacks; -// -// blade_space_t *blade_chat_space; -// const char *session_state_callback_id; -// ks_list_t *participants; -//}; -// -//void blade_module_chat_on_session_state(blade_session_t *bs, blade_session_state_condition_t condition, void *data); -// -//ks_bool_t blade_chat_join_request_handler(blade_module_t *bm, blade_request_t *breq); -//ks_bool_t blade_chat_leave_request_handler(blade_module_t *bm, blade_request_t *breq); -//ks_bool_t blade_chat_send_request_handler(blade_module_t *bm, blade_request_t *breq); -// -//static blade_module_callbacks_t g_module_chat_callbacks = -//{ -// blade_module_chat_on_startup, -// blade_module_chat_on_shutdown, -//}; +ks_bool_t blade_publish_response_handler(blade_rpc_response_t *brpcres, void *data) +{ + blade_handle_t *bh = NULL; + blade_session_t *bs = NULL; + + ks_assert(brpcres); + + bh = blade_rpc_response_handle_get(brpcres); + ks_assert(bh); + + bs = blade_handle_sessions_lookup(bh, blade_rpc_response_sessionid_get(brpcres)); + ks_assert(bs); + + ks_log(KS_LOG_DEBUG, "Session (%s) blade.publish response processing\n", blade_session_id_get(bs)); + + blade_session_read_unlock(bs); + + return KS_FALSE; +} + +ks_bool_t test_echo_request_handler(blade_rpc_request_t *brpcreq, void *data) +{ + blade_handle_t *bh = NULL; + blade_session_t *bs = NULL; + cJSON *params = NULL; + cJSON *result = NULL; + const char *text = NULL; + + ks_assert(brpcreq); + + bh = blade_rpc_request_handle_get(brpcreq); + ks_assert(bh); + + bs = blade_handle_sessions_lookup(bh, blade_rpc_response_sessionid_get(brpcreq)); + ks_assert(bs); + + // @todo get the inner parameters of a blade.execute request for protocolrpcs + params = blade_protocol_execute_request_params_get(brpcreq); + ks_assert(params); + + text = cJSON_GetObjectCstr(params, "text"); + ks_assert(text); + + ks_log(KS_LOG_DEBUG, "Session (%s) test.echo request processing\n", blade_session_id_get(bs)); + + blade_session_read_unlock(bs); + + // @todo build and send response + result = cJSON_CreateObject(); + cJSON_AddStringToObject(result, "text", text); + + blade_protocol_execute_response_send(brpcreq, result); + + return KS_FALSE; +} int main(int argc, char **argv) @@ -62,8 +87,6 @@ int main(int argc, char **argv) blade_handle_t *bh = NULL; config_t config; config_setting_t *config_blade = NULL; - //blade_module_t *mod_chat = NULL; - //blade_identity_t *id = NULL; const char *cfgpath = "blades.cfg"; const char *autoconnect = NULL; @@ -73,7 +96,6 @@ int main(int argc, char **argv) blade_handle_create(&bh); - //if (argc > 1) cfgpath = argv[1]; if (argc > 1) autoconnect = argv[1]; config_init(&config); @@ -93,10 +115,6 @@ int main(int argc, char **argv) return EXIT_FAILURE; } - // must occur before startup - //blade_module_chat_create(&mod_chat, bh); - //blade_handle_module_register(mod_chat); - if (blade_handle_startup(bh, config_blade) != KS_STATUS_SUCCESS) { ks_log(KS_LOG_ERROR, "Blade startup failed\n"); return EXIT_FAILURE; @@ -105,6 +123,7 @@ int main(int argc, char **argv) if (autoconnect) { blade_connection_t *bc = NULL; blade_identity_t *target = NULL; + blade_rpc_t *brpc = NULL; blade_identity_create(&target, blade_handle_pool_get(bh)); @@ -112,9 +131,13 @@ int main(int argc, char **argv) blade_identity_destroy(&target); - ks_sleep_ms(5000); // @todo use session state change callback to know when the session is ready, this ensures it's ready before trying to publish upstream + ks_sleep_ms(5000); // @todo use session state change callback to know when the session is ready, this hack temporarily ensures it's ready before trying to publish upstream - blade_protocol_publish(bh, "test", "mydomain.com"); + blade_rpc_create(&brpc, bh, "test.echo", "test", "mydomain.com", test_echo_request_handler, NULL); + blade_handle_protocolrpc_register(brpc); + + // @todo build up json-based method schema for each protocolrpc registered above, and pass into blade_protocol_publish() to attach to the request, to be stored in the blade_protocol_t tracked by the master node + blade_protocol_publish(bh, "test", "mydomain.com", blade_publish_response_handler, NULL); } loop(bh); @@ -193,339 +216,6 @@ void command_quit(blade_handle_t *bh, char *args) g_shutdown = KS_TRUE; } -void command_locate(blade_handle_t *bh, char *args) -{ - ks_assert(bh); - ks_assert(args); - - blade_protocol_locate(bh, "test", "mydomain.com"); -} - - - -//static void blade_module_chat_cleanup(ks_pool_t *pool, void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type) -//{ -// blade_module_chat_t *bm_chat = (blade_module_chat_t *)ptr; -// -// ks_assert(bm_chat); -// -// switch (action) { -// case KS_MPCL_ANNOUNCE: -// break; -// case KS_MPCL_TEARDOWN: -// break; -// case KS_MPCL_DESTROY: -// break; -// } -//} -// -// -//ks_status_t blade_module_chat_create(blade_module_t **bmP, blade_handle_t *bh) -//{ -// blade_module_chat_t *bm_chat = NULL; -// ks_pool_t *pool = NULL; -// -// ks_assert(bmP); -// ks_assert(bh); -// -// ks_pool_open(&pool); -// ks_assert(pool); -// -// bm_chat = ks_pool_alloc(pool, sizeof(blade_module_chat_t)); -// bm_chat->handle = bh; -// bm_chat->pool = pool; -// bm_chat->tpool = blade_handle_tpool_get(bh); -// bm_chat->session_state_callback_id = NULL; -// -// ks_list_create(&bm_chat->participants, pool); -// ks_assert(bm_chat->participants); -// -// blade_module_create(&bm_chat->module, bh, pool, bm_chat, &g_module_chat_callbacks); -// ks_assert(bm_chat->module); -// -// ks_pool_set_cleanup(pool, bm_chat, NULL, blade_module_chat_cleanup); -// -// ks_log(KS_LOG_DEBUG, "Created\n"); -// -// *bmP = bm_chat->module; -// -// return KS_STATUS_SUCCESS; -//} -// -// -//ks_status_t blade_module_chat_config(blade_module_chat_t *bm_chat, config_setting_t *config) -//{ -// config_setting_t *chat = NULL; -// -// ks_assert(bm_chat); -// ks_assert(config); -// -// if (!config_setting_is_group(config)) { -// ks_log(KS_LOG_DEBUG, "!config_setting_is_group(config)\n"); -// return KS_STATUS_FAIL; -// } -// -// chat = config_setting_get_member(config, "chat"); -// if (chat) { -// } -// -// -// // Configuration is valid, now assign it to the variables that are used -// // If the configuration was invalid, then this does not get changed -// -// ks_log(KS_LOG_DEBUG, "Configured\n"); -// -// return KS_STATUS_SUCCESS; -//} -// -//ks_status_t blade_module_chat_on_startup(blade_module_t *bm, config_setting_t *config) -//{ -// blade_module_chat_t *bm_chat = NULL; -// blade_space_t *space = NULL; -// blade_method_t *method = NULL; -// -// ks_assert(bm); -// ks_assert(config); -// -// bm_chat = (blade_module_chat_t *)blade_module_data_get(bm); -// -// if (blade_module_chat_config(bm_chat, config) != KS_STATUS_SUCCESS) { -// ks_log(KS_LOG_DEBUG, "blade_module_chat_config failed\n"); -// return KS_STATUS_FAIL; -// } -// -// blade_space_create(&space, bm_chat->handle, bm, "blade.chat"); -// ks_assert(space); -// -// bm_chat->blade_chat_space = space; -// -// blade_method_create(&method, space, "join", blade_chat_join_request_handler); -// ks_assert(method); -// blade_space_methods_add(space, method); -// -// blade_method_create(&method, space, "leave", blade_chat_leave_request_handler); -// ks_assert(method); -// blade_space_methods_add(space, method); -// -// blade_method_create(&method, space, "send", blade_chat_send_request_handler); -// ks_assert(method); -// blade_space_methods_add(space, method); -// -// blade_handle_space_register(space); -// -// blade_handle_session_state_callback_register(blade_module_handle_get(bm), bm, blade_module_chat_on_session_state, &bm_chat->session_state_callback_id); -// -// ks_log(KS_LOG_DEBUG, "Started\n"); -// -// return KS_STATUS_SUCCESS; -//} -// -//ks_status_t blade_module_chat_on_shutdown(blade_module_t *bm) -//{ -// blade_module_chat_t *bm_chat = NULL; -// -// ks_assert(bm); -// -// bm_chat = (blade_module_chat_t *)blade_module_data_get(bm); -// ks_assert(bm_chat); -// -// if (bm_chat->session_state_callback_id) blade_handle_session_state_callback_unregister(blade_module_handle_get(bm), bm_chat->session_state_callback_id); -// bm_chat->session_state_callback_id = NULL; -// -// if (bm_chat->blade_chat_space) blade_handle_space_unregister(bm_chat->blade_chat_space); -// -// ks_log(KS_LOG_DEBUG, "Stopped\n"); -// -// return KS_STATUS_SUCCESS; -//} -// -//void blade_module_chat_on_session_state(blade_session_t *bs, blade_session_state_condition_t condition, void *data) -//{ -// blade_module_t *bm = NULL; -// blade_module_chat_t *bm_chat = NULL; -// -// ks_assert(bs); -// ks_assert(data); -// -// bm = (blade_module_t *)data; -// bm_chat = (blade_module_chat_t *)blade_module_data_get(bm); -// ks_assert(bm_chat); -// -// if (blade_session_state_get(bs) == BLADE_SESSION_STATE_HANGUP && condition == BLADE_SESSION_STATE_CONDITION_PRE) { -// cJSON *props = NULL; -// -// ks_log(KS_LOG_DEBUG, "Removing session from chat participants if present\n"); -// -// props = blade_session_properties_get(bs); -// ks_assert(props); -// -// cJSON_DeleteItemFromObject(props, "blade.chat.participant"); -// -// ks_list_delete(bm_chat->participants, blade_session_id_get(bs)); // @todo make copy of session id instead and search manually, also free the id -// } -//} -// -//ks_bool_t blade_chat_join_request_handler(blade_module_t *bm, blade_request_t *breq) -//{ -// blade_module_chat_t *bm_chat = NULL; -// blade_session_t *bs = NULL; -// cJSON *res = NULL; -// cJSON *props = NULL; -// cJSON *props_participant = NULL; -// -// ks_assert(bm); -// ks_assert(breq); -// -// ks_log(KS_LOG_DEBUG, "Request Received!\n"); -// -// bm_chat = (blade_module_chat_t *)blade_module_data_get(bm); -// ks_assert(bm_chat); -// -// bs = blade_handle_sessions_get(breq->handle, breq->session_id); -// ks_assert(bs); -// -// // @todo properties only used to demonstrate a flexible container for session data, should just rely on the participants list/hash -// blade_session_properties_write_lock(bs, KS_TRUE); -// -// props = blade_session_properties_get(bs); -// ks_assert(props); -// -// props_participant = cJSON_GetObjectItem(props, "blade.chat.participant"); -// if (props_participant && props_participant->type == cJSON_True) { -// ks_log(KS_LOG_DEBUG, "Session (%s) attempted to join chat but is already a participant\n", blade_session_id_get(bs)); -// blade_rpc_error_create(&res, NULL, breq->message_id, -10000, "Already a participant of chat"); -// } -// else { -// ks_log(KS_LOG_DEBUG, "Session (%s) joined chat\n", blade_session_id_get(bs)); -// -// if (props_participant) props_participant->type = cJSON_True; -// else cJSON_AddTrueToObject(props, "blade.chat.participant"); -// -// ks_list_append(bm_chat->participants, blade_session_id_get(bs)); // @todo make copy of session id instead and cleanup when removed -// -// blade_rpc_response_create(&res, NULL, breq->message_id); -// -// // @todo create an event to send to participants when a session joins and leaves, send after main response though -// } -// -// blade_session_properties_write_unlock(bs); -// -// blade_session_send(bs, res, NULL); -// -// blade_session_read_unlock(bs); -// -// cJSON_Delete(res); -// -// return KS_FALSE; -//} -// -//ks_bool_t blade_chat_leave_request_handler(blade_module_t *bm, blade_request_t *breq) -//{ -// blade_module_chat_t *bm_chat = NULL; -// blade_session_t *bs = NULL; -// cJSON *res = NULL; -// cJSON *props = NULL; -// cJSON *props_participant = NULL; -// -// ks_assert(bm); -// ks_assert(breq); -// -// ks_log(KS_LOG_DEBUG, "Request Received!\n"); -// -// bm_chat = (blade_module_chat_t *)blade_module_data_get(bm); -// ks_assert(bm_chat); -// -// bs = blade_handle_sessions_get(breq->handle, breq->session_id); -// ks_assert(bs); -// -// blade_session_properties_write_lock(bs, KS_TRUE); -// -// props = blade_session_properties_get(bs); -// ks_assert(props); -// -// props_participant = cJSON_GetObjectItem(props, "blade.chat.participant"); -// if (!props_participant || props_participant->type == cJSON_False) { -// ks_log(KS_LOG_DEBUG, "Session (%s) attempted to leave chat but is not a participant\n", blade_session_id_get(bs)); -// blade_rpc_error_create(&res, NULL, breq->message_id, -10000, "Not a participant of chat"); -// } -// else { -// ks_log(KS_LOG_DEBUG, "Session (%s) left chat\n", blade_session_id_get(bs)); -// -// cJSON_DeleteItemFromObject(props, "blade.chat.participant"); -// -// ks_list_delete(bm_chat->participants, blade_session_id_get(bs)); // @todo make copy of session id instead and search manually, also free the id -// -// blade_rpc_response_create(&res, NULL, breq->message_id); -// -// // @todo create an event to send to participants when a session joins and leaves, send after main response though -// } -// -// blade_session_properties_write_unlock(bs); -// -// blade_session_send(bs, res, NULL); -// -// blade_session_read_unlock(bs); -// -// cJSON_Delete(res); -// -// return KS_FALSE; -//} -// -//ks_bool_t blade_chat_send_request_handler(blade_module_t *bm, blade_request_t *breq) -//{ -// blade_module_chat_t *bm_chat = NULL; -// blade_session_t *bs = NULL; -// cJSON *params = NULL; -// cJSON *res = NULL; -// cJSON *event = NULL; -// const char *message = NULL; -// ks_bool_t sendevent = KS_FALSE; -// -// ks_assert(bm); -// ks_assert(breq); -// -// ks_log(KS_LOG_DEBUG, "Request Received!\n"); -// -// bm_chat = (blade_module_chat_t *)blade_module_data_get(bm); -// ks_assert(bm_chat); -// -// params = cJSON_GetObjectItem(breq->message, "params"); // @todo cache this in blade_request_t for quicker/easier access -// if (!params) { -// ks_log(KS_LOG_DEBUG, "Session (%s) attempted to send chat message with no 'params' object\n", blade_session_id_get(bs)); -// blade_rpc_error_create(&res, NULL, breq->message_id, -32602, "Missing params object"); -// } -// else if (!(message = cJSON_GetObjectCstr(params, "message"))) { -// ks_log(KS_LOG_DEBUG, "Session (%s) attempted to send chat message with no 'message'\n", blade_session_id_get(bs)); -// blade_rpc_error_create(&res, NULL, breq->message_id, -32602, "Missing params message string"); -// } -// -// bs = blade_handle_sessions_get(breq->handle, breq->session_id); -// ks_assert(bs); -// -// if (!res) { -// blade_rpc_response_create(&res, NULL, breq->message_id); -// sendevent = KS_TRUE; -// } -// blade_session_send(bs, res, NULL); -// -// blade_session_read_unlock(bs); -// -// cJSON_Delete(res); -// -// if (sendevent) { -// blade_rpc_event_create(&event, &res, "blade.chat.message"); -// ks_assert(event); -// cJSON_AddStringToObject(res, "from", breq->session_id); // @todo should really be the identity, but we don't have that in place yet -// cJSON_AddStringToObject(res, "message", message); -// -// blade_handle_sessions_send(breq->handle, bm_chat->participants, NULL, event); -// -// cJSON_Delete(event); -// } -// -// return KS_FALSE; -//} - /* For Emacs: * Local Variables: