diff --git a/libs/libblade/libblade.sln b/libs/libblade/libblade.sln
index e8d040b564..8b9d9cce67 100644
--- a/libs/libblade/libblade.sln
+++ b/libs/libblade/libblade.sln
@@ -21,6 +21,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "blades", "test\blades.vcxpr
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bladec", "test\bladec.vcxproj", "{4A70CDA9-AC5B-4818-BCF2-B0DD1B8F5F5F}"
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "switchblade", "switchblade\switchblade.vcxproj", "{8330E669-77F3-4F70-A275-6F7BABE050A7}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
@@ -177,6 +179,22 @@ Global
{4A70CDA9-AC5B-4818-BCF2-B0DD1B8F5F5F}.ReleaseDLL|x64.Build.0 = Release|x64
{4A70CDA9-AC5B-4818-BCF2-B0DD1B8F5F5F}.ReleaseDLL|x86.ActiveCfg = Release|Win32
{4A70CDA9-AC5B-4818-BCF2-B0DD1B8F5F5F}.ReleaseDLL|x86.Build.0 = Release|Win32
+ {8330E669-77F3-4F70-A275-6F7BABE050A7}.Debug|x64.ActiveCfg = Debug|x64
+ {8330E669-77F3-4F70-A275-6F7BABE050A7}.Debug|x64.Build.0 = Debug|x64
+ {8330E669-77F3-4F70-A275-6F7BABE050A7}.Debug|x86.ActiveCfg = Debug|Win32
+ {8330E669-77F3-4F70-A275-6F7BABE050A7}.Debug|x86.Build.0 = Debug|Win32
+ {8330E669-77F3-4F70-A275-6F7BABE050A7}.DebugDLL|x64.ActiveCfg = Debug|x64
+ {8330E669-77F3-4F70-A275-6F7BABE050A7}.DebugDLL|x64.Build.0 = Debug|x64
+ {8330E669-77F3-4F70-A275-6F7BABE050A7}.DebugDLL|x86.ActiveCfg = Debug|Win32
+ {8330E669-77F3-4F70-A275-6F7BABE050A7}.DebugDLL|x86.Build.0 = Debug|Win32
+ {8330E669-77F3-4F70-A275-6F7BABE050A7}.Release|x64.ActiveCfg = Release|x64
+ {8330E669-77F3-4F70-A275-6F7BABE050A7}.Release|x64.Build.0 = Release|x64
+ {8330E669-77F3-4F70-A275-6F7BABE050A7}.Release|x86.ActiveCfg = Release|Win32
+ {8330E669-77F3-4F70-A275-6F7BABE050A7}.Release|x86.Build.0 = Release|Win32
+ {8330E669-77F3-4F70-A275-6F7BABE050A7}.ReleaseDLL|x64.ActiveCfg = Release|x64
+ {8330E669-77F3-4F70-A275-6F7BABE050A7}.ReleaseDLL|x64.Build.0 = Release|x64
+ {8330E669-77F3-4F70-A275-6F7BABE050A7}.ReleaseDLL|x86.ActiveCfg = Release|Win32
+ {8330E669-77F3-4F70-A275-6F7BABE050A7}.ReleaseDLL|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/libs/libblade/libblade.vcxproj b/libs/libblade/libblade.vcxproj
index 95562a7348..bbb5fa2ebb 100644
--- a/libs/libblade/libblade.vcxproj
+++ b/libs/libblade/libblade.vcxproj
@@ -189,45 +189,24 @@
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
+
+
-
+
-
-
-
diff --git a/libs/libblade/libblade.vcxproj.filters b/libs/libblade/libblade.vcxproj.filters
index d25008d137..eb6237bcbc 100644
--- a/libs/libblade/libblade.vcxproj.filters
+++ b/libs/libblade/libblade.vcxproj.filters
@@ -24,67 +24,22 @@
Source Files
-
- Source Files
-
Source Files
-
- Source Files
-
-
- Source Files
-
-
- Source Files
-
-
- Source Files
-
Source Files
-
- Source Files
-
Source Files
-
+
Source Files
-
+
Source Files
-
- Source Files
-
-
- Source Files
-
-
- Source Files
-
-
- Source Files
-
-
- Source Files
-
-
- Source Files
-
-
- Source Files
-
-
- Source Files
-
-
- Source Files
-
-
+
Source Files
@@ -98,43 +53,25 @@
Header Files
-
- Header Files
-
Header Files
-
- Header Files
-
-
- Header Files
-
-
- Header Files
-
Header Files
-
- Header Files
-
Header Files
Header Files
-
+
Header Files
-
+
Header Files
-
- Header Files
-
-
+
Header Files
diff --git a/libs/libblade/src/blade_connection.c b/libs/libblade/src/blade_connection.c
index a7212c10d5..6ba25a120c 100644
--- a/libs/libblade/src/blade_connection.c
+++ b/libs/libblade/src/blade_connection.c
@@ -54,12 +54,9 @@ struct blade_connection_s {
};
void *blade_connection_state_thread(ks_thread_t *thread, void *data);
-ks_status_t blade_connection_state_on_disconnect(blade_connection_t *bc);
-ks_status_t blade_connection_state_on_new(blade_connection_t *bc);
-ks_status_t blade_connection_state_on_connect(blade_connection_t *bc);
-ks_status_t blade_connection_state_on_attach(blade_connection_t *bc);
-ks_status_t blade_connection_state_on_detach(blade_connection_t *bc);
-ks_status_t blade_connection_state_on_ready(blade_connection_t *bc);
+ks_status_t blade_connection_onstate_startup(blade_connection_t *bc);
+ks_status_t blade_connection_onstate_shutdown(blade_connection_t *bc);
+ks_status_t blade_connection_onstate_run(blade_connection_t *bc);
static void blade_connection_cleanup(ks_pool_t *pool, void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type)
@@ -260,29 +257,17 @@ blade_transport_state_callback_t blade_connection_state_callback_lookup(blade_co
ks_assert(bc);
switch (state) {
- case BLADE_CONNECTION_STATE_DISCONNECT:
- if (bc->direction == BLADE_CONNECTION_DIRECTION_INBOUND) callback = bc->transport_callbacks->onstate_disconnect_inbound;
- else if(bc->direction == BLADE_CONNECTION_DIRECTION_OUTBOUND) callback = bc->transport_callbacks->onstate_disconnect_outbound;
+ case BLADE_CONNECTION_STATE_SHUTDOWN:
+ if (bc->direction == BLADE_CONNECTION_DIRECTION_INBOUND) callback = bc->transport_callbacks->onstate_shutdown_inbound;
+ else if(bc->direction == BLADE_CONNECTION_DIRECTION_OUTBOUND) callback = bc->transport_callbacks->onstate_shutdown_outbound;
break;
- case BLADE_CONNECTION_STATE_NEW:
- if (bc->direction == BLADE_CONNECTION_DIRECTION_INBOUND) callback = bc->transport_callbacks->onstate_new_inbound;
- else if(bc->direction == BLADE_CONNECTION_DIRECTION_OUTBOUND) callback = bc->transport_callbacks->onstate_new_outbound;
+ case BLADE_CONNECTION_STATE_STARTUP:
+ if (bc->direction == BLADE_CONNECTION_DIRECTION_INBOUND) callback = bc->transport_callbacks->onstate_startup_inbound;
+ else if(bc->direction == BLADE_CONNECTION_DIRECTION_OUTBOUND) callback = bc->transport_callbacks->onstate_startup_outbound;
break;
- case BLADE_CONNECTION_STATE_CONNECT:
- if (bc->direction == BLADE_CONNECTION_DIRECTION_INBOUND) callback = bc->transport_callbacks->onstate_connect_inbound;
- else if(bc->direction == BLADE_CONNECTION_DIRECTION_OUTBOUND) callback = bc->transport_callbacks->onstate_connect_outbound;
- break;
- case BLADE_CONNECTION_STATE_ATTACH:
- if (bc->direction == BLADE_CONNECTION_DIRECTION_INBOUND) callback = bc->transport_callbacks->onstate_attach_inbound;
- else if(bc->direction == BLADE_CONNECTION_DIRECTION_OUTBOUND) callback = bc->transport_callbacks->onstate_attach_outbound;
- break;
- case BLADE_CONNECTION_STATE_DETACH:
- if (bc->direction == BLADE_CONNECTION_DIRECTION_INBOUND) callback = bc->transport_callbacks->onstate_detach_inbound;
- else if(bc->direction == BLADE_CONNECTION_DIRECTION_OUTBOUND) callback = bc->transport_callbacks->onstate_detach_outbound;
- break;
- case BLADE_CONNECTION_STATE_READY:
- if (bc->direction == BLADE_CONNECTION_DIRECTION_INBOUND) callback = bc->transport_callbacks->onstate_ready_inbound;
- else if(bc->direction == BLADE_CONNECTION_DIRECTION_OUTBOUND) callback = bc->transport_callbacks->onstate_ready_outbound;
+ case BLADE_CONNECTION_STATE_RUN:
+ if (bc->direction == BLADE_CONNECTION_DIRECTION_INBOUND) callback = bc->transport_callbacks->onstate_run_inbound;
+ else if(bc->direction == BLADE_CONNECTION_DIRECTION_OUTBOUND) callback = bc->transport_callbacks->onstate_run_outbound;
break;
default: break;
}
@@ -322,9 +307,9 @@ KS_DECLARE(void) blade_connection_disconnect(blade_connection_t *bc)
{
ks_assert(bc);
- if (bc->state != BLADE_CONNECTION_STATE_DETACH && bc->state != BLADE_CONNECTION_STATE_DISCONNECT && bc->state != BLADE_CONNECTION_STATE_CLEANUP) {
+ if (bc->state != BLADE_CONNECTION_STATE_SHUTDOWN && bc->state != BLADE_CONNECTION_STATE_CLEANUP) {
ks_log(KS_LOG_DEBUG, "Connection (%s) disconnecting\n", bc->id);
- blade_connection_state_set(bc, BLADE_CONNECTION_STATE_DETACH);
+ blade_connection_state_set(bc, BLADE_CONNECTION_STATE_SHUTDOWN);
}
}
@@ -382,24 +367,15 @@ void *blade_connection_state_thread(ks_thread_t *thread, void *data)
state = bc->state;
switch (state) {
- case BLADE_CONNECTION_STATE_DISCONNECT:
- blade_connection_state_on_disconnect(bc);
+ case BLADE_CONNECTION_STATE_SHUTDOWN:
+ blade_connection_onstate_shutdown(bc);
shutdown = KS_TRUE;
break;
- case BLADE_CONNECTION_STATE_NEW:
- blade_connection_state_on_new(bc);
+ case BLADE_CONNECTION_STATE_STARTUP:
+ blade_connection_onstate_startup(bc);
break;
- case BLADE_CONNECTION_STATE_CONNECT:
- blade_connection_state_on_connect(bc);
- break;
- case BLADE_CONNECTION_STATE_ATTACH:
- blade_connection_state_on_attach(bc);
- break;
- case BLADE_CONNECTION_STATE_DETACH:
- blade_connection_state_on_detach(bc);
- break;
- case BLADE_CONNECTION_STATE_READY:
- blade_connection_state_on_ready(bc);
+ case BLADE_CONNECTION_STATE_RUN:
+ blade_connection_onstate_run(bc);
break;
default: break;
}
@@ -411,77 +387,27 @@ void *blade_connection_state_thread(ks_thread_t *thread, void *data)
return NULL;
}
-ks_status_t blade_connection_state_on_disconnect(blade_connection_t *bc)
-{
- blade_transport_state_callback_t callback = NULL;
-
- ks_assert(bc);
-
- callback = blade_connection_state_callback_lookup(bc, BLADE_CONNECTION_STATE_DISCONNECT);
- if (callback) callback(bc, BLADE_CONNECTION_STATE_CONDITION_POST);
-
- blade_connection_state_set(bc, BLADE_CONNECTION_STATE_CLEANUP);
-
- return KS_STATUS_SUCCESS;
-}
-
-ks_status_t blade_connection_state_on_new(blade_connection_t *bc)
+ks_status_t blade_connection_onstate_startup(blade_connection_t *bc)
{
blade_transport_state_callback_t callback = NULL;
blade_connection_state_hook_t hook = BLADE_CONNECTION_STATE_HOOK_SUCCESS;
ks_assert(bc);
- callback = blade_connection_state_callback_lookup(bc, BLADE_CONNECTION_STATE_NEW);
+ callback = blade_connection_state_callback_lookup(bc, BLADE_CONNECTION_STATE_STARTUP);
if (callback) hook = callback(bc, BLADE_CONNECTION_STATE_CONDITION_POST);
if (hook == BLADE_CONNECTION_STATE_HOOK_DISCONNECT) blade_connection_disconnect(bc);
- else if (hook == BLADE_CONNECTION_STATE_HOOK_SUCCESS) {
- blade_connection_state_set(bc, BLADE_CONNECTION_STATE_CONNECT);
- }
-
- return KS_STATUS_SUCCESS;
-}
-
-ks_status_t blade_connection_state_on_connect(blade_connection_t *bc)
-{
- blade_transport_state_callback_t callback = NULL;
- blade_connection_state_hook_t hook = BLADE_CONNECTION_STATE_HOOK_SUCCESS;
-
- ks_assert(bc);
-
- callback = blade_connection_state_callback_lookup(bc, BLADE_CONNECTION_STATE_CONNECT);
- if (callback) hook = callback(bc, BLADE_CONNECTION_STATE_CONDITION_POST);
-
- if (hook == BLADE_CONNECTION_STATE_HOOK_DISCONNECT) blade_connection_disconnect(bc);
- else if (hook == BLADE_CONNECTION_STATE_HOOK_SUCCESS) {
- blade_connection_state_set(bc, BLADE_CONNECTION_STATE_ATTACH);
- }
-
- return KS_STATUS_SUCCESS;
-}
-
-ks_status_t blade_connection_state_on_attach(blade_connection_t *bc)
-{
- blade_transport_state_callback_t callback = NULL;
- blade_connection_state_hook_t hook = BLADE_CONNECTION_STATE_HOOK_SUCCESS;
-
- ks_assert(bc);
-
- callback = blade_connection_state_callback_lookup(bc, BLADE_CONNECTION_STATE_ATTACH);
- if (callback) hook = callback(bc, BLADE_CONNECTION_STATE_CONDITION_POST);
-
- if (hook == BLADE_CONNECTION_STATE_HOOK_DISCONNECT) blade_connection_disconnect(bc);
else if (hook == BLADE_CONNECTION_STATE_HOOK_SUCCESS) {
// @todo this is adding a second lock, since we keep it locked in the callback to allow finishing, we don't want get locking here...
- // or just try unlocking twice to confirm...
- blade_session_t *bs = blade_handle_sessions_get(bc->handle, bc->session);
+ // or just unlock twice...
+ blade_session_t *bs = blade_handle_sessions_lookup(bc->handle, bc->session);
ks_assert(bs); // should not happen because bs should still be locked
- blade_session_connections_add(bs, bc->id);
+ blade_session_connection_set(bs, bc->id);
- blade_connection_state_set(bc, BLADE_CONNECTION_STATE_READY);
- blade_session_state_set(bs, BLADE_SESSION_STATE_READY); // @todo only set this if it's not already in the READY state from prior connection
+ blade_connection_state_set(bc, BLADE_CONNECTION_STATE_RUN);
+ blade_session_state_set(bs, BLADE_SESSION_STATE_STARTUP); // if reconnecting, we go from RUN back to STARTUP for the purpose of the reconnect which will return to RUN
blade_session_read_unlock(bs); // unlock the session we locked obtaining it above
blade_session_read_unlock(bs); // unlock the session we expect to be locked during the callback to ensure we can finish attaching
@@ -490,29 +416,30 @@ ks_status_t blade_connection_state_on_attach(blade_connection_t *bc)
return KS_STATUS_SUCCESS;
}
-ks_status_t blade_connection_state_on_detach(blade_connection_t *bc)
+ks_status_t blade_connection_onstate_shutdown(blade_connection_t *bc)
{
blade_transport_state_callback_t callback = NULL;
ks_assert(bc);
- callback = blade_connection_state_callback_lookup(bc, BLADE_CONNECTION_STATE_DETACH);
+ callback = blade_connection_state_callback_lookup(bc, BLADE_CONNECTION_STATE_SHUTDOWN);
if (callback) callback(bc, BLADE_CONNECTION_STATE_CONDITION_POST);
if (bc->session) {
- blade_session_t *bs = blade_handle_sessions_get(bc->handle, bc->session);
+ blade_session_t *bs = blade_handle_sessions_lookup(bc->handle, bc->session);
ks_assert(bs);
- blade_session_connections_remove(bs, bc->id);
+ blade_session_connection_set(bs, NULL);
blade_session_read_unlock(bs);
// keep bc->session for later in case something triggers a reconnect later and needs the old session id for a hint
}
- blade_connection_state_set(bc, BLADE_CONNECTION_STATE_DISCONNECT);
+
+ blade_connection_state_set(bc, BLADE_CONNECTION_STATE_CLEANUP);
return KS_STATUS_SUCCESS;
}
-ks_status_t blade_connection_state_on_ready(blade_connection_t *bc)
+ks_status_t blade_connection_onstate_run(blade_connection_t *bc)
{
blade_transport_state_callback_t callback = NULL;
blade_connection_state_hook_t hook = BLADE_CONNECTION_STATE_HOOK_SUCCESS;
@@ -540,7 +467,7 @@ ks_status_t blade_connection_state_on_ready(blade_connection_t *bc)
if (!(done = (json == NULL))) {
if (!bs) {
- bs = blade_handle_sessions_get(bc->handle, bc->session);
+ bs = blade_handle_sessions_lookup(bc->handle, bc->session);
ks_assert(bs);
}
blade_session_receiving_push(bs, json);
@@ -550,7 +477,7 @@ ks_status_t blade_connection_state_on_ready(blade_connection_t *bc)
}
if (bs) blade_session_read_unlock(bs);
- callback = blade_connection_state_callback_lookup(bc, BLADE_CONNECTION_STATE_READY);
+ callback = blade_connection_state_callback_lookup(bc, BLADE_CONNECTION_STATE_RUN);
if (callback) hook = callback(bc, BLADE_CONNECTION_STATE_CONDITION_POST);
if (hook == BLADE_CONNECTION_STATE_HOOK_DISCONNECT) blade_connection_disconnect(bc);
diff --git a/libs/libblade/src/blade_datastore.c b/libs/libblade/src/blade_datastore.c
deleted file mode 100644
index ce9e9ecfa0..0000000000
--- a/libs/libblade/src/blade_datastore.c
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * Copyright (c) 2007-2014, Anthony Minessale II
- * 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_datastore_s {
- ks_pool_t *pool;
- ks_thread_pool_t *tpool;
-
- const char *config_database_path;
-
- unqlite *db;
-};
-
-struct blade_datastore_fetch_userdata_s
-{
- blade_datastore_t *bds;
- blade_datastore_fetch_callback_t callback;
- void *userdata;
-};
-typedef struct blade_datastore_fetch_userdata_s blade_datastore_fetch_userdata_t;
-
-
-
-KS_DECLARE(ks_status_t) blade_datastore_destroy(blade_datastore_t **bdsP)
-{
- blade_datastore_t *bds = NULL;
-
- ks_assert(bdsP);
-
- bds = *bdsP;
- *bdsP = NULL;
-
- ks_assert(bds);
-
- blade_datastore_shutdown(bds);
-
- ks_pool_free(bds->pool, &bds);
-
- return KS_STATUS_SUCCESS;
-}
-
-KS_DECLARE(ks_status_t) blade_datastore_create(blade_datastore_t **bdsP, ks_pool_t *pool, ks_thread_pool_t *tpool)
-{
- blade_datastore_t *bds = NULL;
-
- ks_assert(bdsP);
- ks_assert(pool);
- //ks_assert(tpool);
-
- bds = ks_pool_alloc(pool, sizeof(*bds));
- bds->pool = pool;
- bds->tpool = tpool;
- *bdsP = bds;
-
- return KS_STATUS_SUCCESS;
-}
-
-ks_status_t blade_datastore_config(blade_datastore_t *bds, config_setting_t *config)
-{
- config_setting_t *tmp;
- config_setting_t *database = NULL;
- const char *config_database_path = NULL;
-
- ks_assert(bds);
-
- if (!config) return KS_STATUS_FAIL;
- if (!config_setting_is_group(config)) return KS_STATUS_FAIL;
-
- database = config_setting_get_member(config, "database");
- if (!database) return KS_STATUS_FAIL;
- tmp = config_lookup_from(database, "path");
- if (!tmp) return KS_STATUS_FAIL;
- if (config_setting_type(tmp) != CONFIG_TYPE_STRING) return KS_STATUS_FAIL;
- config_database_path = config_setting_get_string(tmp);
-
- if (bds->config_database_path) ks_pool_free(bds->pool, &bds->config_database_path);
- bds->config_database_path = ks_pstrdup(bds->pool, config_database_path);
-
- return KS_STATUS_SUCCESS;
-}
-
-KS_DECLARE(ks_status_t) blade_datastore_startup(blade_datastore_t *bds, config_setting_t *config)
-{
- ks_assert(bds);
-
- // @todo check if already started
-
- if (blade_datastore_config(bds, config) != KS_STATUS_SUCCESS) return KS_STATUS_FAIL;
-
- if (unqlite_open(&bds->db, bds->config_database_path, UNQLITE_OPEN_CREATE) != UNQLITE_OK) {
- const char *errbuf = NULL;
- blade_datastore_error(bds, &errbuf, NULL);
- ks_log(KS_LOG_ERROR, "BDS Open Error: %s\n", errbuf);
- return KS_STATUS_FAIL;
- }
-
- // @todo unqlite_lib_config(UNQLITE_LIB_CONFIG_MEM_ERR_CALLBACK)
-
- // @todo VM init if document store is used (and output consumer callback)
-
- return KS_STATUS_SUCCESS;
-}
-
-KS_DECLARE(ks_status_t) blade_datastore_shutdown(blade_datastore_t *bds)
-{
- ks_assert(bds);
-
- if (bds->db) {
- unqlite_close(bds->db);
- bds->db = NULL;
- }
-
- if (bds->config_database_path) ks_pool_free(bds->pool, &bds->config_database_path);
-
- return KS_STATUS_SUCCESS;
-}
-
-
-KS_DECLARE(void) blade_datastore_error(blade_datastore_t *bds, const char **buffer, int32_t *buffer_length)
-{
- ks_assert(bds);
- ks_assert(bds->db);
- ks_assert(buffer);
-
- unqlite_config(bds->db, UNQLITE_CONFIG_ERR_LOG, buffer, buffer_length);
-}
-
-KS_DECLARE(ks_status_t) blade_datastore_store(blade_datastore_t *bds, const void *key, int32_t key_length, const void *data, int64_t data_length)
-{
- int32_t rc;
- ks_status_t ret = KS_STATUS_SUCCESS;
-
- ks_assert(bds);
- ks_assert(bds->db);
- ks_assert(key);
- ks_assert(key_length > 0);
- ks_assert(data);
- ks_assert(data_length > 0);
-
- rc = unqlite_begin(bds->db);
-
- if (rc != UNQLITE_OK) {
- if (rc == UNQLITE_BUSY) ret = KS_STATUS_TIMEOUT;
- else {
- const char *errbuf;
- blade_datastore_error(bds, &errbuf, NULL);
- ks_log(KS_LOG_ERROR, "BDS Store Error: %s\n", errbuf);
-
- ret = KS_STATUS_FAIL;
- }
- } else if (unqlite_kv_store(bds->db, key, key_length, data, data_length) == UNQLITE_OK) unqlite_commit(bds->db);
- else unqlite_rollback(bds->db);
-
- return ret;
-}
-
-int blade_datastore_fetch_callback(const void *data, unsigned int data_length, void *userdata)
-{
- int rc = UNQLITE_OK;
- blade_datastore_fetch_userdata_t *ud = NULL;
-
- ks_assert(data);
- ks_assert(data_length > 0);
- ks_assert(userdata);
-
- ud = (blade_datastore_fetch_userdata_t *)userdata;
- if (!ud->callback(ud->bds, data, data_length, ud->userdata)) rc = UNQLITE_ABORT;
-
- return rc;
-}
-
-KS_DECLARE(ks_status_t) blade_datastore_fetch(blade_datastore_t *bds,
- blade_datastore_fetch_callback_t callback,
- const void *key,
- int32_t key_length,
- void *userdata)
-{
- int32_t rc;
- ks_status_t ret = KS_STATUS_SUCCESS;
- blade_datastore_fetch_userdata_t ud;
-
- ks_assert(bds);
- ks_assert(bds->db);
- ks_assert(callback);
- ks_assert(key);
- ks_assert(key_length > 0);
-
- ud.bds = bds;
- ud.callback = callback;
- ud.userdata = userdata;
-
- rc = unqlite_kv_fetch_callback(bds->db, key, key_length, blade_datastore_fetch_callback, &ud);
-
- if (rc != UNQLITE_OK) {
- if (rc == UNQLITE_BUSY) ret = KS_STATUS_TIMEOUT;
- else if(rc == UNQLITE_NOTFOUND) ret = KS_STATUS_NOT_FOUND;
- else {
- const char *errbuf;
- blade_datastore_error(bds, &errbuf, NULL);
- ks_log(KS_LOG_ERROR, "BDS Fetch Error: %s\n", errbuf);
-
- ret = KS_STATUS_FAIL;
- }
- }
-
- return ret;
-}
-
-/* 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_jsonrpc.c b/libs/libblade/src/blade_jsonrpc.c
new file mode 100644
index 0000000000..2913a3bb6c
--- /dev/null
+++ b/libs/libblade/src/blade_jsonrpc.c
@@ -0,0 +1,396 @@
+/*
+ * 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_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(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_module.c b/libs/libblade/src/blade_module.c
deleted file mode 100644
index 87ea7b3de9..0000000000
--- a/libs/libblade/src/blade_module.c
+++ /dev/null
@@ -1,153 +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_module_s {
- blade_handle_t *handle;
- ks_pool_t *pool;
- const char *id;
-
- void *module_data;
- blade_module_callbacks_t *module_callbacks;
-};
-
-static void blade_module_cleanup(ks_pool_t *pool, void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type)
-{
- //blade_module_t *bm = (blade_module_t *)ptr;
-
- //ks_assert(bm);
-
- switch (action) {
- case KS_MPCL_ANNOUNCE:
- break;
- case KS_MPCL_TEARDOWN:
- break;
- case KS_MPCL_DESTROY:
- break;
- }
-}
-
-KS_DECLARE(ks_status_t) blade_module_create(blade_module_t **bmP, blade_handle_t *bh, ks_pool_t *pool, void *module_data, blade_module_callbacks_t *module_callbacks)
-{
- blade_module_t *bm = NULL;
- uuid_t uuid;
-
- ks_assert(bmP);
- ks_assert(bh);
- ks_assert(pool);
- ks_assert(module_data);
- ks_assert(module_callbacks);
-
- ks_uuid(&uuid);
-
- bm = ks_pool_alloc(pool, sizeof(blade_module_t));
- bm->handle = bh;
- bm->pool = pool;
- bm->id = ks_uuid_str(pool, &uuid);
- bm->module_data = module_data;
- bm->module_callbacks = module_callbacks;
-
- ks_pool_set_cleanup(pool, bm, NULL, blade_module_cleanup);
-
- ks_log(KS_LOG_DEBUG, "Created\n");
-
- *bmP = bm;
-
- return KS_STATUS_SUCCESS;
-}
-
-KS_DECLARE(ks_status_t) blade_module_destroy(blade_module_t **bmP)
-{
- blade_module_t *bm = NULL;
- ks_pool_t *pool = NULL;
-
- ks_assert(bmP);
- ks_assert(*bmP);
-
- bm = *bmP;
-
- pool = bm->pool;
- //ks_pool_free(bm->pool, bmP);
- ks_pool_close(&pool);
-
- *bmP = NULL;
-
- return KS_STATUS_SUCCESS;
-}
-
-KS_DECLARE(blade_handle_t *) blade_module_handle_get(blade_module_t *bm)
-{
- ks_assert(bm);
-
- return bm->handle;
-}
-
-KS_DECLARE(ks_pool_t *) blade_module_pool_get(blade_module_t *bm)
-{
- ks_assert(bm);
-
- return bm->pool;
-}
-
-KS_DECLARE(const char *) blade_module_id_get(blade_module_t *bm)
-{
- ks_assert(bm);
-
- return bm->id;
-}
-
-KS_DECLARE(void *) blade_module_data_get(blade_module_t *bm)
-{
- ks_assert(bm);
-
- return bm->module_data;
-}
-
-KS_DECLARE(blade_module_callbacks_t *) blade_module_callbacks_get(blade_module_t *bm)
-{
- ks_assert(bm);
-
- return bm->module_callbacks;
-}
-
-/* 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_module_master.c b/libs/libblade/src/blade_module_master.c
new file mode 100644
index 0000000000..fc3163e944
--- /dev/null
+++ b/libs/libblade/src/blade_module_master.c
@@ -0,0 +1,274 @@
+/*
+ * 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"
+
+typedef struct blade_module_master_s blade_module_master_t;
+
+struct blade_module_master_s {
+ blade_handle_t *handle;
+ ks_pool_t *pool;
+ blade_module_t *module;
+
+ blade_space_t *blade_space;
+ blade_space_t *blade_application_space;
+};
+
+
+ks_bool_t blade_register_request_handler(blade_module_t *bm, blade_request_t *breq);
+// @todo blade_unregister_request_handler for more graceful shutdowns which intend to disconnect, and won't reconnect, which expire a session immediately
+ks_bool_t blade_application_register_request_handler(blade_module_t *bm, blade_request_t *breq); // @todo response of registration indicates if you are the primary, or a slave
+// @todo blade_application_unregister_request_handler for ability to unregister a slave (or primary) from the application, upon last node unregistering, the application entry would be automatically destroyed
+// @todo event (or request to confirm acceptance with a response?) that allows a master to tell a slave it's the new primary for an application it has registered to provide when a primary disconnects, or a
+// primary change is requested externally
+// @todo to avoid a race condition, if a slave gets unexpected primary calls before being notified by an event, should it assume it has become the primary and not yet notified?
+
+static blade_module_callbacks_t g_module_master_callbacks =
+{
+ blade_module_master_on_startup,
+ blade_module_master_on_shutdown,
+};
+
+
+static void blade_module_master_cleanup(ks_pool_t *pool, void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type)
+{
+ //blade_module_master_t *bm_master = (blade_module_master_t *)ptr;
+
+ //ks_assert(bm_master);
+
+ switch (action) {
+ case KS_MPCL_ANNOUNCE:
+ break;
+ case KS_MPCL_TEARDOWN:
+ break;
+ case KS_MPCL_DESTROY:
+ break;
+ }
+}
+
+KS_DECLARE(ks_status_t) blade_module_master_create(blade_module_t **bmP, blade_handle_t *bh)
+{
+ blade_module_master_t *bm_master = NULL;
+ ks_pool_t *pool = NULL;
+
+ ks_assert(bmP);
+ ks_assert(bh);
+
+ ks_pool_open(&pool);
+ ks_assert(pool);
+
+ bm_master = ks_pool_alloc(pool, sizeof(blade_module_master_t));
+ bm_master->handle = bh;
+ bm_master->pool = pool;
+
+ blade_module_create(&bm_master->module, bh, pool, bm_master, &g_module_master_callbacks);
+
+ ks_pool_set_cleanup(pool, bm_master, NULL, blade_module_master_cleanup);
+
+ ks_log(KS_LOG_DEBUG, "Created\n");
+
+ *bmP = bm_master->module;
+
+ return KS_STATUS_SUCCESS;
+}
+
+
+ks_status_t blade_module_master_config(blade_module_master_t *bm_master, config_setting_t *config)
+{
+ ks_assert(bm_master);
+ ks_assert(config);
+
+ ks_log(KS_LOG_DEBUG, "Configured\n");
+
+ return KS_STATUS_SUCCESS;
+}
+
+KS_DECLARE(ks_status_t) blade_module_master_on_startup(blade_module_t *bm, config_setting_t *config)
+{
+ blade_module_master_t *bm_master = NULL;
+ blade_space_t *space = NULL;
+ blade_method_t *method = NULL;
+
+ ks_assert(bm);
+ ks_assert(config);
+
+ bm_master = (blade_module_master_t *)blade_module_data_get(bm);
+
+ if (blade_module_master_config(bm_master, config) != KS_STATUS_SUCCESS) {
+ ks_log(KS_LOG_DEBUG, "blade_module_master_config failed\n");
+ return KS_STATUS_FAIL;
+ }
+
+ blade_space_create(&space, bm_master->handle, bm, "blade");
+ ks_assert(space);
+
+ bm_master->blade_space = space;
+
+ blade_method_create(&method, space, "register", blade_register_request_handler);
+ ks_assert(method);
+ blade_space_methods_add(space, method);
+
+ blade_handle_space_register(space);
+
+
+ blade_space_create(&space, bm_master->handle, bm, "blade.application");
+ ks_assert(space);
+
+ bm_master->blade_application_space = space;
+
+ blade_method_create(&method, space, "register", blade_application_register_request_handler);
+ ks_assert(method);
+ blade_space_methods_add(space, method);
+
+ blade_handle_space_register(space);
+
+
+ ks_log(KS_LOG_DEBUG, "Started\n");
+
+ return KS_STATUS_SUCCESS;
+}
+
+KS_DECLARE(ks_status_t) blade_module_master_on_shutdown(blade_module_t *bm)
+{
+ blade_module_master_t *bm_master = NULL;
+
+ ks_assert(bm);
+
+ bm_master = (blade_module_master_t *)blade_module_data_get(bm);
+
+ if (bm_master->blade_application_space) blade_handle_space_unregister(bm_master->blade_application_space);
+ if (bm_master->blade_space) blade_handle_space_unregister(bm_master->blade_space);
+
+ ks_log(KS_LOG_DEBUG, "Stopped\n");
+
+ return KS_STATUS_SUCCESS;
+}
+
+ks_bool_t blade_register_request_handler(blade_module_t *bm, blade_request_t *breq)
+{
+ blade_module_master_t *bm_master = NULL;
+ blade_session_t *bs = NULL;
+ cJSON *params = NULL;
+ cJSON *res = NULL;
+ const char *params_identity = NULL;
+ const char *identity = NULL;
+
+ ks_assert(bm);
+ ks_assert(breq);
+
+ ks_log(KS_LOG_DEBUG, "Request Received!\n");
+
+ bm_master = (blade_module_master_t *)blade_module_data_get(bm);
+ ks_assert(bm_master);
+
+ bs = blade_handle_sessions_get(breq->handle, breq->session_id);
+ ks_assert(bs);
+
+ blade_session_properties_write_lock(bs, KS_TRUE);
+
+ 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 register 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 (!(params_identity = cJSON_GetObjectCstr(params, "identity"))) {
+ ks_log(KS_LOG_DEBUG, "Session (%s) attempted to register with no 'identity'\n", blade_session_id_get(bs));
+ blade_rpc_error_create(&res, NULL, breq->message_id, -32602, "Missing params identity string");
+ } else {
+ identity = blade_session_identity_get(bs);
+ if (identity && identity[0]) {
+ ks_log(KS_LOG_DEBUG, "Session (%s) attempted to register with master but is already registered as %s\n", blade_session_id_get(bs), identity);
+ blade_rpc_error_create(&res, NULL, breq->message_id, -1000, "Already registered");
+ } else {
+ // @todo plug in authentication to confirm if this registration is permitted, just allow it for now as long as it's not already in use
+
+ blade_rpc_response_create(&res, NULL, breq->message_id);
+
+ // @todo this is completely unfinished, return to finish this after catching up other changes
+ //blade_handle_session_identify(bh, identity, bs);
+ //blade_session_identity_set(bs, params_identity);
+ }
+ }
+
+ 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_application_register_request_handler(blade_module_t *bm, blade_request_t *breq)
+{
+ blade_module_master_t *bm_master = NULL;
+ blade_session_t *bs = NULL;
+ //cJSON *res = NULL;
+
+ ks_assert(bm);
+ ks_assert(breq);
+
+ ks_log(KS_LOG_DEBUG, "Request Received!\n");
+
+ bm_master = (blade_module_master_t *)blade_module_data_get(bm);
+ ks_assert(bm_master);
+
+ bs = blade_handle_sessions_get(breq->handle, breq->session_id);
+ ks_assert(bs);
+
+ //blade_rpc_error_create(&res, NULL, breq->message_id, -10000, "???");
+ //blade_rpc_response_create(&res, NULL, breq->message_id);
+
+
+ //blade_session_send(bs, res, NULL);
+
+ blade_session_read_unlock(bs);
+
+ //cJSON_Delete(res);
+
+ return KS_FALSE;
+}
+
+
+/* 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_module_wss.c b/libs/libblade/src/blade_module_wss.c
deleted file mode 100644
index c5fc231e19..0000000000
--- a/libs/libblade/src/blade_module_wss.c
+++ /dev/null
@@ -1,1131 +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"
-
-#define BLADE_MODULE_WSS_TRANSPORT_NAME "wss"
-#define BLADE_MODULE_WSS_ENDPOINTS_MULTIHOME_MAX 16
-
-typedef struct blade_module_wss_s blade_module_wss_t;
-typedef struct blade_transport_wss_s blade_transport_wss_t;
-
-struct blade_module_wss_s {
- blade_handle_t *handle;
- ks_pool_t *pool;
- blade_module_t *module;
- blade_module_callbacks_t *module_callbacks;
- blade_transport_callbacks_t *transport_callbacks;
-
- ks_sockaddr_t config_wss_endpoints_ipv4[BLADE_MODULE_WSS_ENDPOINTS_MULTIHOME_MAX];
- ks_sockaddr_t config_wss_endpoints_ipv6[BLADE_MODULE_WSS_ENDPOINTS_MULTIHOME_MAX];
- int32_t config_wss_endpoints_ipv4_length;
- int32_t config_wss_endpoints_ipv6_length;
- int32_t config_wss_endpoints_backlog;
-
- volatile ks_bool_t shutdown;
-
- struct pollfd *listeners_poll;
- int32_t listeners_count;
-};
-
-struct blade_transport_wss_s {
- blade_module_wss_t *module;
- ks_pool_t *pool;
-
- const char *session_id;
- ks_socket_t sock;
- kws_t *kws;
-};
-
-
-
-ks_status_t blade_module_wss_listen(blade_module_wss_t *bm, ks_sockaddr_t *addr);
-void *blade_module_wss_listeners_thread(ks_thread_t *thread, void *data);
-
-
-ks_status_t blade_transport_wss_create(blade_transport_wss_t **bt_wssP, ks_pool_t *pool, blade_module_wss_t *bm_wss, ks_socket_t sock, const char *session_id);
-
-ks_status_t blade_transport_wss_on_connect(blade_connection_t **bcP, blade_module_t *bm, blade_identity_t *target, const char *session_id);
-blade_connection_rank_t blade_transport_wss_on_rank(blade_connection_t *bc, blade_identity_t *target);
-
-ks_status_t blade_transport_wss_on_send(blade_connection_t *bc, cJSON *json);
-ks_status_t blade_transport_wss_on_receive(blade_connection_t *bc, cJSON **json);
-
-blade_connection_state_hook_t blade_transport_wss_on_state_disconnect(blade_connection_t *bc, blade_connection_state_condition_t condition);
-blade_connection_state_hook_t blade_transport_wss_on_state_new_inbound(blade_connection_t *bc, blade_connection_state_condition_t condition);
-blade_connection_state_hook_t blade_transport_wss_on_state_new_outbound(blade_connection_t *bc, blade_connection_state_condition_t condition);
-blade_connection_state_hook_t blade_transport_wss_on_state_connect_inbound(blade_connection_t *bc, blade_connection_state_condition_t condition);
-blade_connection_state_hook_t blade_transport_wss_on_state_connect_outbound(blade_connection_t *bc, blade_connection_state_condition_t condition);
-blade_connection_state_hook_t blade_transport_wss_on_state_attach_inbound(blade_connection_t *bc, blade_connection_state_condition_t condition);
-blade_connection_state_hook_t blade_transport_wss_on_state_attach_outbound(blade_connection_t *bc, blade_connection_state_condition_t condition);
-blade_connection_state_hook_t blade_transport_wss_on_state_detach_inbound(blade_connection_t *bc, blade_connection_state_condition_t condition);
-blade_connection_state_hook_t blade_transport_wss_on_state_detach_outbound(blade_connection_t *bc, blade_connection_state_condition_t condition);
-blade_connection_state_hook_t blade_transport_wss_on_state_ready_inbound(blade_connection_t *bc, blade_connection_state_condition_t condition);
-blade_connection_state_hook_t blade_transport_wss_on_state_ready_outbound(blade_connection_t *bc, blade_connection_state_condition_t condition);
-
-
-
-static blade_module_callbacks_t g_module_wss_callbacks =
-{
- blade_module_wss_on_startup,
- blade_module_wss_on_shutdown,
-};
-
-static blade_transport_callbacks_t g_transport_wss_callbacks =
-{
- blade_transport_wss_on_connect,
- blade_transport_wss_on_rank,
- blade_transport_wss_on_send,
- blade_transport_wss_on_receive,
-
- blade_transport_wss_on_state_disconnect,
- blade_transport_wss_on_state_disconnect,
- blade_transport_wss_on_state_new_inbound,
- blade_transport_wss_on_state_new_outbound,
- blade_transport_wss_on_state_connect_inbound,
- blade_transport_wss_on_state_connect_outbound,
- blade_transport_wss_on_state_attach_inbound,
- blade_transport_wss_on_state_attach_outbound,
- blade_transport_wss_on_state_detach_inbound,
- blade_transport_wss_on_state_detach_outbound,
- blade_transport_wss_on_state_ready_inbound,
- blade_transport_wss_on_state_ready_outbound,
-};
-
-
-static void blade_module_wss_cleanup(ks_pool_t *pool, void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type)
-{
- //blade_module_wss_t *bm_wss = (blade_module_wss_t *)ptr;
-
- //ks_assert(bm_wss);
-
- switch (action) {
- case KS_MPCL_ANNOUNCE:
- break;
- case KS_MPCL_TEARDOWN:
- break;
- case KS_MPCL_DESTROY:
- break;
- }
-}
-
-KS_DECLARE(ks_status_t) blade_module_wss_create(blade_module_t **bmP, blade_handle_t *bh)
-{
- blade_module_wss_t *bm_wss = NULL;
- ks_pool_t *pool = NULL;
-
- ks_assert(bmP);
- ks_assert(bh);
-
- ks_pool_open(&pool);
- ks_assert(pool);
-
- bm_wss = ks_pool_alloc(pool, sizeof(blade_module_wss_t));
- bm_wss->handle = bh;
- bm_wss->pool = pool;
-
- blade_module_create(&bm_wss->module, bh, pool, bm_wss, &g_module_wss_callbacks);
- bm_wss->module_callbacks = &g_module_wss_callbacks;
- bm_wss->transport_callbacks = &g_transport_wss_callbacks;
-
- ks_pool_set_cleanup(pool, bm_wss, NULL, blade_module_wss_cleanup);
-
- ks_log(KS_LOG_DEBUG, "Created\n");
-
- *bmP = bm_wss->module;
-
- return KS_STATUS_SUCCESS;
-}
-
-
-ks_status_t blade_module_wss_config(blade_module_wss_t *bm_wss, config_setting_t *config)
-{
- config_setting_t *wss = NULL;
- config_setting_t *wss_endpoints = NULL;
- config_setting_t *wss_endpoints_ipv4 = NULL;
- config_setting_t *wss_endpoints_ipv6 = NULL;
- config_setting_t *wss_ssl = NULL;
- config_setting_t *element;
- config_setting_t *tmp1;
- config_setting_t *tmp2;
- ks_sockaddr_t config_wss_endpoints_ipv4[BLADE_MODULE_WSS_ENDPOINTS_MULTIHOME_MAX];
- ks_sockaddr_t config_wss_endpoints_ipv6[BLADE_MODULE_WSS_ENDPOINTS_MULTIHOME_MAX];
- int32_t config_wss_endpoints_ipv4_length = 0;
- int32_t config_wss_endpoints_ipv6_length = 0;
- int32_t config_wss_endpoints_backlog = 8;
-
- ks_assert(bm_wss);
- ks_assert(config);
-
- if (!config_setting_is_group(config)) {
- ks_log(KS_LOG_DEBUG, "!config_setting_is_group(config)\n");
- return KS_STATUS_FAIL;
- }
-
- wss = config_setting_get_member(config, "wss");
- if (wss) {
- wss_endpoints = config_setting_get_member(wss, "endpoints");
- if (!wss_endpoints) {
- ks_log(KS_LOG_DEBUG, "!wss_endpoints\n");
- return KS_STATUS_FAIL;
- }
- wss_endpoints_ipv4 = config_lookup_from(wss_endpoints, "ipv4");
- wss_endpoints_ipv6 = config_lookup_from(wss_endpoints, "ipv6");
- if (wss_endpoints_ipv4) {
- if (config_setting_type(wss_endpoints_ipv4) != CONFIG_TYPE_LIST) return KS_STATUS_FAIL;
- if ((config_wss_endpoints_ipv4_length = config_setting_length(wss_endpoints_ipv4)) > BLADE_MODULE_WSS_ENDPOINTS_MULTIHOME_MAX)
- return KS_STATUS_FAIL;
-
- for (int32_t index = 0; index < config_wss_endpoints_ipv4_length; ++index) {
- element = config_setting_get_elem(wss_endpoints_ipv4, index);
- tmp1 = config_lookup_from(element, "address");
- tmp2 = config_lookup_from(element, "port");
- if (!tmp1 || !tmp2) return KS_STATUS_FAIL;
- if (config_setting_type(tmp1) != CONFIG_TYPE_STRING) return KS_STATUS_FAIL;
- if (config_setting_type(tmp2) != CONFIG_TYPE_INT) return KS_STATUS_FAIL;
-
- if (ks_addr_set(&config_wss_endpoints_ipv4[index],
- config_setting_get_string(tmp1),
- config_setting_get_int(tmp2),
- AF_INET) != KS_STATUS_SUCCESS) return KS_STATUS_FAIL;
- ks_log(KS_LOG_DEBUG,
- "Binding to IPV4 %s on port %d\n",
- ks_addr_get_host(&config_wss_endpoints_ipv4[index]),
- ks_addr_get_port(&config_wss_endpoints_ipv4[index]));
- }
- }
- if (wss_endpoints_ipv6) {
- if (config_setting_type(wss_endpoints_ipv6) != CONFIG_TYPE_LIST) return KS_STATUS_FAIL;
- if ((config_wss_endpoints_ipv6_length = config_setting_length(wss_endpoints_ipv6)) > BLADE_MODULE_WSS_ENDPOINTS_MULTIHOME_MAX)
- return KS_STATUS_FAIL;
-
- for (int32_t index = 0; index < config_wss_endpoints_ipv6_length; ++index) {
- element = config_setting_get_elem(wss_endpoints_ipv6, index);
- tmp1 = config_lookup_from(element, "address");
- tmp2 = config_lookup_from(element, "port");
- if (!tmp1 || !tmp2) return KS_STATUS_FAIL;
- if (config_setting_type(tmp1) != CONFIG_TYPE_STRING) return KS_STATUS_FAIL;
- if (config_setting_type(tmp2) != CONFIG_TYPE_INT) return KS_STATUS_FAIL;
-
-
- if (ks_addr_set(&config_wss_endpoints_ipv6[index],
- config_setting_get_string(tmp1),
- config_setting_get_int(tmp2),
- AF_INET6) != KS_STATUS_SUCCESS) return KS_STATUS_FAIL;
- ks_log(KS_LOG_DEBUG,
- "Binding to IPV6 %s on port %d\n",
- ks_addr_get_host(&config_wss_endpoints_ipv6[index]),
- ks_addr_get_port(&config_wss_endpoints_ipv6[index]));
- }
- }
- if (config_wss_endpoints_ipv4_length + config_wss_endpoints_ipv6_length <= 0) return KS_STATUS_FAIL;
- tmp1 = config_lookup_from(wss_endpoints, "backlog");
- if (tmp1) {
- if (config_setting_type(tmp1) != CONFIG_TYPE_INT) return KS_STATUS_FAIL;
- config_wss_endpoints_backlog = config_setting_get_int(tmp1);
- }
- wss_ssl = config_setting_get_member(wss, "ssl");
- if (wss_ssl) {
- // @todo: SSL stuffs from wss_ssl into config_wss_ssl envelope
- }
- }
-
-
- // Configuration is valid, now assign it to the variables that are used
- // If the configuration was invalid, then this does not get changed
- for (int32_t index = 0; index < config_wss_endpoints_ipv4_length; ++index)
- bm_wss->config_wss_endpoints_ipv4[index] = config_wss_endpoints_ipv4[index];
- for (int32_t index = 0; index < config_wss_endpoints_ipv6_length; ++index)
- bm_wss->config_wss_endpoints_ipv6[index] = config_wss_endpoints_ipv6[index];
- bm_wss->config_wss_endpoints_ipv4_length = config_wss_endpoints_ipv4_length;
- bm_wss->config_wss_endpoints_ipv6_length = config_wss_endpoints_ipv6_length;
- bm_wss->config_wss_endpoints_backlog = config_wss_endpoints_backlog;
- //bm_wss->config_wss_ssl = config_wss_ssl;
-
- ks_log(KS_LOG_DEBUG, "Configured\n");
-
- return KS_STATUS_SUCCESS;
-}
-
-KS_DECLARE(ks_status_t) blade_module_wss_on_startup(blade_module_t *bm, config_setting_t *config)
-{
- blade_module_wss_t *bm_wss = NULL;
-
- ks_assert(bm);
- ks_assert(config);
-
- bm_wss = (blade_module_wss_t *)blade_module_data_get(bm);
-
- if (blade_module_wss_config(bm_wss, config) != KS_STATUS_SUCCESS) {
- ks_log(KS_LOG_DEBUG, "blade_module_wss_config failed\n");
- return KS_STATUS_FAIL;
- }
-
- for (int32_t index = 0; index < bm_wss->config_wss_endpoints_ipv4_length; ++index) {
- if (blade_module_wss_listen(bm_wss, &bm_wss->config_wss_endpoints_ipv4[index]) != KS_STATUS_SUCCESS) {
- ks_log(KS_LOG_DEBUG, "blade_module_wss_listen (v4) failed\n");
- return KS_STATUS_FAIL;
- }
- }
- for (int32_t index = 0; index < bm_wss->config_wss_endpoints_ipv6_length; ++index) {
- if (blade_module_wss_listen(bm_wss, &bm_wss->config_wss_endpoints_ipv6[index]) != KS_STATUS_SUCCESS) {
- ks_log(KS_LOG_DEBUG, "blade_module_wss_listen (v6) failed\n");
- return KS_STATUS_FAIL;
- }
- }
-
-
- if (bm_wss->listeners_count > 0 &&
- ks_thread_pool_add_job(blade_handle_tpool_get(bm_wss->handle), blade_module_wss_listeners_thread, bm_wss) != KS_STATUS_SUCCESS) {
- // @todo error logging
- return KS_STATUS_FAIL;
- }
-
- blade_handle_transport_register(bm_wss->handle, bm, BLADE_MODULE_WSS_TRANSPORT_NAME, bm_wss->transport_callbacks);
-
- ks_log(KS_LOG_DEBUG, "Started\n");
-
- return KS_STATUS_SUCCESS;
-}
-
-KS_DECLARE(ks_status_t) blade_module_wss_on_shutdown(blade_module_t *bm)
-{
- blade_module_wss_t *bm_wss = NULL;
-
- ks_assert(bm);
-
- bm_wss = (blade_module_wss_t *)blade_module_data_get(bm);
-
- if (bm_wss->listeners_count > 0) {
- bm_wss->shutdown = KS_TRUE;
- while (bm_wss->shutdown) ks_sleep_ms(1);
- }
-
- blade_handle_transport_unregister(bm_wss->handle, BLADE_MODULE_WSS_TRANSPORT_NAME);
-
- for (int32_t index = 0; index < bm_wss->listeners_count; ++index) {
- ks_socket_t sock = bm_wss->listeners_poll[index].fd;
- ks_socket_shutdown(sock, SHUT_RDWR);
- ks_socket_close(&sock);
- }
-
- ks_log(KS_LOG_DEBUG, "Stopped\n");
-
- return KS_STATUS_SUCCESS;
-}
-
-ks_status_t blade_module_wss_listen(blade_module_wss_t *bm_wss, ks_sockaddr_t *addr)
-{
- ks_socket_t listener = KS_SOCK_INVALID;
- int32_t listener_index = -1;
- ks_status_t ret = KS_STATUS_SUCCESS;
-
- ks_assert(bm_wss);
- ks_assert(addr);
-
- if ((listener = socket(addr->family, SOCK_STREAM, IPPROTO_TCP)) == KS_SOCK_INVALID) {
- ks_log(KS_LOG_DEBUG, "listener == KS_SOCK_INVALID\n");
- ret = KS_STATUS_FAIL;
- goto done;
- }
-
- ks_socket_option(listener, SO_REUSEADDR, KS_TRUE);
- ks_socket_option(listener, TCP_NODELAY, KS_TRUE);
- if (addr->family == AF_INET6) ks_socket_option(listener, IPV6_V6ONLY, KS_TRUE);
-
- if (ks_addr_bind(listener, addr) != KS_STATUS_SUCCESS) {
- ks_log(KS_LOG_DEBUG, "ks_addr_bind(listener, addr) != KS_STATUS_SUCCESS\n");
- ret = KS_STATUS_FAIL;
- goto done;
- }
-
- if (listen(listener, bm_wss->config_wss_endpoints_backlog) != 0) {
- ks_log(KS_LOG_DEBUG, "listen(listener, backlog) != 0\n");
- ret = KS_STATUS_FAIL;
- goto done;
- }
-
- listener_index = bm_wss->listeners_count++;
- bm_wss->listeners_poll = (struct pollfd *)ks_pool_resize(bm_wss->pool,
- bm_wss->listeners_poll,
- sizeof(struct pollfd) * bm_wss->listeners_count);
- ks_assert(bm_wss->listeners_poll);
- bm_wss->listeners_poll[listener_index].fd = listener;
- bm_wss->listeners_poll[listener_index].events = POLLIN; // | POLLERR;
-
- ks_log(KS_LOG_DEBUG, "Bound %s on port %d at index %d\n", ks_addr_get_host(addr), ks_addr_get_port(addr), listener_index);
-
- done:
- if (ret != KS_STATUS_SUCCESS) {
- if (listener != KS_SOCK_INVALID) {
- ks_socket_shutdown(listener, SHUT_RDWR);
- ks_socket_close(&listener);
- }
- }
- return ret;
-}
-
-void *blade_module_wss_listeners_thread(ks_thread_t *thread, void *data)
-{
- blade_module_wss_t *bm_wss = NULL;
- blade_transport_wss_t *bt_wss = NULL;
- blade_connection_t *bc = NULL;
-
- ks_assert(thread);
- ks_assert(data);
-
- bm_wss = (blade_module_wss_t *)data;
-
- ks_log(KS_LOG_DEBUG, "Started\n");
- while (!bm_wss->shutdown) {
- // @todo take exact timeout from a setting in config_wss_endpoints
- if (ks_poll(bm_wss->listeners_poll, bm_wss->listeners_count, 100) > 0) {
- for (int32_t index = 0; index < bm_wss->listeners_count; ++index) {
- ks_socket_t sock = KS_SOCK_INVALID;
-
- if (bm_wss->listeners_poll[index].revents & POLLERR) {
- // @todo: error handling, just skip the listener for now, it might recover, could skip X times before closing?
- ks_log(KS_LOG_DEBUG, "POLLERR on index %d\n", index);
- continue;
- }
- if (!(bm_wss->listeners_poll[index].revents & POLLIN)) continue;
-
- if ((sock = accept(bm_wss->listeners_poll[index].fd, NULL, NULL)) == KS_SOCK_INVALID) {
- // @todo: error handling, just skip the socket for now as most causes are because remote side became unreachable
- ks_log(KS_LOG_DEBUG, "Accept failed on index %d\n", index);
- continue;
- }
-
- // @todo getsockname and getpeername (getpeername can be skipped if passing to accept instead)
-
- ks_log(KS_LOG_DEBUG, "Socket accepted\n", index);
-
- // @todo make new function to wrap the following code all the way through assigning initial state to reuse in outbound connects
- blade_connection_create(&bc, bm_wss->handle);
- ks_assert(bc);
-
- blade_transport_wss_create(&bt_wss, blade_connection_pool_get(bc), bm_wss, sock, NULL);
- ks_assert(bt_wss);
-
- blade_connection_transport_set(bc, bt_wss, bm_wss->transport_callbacks);
-
- blade_connection_read_lock(bc, KS_TRUE);
-
- if (blade_connection_startup(bc, BLADE_CONNECTION_DIRECTION_INBOUND) != KS_STATUS_SUCCESS) {
- ks_log(KS_LOG_DEBUG, "Connection (%s) startup failed\n", blade_connection_id_get(bc));
- blade_connection_read_unlock(bc);
- blade_connection_destroy(&bc);
- continue;
- }
- ks_log(KS_LOG_DEBUG, "Connection (%s) started\n", blade_connection_id_get(bc));
-
- blade_handle_connections_add(bc);
-
- blade_connection_state_set(bc, BLADE_CONNECTION_STATE_NEW);
-
- blade_connection_read_unlock(bc);
- // @todo end of reusable function, lock ensures it cannot be destroyed until this code finishes
- }
- }
- }
- ks_log(KS_LOG_DEBUG, "Stopped\n");
-
- bm_wss->shutdown = KS_FALSE;
-
- return NULL;
-}
-
-static void blade_transport_wss_cleanup(ks_pool_t *pool, void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type)
-{
- blade_transport_wss_t *bt_wss = (blade_transport_wss_t *)ptr;
-
- ks_assert(bt_wss);
-
- switch (action) {
- case KS_MPCL_ANNOUNCE:
- break;
- case KS_MPCL_TEARDOWN:
- if (bt_wss->session_id) ks_pool_free(bt_wss->pool, &bt_wss->session_id);
- if (bt_wss->kws) kws_destroy(&bt_wss->kws);
- else ks_socket_close(&bt_wss->sock);
- break;
- case KS_MPCL_DESTROY:
- break;
- }
-}
-
-
-ks_status_t blade_transport_wss_create(blade_transport_wss_t **bt_wssP, ks_pool_t *pool, blade_module_wss_t *bm_wss, ks_socket_t sock, const char *session_id)
-{
- blade_transport_wss_t *bt_wss = NULL;
-
- ks_assert(bt_wssP);
- ks_assert(bm_wss);
- ks_assert(sock != KS_SOCK_INVALID);
-
- bt_wss = ks_pool_alloc(pool, sizeof(blade_transport_wss_t));
- bt_wss->module = bm_wss;
- bt_wss->pool = pool;
- bt_wss->sock = sock;
- if (session_id) bt_wss->session_id = ks_pstrdup(pool, session_id);
-
- ks_pool_set_cleanup(pool, bt_wss, NULL, blade_transport_wss_cleanup);
-
- ks_log(KS_LOG_DEBUG, "Created\n");
-
- *bt_wssP = bt_wss;
-
- return KS_STATUS_SUCCESS;
-}
-
-ks_status_t blade_transport_wss_on_connect(blade_connection_t **bcP, blade_module_t *bm, blade_identity_t *target, const char *session_id)
-{
- ks_status_t ret = KS_STATUS_SUCCESS;
- blade_module_wss_t *bm_wss = NULL;
- ks_sockaddr_t addr;
- ks_socket_t sock = KS_SOCK_INVALID;
- int family = AF_INET;
- const char *ip = NULL;
- const char *portstr = NULL;
- ks_port_t port = 1234;
- blade_transport_wss_t *bt_wss = NULL;
- blade_connection_t *bc = NULL;
-
- ks_assert(bcP);
- ks_assert(bm);
- ks_assert(target);
-
- bm_wss = (blade_module_wss_t *)blade_module_data_get(bm);
-
- *bcP = NULL;
-
- ks_log(KS_LOG_DEBUG, "Connect Callback: %s\n", blade_identity_uri(target));
-
- // @todo completely rework all of this once more is known about connecting when an identity has no explicit transport details but this transport
- // has been choosen anyway
- ip = blade_identity_parameter_get(target, "host");
- portstr = blade_identity_parameter_get(target, "port");
- if (!ip) {
- // @todo: temporary, this should fall back on DNS SRV or whatever else can turn "a@b.com" into an ip (and port?) to connect to
- // also need to deal with hostname lookup, so identities with wss transport need to have a host parameter that is an IP for the moment
- ks_log(KS_LOG_DEBUG, "No host provided\n");
- ret = KS_STATUS_FAIL;
- goto done;
- }
-
- // @todo wrap this code to get address family from string IP between IPV4 and IPV6, and put it in libks somewhere
- {
- ks_size_t len = strlen(ip);
-
- if (len <= 3) {
- ks_log(KS_LOG_DEBUG, "Invalid host provided\n");
- ret = KS_STATUS_FAIL;
- goto done;
- }
- if (ip[1] == '.' || ip[2] == '.' || (len > 3 && ip[3] == '.')) family = AF_INET;
- else family = AF_INET6;
- }
-
- if (portstr) {
- int p = atoi(portstr);
- if (p > 0 && p <= UINT16_MAX) port = p;
- }
-
- ks_log(KS_LOG_DEBUG, "Connecting to %s on port %d\n", ip, port);
-
- ks_addr_set(&addr, ip, port, family);
- if ((sock = ks_socket_connect(SOCK_STREAM, IPPROTO_TCP, &addr)) == KS_SOCK_INVALID) {
- // @todo: error handling, just fail for now as most causes are because remote side became unreachable
- ks_log(KS_LOG_DEBUG, "Connect failed\n");
- ret = KS_STATUS_FAIL;
- goto done;
- }
-
- ks_log(KS_LOG_DEBUG, "Socket connected\n");
-
- // @todo see above listener code, make reusable function for the following code
- blade_connection_create(&bc, bm_wss->handle);
- ks_assert(bc);
-
- blade_transport_wss_create(&bt_wss, blade_connection_pool_get(bc), bm_wss, sock, session_id);
- ks_assert(bt_wss);
-
- blade_connection_transport_set(bc, bt_wss, bm_wss->transport_callbacks);
-
- blade_connection_read_lock(bc, KS_TRUE);
-
- if (blade_connection_startup(bc, BLADE_CONNECTION_DIRECTION_OUTBOUND) != KS_STATUS_SUCCESS) {
- ks_log(KS_LOG_DEBUG, "Connection (%s) startup failed\n", blade_connection_id_get(bc));
- blade_connection_read_unlock(bc);
- blade_connection_destroy(&bc);
- ret = KS_STATUS_FAIL;
- goto done;
- }
- ks_log(KS_LOG_DEBUG, "Connection (%s) started\n", blade_connection_id_get(bc));
-
- blade_handle_connections_add(bc);
-
- blade_connection_state_set(bc, BLADE_CONNECTION_STATE_NEW);
-
- blade_connection_read_unlock(bc);
-
- // @todo consider ramification of unlocking above, while returning the new connection object back to the framework, thread might run and disconnect quickly
- // @todo have blade_handle_connect and blade_transport_wss_on_connect (and the abstracted callback) return a copy of the connection id (allocated from blade_handle_t's pool temporarily) rather than the connection pointer itself
- // which will then require getting the connection and thus relock it for any further use, if it disconnects during that time the connection will be locked preventing obtaining and then return NULL if removed
- *bcP = bc;
-
- done:
- return ret;
-}
-
-blade_connection_rank_t blade_transport_wss_on_rank(blade_connection_t *bc, blade_identity_t *target)
-{
- ks_assert(bc);
- ks_assert(target);
-
- return BLADE_CONNECTION_RANK_POOR;
-}
-
-ks_status_t blade_transport_wss_write(blade_transport_wss_t *bt_wss, cJSON *json)
-{
- ks_status_t ret = KS_STATUS_SUCCESS;
- char *json_str = cJSON_PrintUnformatted(json);
- ks_size_t json_str_len = 0;
- if (!json_str) {
- ks_log(KS_LOG_DEBUG, "Failed to generate json string\n");
- ret = KS_STATUS_FAIL;
- goto done;
- }
- // @todo determine if WSOC_TEXT null terminates when read_frame is called, or if it's safe to include like this
- json_str_len = strlen(json_str) + 1;
- if ((ks_size_t)kws_write_frame(bt_wss->kws, WSOC_TEXT, json_str, json_str_len) != json_str_len) {
- ks_log(KS_LOG_DEBUG, "Failed to write frame\n");
- ret = KS_STATUS_FAIL;
- goto done;
- }
- ks_log(KS_LOG_DEBUG, "Frame written %d bytes\n", json_str_len);
-
- done:
- if (json_str) free(json_str);
-
- return ret;
-}
-
-ks_status_t blade_transport_wss_on_send(blade_connection_t *bc, cJSON *json)
-{
- blade_transport_wss_t *bt_wss = NULL;
-
- ks_assert(bc);
- ks_assert(json);
-
- bt_wss = (blade_transport_wss_t *)blade_connection_transport_get(bc);
-
- return blade_transport_wss_write(bt_wss, json);
-}
-
-ks_status_t blade_transport_wss_read(blade_transport_wss_t *bt_wss, cJSON **json)
-{
- // @todo get exact timeout from service config?
- int32_t poll_flags = ks_wait_sock(bt_wss->sock, 1, KS_POLL_READ); // | KS_POLL_ERROR);
-
- *json = NULL;
-
- if (poll_flags & KS_POLL_ERROR) {
- ks_log(KS_LOG_DEBUG, "POLLERR\n");
- return KS_STATUS_FAIL;
- }
- if (poll_flags & KS_POLL_READ) {
- kws_opcode_t opcode;
- uint8_t *frame_data = NULL;
- ks_ssize_t frame_data_len = kws_read_frame(bt_wss->kws, &opcode, &frame_data);
-
- if (frame_data_len <= 0) {
- // @todo error logging, strerror(ks_errno())
- // 0 means socket closed with WS_NONE, which closes websocket with no additional reason
- // -1 means socket closed with a general failure
- // -2 means nonblocking wait
- // other values are based on WS_XXX reasons
- // negative values are based on reasons, except for -1 is but -2 is nonblocking wait, and
- ks_log(KS_LOG_DEBUG, "Failed to read frame\n");
- return KS_STATUS_FAIL;
- }
- ks_log(KS_LOG_DEBUG, "Frame read %d bytes\n", frame_data_len);
-
- if (!(*json = cJSON_Parse((char *)frame_data))) {
- ks_log(KS_LOG_DEBUG, "Failed to parse frame\n");
- return KS_STATUS_FAIL;
- }
- }
- return KS_STATUS_SUCCESS;
-}
-
-ks_status_t blade_transport_wss_on_receive(blade_connection_t *bc, cJSON **json)
-{
- blade_transport_wss_t *bt_wss = NULL;
-
- ks_assert(bc);
- ks_assert(json);
-
- bt_wss = (blade_transport_wss_t *)blade_connection_transport_get(bc);
-
- return blade_transport_wss_read(bt_wss, json);
-}
-
-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_t *bt_wss = NULL;
- cJSON *json = NULL;
-
- ks_assert(bc);
- //ks_assert(id);
- ks_assert(message);
-
- bt_wss = (blade_transport_wss_t *)blade_connection_transport_get(bc);
-
- blade_rpc_error_create(&json, NULL, id, code, message);
-
- if (blade_transport_wss_write(bt_wss, json) != KS_STATUS_SUCCESS) {
- ks_log(KS_LOG_DEBUG, "Failed to write error message\n");
- ret = KS_STATUS_FAIL;
- }
-
- cJSON_Delete(json);
- return ret;
-}
-
-blade_connection_state_hook_t blade_transport_wss_on_state_disconnect(blade_connection_t *bc, blade_connection_state_condition_t condition)
-{
- //blade_transport_wss_t *bt_wss = NULL;
-
- ks_assert(bc);
-
- ks_log(KS_LOG_DEBUG, "State Callback: %d\n", (int32_t)condition);
-
- if (condition == BLADE_CONNECTION_STATE_CONDITION_PRE) return BLADE_CONNECTION_STATE_HOOK_SUCCESS;
-
- //bt_wss = (blade_transport_wss_t *)blade_connection_transport_get(bc);
-
- //blade_transport_wss_destroy(&bt_wss);
-
- return BLADE_CONNECTION_STATE_HOOK_SUCCESS;
-}
-
-blade_connection_state_hook_t blade_transport_wss_on_state_new_inbound(blade_connection_t *bc, blade_connection_state_condition_t condition)
-{
- ks_assert(bc);
-
- ks_log(KS_LOG_DEBUG, "State Callback: %d\n", (int32_t)condition);
-
- if (condition == BLADE_CONNECTION_STATE_CONDITION_PRE) return BLADE_CONNECTION_STATE_HOOK_SUCCESS;
-
- return BLADE_CONNECTION_STATE_HOOK_SUCCESS;
-}
-
-blade_connection_state_hook_t blade_transport_wss_on_state_new_outbound(blade_connection_t *bc, blade_connection_state_condition_t condition)
-{
- ks_assert(bc);
-
- ks_log(KS_LOG_DEBUG, "State Callback: %d\n", (int32_t)condition);
-
- if (condition == BLADE_CONNECTION_STATE_CONDITION_PRE) return BLADE_CONNECTION_STATE_HOOK_SUCCESS;
-
- return BLADE_CONNECTION_STATE_HOOK_SUCCESS;
-}
-
-blade_connection_state_hook_t blade_transport_wss_on_state_connect_inbound(blade_connection_t *bc, blade_connection_state_condition_t condition)
-{
- blade_transport_wss_t *bt_wss = NULL;
-
- ks_assert(bc);
-
- ks_log(KS_LOG_DEBUG, "State Callback: %d\n", (int32_t)condition);
-
- if (condition == BLADE_CONNECTION_STATE_CONDITION_PRE) return BLADE_CONNECTION_STATE_HOOK_SUCCESS;
-
- bt_wss = (blade_transport_wss_t *)blade_connection_transport_get(bc);
-
- // @todo: SSL init stuffs based on data from config to pass into kws_init
- if (kws_init(&bt_wss->kws, bt_wss->sock, NULL, NULL, KWS_BLOCK, bt_wss->pool) != KS_STATUS_SUCCESS) {
- ks_log(KS_LOG_DEBUG, "Failed websocket init\n");
- return BLADE_CONNECTION_STATE_HOOK_DISCONNECT;
- }
-
- return BLADE_CONNECTION_STATE_HOOK_SUCCESS;
-}
-
-blade_connection_state_hook_t blade_transport_wss_on_state_connect_outbound(blade_connection_t *bc, blade_connection_state_condition_t condition)
-{
- blade_transport_wss_t *bt_wss = NULL;
-
- ks_assert(bc);
-
- ks_log(KS_LOG_DEBUG, "State Callback: %d\n", (int32_t)condition);
-
- if (condition == BLADE_CONNECTION_STATE_CONDITION_PRE) return BLADE_CONNECTION_STATE_HOOK_SUCCESS;
-
- bt_wss = (blade_transport_wss_t *)blade_connection_transport_get(bc);
-
- // @todo: SSL init stuffs based on data from config to pass into kws_init
- if (kws_init(&bt_wss->kws, bt_wss->sock, NULL, "/blade:blade.invalid:blade", KWS_BLOCK, bt_wss->pool) != KS_STATUS_SUCCESS) {
- ks_log(KS_LOG_DEBUG, "Failed websocket init\n");
- return BLADE_CONNECTION_STATE_HOOK_DISCONNECT;
- }
-
- return BLADE_CONNECTION_STATE_HOOK_SUCCESS;
-}
-
-blade_connection_state_hook_t blade_transport_wss_on_state_attach_inbound(blade_connection_t *bc, blade_connection_state_condition_t condition)
-{
- blade_connection_state_hook_t ret = BLADE_CONNECTION_STATE_HOOK_SUCCESS;
- blade_transport_wss_t *bt_wss = NULL;
- cJSON *json_req = NULL;
- cJSON *json_res = NULL;
- cJSON *json_params = NULL;
- cJSON *json_result = NULL;
- //cJSON *error = NULL;
- blade_session_t *bs = NULL;
- blade_handle_t *bh = NULL;
- const char *jsonrpc = NULL;
- const char *id = NULL;
- const char *method = NULL;
- const char *sid = NULL;
- ks_time_t timeout;
-
- ks_assert(bc);
-
- bh = blade_connection_handle_get(bc);
- ks_assert(bh);
-
- ks_log(KS_LOG_DEBUG, "State Callback: %d\n", (int32_t)condition);
-
- if (condition == BLADE_CONNECTION_STATE_CONDITION_PRE) return BLADE_CONNECTION_STATE_HOOK_SUCCESS;
-
- bt_wss = (blade_transport_wss_t *)blade_connection_transport_get(bc);
-
- // @todo very temporary, really need monotonic clock and get timeout delay and sleep delay from config
- timeout = ks_time_now() + (5 * KS_USEC_PER_SEC);
- while (blade_transport_wss_read(bt_wss, &json_req) == KS_STATUS_SUCCESS) {
- if (json_req) break;
- ks_sleep_ms(250);
- if (ks_time_now() >= timeout) break;
- }
-
- if (!json_req) {
- ks_log(KS_LOG_DEBUG, "Failed to receive message before timeout\n");
- blade_transport_wss_rpc_error_send(bc, NULL, -32600, "Timeout while expecting request");
- ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT;
- goto done;
- }
-
- // @todo validation wrapper for request and response/error to confirm jsonrpc and provide enum for output as to which it is
- 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_rpc_error_send(bc, NULL, -32600, "Invalid request, missing 'jsonrpc' field");
- ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT;
- goto done;
- }
-
- id = cJSON_GetObjectCstr(json_req, "id"); // @todo switch to number if we are not using a uuid for message id
- if (!id) {
- ks_log(KS_LOG_DEBUG, "Received message is missing 'id'\n");
- blade_transport_wss_rpc_error_send(bc, NULL, -32600, "Invalid request, missing 'id' field");
- ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT;
- goto done;
- }
-
- method = cJSON_GetObjectCstr(json_req, "method");
- if (!method || strcasecmp(method, "blade.session.attach")) {
- ks_log(KS_LOG_DEBUG, "Received message is missing 'method' or is an unexpected method\n");
- blade_transport_wss_rpc_error_send(bc, id, -32601, "Missing or unexpected 'method' field");
- ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT;
- goto done;
- }
-
- json_params = cJSON_GetObjectItem(json_req, "params");
- if (json_params) {
- sid = cJSON_GetObjectCstr(json_params, "session-id");
- if (sid) {
- // @todo validate uuid format by parsing, not currently available in uuid functions, send -32602 (invalid params) if invalid
- ks_log(KS_LOG_DEBUG, "Session (%s) requested\n", sid);
- }
- }
-
- if (sid) {
- bs = blade_handle_sessions_get(bh, sid); // bs comes out read locked if not null to prevent it being cleaned up before we are done
- if (bs) {
- if (blade_session_terminating(bs)) {
- blade_session_read_unlock(bs);
- ks_log(KS_LOG_DEBUG, "Session (%s) terminating\n", blade_session_id_get(bs));
- bs = NULL;
- } else {
- ks_log(KS_LOG_DEBUG, "Session (%s) located\n", blade_session_id_get(bs));
- }
- }
- }
-
- if (!bs) {
- blade_session_create(&bs, bh, NULL);
- ks_assert(bs);
-
- ks_log(KS_LOG_DEBUG, "Session (%s) created\n", blade_session_id_get(bs));
-
- blade_session_read_lock(bs, KS_TRUE); // this will be done by blade_handle_sessions_get() otherwise
-
- if (blade_session_startup(bs) != KS_STATUS_SUCCESS) {
- ks_log(KS_LOG_DEBUG, "Session (%s) startup failed\n", blade_session_id_get(bs));
- 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;
- goto done;
- }
- ks_log(KS_LOG_DEBUG, "Session (%s) started\n", blade_session_id_get(bs));
- blade_handle_sessions_add(bs);
- }
-
- blade_rpc_response_create(&json_res, &json_result, id);
- ks_assert(json_res);
-
- cJSON_AddStringToObject(json_result, "session-id", blade_session_id_get(bs));
-
- if (blade_transport_wss_write(bt_wss, json_res) != KS_STATUS_SUCCESS) {
- ks_log(KS_LOG_DEBUG, "Failed to write response message\n");
- ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT;
- goto done;
- }
-
- blade_connection_session_set(bc, blade_session_id_get(bs));
-
- done:
- // @note the state machine expects if we return SUCCESS, that the session assigned to the connection will be read locked to ensure that the state
- // machine can finish attaching the session, if you BYPASS then you can handle everything here in the callback, but this should be fairly standard
- // behaviour to simply go as far as assigning a session to the connection and let the system handle the rest
- if (json_req) cJSON_Delete(json_req);
- if (json_res) cJSON_Delete(json_res);
-
-
- return ret;
-}
-
-blade_connection_state_hook_t blade_transport_wss_on_state_attach_outbound(blade_connection_t *bc, blade_connection_state_condition_t condition)
-{
- blade_connection_state_hook_t ret = BLADE_CONNECTION_STATE_HOOK_SUCCESS;
- blade_handle_t *bh = NULL;
- blade_transport_wss_t *bt_wss = NULL;
- ks_pool_t *pool = NULL;
- cJSON *json_req = NULL;
- cJSON *json_params = NULL;
- cJSON *json_res = NULL;
- const char *mid = NULL;
- ks_time_t timeout;
- const char *jsonrpc = NULL;
- const char *id = NULL;
- cJSON *json_error = NULL;
- cJSON *json_result = NULL;
- const char *sid = NULL;
- blade_session_t *bs = NULL;
-
- ks_assert(bc);
-
- ks_log(KS_LOG_DEBUG, "State Callback: %d\n", (int32_t)condition);
-
- if (condition == BLADE_CONNECTION_STATE_CONDITION_PRE) return BLADE_CONNECTION_STATE_HOOK_SUCCESS;
-
- bh = blade_connection_handle_get(bc);
- bt_wss = (blade_transport_wss_t *)blade_connection_transport_get(bc);
- pool = blade_handle_pool_get(bh);
-
-
- blade_rpc_request_create(pool, &json_req, &json_params, &mid, "blade.session.attach");
- ks_assert(json_req);
-
- if (bt_wss->session_id) cJSON_AddStringToObject(json_params, "session-id", bt_wss->session_id);
-
- ks_log(KS_LOG_DEBUG, "Session (%s) requested\n", (bt_wss->session_id ? bt_wss->session_id : "none"));
-
- if (blade_transport_wss_write(bt_wss, json_req) != KS_STATUS_SUCCESS) {
- ks_log(KS_LOG_DEBUG, "Failed to write request message\n");
- ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT;
- goto done;
- }
-
-
- timeout = ks_time_now() + (5 * KS_USEC_PER_SEC);
- while (blade_transport_wss_read(bt_wss, &json_res) == KS_STATUS_SUCCESS) {
- if (json_res) break;
- ks_sleep_ms(250);
- if (ks_time_now() >= timeout) break;
- }
-
- if (!json_res) {
- ks_log(KS_LOG_DEBUG, "Failed to receive message before timeout\n");
- ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT;
- goto done;
- }
-
- // @todo validation wrapper for request and response/error to confirm jsonrpc and provide enum for output as to which it is
- jsonrpc = cJSON_GetObjectCstr(json_res, "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");
- ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT;
- goto done;
- }
-
- id = cJSON_GetObjectCstr(json_res, "id"); // @todo switch to number if we are not using a uuid for message id
- if (!id || strcasecmp(mid, id)) {
- ks_log(KS_LOG_DEBUG, "Received message has missing or unexpected 'id'\n");
- ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT;
- goto done;
- }
-
- json_error = cJSON_GetObjectItem(json_res, "error");
- if (json_error) {
- ks_log(KS_LOG_DEBUG, "Error message ... add the details\n");
- ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT;
- goto done;
- }
-
- json_result = cJSON_GetObjectItem(json_res, "result");
- if (!json_result) {
- ks_log(KS_LOG_DEBUG, "Received message is missing 'result'\n");
- ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT;
- goto done;
- }
-
- sid = cJSON_GetObjectCstr(json_result, "session-id");
- if (!sid) {
- ks_log(KS_LOG_DEBUG, "Received message 'result' is missing 'session-id'\n");
- ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT;
- goto done;
- }
-
- if (sid) {
- // @todo validate uuid format by parsing, not currently available in uuid functions
- bs = blade_handle_sessions_get(bh, sid); // bs comes out read locked if not null to prevent it being cleaned up before we are done
- if (bs) {
- ks_log(KS_LOG_DEBUG, "Session (%s) located\n", blade_session_id_get(bs));
- }
- }
-
- if (!bs) {
- blade_session_create(&bs, bh, sid);
- ks_assert(bs);
-
- ks_log(KS_LOG_DEBUG, "Session (%s) created\n", blade_session_id_get(bs));
-
- blade_session_read_lock(bs, KS_TRUE); // this will be done by blade_handle_sessions_get() otherwise
-
- if (blade_session_startup(bs) != KS_STATUS_SUCCESS) {
- ks_log(KS_LOG_DEBUG, "Session (%s) startup failed\n", blade_session_id_get(bs));
- blade_session_read_unlock(bs);
- blade_session_destroy(&bs);
- ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT;
- goto done;
- }
- ks_log(KS_LOG_DEBUG, "Session (%s) started\n", blade_session_id_get(bs));
- blade_handle_sessions_add(bs);
- }
-
- blade_connection_session_set(bc, blade_session_id_get(bs));
-
- done:
- if (json_req) cJSON_Delete(json_req);
- if (json_res) cJSON_Delete(json_res);
-
- return ret;
-}
-
-blade_connection_state_hook_t blade_transport_wss_on_state_detach_inbound(blade_connection_t *bc, blade_connection_state_condition_t condition)
-{
- ks_assert(bc);
-
- ks_log(KS_LOG_DEBUG, "State Callback: %d\n", (int32_t)condition);
-
- return BLADE_CONNECTION_STATE_HOOK_SUCCESS;
-}
-
-blade_connection_state_hook_t blade_transport_wss_on_state_detach_outbound(blade_connection_t *bc, blade_connection_state_condition_t condition)
-{
- ks_assert(bc);
-
- ks_log(KS_LOG_DEBUG, "State Callback: %d\n", (int32_t)condition);
-
- return BLADE_CONNECTION_STATE_HOOK_SUCCESS;
-}
-
-blade_connection_state_hook_t blade_transport_wss_on_state_ready_inbound(blade_connection_t *bc, blade_connection_state_condition_t condition)
-{
- ks_assert(bc);
-
- if (condition == BLADE_CONNECTION_STATE_CONDITION_PRE) {
- ks_log(KS_LOG_DEBUG, "State Callback: %d\n", (int32_t)condition);
- }
-
- return BLADE_CONNECTION_STATE_HOOK_SUCCESS;
-}
-
-blade_connection_state_hook_t blade_transport_wss_on_state_ready_outbound(blade_connection_t *bc, blade_connection_state_condition_t condition)
-{
- ks_assert(bc);
-
- if (condition == BLADE_CONNECTION_STATE_CONDITION_PRE) {
- blade_handle_t *bh = NULL;
- blade_session_t *bs = NULL;
-
- ks_log(KS_LOG_DEBUG, "State Callback: %d\n", (int32_t)condition);
-
- bh = blade_connection_handle_get(bc);
- ks_assert(bh);
-
- bs = blade_handle_sessions_get(bh, blade_connection_session_get(bc));
- ks_assert(bs);
-
- blade_session_read_unlock(bs);
- }
-
- return BLADE_CONNECTION_STATE_HOOK_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_protocol.c b/libs/libblade/src/blade_protocol.c
deleted file mode 100644
index 301909facc..0000000000
--- a/libs/libblade/src/blade_protocol.c
+++ /dev/null
@@ -1,339 +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"
-
-static void blade_request_cleanup(ks_pool_t *pool, void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type)
-{
- blade_request_t *breq = (blade_request_t *)ptr;
-
- ks_assert(breq);
-
- switch (action) {
- case KS_MPCL_ANNOUNCE:
- break;
- case KS_MPCL_TEARDOWN:
- ks_pool_free(breq->pool, (void **)&breq->session_id);
- cJSON_Delete(breq->message);
- break;
- case KS_MPCL_DESTROY:
- break;
- }
-}
-
-KS_DECLARE(ks_status_t) blade_request_create(blade_request_t **breqP,
- blade_handle_t *bh,
- ks_pool_t *pool,
- const char *session_id,
- cJSON *json,
- blade_response_callback_t callback)
-{
- blade_request_t *breq = NULL;
-
- ks_assert(breqP);
- ks_assert(bh);
- ks_assert(pool);
- ks_assert(session_id);
- ks_assert(json);
-
- breq = ks_pool_alloc(pool, sizeof(blade_request_t));
- breq->handle = bh;
- breq->pool = pool;
- breq->session_id = ks_pstrdup(pool, session_id);
- breq->message = cJSON_Duplicate(json, 1);
- breq->message_id = cJSON_GetObjectCstr(breq->message, "id");
- breq->callback = callback;
-
- ks_pool_set_cleanup(pool, breq, NULL, blade_request_cleanup);
-
- *breqP = breq;
-
- return KS_STATUS_SUCCESS;
-}
-
-KS_DECLARE(ks_status_t) blade_request_destroy(blade_request_t **breqP)
-{
- blade_request_t *breq = NULL;
-
- ks_assert(breqP);
- ks_assert(*breqP);
-
- breq = *breqP;
-
- ks_pool_free(breq->pool, breqP);
-
- return KS_STATUS_SUCCESS;
-}
-
-static void blade_response_cleanup(ks_pool_t *pool, void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type)
-{
- blade_response_t *bres = (blade_response_t *)ptr;
-
- ks_assert(bres);
-
- switch (action) {
- case KS_MPCL_ANNOUNCE:
- break;
- case KS_MPCL_TEARDOWN:
- ks_pool_free(bres->pool, (void **)&bres->session_id);
- blade_request_destroy(&bres->request);
- cJSON_Delete(bres->message);
- break;
- case KS_MPCL_DESTROY:
- break;
- }
-}
-
-KS_DECLARE(ks_status_t) blade_response_create(blade_response_t **bresP,
- blade_handle_t *bh,
- ks_pool_t *pool,
- const char *session_id,
- blade_request_t *breq,
- cJSON *json)
-{
- blade_response_t *bres = NULL;
-
- ks_assert(bresP);
- ks_assert(bh);
- ks_assert(pool);
- ks_assert(session_id);
- ks_assert(breq);
- ks_assert(json);
-
- bres = ks_pool_alloc(pool, sizeof(blade_response_t));
- bres->handle = bh;
- bres->pool = pool;
- bres->session_id = ks_pstrdup(pool, session_id);
- bres->request = breq;
- bres->message = cJSON_Duplicate(json, 1);
-
- ks_pool_set_cleanup(pool, bres, NULL, blade_response_cleanup);
-
- *bresP = bres;
-
- return KS_STATUS_SUCCESS;
-}
-
-KS_DECLARE(ks_status_t) blade_response_destroy(blade_response_t **bresP)
-{
- blade_response_t *bres = NULL;
-
- ks_assert(bresP);
- ks_assert(*bresP);
-
- bres = *bresP;
-
- ks_pool_free(bres->pool, bresP);
-
- return KS_STATUS_SUCCESS;
-}
-
-static void blade_event_cleanup(ks_pool_t *pool, void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type)
-{
- blade_event_t *bev = (blade_event_t *)ptr;
-
- ks_assert(bev);
-
- switch (action) {
- case KS_MPCL_ANNOUNCE:
- break;
- case KS_MPCL_TEARDOWN:
- ks_pool_free(bev->pool, &bev->session_id);
- cJSON_Delete(bev->message);
- break;
- case KS_MPCL_DESTROY:
- break;
- }
-}
-
-KS_DECLARE(ks_status_t) blade_event_create(blade_event_t **bevP,
- blade_handle_t *bh,
- ks_pool_t *pool,
- const char *session_id,
- cJSON *json)
-{
- blade_event_t *bev = NULL;
-
- ks_assert(bevP);
- ks_assert(bh);
- ks_assert(pool);
- ks_assert(session_id);
- ks_assert(json);
-
- bev = ks_pool_alloc(pool, sizeof(blade_event_t));
- bev->handle = bh;
- bev->pool = pool;
- bev->session_id = ks_pstrdup(pool, session_id);
- bev->message = cJSON_Duplicate(json, 1);
-
- ks_pool_set_cleanup(pool, bev, NULL, blade_event_cleanup);
-
- *bevP = bev;
-
- return KS_STATUS_SUCCESS;
-}
-
-KS_DECLARE(ks_status_t) blade_event_destroy(blade_event_t **bevP)
-{
- blade_event_t *bev = NULL;
-
- ks_assert(bevP);
- ks_assert(*bevP);
-
- bev = *bevP;
-
- ks_pool_free(bev->pool, bevP);
-
- return KS_STATUS_SUCCESS;
-}
-
-
-KS_DECLARE(ks_status_t) blade_rpc_request_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;
-}
-
-KS_DECLARE(ks_status_t) blade_rpc_response_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(ks_status_t) blade_rpc_error_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;
-}
-
-KS_DECLARE(ks_status_t) blade_rpc_event_create(cJSON **json, cJSON **result, const char *event)
-{
- cJSON *root = NULL;
- cJSON *b = NULL;
- cJSON *r = NULL;
-
- ks_assert(json);
- ks_assert(event);
-
- root = cJSON_CreateObject();
-
- cJSON_AddStringToObject(root, "jsonrpc", "2.0");
-
- b = cJSON_CreateObject();
- cJSON_AddStringToObject(b, "event", event);
- cJSON_AddItemToObject(root, "blade", b);
-
- if (result) {
- r = cJSON_CreateObject();
- cJSON_AddItemToObject(root, "result", r);
- *result = r;
- }
-
- *json = root;
-
- 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 2c7103293a..786b9377a7 100644
--- a/libs/libblade/src/blade_session.c
+++ b/libs/libblade/src/blade_session.c
@@ -44,20 +44,24 @@ struct blade_session_s {
ks_cond_t *cond;
- ks_list_t *connections;
+ const char *connection;
ks_time_t ttl;
ks_q_t *sending;
ks_q_t *receiving;
+ ks_hash_t *identities;
+ ks_hash_t *realms;
+ ks_hash_t *routes;
+
cJSON *properties;
ks_rwl_t *properties_lock;
};
void *blade_session_state_thread(ks_thread_t *thread, void *data);
-ks_status_t blade_session_state_on_destroy(blade_session_t *bs);
-ks_status_t blade_session_state_on_hangup(blade_session_t *bs);
-ks_status_t blade_session_state_on_ready(blade_session_t *bs);
+ks_status_t blade_session_onstate_startup(blade_session_t *bs);
+ks_status_t blade_session_onstate_shutdown(blade_session_t *bs);
+ks_status_t blade_session_onstate_run(blade_session_t *bs);
ks_status_t blade_session_process(blade_session_t *bs, cJSON *json);
static void blade_session_cleanup(ks_pool_t *pool, void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type)
@@ -84,7 +88,7 @@ static void blade_session_cleanup(ks_pool_t *pool, void *ptr, void *arg, ks_pool
bs->properties_lock = NULL;
bs->receiving = NULL;
bs->sending = NULL;
- bs->connections = NULL;
+ bs->connection = NULL;
bs->cond = NULL;
bs->lock = NULL;
@@ -95,7 +99,7 @@ static void blade_session_cleanup(ks_pool_t *pool, void *ptr, void *arg, ks_pool
}
-KS_DECLARE(ks_status_t) blade_session_create(blade_session_t **bsP, blade_handle_t *bh, const char *sid)
+KS_DECLARE(ks_status_t) blade_session_create(blade_session_t **bsP, blade_handle_t *bh, const char *id)
{
blade_session_t *bs = NULL;
ks_pool_t *pool = NULL;
@@ -110,7 +114,7 @@ KS_DECLARE(ks_status_t) blade_session_create(blade_session_t **bsP, blade_handle
bs->handle = bh;
bs->pool = pool;
- if (sid) bs->id = ks_pstrdup(pool, sid);
+ if (id) bs->id = ks_pstrdup(pool, id);
else {
uuid_t id;
ks_uuid(&id);
@@ -123,14 +127,20 @@ KS_DECLARE(ks_status_t) blade_session_create(blade_session_t **bsP, blade_handle
ks_cond_create(&bs->cond, pool);
ks_assert(bs->cond);
- ks_list_create(&bs->connections, pool);
- ks_assert(bs->connections);
-
ks_q_create(&bs->sending, pool, 0);
ks_assert(bs->sending);
ks_q_create(&bs->receiving, pool, 0);
ks_assert(bs->receiving);
+ ks_hash_create(&bs->identities, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_RWLOCK | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_FREE_KEY, bs->pool);
+ ks_assert(bs->identities);
+
+ ks_hash_create(&bs->realms, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_RWLOCK | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_FREE_KEY, bs->pool);
+ ks_assert(bs->realms);
+
+ ks_hash_create(&bs->routes, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_RWLOCK | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_FREE_KEY, bs->pool);
+ ks_assert(bs->routes);
+
bs->properties = cJSON_CreateObject();
ks_assert(bs->properties);
ks_rwl_create(&bs->properties_lock, pool);
@@ -187,10 +197,24 @@ KS_DECLARE(ks_status_t) blade_session_startup(blade_session_t *bs)
KS_DECLARE(ks_status_t) blade_session_shutdown(blade_session_t *bs)
{
+ ks_hash_iterator_t *it = NULL;
cJSON *json = NULL;
ks_assert(bs);
+ // if this is an upstream session there will be no routes, so this is harmless to always run regardless
+ ks_hash_read_lock(bs->routes);
+ for (it = ks_hash_first(bs->routes, KS_UNLOCKED); it; it = ks_hash_next(&it)) {
+ void *key = NULL;
+ void *value = NULL;
+
+ ks_hash_this(it, &key, NULL, &value);
+
+ blade_handle_route_remove(bs->handle, (const char *)key);
+ }
+ ks_hash_read_unlock(bs->routes);
+
+ // this will also clear the identities and realms in the handle if this is the upstream session
blade_handle_sessions_remove(bs);
while (ks_q_trypop(bs->sending, (void **)&json) == KS_STATUS_SUCCESS && json) cJSON_Delete(json);
@@ -222,6 +246,87 @@ KS_DECLARE(blade_session_state_t) blade_session_state_get(blade_session_t *bs)
return bs->state;
}
+KS_DECLARE(ks_status_t) blade_session_identity_add(blade_session_t *bs, const char *identity)
+{
+ char *key = NULL;
+
+ ks_assert(bs);
+ ks_assert(identity);
+
+ key = ks_pstrdup(bs->pool, identity);
+ ks_hash_insert(bs->identities, (void *)key, (void *)KS_TRUE);
+
+ return KS_STATUS_SUCCESS;
+}
+
+KS_DECLARE(ks_status_t) blade_session_identity_remove(blade_session_t *bs, const char *identity)
+{
+ ks_assert(bs);
+ ks_assert(identity);
+
+ ks_hash_remove(bs->identities, (void *)identity);
+
+ return KS_STATUS_SUCCESS;
+}
+
+KS_DECLARE(ks_hash_t *) blade_session_identities_get(blade_session_t *bs)
+{
+ ks_assert(bs);
+ return bs->identities;
+}
+
+KS_DECLARE(ks_status_t) blade_session_realm_add(blade_session_t *bs, const char *realm)
+{
+ char *key = NULL;
+
+ ks_assert(bs);
+ ks_assert(realm);
+
+ key = ks_pstrdup(bs->pool, realm);
+ ks_hash_insert(bs->realms, (void *)key, (void *)KS_TRUE);
+
+ return KS_STATUS_SUCCESS;
+}
+
+KS_DECLARE(ks_status_t) blade_session_realm_remove(blade_session_t *bs, const char *realm)
+{
+ ks_assert(bs);
+ ks_assert(realm);
+
+ ks_hash_remove(bs->realms, (void *)realm);
+
+ return KS_STATUS_SUCCESS;
+}
+
+KS_DECLARE(ks_hash_t *) blade_session_realms_get(blade_session_t *bs)
+{
+ ks_assert(bs);
+ return bs->realms;
+}
+
+KS_DECLARE(ks_status_t) blade_session_route_add(blade_session_t *bs, const char *identity)
+{
+ char *key = NULL;
+
+ ks_assert(bs);
+ ks_assert(identity);
+
+ key = ks_pstrdup(bs->pool, identity);
+ ks_hash_insert(bs->routes, (void *)key, (void *)KS_TRUE);
+
+ return KS_STATUS_SUCCESS;
+}
+
+KS_DECLARE(ks_status_t) blade_session_route_remove(blade_session_t *bs, const char *identity)
+{
+ ks_assert(bs);
+ ks_assert(identity);
+
+ ks_hash_remove(bs->routes, (void *)identity);
+
+ return KS_STATUS_SUCCESS;
+}
+
KS_DECLARE(cJSON *) blade_session_properties_get(blade_session_t *bs)
{
ks_assert(bs);
@@ -321,7 +426,7 @@ KS_DECLARE(void) blade_session_hangup(blade_session_t *bs)
if (!blade_session_terminating(bs)) {
ks_log(KS_LOG_DEBUG, "Session (%s) hanging up\n", bs->id);
- blade_session_state_set(bs, BLADE_SESSION_STATE_HANGUP);
+ blade_session_state_set(bs, BLADE_SESSION_STATE_SHUTDOWN);
}
}
@@ -329,83 +434,41 @@ KS_DECLARE(ks_bool_t) blade_session_terminating(blade_session_t *bs)
{
ks_assert(bs);
- return bs->state == BLADE_SESSION_STATE_HANGUP || bs->state == BLADE_SESSION_STATE_DESTROY || bs->state == BLADE_SESSION_STATE_CLEANUP;
+ return bs->state == BLADE_SESSION_STATE_SHUTDOWN || bs->state == BLADE_SESSION_STATE_CLEANUP;
}
-KS_DECLARE(ks_status_t) blade_session_connections_add(blade_session_t *bs, const char *id)
+KS_DECLARE(const char *) blade_session_connection_get(blade_session_t *bs)
{
- ks_status_t ret = KS_STATUS_SUCCESS;
- const char *cid = NULL;
-
ks_assert(bs);
-
- cid = ks_pstrdup(bs->pool, id);
- ks_assert(cid);
-
- ks_list_append(bs->connections, cid);
- bs->ttl = 0;
-
- ks_log(KS_LOG_DEBUG, "Session (%s) connection added (%s)\n", bs->id, id);
-
-
- return ret;
+ return bs->connection;
}
-KS_DECLARE(ks_status_t) blade_session_connections_remove(blade_session_t *bs, const char *id)
+KS_DECLARE(ks_status_t) blade_session_connection_set(blade_session_t *bs, const char *id)
{
- ks_status_t ret = KS_STATUS_SUCCESS;
-
ks_assert(bs);
- ks_list_iterator_start(bs->connections);
- while (ks_list_iterator_hasnext(bs->connections)) {
- const char *cid = (const char *)ks_list_iterator_next(bs->connections);
- if (!strcasecmp(cid, id)) {
- ks_log(KS_LOG_DEBUG, "Session (%s) connection removed (%s)\n", bs->id, id);
- ks_list_delete_iterator(bs->connections);
- ks_pool_free(bs->pool, &cid);
- break;
+ if (id) {
+ if (bs->connection) {
+ // @todo best that can be done in this situation is see if the connection is still available, and if so then disconnect it... this really shouldn't happen
+ ks_pool_free(bs->pool, &bs->connection);
}
- }
- ks_list_iterator_stop(bs->connections);
+ bs->connection = ks_pstrdup(bs->pool, id);
+ ks_assert(bs->connection);
- if (ks_list_size(bs->connections) == 0) bs->ttl = ks_time_now() + (5 * KS_USEC_PER_SEC);
+ bs->ttl = 0;
- return ret;
-}
+ ks_log(KS_LOG_DEBUG, "Session (%s) associated to connection (%s)\n", bs->id, id);
-ks_status_t blade_session_connections_choose(blade_session_t *bs, cJSON *json, blade_connection_t **bcP)
-{
- ks_status_t ret = KS_STATUS_SUCCESS;
- blade_connection_t *bc = NULL;
- const char *cid = NULL;
+ // @todo signal the wait condition for the state machine to see a reconnect immediately
+ } else if (bs->connection) {
+ ks_log(KS_LOG_DEBUG, "Session (%s) cleared connection (%s)\n", bs->id, bs->connection);
- ks_assert(bs);
- ks_assert(json);
- ks_assert(bcP);
+ ks_pool_free(bs->pool, &bs->connection);
- // @todo may be multiple connections, for now let's just assume there will be only one
- // later there will need to be a way to pick which connection to use
- cid = ks_list_get_at(bs->connections, 0);
- if (!cid) {
- // no connections available
- ret = KS_STATUS_FAIL;
- goto done;
+ bs->ttl = ks_time_now() + (5 * KS_USEC_PER_SEC);
}
- bc = blade_handle_connections_get(bs->handle, cid);
- if (!bc) {
- // @todo error logging... this shouldn't happen
- ret = KS_STATUS_FAIL;
- goto done;
- }
- // @todo make sure the connection is in the READY state before allowing it to be choosen, just in case it is detaching or not quite fully attached
-
- *bcP = bc;
-
-done:
-
- return ret;
+ return KS_STATUS_SUCCESS;
}
KS_DECLARE(ks_status_t) blade_session_sending_push(blade_session_t *bs, cJSON *json)
@@ -471,45 +534,40 @@ void *blade_session_state_thread(ks_thread_t *thread, void *data)
state = bs->state;
- if (!ks_list_empty(bs->connections)) {
- while (blade_session_sending_pop(bs, &json) == KS_STATUS_SUCCESS && json) {
- blade_connection_t *bc = NULL;
- if (blade_session_connections_choose(bs, json, &bc) == KS_STATUS_SUCCESS) {
+ if (bs->connection) {
+ blade_connection_t *bc = blade_handle_connections_lookup(bs->handle, bs->connection);
+ if (bc) {
+ // @note in order for this to work on session reconnecting, the assumption is that as soon as a session has a connection set,
+ // 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) {
blade_connection_sending_push(bc, json);
- blade_connection_read_unlock(bc);
- } else {
- // @todo review this, possible the connection is dropped after popping a message, which results in it just being deleted without sending
+ cJSON_Delete(json);
}
- cJSON_Delete(json);
+ blade_connection_read_unlock(bc);
}
}
+ // @todo evolve this system, it's probably not the best way to handle receiving session state updates externally
blade_handle_session_state_callbacks_execute(bs, BLADE_SESSION_STATE_CONDITION_POST);
switch (state) {
- case BLADE_SESSION_STATE_DESTROY:
- blade_session_state_on_destroy(bs);
+ 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);
+ break;
+ case BLADE_SESSION_STATE_SHUTDOWN:
+ blade_session_onstate_shutdown(bs);
shutdown = KS_TRUE;
break;
- case BLADE_SESSION_STATE_HANGUP:
- blade_session_state_on_hangup(bs);
- break;
- case BLADE_SESSION_STATE_CONNECT:
- ks_log(KS_LOG_DEBUG, "Session (%s) state connect\n", bs->id);
- break;
- case BLADE_SESSION_STATE_ATTACH:
- ks_log(KS_LOG_DEBUG, "Session (%s) state attach\n", bs->id);
- break;
- case BLADE_SESSION_STATE_DETACH:
- ks_log(KS_LOG_DEBUG, "Session (%s) state detach\n", bs->id);
- break;
- case BLADE_SESSION_STATE_READY:
- blade_session_state_on_ready(bs);
+ case BLADE_SESSION_STATE_RUN:
+ blade_session_onstate_run(bs);
break;
default: break;
}
- if (ks_list_empty(bs->connections) &&
+ if (!bs->connection &&
bs->ttl > 0 &&
!blade_session_terminating(bs) &&
ks_time_now() >= bs->ttl) {
@@ -524,56 +582,43 @@ void *blade_session_state_thread(ks_thread_t *thread, void *data)
return NULL;
}
-ks_status_t blade_session_state_on_destroy(blade_session_t *bs)
+ks_status_t blade_session_onstate_shutdown(blade_session_t *bs)
{
ks_assert(bs);
- ks_log(KS_LOG_DEBUG, "Session (%s) state destroy\n", bs->id);
+ ks_log(KS_LOG_DEBUG, "Session (%s) state shutdown\n", bs->id);
blade_session_state_set(bs, BLADE_SESSION_STATE_CLEANUP);
- // @todo ignoring returns for now, see what makes sense later
- return KS_STATUS_SUCCESS;
-}
-
-ks_status_t blade_session_state_on_hangup(blade_session_t *bs)
-{
- ks_assert(bs);
-
- ks_log(KS_LOG_DEBUG, "Session (%s) state hangup\n", bs->id);
-
- ks_list_iterator_start(bs->connections);
- while (ks_list_iterator_hasnext(bs->connections)) {
- const char *cid = (const char *)ks_list_iterator_next(bs->connections);
- blade_connection_t *bc = blade_handle_connections_get(bs->handle, cid);
- ks_assert(bc);
-
- blade_connection_disconnect(bc);
- blade_connection_read_unlock(bc);
+ if (bs->connection) {
+ blade_connection_t *bc = blade_handle_connections_lookup(bs->handle, bs->connection);
+ if (bc) {
+ blade_connection_disconnect(bc);
+ blade_connection_read_unlock(bc);
+ }
}
- ks_list_iterator_stop(bs->connections);
- // @todo review this code, it may end up blocking forever as the mutex for the session is locked and the connection thread will not be able to lock to remove the connection...
- // isolate another mutex for the connection list, simclist is not intrinsicly thread safe like other containers
- while (!ks_list_empty(bs->connections)) ks_sleep(100);
-
- blade_session_state_set(bs, BLADE_SESSION_STATE_DESTROY);
+ // @note wait for the connection to disconnect before we resume session cleanup
+ while (bs->connection) ks_sleep(100);
return KS_STATUS_SUCCESS;
}
-ks_status_t blade_session_state_on_ready(blade_session_t *bs)
+ks_status_t blade_session_onstate_run(blade_session_t *bs)
{
cJSON *json = NULL;
ks_assert(bs);
- //ks_log(KS_LOG_DEBUG, "Session (%s) state ready\n", bs->id);
+ //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 (ks_list_size(bs->connections) > 0) {
+ 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);
}
@@ -584,9 +629,9 @@ ks_status_t blade_session_state_on_ready(blade_session_t *bs)
}
-KS_DECLARE(ks_status_t) blade_session_send(blade_session_t *bs, cJSON *json, blade_response_callback_t callback)
+KS_DECLARE(ks_status_t) blade_session_send(blade_session_t *bs, cJSON *json, blade_jsonrpc_response_callback_t callback)
{
- blade_request_t *request = NULL;
+ blade_jsonrpc_request_t *bjsonrpcreq = NULL;
const char *method = NULL;
const char *id = NULL;
@@ -594,36 +639,31 @@ KS_DECLARE(ks_status_t) blade_session_send(blade_session_t *bs, cJSON *json, bla
ks_assert(json);
method = cJSON_GetObjectCstr(json, "method");
+
id = cJSON_GetObjectCstr(json, "id");
- if (!id) {
- cJSON *blade = NULL;
- const char *event = NULL;
+ ks_assert(id);
- blade = cJSON_GetObjectItem(json, "blade");
- event = cJSON_GetObjectCstr(blade, "event");
-
- ks_log(KS_LOG_DEBUG, "Session (%s) sending event (%s)\n", bs->id, event);
- } else if (method) {
+ if (method) {
// @note This is scenario 1
// 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_request_create(&request, bs->handle, blade_handle_pool_get(bs->handle), bs->id, json, callback);
- ks_assert(request);
+ blade_jsonrpc_request_create(&bjsonrpcreq, bs->handle, blade_handle_pool_get(bs->handle), bs->id, json, callback);
+ ks_assert(bjsonrpcreq);
// @todo set request TTL and figure out when requests are checked for expiration (separate thread in the handle?)
- blade_handle_requests_add(request);
+ blade_handle_requests_add(bjsonrpcreq);
} 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);
}
- if (ks_list_empty(bs->connections)) {
+ if (!bs->connection) {
blade_session_sending_push(bs, json);
} else {
- blade_connection_t *bc = NULL;
- if (blade_session_connections_choose(bs, json, &bc) != KS_STATUS_SUCCESS) {
+ blade_connection_t *bc = blade_handle_connections_lookup(bs->handle, bs->connection);
+ if (!bc) {
blade_session_sending_push(bs, json);
return KS_STATUS_FAIL;
}
@@ -636,12 +676,9 @@ 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_request_t *breq = NULL;
- blade_response_t *bres = NULL;
- blade_event_t *bev = NULL;
+ blade_jsonrpc_request_t *bjsonrpcreq = NULL;
+ blade_jsonrpc_response_t *bjsonrpcres = NULL;
const char *jsonrpc = NULL;
- cJSON *blade = NULL;
- const char *blade_event = NULL;
const char *id = NULL;
const char *method = NULL;
ks_bool_t disconnect = KS_FALSE;
@@ -660,99 +697,63 @@ ks_status_t blade_session_process(blade_session_t *bs, cJSON *json)
return KS_STATUS_FAIL;
}
- blade = cJSON_GetObjectItem(json, "blade");
- if (blade) {
- blade_event = cJSON_GetObjectCstr(blade, "event");
+
+ id = cJSON_GetObjectCstr(json, "id");
+ if (!id) {
+ ks_log(KS_LOG_DEBUG, "Received message is missing 'id'\n");
+ // @todo send error response, code = -32600 (invalid request)
+ // @todo hangup session entirely?
+ return KS_STATUS_FAIL;
}
- if (blade_event) {
- blade_event_callback_t callback = blade_handle_event_lookup(blade_session_handle_get(bs), blade_event);
- if (!callback) {
- ks_log(KS_LOG_DEBUG, "Received event message with no event callback '%s'\n", blade_event);
- } else {
- ks_log(KS_LOG_DEBUG, "Session (%s) processing event %s\n", bs->id, blade_event);
+ method = cJSON_GetObjectCstr(json, "method");
+ 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_event_create(&bev, bs->handle, bs->pool, bs->id, json);
- ks_assert(bev);
+ ks_log(KS_LOG_DEBUG, "Session (%s) receiving request (%s) for %s\n", bs->id, id, method);
- disconnect = callback(bev);
+ bjsonrpc = blade_handle_jsonrpc_lookup(bs->handle, method);
- blade_event_destroy(&bev);
+ if (!bjsonrpc) {
+ ks_log(KS_LOG_DEBUG, "Received unknown jsonrpc method %s\n", method);
+ // @todo send error response, code = -32601 (method not found)
+ return KS_STATUS_FAIL;
}
+ callback = blade_jsonrpc_callback_get(bjsonrpc);
+ ks_assert(callback);
+
+ blade_jsonrpc_request_create(&bjsonrpcreq, bs->handle, blade_handle_pool_get(bs->handle), bs->id, json, NULL);
+ ks_assert(bjsonrpcreq);
+
+ disconnect = callback(bjsonrpcreq, blade_jsonrpc_callback_data_get(bjsonrpc));
+
+ blade_jsonrpc_request_destroy(&bjsonrpcreq);
} else {
- id = cJSON_GetObjectCstr(json, "id");
- if (!id) {
- ks_log(KS_LOG_DEBUG, "Received non-event message is missing 'id'\n");
- // @todo send error response, code = -32600 (invalid request)
+ // @note This is scenario 4
+ // 4) Receiving a response or error (client: method caller or consumer)
+ blade_jsonrpc_response_callback_t callback = NULL;
+
+ ks_log(KS_LOG_DEBUG, "Session (%s) receiving response (%s)\n", bs->id, id);
+
+ bjsonrpcreq = blade_handle_requests_lookup(bs->handle, id);
+ if (!bjsonrpcreq) {
// @todo hangup session entirely?
return KS_STATUS_FAIL;
}
+ blade_handle_requests_remove(bjsonrpcreq);
- method = cJSON_GetObjectCstr(json, "method");
- if (method) {
- // @note This is scenario 2
- // 2) Receiving a request (server: method callee or provider)
- blade_space_t *tmp_space = NULL;
- blade_method_t *tmp_method = NULL;
- blade_request_callback_t callback = NULL;
- char *space_name = ks_pstrdup(bs->pool, method);
- char *method_name = strrchr(space_name, '.');
+ callback = blade_jsonrpc_request_callback_get(bjsonrpcreq);
+ ks_assert(callback);
- ks_log(KS_LOG_DEBUG, "Session (%s) receiving request (%s) for %s\n", bs->id, id, method);
+ blade_jsonrpc_response_create(&bjsonrpcres, bs->handle, bs->pool, bs->id, bjsonrpcreq, json);
+ ks_assert(bjsonrpcres);
- if (!method_name || method_name == space_name) {
- ks_log(KS_LOG_DEBUG, "Received unparsable method\n");
- ks_pool_free(bs->pool, (void **)&space_name);
- // @todo send error response, code = -32601 (method not found)
- return KS_STATUS_FAIL;
- }
- *method_name = '\0';
- method_name++; // @todo check if can be postfixed safely on previous assignment, can't recall
+ disconnect = callback(bjsonrpcres);
- ks_log(KS_LOG_DEBUG, "Looking for space %s\n", space_name);
-
- tmp_space = blade_handle_space_lookup(bs->handle, space_name);
- if (tmp_space) {
- ks_log(KS_LOG_DEBUG, "Looking for method %s\n", method_name);
- tmp_method = blade_space_methods_get(tmp_space, method_name);
- }
-
- ks_pool_free(bs->pool, (void **)&space_name);
-
- if (!tmp_method) {
- ks_log(KS_LOG_DEBUG, "Received unknown method\n");
- // @todo send error response, code = -32601 (method not found)
- return KS_STATUS_FAIL;
- }
- callback = blade_method_callback_get(tmp_method);
- ks_assert(callback);
-
- blade_request_create(&breq, bs->handle, blade_handle_pool_get(bs->handle), bs->id, json, NULL);
- ks_assert(breq);
-
- disconnect = callback(blade_space_module_get(tmp_space), breq);
-
- blade_request_destroy(&breq);
- } else {
- // @note This is scenario 4
- // 4) Receiving a response or error (client: method caller or consumer)
-
- ks_log(KS_LOG_DEBUG, "Session (%s) receiving response (%s)\n", bs->id, id);
-
- breq = blade_handle_requests_get(bs->handle, id);
- if (!breq) {
- // @todo hangup session entirely?
- return KS_STATUS_FAIL;
- }
- blade_handle_requests_remove(breq);
-
- blade_response_create(&bres, bs->handle, bs->pool, bs->id, breq, json);
- ks_assert(bres);
-
- disconnect = breq->callback(bres);
-
- blade_response_destroy(&bres);
- }
+ blade_jsonrpc_response_destroy(&bjsonrpcres);
}
if (disconnect) {
diff --git a/libs/libblade/src/blade_space.c b/libs/libblade/src/blade_space.c
deleted file mode 100644
index 6aa3482be0..0000000000
--- a/libs/libblade/src/blade_space.c
+++ /dev/null
@@ -1,172 +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_space_s {
- blade_handle_t *handle;
- ks_pool_t *pool;
- blade_module_t *module;
-
- const char *path;
- ks_hash_t *methods;
-};
-
-static void blade_space_cleanup(ks_pool_t *pool, void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type)
-{
- blade_space_t *bs = (blade_space_t *)ptr;
-
- ks_assert(bs);
-
- switch (action) {
- case KS_MPCL_ANNOUNCE:
- break;
- case KS_MPCL_TEARDOWN:
- ks_pool_free(bs->pool, &bs->path);
- ks_hash_destroy(&bs->methods);
- break;
- case KS_MPCL_DESTROY:
- break;
- }
-}
-
-KS_DECLARE(ks_status_t) blade_space_create(blade_space_t **bsP, blade_handle_t *bh, blade_module_t *bm, const char *path)
-{
- blade_space_t *bs = NULL;
- ks_pool_t *pool = NULL;
-
- ks_assert(bsP);
- ks_assert(bh);
- ks_assert(path);
-
- pool = blade_module_pool_get(bm);
- ks_assert(pool);
-
- bs = ks_pool_alloc(pool, sizeof(blade_space_t));
- bs->handle = bh;
- bs->pool = pool;
- bs->module = bm;
- bs->path = ks_pstrdup(pool, path);
- ks_hash_create(&bs->methods, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_RWLOCK | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_FREE_VALUE, bs->pool);
- ks_assert(bs);
-
- ks_pool_set_cleanup(pool, bs, NULL, blade_space_cleanup);
-
- *bsP = bs;
-
- ks_log(KS_LOG_DEBUG, "Space Created: %s\n", path);
-
- return KS_STATUS_SUCCESS;
-}
-
-KS_DECLARE(blade_handle_t *) blade_space_handle_get(blade_space_t *bs)
-{
- ks_assert(bs);
-
- return bs->handle;
-}
-
-KS_DECLARE(ks_pool_t *) blade_space_pool_get(blade_space_t *bs)
-{
- ks_assert(bs);
-
- return bs->pool;
-}
-
-KS_DECLARE(blade_module_t *) blade_space_module_get(blade_space_t *bs)
-{
- ks_assert(bs);
-
- return bs->module;
-}
-
-KS_DECLARE(const char *) blade_space_path_get(blade_space_t *bs)
-{
- ks_assert(bs);
-
- return bs->path;
-}
-
-KS_DECLARE(ks_status_t) blade_space_methods_add(blade_space_t *bs, blade_method_t *bm)
-{
- const char *name = NULL;
-
- ks_assert(bs);
- ks_assert(bm);
-
- name = blade_method_name_get(bm);
- ks_assert(name);
-
- ks_hash_insert(bs->methods, (void *)name, (void *)bm);
-
- return KS_STATUS_SUCCESS;
-}
-
-KS_DECLARE(ks_status_t) blade_space_methods_remove(blade_space_t *bs, blade_method_t *bm)
-{
- const char *name = NULL;
-
- ks_assert(bs);
- ks_assert(bm);
-
- name = blade_method_name_get(bm);
- ks_assert(name);
-
- ks_hash_remove(bs->methods, (void *)name);
-
- return KS_STATUS_SUCCESS;
-}
-
-KS_DECLARE(blade_method_t *) blade_space_methods_get(blade_space_t *bs, const char *name)
-{
- blade_method_t *bm = NULL;
- ks_assert(bs);
- ks_assert(name);
-
- bm = ks_hash_search(bs->methods, (void *)name, KS_READLOCKED);
- ks_hash_read_unlock(bs->methods);
-
- return bm;
-}
-
-
-/* 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_stack.c b/libs/libblade/src/blade_stack.c
index cd62528d24..b40633b475 100644
--- a/libs/libblade/src/blade_stack.c
+++ b/libs/libblade/src/blade_stack.c
@@ -42,75 +42,45 @@ struct blade_handle_s {
ks_pool_t *pool;
ks_thread_pool_t *tpool;
- ks_hash_t *modules; // registered modules
- ks_hash_t *transports; // registered transports exposed by modules, NOT active connections
- ks_hash_t *spaces; // registered method spaces exposed by modules
+ // These are for the master identity, since it has no upstream, but the realm list will also propagate through other router nodes in "blade.connect" calls
+ const char *master_user;
+ const char **master_realms;
+ int32_t master_realms_length;
- // registered event callback registry
- // @todo should probably use a blade_handle_event_registration_t and contain optional userdata to pass from registration back into the callback, like
- // a blade_module_t to get at inner module data for events that service modules may need to subscribe to between each other, but this may evolve into
- // an implementation based on ESL
- ks_hash_t *events;
+ // local identities such as upstream-session-id@mydomain.com, messages with a destination matching a key in this hash will be received and processed locally
+ // @todo currently the value is unused, but may find use for it later (could store a blade_identity_t, but these are becoming less useful in the core)
+ ks_hash_t *identities;
- //blade_identity_t *identity;
- blade_datastore_t *datastore;
+ // realms for new identities, identities get created in all of these realms, these originate from the master and may be reduced down to a single realm by
+ // the master router, or by each router as it sees fit
+ ks_hash_t *realms;
+
+ // The guts of routing messages, this maps a remote identity key to a local sessionid value, sessions must also track the identities coming through them to
+ // allow for removing downstream identities from these routes when they are no longer available upon session termination
+ // When any node registers an identity through this node, whether it is a locally connected session or downstream through another router node, the registered
+ // identity will be added to this hash, with the sessionid of the session it came through as the value
+ // Any future message received and destined for identities that are not our own (see identities hash above), will use this hash for downstream relays or will
+ // otherwise attempt to send upstream if it did not come from upstream
+ // Messages must never back-travel through a session they were received from, thus when recieved from a downstream session, that downstream session is excluded
+ // for further downstream routing scenarios to avoid any possible circular routing, message routing must be checked through downstreams before passing upstream
+ ks_hash_t *routes;
+
+ 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 *connections; // active connections keyed by connection id
ks_hash_t *sessions; // active sessions keyed by session id
+
+ ks_mutex_t *upstream_mutex; // locked when messing with upstream_id
+ const char *upstream_id; // session id of the currently active upstream session
+
ks_hash_t *session_state_callbacks;
-
- ks_hash_t *requests; // outgoing requests waiting for a response keyed by the message id
};
-typedef struct blade_handle_transport_registration_s blade_handle_transport_registration_t;
-struct blade_handle_transport_registration_s {
- ks_pool_t *pool;
-
- blade_module_t *module;
- blade_transport_callbacks_t *callbacks;
-};
-
-
-static void blade_handle_transport_registration_cleanup(ks_pool_t *pool, void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type)
-{
- //blade_handle_transport_registration_t *bhtr = (blade_handle_transport_registration_t *)ptr;
-
- //ks_assert(bhtr);
-
- switch (action) {
- case KS_MPCL_ANNOUNCE:
- break;
- case KS_MPCL_TEARDOWN:
- break;
- case KS_MPCL_DESTROY:
- break;
- }
-}
-
-KS_DECLARE(ks_status_t) blade_handle_transport_registration_create(blade_handle_transport_registration_t **bhtrP,
- ks_pool_t *pool,
- blade_module_t *module,
- blade_transport_callbacks_t *callbacks)
-{
- blade_handle_transport_registration_t *bhtr = NULL;
-
- ks_assert(bhtrP);
- ks_assert(pool);
- ks_assert(module);
- ks_assert(callbacks);
-
- bhtr = ks_pool_alloc(pool, sizeof(blade_handle_transport_registration_t));
- bhtr->pool = pool;
- bhtr->module = module;
- bhtr->callbacks = callbacks;
-
- ks_pool_set_cleanup(pool, bhtr, NULL, blade_handle_transport_registration_cleanup);
-
- *bhtrP = bhtr;
-
- return KS_STATUS_SUCCESS;
-}
typedef struct blade_handle_session_state_callback_registration_s blade_handle_session_state_callback_registration_t;
@@ -177,15 +147,25 @@ static void blade_handle_cleanup(ks_pool_t *pool, void *ptr, void *arg, ks_pool_
case KS_MPCL_ANNOUNCE:
break;
case KS_MPCL_TEARDOWN:
- while ((it = ks_hash_first(bh->modules, KS_UNLOCKED)) != NULL) {
+ while ((it = ks_hash_first(bh->transports, KS_UNLOCKED)) != NULL) {
void *key = NULL;
- blade_module_t *value = NULL;
+ blade_transport_t *value = NULL;
ks_hash_this(it, (const void **)&key, NULL, (void **)&value);
- ks_hash_remove(bh->modules, key);
+ ks_hash_remove(bh->transports, key);
- blade_module_destroy(&value); // must call destroy to close the module pool, FREE_VALUE would attempt to free the module from the main handle pool used for the modules hash
+ 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) {
+ void *key = NULL;
+ blade_jsonrpc_t *value = NULL;
+
+ ks_hash_this(it, (const void **)&key, NULL, (void **)&value);
+ ks_hash_remove(bh->jsonrpcs, 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
+ }
+
ks_thread_pool_destroy(&bh->tpool);
break;
case KS_MPCL_DESTROY:
@@ -213,29 +193,37 @@ KS_DECLARE(ks_status_t) blade_handle_create(blade_handle_t **bhP)
bh->pool = pool;
bh->tpool = tpool;
- ks_hash_create(&bh->modules, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_RWLOCK | KS_HASH_FLAG_DUP_CHECK, bh->pool);
- ks_assert(bh->modules);
+ ks_hash_create(&bh->identities, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_RWLOCK | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_FREE_KEY, bh->pool);
+ ks_assert(bh->identities);
- ks_hash_create(&bh->transports, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_RWLOCK | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_FREE_KEY | KS_HASH_FLAG_FREE_VALUE, bh->pool);
+ ks_hash_create(&bh->realms, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_RWLOCK | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_FREE_KEY, bh->pool);
+ ks_assert(bh->realms);
+
+ // @note can let removes free keys and values for routes, both are strings and allocated from the same pool as the hash itself
+ ks_hash_create(&bh->routes, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_RWLOCK | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_FREE_KEY | KS_HASH_FLAG_FREE_VALUE, bh->pool);
+ ks_assert(bh->routes);
+
+ 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->spaces, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_RWLOCK | KS_HASH_FLAG_DUP_CHECK, bh->pool);
- ks_assert(bh->spaces);
+ 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->events, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_RWLOCK | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_FREE_KEY, bh->pool);
- ks_assert(bh->events);
+ 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->connections, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_RWLOCK | KS_HASH_FLAG_DUP_CHECK, bh->pool);
ks_assert(bh->connections);
ks_hash_create(&bh->sessions, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_RWLOCK | KS_HASH_FLAG_DUP_CHECK, bh->pool);
ks_assert(bh->sessions);
+
+ ks_mutex_create(&bh->upstream_mutex, KS_MUTEX_FLAG_DEFAULT, bh->pool);
+ ks_assert(bh->upstream_mutex);
+
ks_hash_create(&bh->session_state_callbacks, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_RWLOCK | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_FREE_VALUE, bh->pool);
ks_assert(bh->session_state_callbacks);
- ks_hash_create(&bh->requests, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_RWLOCK | KS_HASH_FLAG_DUP_CHECK, bh->pool);
- ks_assert(bh->requests);
-
ks_pool_set_cleanup(pool, bh, NULL, blade_handle_cleanup);
*bhP = bh;
@@ -260,6 +248,7 @@ KS_DECLARE(ks_status_t) blade_handle_destroy(blade_handle_t **bhP)
pool = bh->pool;
// shutdown cannot happen inside of the cleanup callback because it'll lock a mutex for the pool during cleanup callbacks which connections and sessions need to finish their cleanup
+ // and more importantly, memory needs to remain intact until shutdown is completed to avoid various things hitting teardown before shutdown runs
blade_handle_shutdown(bh);
ks_pool_close(&pool);
@@ -269,41 +258,91 @@ KS_DECLARE(ks_status_t) blade_handle_destroy(blade_handle_t **bhP)
ks_status_t blade_handle_config(blade_handle_t *bh, config_setting_t *config)
{
+ config_setting_t *master = NULL;
+ config_setting_t *master_user = NULL;
+ config_setting_t *master_realms = NULL;
+ const char *user = NULL;
+ const char **realms = NULL;
+ int32_t realms_length = 0;
+
ks_assert(bh);
if (!config) return KS_STATUS_FAIL;
- if (!config_setting_is_group(config)) return KS_STATUS_FAIL;
+ if (!config_setting_is_group(config)) {
+ ks_log(KS_LOG_DEBUG, "!config_setting_is_group(config)\n");
+ return KS_STATUS_FAIL;
+ }
+
+ master = config_setting_get_member(config, "master");
+ if (master) {
+ master_user = config_lookup_from(master, "user");
+ if (master_user) {
+ if (config_setting_type(master_user) != CONFIG_TYPE_STRING) return KS_STATUS_FAIL;
+ user = config_setting_get_string(master_user);
+ }
+ master_realms = config_lookup_from(master, "realms");
+ if (master_realms) {
+ if (config_setting_type(master_realms) != CONFIG_TYPE_LIST) return KS_STATUS_FAIL;
+ realms_length = config_setting_length(master_realms);
+ if (realms_length > 0) {
+ realms = ks_pool_alloc(bh->pool, sizeof(const char *) * realms_length);
+ for (int32_t index = 0; index < realms_length; ++index) {
+ const char *realm = config_setting_get_string_elem(master_realms, index);
+ if (!realm) return KS_STATUS_FAIL;
+ realms[index] = ks_pstrdup(bh->pool, realm);
+ }
+ }
+ }
+ }
+
+ // @todo in spirit of simple config, keep the list of routers you can attempt as a client at a root level config setting "routers" using identities with transport parameters if required
+
+ if (user && realms_length > 0) {
+ bh->master_user = ks_pstrdup(bh->pool, user);
+ bh->master_realms = realms;
+ bh->master_realms_length = realms_length;
+ }
return KS_STATUS_SUCCESS;
}
KS_DECLARE(ks_status_t) blade_handle_startup(blade_handle_t *bh, config_setting_t *config)
{
- blade_module_t *module = NULL;
+ blade_transport_t *bt = NULL;
ks_hash_iterator_t *it = NULL;
ks_assert(bh);
- // register internal modules
- blade_module_wss_create(&module, bh);
- ks_assert(module);
- blade_handle_module_register(module);
-
-
if (blade_handle_config(bh, config) != KS_STATUS_SUCCESS) {
ks_log(KS_LOG_DEBUG, "blade_handle_config failed\n");
return KS_STATUS_FAIL;
}
+ // register internals
+ blade_transport_wss_create(&bt, bh);
+ ks_assert(bt);
+ bh->default_transport = bt;
+ blade_handle_transport_register(bt);
- for (it = ks_hash_first(bh->modules, KS_UNLOCKED); it; it = ks_hash_next(&it)) {
+ for (int32_t index = 0; index < bh->master_realms_length; ++index) {
+ const char *realm = bh->master_realms[index];
+ //char *identity = ks_pstrcat(bh->pool, bh->master_user, "@", realm); // @todo this does not work... why?
+ char *identity = ks_psprintf(bh->pool, "%s@%s", bh->master_user, realm);
+
+ blade_handle_identity_register(bh, identity);
+ blade_handle_realm_register(bh, realm);
+
+ ks_pool_free(bh->pool, &identity);
+ }
+
+ for (it = ks_hash_first(bh->transports, KS_UNLOCKED); it; it = ks_hash_next(&it)) {
void *key = NULL;
- blade_module_t *value = NULL;
- blade_module_callbacks_t *callbacks = NULL;
+ blade_transport_t *value = NULL;
+ blade_transport_callbacks_t *callbacks = NULL;
ks_hash_this(it, (const void **)&key, NULL, (void **)&value);
- callbacks = blade_module_callbacks_get(value);
+ callbacks = blade_transport_callbacks_get(value);
ks_assert(callbacks);
if (callbacks->onstartup) callbacks->onstartup(value, config);
@@ -318,20 +357,20 @@ KS_DECLARE(ks_status_t) blade_handle_shutdown(blade_handle_t *bh)
ks_assert(bh);
- ks_hash_read_lock(bh->modules);
- for (it = ks_hash_first(bh->modules, KS_UNLOCKED); it; it = ks_hash_next(&it)) {
+ ks_hash_read_lock(bh->transports);
+ for (it = ks_hash_first(bh->transports, KS_UNLOCKED); it; it = ks_hash_next(&it)) {
void *key = NULL;
- blade_module_t *value = NULL;
- blade_module_callbacks_t *callbacks = NULL;
+ blade_transport_t *value = NULL;
+ blade_transport_callbacks_t *callbacks = NULL;
ks_hash_this(it, (const void **)&key, NULL, (void **)&value);
- callbacks = blade_module_callbacks_get(value);
+ callbacks = blade_transport_callbacks_get(value);
ks_assert(callbacks);
if (callbacks->onshutdown) callbacks->onshutdown(value);
}
- ks_hash_read_unlock(bh->modules);
+ ks_hash_read_unlock(bh->transports);
ks_hash_read_lock(bh->connections);
for (it = ks_hash_first(bh->connections, KS_UNLOCKED); it; it = ks_hash_next(&it)) {
@@ -357,8 +396,6 @@ KS_DECLARE(ks_status_t) blade_handle_shutdown(blade_handle_t *bh)
ks_hash_read_unlock(bh->sessions);
while (ks_hash_count(bh->sessions) > 0) ks_sleep_ms(100);
- // @todo old code, datastore will be completely revamped under the new architecture
- if (blade_handle_datastore_available(bh)) blade_datastore_destroy(&bh->datastore);
return KS_STATUS_SUCCESS;
}
@@ -375,53 +412,163 @@ KS_DECLARE(ks_thread_pool_t *) blade_handle_tpool_get(blade_handle_t *bh)
return bh->tpool;
}
-KS_DECLARE(ks_status_t) blade_handle_module_register(blade_module_t *bm)
+KS_DECLARE(ks_status_t) blade_handle_identity_register(blade_handle_t *bh, const char *identity)
{
- blade_handle_t *bh = NULL;
- const char *id = NULL;
-
- ks_assert(bm);
-
- bh = blade_module_handle_get(bm);
- ks_assert(bh);
-
- id = blade_module_id_get(bm);
- ks_assert(id);
-
- ks_hash_insert(bh->modules, (void *)id, bm);
-
- ks_log(KS_LOG_DEBUG, "Module Registered\n");
-
- return KS_STATUS_SUCCESS;
-}
-
-
-KS_DECLARE(ks_status_t) blade_handle_transport_register(blade_handle_t *bh, blade_module_t *bm, const char *name, blade_transport_callbacks_t *callbacks)
-{
- blade_handle_transport_registration_t *bhtr = NULL;
char *key = NULL;
ks_assert(bh);
- ks_assert(bm);
- ks_assert(name);
- ks_assert(callbacks);
+ ks_assert(identity);
- blade_handle_transport_registration_create(&bhtr, bh->pool, bm, callbacks);
- ks_assert(bhtr);
-
- key = ks_pstrdup(bh->pool, name);
- ks_assert(key);
-
- ks_hash_insert(bh->transports, (void *)key, bhtr);
-
- ks_log(KS_LOG_DEBUG, "Transport Registered: %s\n", name);
+ key = ks_pstrdup(bh->pool, identity);
+ ks_hash_insert(bh->identities, (void *)key, (void *)KS_TRUE);
+
+ ks_log(KS_LOG_DEBUG, "Identity Registered: %s\n", key);
return KS_STATUS_SUCCESS;
}
-KS_DECLARE(ks_status_t) blade_handle_transport_unregister(blade_handle_t *bh, const char *name)
+KS_DECLARE(ks_status_t) blade_handle_identity_unregister(blade_handle_t *bh, const char *identity)
{
ks_assert(bh);
+ ks_assert(identity);
+
+ ks_log(KS_LOG_DEBUG, "Identity Unregistered: %s\n", identity);
+
+ ks_hash_remove(bh->identities, (void *)identity);
+
+ return KS_STATUS_SUCCESS;
+}
+
+KS_DECLARE(ks_bool_t) blade_handle_identity_local(blade_handle_t *bh, const char *identity)
+{
+ void *exists = NULL;
+
+ ks_assert(bh);
+ ks_assert(identity);
+
+ exists = ks_hash_search(bh->routes, (void *)identity, KS_READLOCKED);
+ ks_hash_read_unlock(bh->routes);
+
+ return (ks_bool_t)(uintptr_t)exists == KS_TRUE;
+}
+
+KS_DECLARE(ks_status_t) blade_handle_realm_register(blade_handle_t *bh, const char *realm)
+{
+ char *key = NULL;
+
+ ks_assert(bh);
+ ks_assert(realm);
+
+ key = ks_pstrdup(bh->pool, realm);
+ ks_hash_insert(bh->realms, (void *)key, (void *)KS_TRUE);
+
+ ks_log(KS_LOG_DEBUG, "Realm Registered: %s\n", key);
+
+ return KS_STATUS_SUCCESS;
+}
+
+KS_DECLARE(ks_status_t) blade_handle_realm_unregister(blade_handle_t *bh, const char *realm)
+{
+ ks_assert(bh);
+ ks_assert(realm);
+
+ ks_log(KS_LOG_DEBUG, "Realm Unregistered: %s\n", realm);
+
+ ks_hash_remove(bh->realms, (void *)realm);
+
+ return KS_STATUS_SUCCESS;
+}
+
+KS_DECLARE(ks_hash_t *) blade_handle_realms_get(blade_handle_t *bh)
+{
+ ks_assert(bh);
+ return bh->realms;
+}
+
+KS_DECLARE(ks_status_t) blade_handle_route_add(blade_handle_t *bh, const char *identity, const char *id)
+{
+ char *key = NULL;
+ char *value = NULL;
+
+ ks_assert(bh);
+ ks_assert(identity);
+ ks_assert(id);
+
+ key = ks_pstrdup(bh->pool, identity);
+ value = ks_pstrdup(bh->pool, id);
+
+ ks_hash_insert(bh->identities, (void *)key, (void *)id);
+
+ ks_log(KS_LOG_DEBUG, "Route Added: %s through %s\n", key, id);
+
+ // @todo when a route is added, upstream needs to be notified that the identity can be found through the session to the
+ // upstream router, and likewise up the chain to the Master Router Node, to create a complete route from anywhere else
+ return KS_STATUS_SUCCESS;
+}
+
+KS_DECLARE(ks_status_t) blade_handle_route_remove(blade_handle_t *bh, const char *identity)
+{
+ ks_assert(bh);
+ ks_assert(identity);
+
+ ks_log(KS_LOG_DEBUG, "Route Removed: %s\n", identity);
+
+ ks_hash_remove(bh->identities, (void *)identity);
+
+ // @todo when a route is removed, upstream needs to be notified, for whatever reason the identity is no longer
+ // available through this node so the routes leading here need to be cleared, the disconnected node cannot be informed
+ // and does not need to change it's routes because upstream is not included in routes (and thus should never call to remove
+ // a route if an upstream session is closed)
+
+ return KS_STATUS_SUCCESS;
+}
+
+KS_DECLARE(blade_session_t *) blade_handle_route_lookup(blade_handle_t *bh, const char *identity)
+{
+ blade_session_t *bs = NULL;
+ const char *id = NULL;
+
+ ks_assert(bh);
+ ks_assert(identity);
+
+ id = ks_hash_search(bh->routes, (void *)identity, KS_READLOCKED);
+ if (id) bs = blade_handle_sessions_lookup(bh, id);
+ ks_hash_read_unlock(bh->routes);
+
+ return bs;
+}
+
+KS_DECLARE(ks_status_t) blade_handle_transport_register(blade_transport_t *bt)
+{
+ blade_handle_t *bh = NULL;
+ char *key = NULL;
+
+ ks_assert(bt);
+
+ bh = blade_transport_handle_get(bt);
+ ks_assert(bh);
+
+ key = ks_pstrdup(bh->pool, blade_transport_name_get(bt));
+ ks_assert(key);
+
+ ks_hash_insert(bh->transports, (void *)key, bt);
+
+ ks_log(KS_LOG_DEBUG, "Transport Registered: %s\n", key);
+
+ return KS_STATUS_SUCCESS;
+}
+
+KS_DECLARE(ks_status_t) blade_handle_transport_unregister(blade_transport_t *bt)
+{
+ blade_handle_t *bh = NULL;
+ const char *name = NULL;
+
+ ks_assert(bt);
+
+ bh = blade_transport_handle_get(bt);
+ ks_assert(bh);
+
+ name = blade_transport_name_get(bt);
ks_assert(name);
ks_log(KS_LOG_DEBUG, "Transport Unregistered: %s\n", name);
@@ -431,170 +578,141 @@ KS_DECLARE(ks_status_t) blade_handle_transport_unregister(blade_handle_t *bh, co
return KS_STATUS_SUCCESS;
}
-KS_DECLARE(ks_status_t) blade_handle_space_register(blade_space_t *bs)
+
+KS_DECLARE(ks_status_t) blade_handle_jsonrpc_register(blade_jsonrpc_t *bjsonrpc)
{
blade_handle_t *bh = NULL;
- const char *path = NULL;
-
- ks_assert(bs);
-
- bh = blade_space_handle_get(bs);
- ks_assert(bh);
-
- path = blade_space_path_get(bs);
- ks_assert(path);
-
- ks_hash_insert(bh->spaces, (void *)path, bs);
-
- ks_log(KS_LOG_DEBUG, "Space Registered: %s\n", path);
-
- return KS_STATUS_SUCCESS;
-}
-
-KS_DECLARE(ks_status_t) blade_handle_space_unregister(blade_space_t *bs)
-{
- blade_handle_t *bh = NULL;
- const char *path = NULL;
-
- ks_assert(bs);
-
- bh = blade_space_handle_get(bs);
- ks_assert(bh);
-
- path = blade_space_path_get(bs);
- ks_assert(path);
-
- ks_log(KS_LOG_DEBUG, "Space Unregistered: %s\n", path);
-
- ks_hash_remove(bh->spaces, (void *)path);
-
- return KS_STATUS_SUCCESS;
-}
-
-KS_DECLARE(blade_space_t *) blade_handle_space_lookup(blade_handle_t *bh, const char *path)
-{
- blade_space_t *bs = NULL;
-
- ks_assert(bh);
- ks_assert(path);
-
- bs = ks_hash_search(bh->spaces, (void *)path, KS_READLOCKED);
- ks_hash_read_unlock(bh->spaces);
-
- return bs;
-}
-
-KS_DECLARE(ks_status_t) blade_handle_event_register(blade_handle_t *bh, const char *event, blade_event_callback_t callback)
-{
char *key = NULL;
- ks_assert(bh);
- ks_assert(event);
- ks_assert(callback);
+ ks_assert(bjsonrpc);
- key = ks_pstrdup(bh->pool, event);
+ bh = blade_jsonrpc_handle_get(bjsonrpc);
+ ks_assert(bh);
+
+ key = ks_pstrdup(bh->pool, blade_jsonrpc_method_get(bjsonrpc));
ks_assert(key);
- ks_hash_insert(bh->events, (void *)key, (void *)(intptr_t)callback);
+ ks_hash_insert(bh->jsonrpcs, (void *)key, bjsonrpc);
- ks_log(KS_LOG_DEBUG, "Event Registered: %s\n", event);
+ ks_log(KS_LOG_DEBUG, "JSONRPC Registered: %s\n", key);
return KS_STATUS_SUCCESS;
}
-KS_DECLARE(ks_status_t) blade_handle_event_unregister(blade_handle_t *bh, const char *event)
+KS_DECLARE(ks_status_t) blade_handle_jsonrpc_unregister(blade_jsonrpc_t *bjsonrpc)
{
+ blade_handle_t *bh = NULL;
+ const char *method = NULL;
+
+ ks_assert(bjsonrpc);
+
+ bh = blade_jsonrpc_handle_get(bjsonrpc);
ks_assert(bh);
- ks_assert(event);
- ks_log(KS_LOG_DEBUG, "Event Unregistered: %s\n", event);
+ method = blade_jsonrpc_method_get(bjsonrpc);
+ ks_assert(method);
- ks_hash_remove(bh->events, (void *)event);
+ ks_log(KS_LOG_DEBUG, "JSONRPC Unregistered: %s\n", method);
+
+ ks_hash_remove(bh->jsonrpcs, (void *)method);
return KS_STATUS_SUCCESS;
}
-KS_DECLARE(blade_event_callback_t) blade_handle_event_lookup(blade_handle_t *bh, const char *event)
+KS_DECLARE(blade_jsonrpc_t *) blade_handle_jsonrpc_lookup(blade_handle_t *bh, const char *method)
{
- blade_event_callback_t callback = NULL;
+ blade_jsonrpc_t *bjsonrpc = NULL;
ks_assert(bh);
- ks_assert(event);
+ ks_assert(method);
- callback = (blade_event_callback_t)(intptr_t)ks_hash_search(bh->events, (void *)event, KS_READLOCKED);
- ks_hash_read_unlock(bh->events);
+ bjsonrpc = ks_hash_search(bh->jsonrpcs, (void *)method, KS_READLOCKED);
+ ks_hash_read_unlock(bh->jsonrpcs);
- return callback;
+ return bjsonrpc;
}
+
+KS_DECLARE(ks_status_t) blade_handle_requests_add(blade_jsonrpc_request_t *bjsonrpcreq)
+{
+ blade_handle_t *bh = NULL;
+ const char *key = NULL;
+
+ ks_assert(bjsonrpcreq);
+
+ bh = blade_jsonrpc_request_handle_get(bjsonrpcreq);
+ ks_assert(bh);
+
+ key = ks_pstrdup(bh->pool, blade_jsonrpc_request_messageid_get(bjsonrpcreq));
+ ks_assert(key);
+
+ ks_hash_insert(bh->requests, (void *)key, bjsonrpcreq);
+
+ return KS_STATUS_SUCCESS;
+}
+
+KS_DECLARE(ks_status_t) blade_handle_requests_remove(blade_jsonrpc_request_t *bjsonrpcreq)
+{
+ blade_handle_t *bh = NULL;
+ const char *id = NULL;
+
+ ks_assert(bjsonrpcreq);
+
+ bh = blade_jsonrpc_request_handle_get(bjsonrpcreq);
+ ks_assert(bh);
+
+ id = blade_jsonrpc_request_messageid_get(bjsonrpcreq);
+ ks_assert(id);
+
+ ks_hash_remove(bh->requests, (void *)id);
+
+ return KS_STATUS_SUCCESS;
+}
+
+KS_DECLARE(blade_jsonrpc_request_t *) blade_handle_requests_lookup(blade_handle_t *bh, const char *id)
+{
+ blade_jsonrpc_request_t *bjsonrpcreq = NULL;
+
+ ks_assert(bh);
+ ks_assert(id);
+
+ bjsonrpcreq = ks_hash_search(bh->requests, (void *)id, KS_READLOCKED);
+ ks_hash_read_unlock(bh->requests);
+
+ return bjsonrpcreq;
+}
+
+
KS_DECLARE(ks_status_t) blade_handle_connect(blade_handle_t *bh, blade_connection_t **bcP, blade_identity_t *target, const char *session_id)
{
ks_status_t ret = KS_STATUS_SUCCESS;
- blade_handle_transport_registration_t *bhtr = NULL;
+ blade_transport_t *bt = NULL;
+ blade_transport_callbacks_t *callbacks = NULL;
const char *tname = NULL;
ks_assert(bh);
ks_assert(target);
- // @todo this should take a callback, and push this to a queue to be processed async from another thread on the handle
- // which will allow the onconnect callback to block while doing things like DNS lookups without having unknown
- // impact depending on the caller thread
+ if (bh->upstream_id) return KS_STATUS_DUPLICATE_OPERATION;
ks_hash_read_lock(bh->transports);
tname = blade_identity_parameter_get(target, "transport");
if (tname) {
- bhtr = ks_hash_search(bh->transports, (void *)tname, KS_UNLOCKED);
- if (!bhtr) {
- // @todo error logging, target has an explicit transport that is not available in the local transports registry
- // discuss later whether this scenario should still attempt other transports when target is explicit
- // @note discussions indicate that by default messages should favor relaying through a master service, unless
- // an existing direct connection already exists to the target (which if the target is the master node, then there is
- // no conflict of proper routing). This also applies to routing for identities which relate to groups, relaying should
- // most often occur through a master service, however there may be scenarios that exist where an existing session
- // exists dedicated to faster delivery for a group (IE, through an ampq cluster directly, such as master services
- // syncing with each other through a pub/sub). There is also the potential that instead of a separate session, the
- // current session with a master service may be able to have another connection attached which represents access through
- // amqp, which in turn acts as a preferred router for only group identities
- // This information does not directly apply to connecting, but should be noted for the next level up where you simply
- // send a message which will not actually connect, only check for existing sessions for the target and master service
- // @note relaying by master services should take a slightly different path, when they receive something not for the
- // master service itself, it should relay this on to all other master services, which in turn all including original
- // receiver pass on to any sessions matching an identity that is part of the group, alternatively they can use a pub/sub
- // like amqp to relay between the master services more efficiently than using the websocket to send every master service
- // session the message individually
- }
- } else {
- for (ks_hash_iterator_t *it = ks_hash_first(bh->transports, KS_UNLOCKED); it; it = ks_hash_next(&it)) {
- // @todo use onrank (or replace with whatever method is used for determining what transport to use) and keep highest ranked callbacks
- }
+ bt = ks_hash_search(bh->transports, (void *)tname, KS_UNLOCKED);
}
ks_hash_read_unlock(bh->transports);
- // @todo need to be able to get to the blade_module_t from the callbacks, may require envelope around registration of callbacks to include module
- // this is required because onconnect transport callback needs to be able to get back to the module data to create the connection being returned
- if (bhtr) ret = bhtr->callbacks->onconnect(bcP, bhtr->module, target, session_id);
- else ret = KS_STATUS_FAIL;
+ if (!bt) bt = bh->default_transport;
+
+ callbacks = blade_transport_callbacks_get(bt);
+
+ if (callbacks->onconnect) ret = callbacks->onconnect(bcP, bt, target, session_id);
return ret;
}
-KS_DECLARE(blade_connection_t *) blade_handle_connections_get(blade_handle_t *bh, const char *cid)
-{
- blade_connection_t *bc = NULL;
-
- ks_assert(bh);
- ks_assert(cid);
-
- ks_hash_read_lock(bh->connections);
- bc = ks_hash_search(bh->connections, (void *)cid, KS_UNLOCKED);
- if (bc && blade_connection_read_lock(bc, KS_FALSE) != KS_STATUS_SUCCESS) bc = NULL;
- ks_hash_read_unlock(bh->connections);
-
- return bc;
-}
-
KS_DECLARE(ks_status_t) blade_handle_connections_add(blade_connection_t *bc)
{
ks_status_t ret = KS_STATUS_SUCCESS;
@@ -630,33 +748,25 @@ KS_DECLARE(ks_status_t) blade_handle_connections_remove(blade_connection_t *bc)
blade_connection_write_unlock(bc);
- // @todo call bh->connection_callbacks
-
return ret;
}
-KS_DECLARE(blade_session_t *) blade_handle_sessions_get(blade_handle_t *bh, const char *sid)
+KS_DECLARE(blade_connection_t *) blade_handle_connections_lookup(blade_handle_t *bh, const char *id)
{
- blade_session_t *bs = NULL;
+ blade_connection_t *bc = NULL;
ks_assert(bh);
- ks_assert(sid);
+ 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->connections);
+ bc = ks_hash_search(bh->connections, (void *)id, KS_UNLOCKED);
+ if (bc && blade_connection_read_lock(bc, KS_FALSE) != KS_STATUS_SUCCESS) bc = NULL;
+ ks_hash_read_unlock(bh->connections);
- ks_hash_read_lock(bh->sessions);
- bs = ks_hash_search(bh->sessions, (void *)sid, KS_UNLOCKED);
- if (bs && blade_session_read_lock(bs, KS_FALSE) != KS_STATUS_SUCCESS) bs = NULL;
- ks_hash_read_unlock(bh->sessions);
-
- return bs;
+ return bc;
}
+
KS_DECLARE(ks_status_t) blade_handle_sessions_add(blade_session_t *bs)
{
ks_status_t ret = KS_STATUS_SUCCESS;
@@ -678,6 +788,8 @@ KS_DECLARE(ks_status_t) blade_handle_sessions_remove(blade_session_t *bs)
{
ks_status_t ret = KS_STATUS_SUCCESS;
blade_handle_t *bh = NULL;
+ const char *id = NULL;
+ ks_hash_iterator_t *it = NULL;
ks_assert(bs);
@@ -686,15 +798,89 @@ KS_DECLARE(ks_status_t) blade_handle_sessions_remove(blade_session_t *bs)
blade_session_write_lock(bs, KS_TRUE);
+ id = blade_session_id_get(bs);
+ ks_assert(id);
+
ks_hash_write_lock(bh->sessions);
- if (ks_hash_remove(bh->sessions, (void *)blade_session_id_get(bs)) == NULL) ret = KS_STATUS_FAIL;
+ if (ks_hash_remove(bh->sessions, (void *)id) == NULL) ret = KS_STATUS_FAIL;
+
+ ks_mutex_lock(bh->upstream_mutex);
+ if (bh->upstream_id && !ks_safe_strcasecmp(bh->upstream_id, id)) {
+ // the session is the upstream being terminated, so clear out all of the local identities and realms from the handle,
+ // @todo this complicates any remaining connected downstream sessions, because they are based on realms that may not
+ // be available after a new upstream is registered, therefore all downstream sessions should be fully terminated when
+ // this happens, and ignore inbound downstream sessions until the upstream is available again, and require new
+ // downstream inbound sessions to be completely reestablished fresh
+ while ((it = ks_hash_first(bh->identities, KS_UNLOCKED))) {
+ void *key = NULL;
+ void *value = NULL;
+ ks_hash_this(it, &key, NULL, &value);
+ ks_hash_remove(bh->identities, key);
+ }
+ while ((it = ks_hash_first(bh->realms, KS_UNLOCKED))) {
+ void *key = NULL;
+ void *value = NULL;
+ ks_hash_this(it, &key, NULL, &value);
+ ks_hash_remove(bh->realms, key);
+ }
+ ks_pool_free(bh->pool, &bh->upstream_id);
+ }
+ ks_mutex_unlock(bh->upstream_mutex);
+
ks_hash_write_unlock(bh->sessions);
blade_session_write_unlock(bs);
+
+
return ret;
}
+KS_DECLARE(blade_session_t *) blade_handle_sessions_lookup(blade_handle_t *bh, const char *id)
+{
+ blade_session_t *bs = NULL;
+
+ 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;
+ ks_hash_read_unlock(bh->sessions);
+
+ return bs;
+}
+
+KS_DECLARE(ks_status_t) blade_handle_upstream_set(blade_handle_t *bh, const char *id)
+{
+ ks_status_t ret = KS_STATUS_SUCCESS;
+
+ ks_assert(bh);
+
+ ks_mutex_lock(bh->upstream_mutex);
+
+ if (bh->upstream_id) {
+ ret = KS_STATUS_DUPLICATE_OPERATION;
+ goto done;
+ }
+
+ bh->upstream_id = ks_pstrdup(bh->pool, id);
+
+done:
+
+ ks_mutex_unlock(bh->upstream_mutex);
+
+ return ret;
+}
+
+
KS_DECLARE(void) blade_handle_sessions_send(blade_handle_t *bh, ks_list_t *sessions, const char *exclude, cJSON *json)
{
blade_session_t *bs = NULL;
@@ -707,7 +893,7 @@ KS_DECLARE(void) blade_handle_sessions_send(blade_handle_t *bh, ks_list_t *sessi
while (ks_list_iterator_hasnext(sessions)) {
const char *sessionid = ks_list_iterator_next(sessions);
if (exclude && !strcmp(exclude, sessionid)) continue;
- bs = blade_handle_sessions_get(bh, sessionid);
+ bs = blade_handle_sessions_lookup(bh, sessionid);
if (!bs) {
ks_log(KS_LOG_DEBUG, "This should not happen\n");
continue;
@@ -771,85 +957,6 @@ KS_DECLARE(void) blade_handle_session_state_callbacks_execute(blade_session_t *b
}
-KS_DECLARE(blade_request_t *) blade_handle_requests_get(blade_handle_t *bh, const char *mid)
-{
- blade_request_t *breq = NULL;
-
- ks_assert(bh);
- ks_assert(mid);
-
- breq = ks_hash_search(bh->requests, (void *)mid, KS_READLOCKED);
- ks_hash_read_unlock(bh->requests);
-
- return breq;
-}
-
-KS_DECLARE(ks_status_t) blade_handle_requests_add(blade_request_t *br)
-{
- blade_handle_t *bh = NULL;
-
- ks_assert(br);
-
- bh = br->handle;
- ks_assert(bh);
-
- ks_hash_insert(bh->requests, (void *)br->message_id, br);
-
- return KS_STATUS_SUCCESS;
-}
-
-KS_DECLARE(ks_status_t) blade_handle_requests_remove(blade_request_t *br)
-{
- blade_handle_t *bh = NULL;
-
- ks_assert(br);
-
- bh = br->handle;
- ks_assert(bh);
-
- ks_hash_remove(bh->requests, (void *)br->message_id);
-
- return KS_STATUS_SUCCESS;
-}
-
-
-
-KS_DECLARE(ks_bool_t) blade_handle_datastore_available(blade_handle_t *bh)
-{
- ks_assert(bh);
-
- return bh->datastore != NULL;
-}
-
-KS_DECLARE(ks_status_t) blade_handle_datastore_store(blade_handle_t *bh, const void *key, int32_t key_length, const void *data, int64_t data_length)
-{
- ks_assert(bh);
- ks_assert(key);
- ks_assert(key_length > 0);
- ks_assert(data);
- ks_assert(data_length > 0);
-
- if (!blade_handle_datastore_available(bh)) return KS_STATUS_INACTIVE;
-
- return blade_datastore_store(bh->datastore, key, key_length, data, data_length);
-}
-
-KS_DECLARE(ks_status_t) blade_handle_datastore_fetch(blade_handle_t *bh,
- blade_datastore_fetch_callback_t callback,
- const void *key,
- int32_t key_length,
- void *userdata)
-{
- ks_assert(bh);
- ks_assert(callback);
- ks_assert(key);
- ks_assert(key_length > 0);
-
- if (!blade_handle_datastore_available(bh)) return KS_STATUS_INACTIVE;
-
- return blade_datastore_fetch(bh->datastore, callback, key, key_length, userdata);
-}
-
/* For Emacs:
* Local Variables:
* mode:c
diff --git a/libs/libblade/src/blade_method.c b/libs/libblade/src/blade_transport.c
similarity index 57%
rename from libs/libblade/src/blade_method.c
rename to libs/libblade/src/blade_transport.c
index 8e7a69a243..2e8f494c1f 100644
--- a/libs/libblade/src/blade_method.c
+++ b/libs/libblade/src/blade_transport.c
@@ -33,78 +33,100 @@
#include "blade.h"
-struct blade_method_s {
+struct blade_transport_s {
blade_handle_t *handle;
ks_pool_t *pool;
- blade_space_t *space;
const char *name;
-
- blade_request_callback_t callback;
- // @todo more fun descriptive information about the call for remote registrations
+ void *data;
+ blade_transport_callbacks_t *callbacks;
};
-static void blade_method_cleanup(ks_pool_t *pool, void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type)
-{
- blade_method_t *bm = (blade_method_t *)ptr;
- ks_assert(bm);
+static void blade_transport_cleanup(ks_pool_t *pool, void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type)
+{
+ //blade_transport_t *bt = (blade_transport_t *)ptr;
+
+ //ks_assert(bt);
switch (action) {
case KS_MPCL_ANNOUNCE:
break;
case KS_MPCL_TEARDOWN:
- ks_pool_free(bm->pool, &bm->name);
break;
case KS_MPCL_DESTROY:
break;
}
}
-KS_DECLARE(ks_status_t) blade_method_create(blade_method_t **bmP, blade_space_t *bs, const char *name, blade_request_callback_t callback)
+KS_DECLARE(ks_status_t) blade_transport_create(blade_transport_t **btP, blade_handle_t *bh, ks_pool_t *pool, const char *name, void *data, blade_transport_callbacks_t *callbacks)
{
- blade_handle_t *bh = NULL;
- blade_method_t *bm = NULL;
- ks_pool_t *pool = NULL;
+ blade_transport_t *bt = NULL;
- ks_assert(bmP);
- ks_assert(bs);
- ks_assert(name);
-
- bh = blade_space_handle_get(bs);
+ ks_assert(btP);
ks_assert(bh);
-
- pool = blade_space_pool_get(bs);
ks_assert(pool);
+ ks_assert(name);
+ ks_assert(callbacks);
- bm = ks_pool_alloc(pool, sizeof(blade_method_t));
- bm->handle = bh;
- bm->pool = pool;
- bm->space = bs;
- bm->name = ks_pstrdup(pool, name);
- bm->callback = callback;
+ bt = ks_pool_alloc(pool, sizeof(blade_transport_t));
+ bt->handle = bh;
+ bt->pool = pool;
+ bt->name = ks_pstrdup(pool, name);
+ bt->data = data;
+ bt->callbacks = callbacks;
- ks_pool_set_cleanup(pool, bm, NULL, blade_method_cleanup);
+ ks_pool_set_cleanup(pool, bt, NULL, blade_transport_cleanup);
- *bmP = bm;
+ ks_log(KS_LOG_DEBUG, "Created transport %s\n", name);
+
+ *btP = bt;
return KS_STATUS_SUCCESS;
}
-KS_DECLARE(const char *) blade_method_name_get(blade_method_t *bm)
+KS_DECLARE(ks_status_t) blade_transport_destroy(blade_transport_t **btP)
{
- ks_assert(bm);
+ blade_transport_t *bt = NULL;
+ ks_pool_t *pool = NULL;
- return bm->name;
+ ks_assert(btP);
+ ks_assert(*btP);
+
+ bt = *btP;
+
+ pool = bt->pool;
+
+ ks_pool_close(&pool);
+
+ *btP = NULL;
+
+ return KS_STATUS_SUCCESS;
}
-KS_DECLARE(blade_request_callback_t) blade_method_callback_get(blade_method_t *bm)
+KS_DECLARE(blade_handle_t *) blade_transport_handle_get(blade_transport_t *bt)
{
- ks_assert(bm);
-
- return bm->callback;
+ ks_assert(bt);
+ return bt->handle;
}
+KS_DECLARE(const char *) blade_transport_name_get(blade_transport_t *bt)
+{
+ ks_assert(bt);
+ return bt->name;
+}
+
+KS_DECLARE(void *) blade_transport_data_get(blade_transport_t *bt)
+{
+ ks_assert(bt);
+ return bt->data;
+}
+
+KS_DECLARE(blade_transport_callbacks_t *) blade_transport_callbacks_get(blade_transport_t *bt)
+{
+ ks_assert(bt);
+ return bt->callbacks;
+}
/* For Emacs:
* Local Variables:
diff --git a/libs/libblade/src/blade_transport_wss.c b/libs/libblade/src/blade_transport_wss.c
new file mode 100644
index 0000000000..397db24d4e
--- /dev/null
+++ b/libs/libblade/src/blade_transport_wss.c
@@ -0,0 +1,1177 @@
+/*
+ * 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"
+
+#define BLADE_MODULE_WSS_TRANSPORT_NAME "wss"
+#define BLADE_MODULE_WSS_ENDPOINTS_MULTIHOME_MAX 16
+
+typedef struct blade_transport_wss_s blade_transport_wss_t;
+typedef struct blade_transport_wss_link_s blade_transport_wss_link_t;
+
+struct blade_transport_wss_s {
+ blade_handle_t *handle;
+ ks_pool_t *pool;
+ blade_transport_t *transport;
+ blade_transport_callbacks_t *callbacks;
+
+ ks_sockaddr_t endpoints_ipv4[BLADE_MODULE_WSS_ENDPOINTS_MULTIHOME_MAX];
+ ks_sockaddr_t endpoints_ipv6[BLADE_MODULE_WSS_ENDPOINTS_MULTIHOME_MAX];
+ int32_t endpoints_ipv4_length;
+ int32_t endpoints_ipv6_length;
+ int32_t endpoints_backlog;
+
+ volatile ks_bool_t shutdown;
+
+ struct pollfd *listeners_poll;
+ int32_t listeners_count;
+};
+
+struct blade_transport_wss_link_s {
+ blade_transport_wss_t *transport;
+ ks_pool_t *pool;
+
+ const char *session_id;
+ ks_socket_t sock;
+ kws_t *kws;
+};
+
+
+
+ks_status_t blade_transport_wss_listen(blade_transport_wss_t *btwss, ks_sockaddr_t *addr);
+void *blade_transport_wss_listeners_thread(ks_thread_t *thread, void *data);
+
+
+ks_status_t blade_transport_wss_link_create(blade_transport_wss_link_t **btwsslP, ks_pool_t *pool, blade_transport_wss_t *btwss, ks_socket_t sock, const char *session_id);
+
+ks_status_t blade_transport_wss_onstartup(blade_transport_t *bt, config_setting_t *config);
+ks_status_t blade_transport_wss_onshutdown(blade_transport_t *bt);
+
+ks_status_t blade_transport_wss_onconnect(blade_connection_t **bcP, blade_transport_t *bt, blade_identity_t *target, const char *session_id);
+
+ks_status_t blade_transport_wss_onsend(blade_connection_t *bc, cJSON *json);
+ks_status_t blade_transport_wss_onreceive(blade_connection_t *bc, cJSON **json);
+
+blade_connection_state_hook_t blade_transport_wss_onstate_startup_inbound(blade_connection_t *bc, blade_connection_state_condition_t condition);
+blade_connection_state_hook_t blade_transport_wss_onstate_startup_outbound(blade_connection_t *bc, blade_connection_state_condition_t condition);
+blade_connection_state_hook_t blade_transport_wss_onstate_shutdown(blade_connection_t *bc, blade_connection_state_condition_t condition);
+blade_connection_state_hook_t blade_transport_wss_onstate_run_inbound(blade_connection_t *bc, blade_connection_state_condition_t condition);
+blade_connection_state_hook_t blade_transport_wss_onstate_run_outbound(blade_connection_t *bc, blade_connection_state_condition_t condition);
+
+
+
+static blade_transport_callbacks_t g_transport_wss_callbacks =
+{
+ blade_transport_wss_onstartup,
+ blade_transport_wss_onshutdown,
+
+ blade_transport_wss_onconnect,
+
+ blade_transport_wss_onsend,
+ blade_transport_wss_onreceive,
+
+ blade_transport_wss_onstate_startup_inbound,
+ blade_transport_wss_onstate_startup_outbound,
+ blade_transport_wss_onstate_shutdown,
+ blade_transport_wss_onstate_shutdown,
+ blade_transport_wss_onstate_run_inbound,
+ blade_transport_wss_onstate_run_outbound,
+};
+
+
+static void blade_transport_wss_cleanup(ks_pool_t *pool, void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type)
+{
+ //blade_transport_wss_t *btwss = (blade_transport_wss_t *)ptr;
+
+ //ks_assert(btwss);
+
+ switch (action) {
+ case KS_MPCL_ANNOUNCE:
+ break;
+ case KS_MPCL_TEARDOWN:
+ break;
+ case KS_MPCL_DESTROY:
+ break;
+ }
+}
+
+KS_DECLARE(ks_status_t) blade_transport_wss_create(blade_transport_t **btP, blade_handle_t *bh)
+{
+ blade_transport_wss_t *btwss = NULL;
+ ks_pool_t *pool = NULL;
+
+ ks_assert(btP);
+ ks_assert(bh);
+
+ ks_pool_open(&pool);
+ ks_assert(pool);
+
+ btwss = ks_pool_alloc(pool, sizeof(blade_transport_wss_t));
+ btwss->handle = bh;
+ btwss->pool = pool;
+
+ blade_transport_create(&btwss->transport, bh, pool, BLADE_MODULE_WSS_TRANSPORT_NAME, btwss, &g_transport_wss_callbacks);
+ btwss->callbacks = &g_transport_wss_callbacks;
+
+ ks_pool_set_cleanup(pool, btwss, NULL, blade_transport_wss_cleanup);
+
+ ks_log(KS_LOG_DEBUG, "Created\n");
+
+ *btP = btwss->transport;
+
+ return KS_STATUS_SUCCESS;
+}
+
+static void blade_transport_wss_link_cleanup(ks_pool_t *pool, void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type)
+{
+ blade_transport_wss_link_t *btwssl = (blade_transport_wss_link_t *)ptr;
+
+ ks_assert(btwssl);
+
+ switch (action) {
+ case KS_MPCL_ANNOUNCE:
+ break;
+ case KS_MPCL_TEARDOWN:
+ if (btwssl->session_id) ks_pool_free(btwssl->pool, &btwssl->session_id);
+ if (btwssl->kws) kws_destroy(&btwssl->kws);
+ else ks_socket_close(&btwssl->sock);
+ break;
+ case KS_MPCL_DESTROY:
+ break;
+ }
+}
+
+
+ks_status_t blade_transport_wss_link_create(blade_transport_wss_link_t **btwsslP, ks_pool_t *pool, blade_transport_wss_t *btwss, ks_socket_t sock, const char *session_id)
+{
+ blade_transport_wss_link_t *btwssl = NULL;
+
+ ks_assert(btwsslP);
+ ks_assert(btwss);
+ ks_assert(sock != KS_SOCK_INVALID);
+
+ btwssl = ks_pool_alloc(pool, sizeof(blade_transport_wss_link_t));
+ btwssl->transport = btwss;
+ btwssl->pool = pool;
+ btwssl->sock = sock;
+ if (session_id) btwssl->session_id = ks_pstrdup(pool, session_id);
+
+ ks_pool_set_cleanup(pool, btwssl, NULL, blade_transport_wss_link_cleanup);
+
+ ks_log(KS_LOG_DEBUG, "Created\n");
+
+ *btwsslP = btwssl;
+
+ return KS_STATUS_SUCCESS;
+}
+
+ks_status_t blade_transport_wss_config(blade_transport_wss_t *btwss, config_setting_t *config)
+{
+ config_setting_t *transport = NULL;
+ config_setting_t *transport_wss = NULL;
+ config_setting_t *transport_wss_endpoints = NULL;
+ config_setting_t *transport_wss_endpoints_ipv4 = NULL;
+ config_setting_t *transport_wss_endpoints_ipv6 = NULL;
+ config_setting_t *transport_wss_ssl = NULL;
+ config_setting_t *element;
+ config_setting_t *tmp1;
+ config_setting_t *tmp2;
+ ks_sockaddr_t endpoints_ipv4[BLADE_MODULE_WSS_ENDPOINTS_MULTIHOME_MAX];
+ ks_sockaddr_t endpoints_ipv6[BLADE_MODULE_WSS_ENDPOINTS_MULTIHOME_MAX];
+ int32_t endpoints_ipv4_length = 0;
+ int32_t endpoints_ipv6_length = 0;
+ int32_t endpoints_backlog = 8;
+
+ ks_assert(btwss);
+ ks_assert(config);
+
+ if (!config_setting_is_group(config)) {
+ ks_log(KS_LOG_DEBUG, "!config_setting_is_group(config)\n");
+ return KS_STATUS_FAIL;
+ }
+ transport = config_setting_get_member(config, "transport");
+ if (transport) {
+ transport_wss = config_setting_get_member(transport, "wss");
+ if (transport_wss) {
+ transport_wss_endpoints = config_setting_get_member(transport_wss, "endpoints");
+ if (!transport_wss_endpoints) {
+ ks_log(KS_LOG_DEBUG, "!wss_endpoints\n");
+ return KS_STATUS_FAIL;
+ }
+ transport_wss_endpoints_ipv4 = config_lookup_from(transport_wss_endpoints, "ipv4");
+ transport_wss_endpoints_ipv6 = config_lookup_from(transport_wss_endpoints, "ipv6");
+ if (transport_wss_endpoints_ipv4) {
+ if (config_setting_type(transport_wss_endpoints_ipv4) != CONFIG_TYPE_LIST) return KS_STATUS_FAIL;
+ if ((endpoints_ipv4_length = config_setting_length(transport_wss_endpoints_ipv4)) > BLADE_MODULE_WSS_ENDPOINTS_MULTIHOME_MAX)
+ return KS_STATUS_FAIL;
+
+ for (int32_t index = 0; index < endpoints_ipv4_length; ++index) {
+ element = config_setting_get_elem(transport_wss_endpoints_ipv4, index);
+ tmp1 = config_lookup_from(element, "address");
+ tmp2 = config_lookup_from(element, "port");
+ if (!tmp1 || !tmp2) return KS_STATUS_FAIL;
+ if (config_setting_type(tmp1) != CONFIG_TYPE_STRING) return KS_STATUS_FAIL;
+ if (config_setting_type(tmp2) != CONFIG_TYPE_INT) return KS_STATUS_FAIL;
+
+ if (ks_addr_set(&endpoints_ipv4[index],
+ config_setting_get_string(tmp1),
+ config_setting_get_int(tmp2),
+ AF_INET) != KS_STATUS_SUCCESS) return KS_STATUS_FAIL;
+ ks_log(KS_LOG_DEBUG,
+ "Binding to IPV4 %s on port %d\n",
+ ks_addr_get_host(&endpoints_ipv4[index]),
+ ks_addr_get_port(&endpoints_ipv4[index]));
+ }
+ }
+ if (transport_wss_endpoints_ipv6) {
+ if (config_setting_type(transport_wss_endpoints_ipv6) != CONFIG_TYPE_LIST) return KS_STATUS_FAIL;
+ if ((endpoints_ipv6_length = config_setting_length(transport_wss_endpoints_ipv6)) > BLADE_MODULE_WSS_ENDPOINTS_MULTIHOME_MAX)
+ return KS_STATUS_FAIL;
+
+ for (int32_t index = 0; index < endpoints_ipv6_length; ++index) {
+ element = config_setting_get_elem(transport_wss_endpoints_ipv6, index);
+ tmp1 = config_lookup_from(element, "address");
+ tmp2 = config_lookup_from(element, "port");
+ if (!tmp1 || !tmp2) return KS_STATUS_FAIL;
+ if (config_setting_type(tmp1) != CONFIG_TYPE_STRING) return KS_STATUS_FAIL;
+ if (config_setting_type(tmp2) != CONFIG_TYPE_INT) return KS_STATUS_FAIL;
+
+
+ if (ks_addr_set(&endpoints_ipv6[index],
+ config_setting_get_string(tmp1),
+ config_setting_get_int(tmp2),
+ AF_INET6) != KS_STATUS_SUCCESS) return KS_STATUS_FAIL;
+ ks_log(KS_LOG_DEBUG,
+ "Binding to IPV6 %s on port %d\n",
+ ks_addr_get_host(&endpoints_ipv6[index]),
+ ks_addr_get_port(&endpoints_ipv6[index]));
+ }
+ }
+ if (endpoints_ipv4_length + endpoints_ipv6_length <= 0) return KS_STATUS_FAIL;
+ tmp1 = config_lookup_from(transport_wss_endpoints, "backlog");
+ if (tmp1) {
+ if (config_setting_type(tmp1) != CONFIG_TYPE_INT) return KS_STATUS_FAIL;
+ endpoints_backlog = config_setting_get_int(tmp1);
+ }
+ transport_wss_ssl = config_setting_get_member(transport_wss, "ssl");
+ if (transport_wss_ssl) {
+ // @todo: SSL stuffs from wss_ssl into config_wss_ssl envelope
+ }
+ }
+ }
+
+
+ // Configuration is valid, now assign it to the variables that are used
+ // If the configuration was invalid, then this does not get changed
+ for (int32_t index = 0; index < endpoints_ipv4_length; ++index)
+ btwss->endpoints_ipv4[index] = endpoints_ipv4[index];
+ for (int32_t index = 0; index < endpoints_ipv6_length; ++index)
+ btwss->endpoints_ipv6[index] = endpoints_ipv6[index];
+ btwss->endpoints_ipv4_length = endpoints_ipv4_length;
+ btwss->endpoints_ipv6_length = endpoints_ipv6_length;
+ btwss->endpoints_backlog = endpoints_backlog;
+ //btwss->ssl = ssl;
+
+ ks_log(KS_LOG_DEBUG, "Configured\n");
+
+ return KS_STATUS_SUCCESS;
+}
+
+
+ks_status_t blade_transport_wss_onstartup(blade_transport_t *bt, config_setting_t *config)
+{
+ blade_transport_wss_t *btwss = NULL;
+
+ ks_assert(bt);
+ ks_assert(config);
+
+ btwss = (blade_transport_wss_t *)blade_transport_data_get(bt);
+
+ if (blade_transport_wss_config(btwss, config) != KS_STATUS_SUCCESS) {
+ ks_log(KS_LOG_DEBUG, "blade_module_wss_config failed\n");
+ return KS_STATUS_FAIL;
+ }
+
+ for (int32_t index = 0; index < btwss->endpoints_ipv4_length; ++index) {
+ if (blade_transport_wss_listen(btwss, &btwss->endpoints_ipv4[index]) != KS_STATUS_SUCCESS) {
+ ks_log(KS_LOG_DEBUG, "blade_transport_wss_listen (v4) failed\n");
+ return KS_STATUS_FAIL;
+ }
+ }
+ for (int32_t index = 0; index < btwss->endpoints_ipv6_length; ++index) {
+ if (blade_transport_wss_listen(btwss, &btwss->endpoints_ipv6[index]) != KS_STATUS_SUCCESS) {
+ ks_log(KS_LOG_DEBUG, "blade_transport_wss_listen (v6) failed\n");
+ return KS_STATUS_FAIL;
+ }
+ }
+
+
+ if (btwss->listeners_count > 0 &&
+ ks_thread_pool_add_job(blade_handle_tpool_get(btwss->handle), blade_transport_wss_listeners_thread, btwss) != KS_STATUS_SUCCESS) {
+ // @todo error logging
+ return KS_STATUS_FAIL;
+ }
+
+ ks_log(KS_LOG_DEBUG, "Started\n");
+
+ return KS_STATUS_SUCCESS;
+}
+
+ks_status_t blade_transport_wss_onshutdown(blade_transport_t *bt)
+{
+ blade_transport_wss_t *btwss = NULL;
+
+ ks_assert(bt);
+
+ btwss = (blade_transport_wss_t *)blade_transport_data_get(bt);
+
+ if (btwss->listeners_count > 0) {
+ btwss->shutdown = KS_TRUE;
+ while (btwss->shutdown) ks_sleep_ms(1);
+ }
+
+ for (int32_t index = 0; index < btwss->listeners_count; ++index) {
+ ks_socket_t sock = btwss->listeners_poll[index].fd;
+ ks_socket_shutdown(sock, SHUT_RDWR);
+ ks_socket_close(&sock);
+ }
+
+ ks_log(KS_LOG_DEBUG, "Stopped\n");
+
+ return KS_STATUS_SUCCESS;
+}
+
+ks_status_t blade_transport_wss_listen(blade_transport_wss_t *btwss, ks_sockaddr_t *addr)
+{
+ ks_socket_t listener = KS_SOCK_INVALID;
+ int32_t listener_index = -1;
+ ks_status_t ret = KS_STATUS_SUCCESS;
+
+ ks_assert(btwss);
+ ks_assert(addr);
+
+ if ((listener = socket(addr->family, SOCK_STREAM, IPPROTO_TCP)) == KS_SOCK_INVALID) {
+ ks_log(KS_LOG_DEBUG, "listener == KS_SOCK_INVALID\n");
+ ret = KS_STATUS_FAIL;
+ goto done;
+ }
+
+ ks_socket_option(listener, SO_REUSEADDR, KS_TRUE);
+ ks_socket_option(listener, TCP_NODELAY, KS_TRUE);
+ if (addr->family == AF_INET6) ks_socket_option(listener, IPV6_V6ONLY, KS_TRUE);
+
+ if (ks_addr_bind(listener, addr) != KS_STATUS_SUCCESS) {
+ ks_log(KS_LOG_DEBUG, "ks_addr_bind(listener, addr) != KS_STATUS_SUCCESS\n");
+ ret = KS_STATUS_FAIL;
+ goto done;
+ }
+
+ if (listen(listener, btwss->endpoints_backlog) != 0) {
+ ks_log(KS_LOG_DEBUG, "listen(listener, backlog) != 0\n");
+ ret = KS_STATUS_FAIL;
+ goto done;
+ }
+
+ listener_index = btwss->listeners_count++;
+ btwss->listeners_poll = (struct pollfd *)ks_pool_resize(btwss->pool,
+ btwss->listeners_poll,
+ sizeof(struct pollfd) * btwss->listeners_count);
+ ks_assert(btwss->listeners_poll);
+ btwss->listeners_poll[listener_index].fd = listener;
+ btwss->listeners_poll[listener_index].events = POLLIN; // | POLLERR;
+
+ ks_log(KS_LOG_DEBUG, "Bound %s on port %d at index %d\n", ks_addr_get_host(addr), ks_addr_get_port(addr), listener_index);
+
+done:
+ if (ret != KS_STATUS_SUCCESS) {
+ if (listener != KS_SOCK_INVALID) {
+ ks_socket_shutdown(listener, SHUT_RDWR);
+ ks_socket_close(&listener);
+ }
+ }
+ return ret;
+}
+
+void *blade_transport_wss_listeners_thread(ks_thread_t *thread, void *data)
+{
+ blade_transport_wss_t *btwss = NULL;
+ blade_transport_wss_link_t *btwssl = NULL;
+ blade_connection_t *bc = NULL;
+
+ ks_assert(thread);
+ ks_assert(data);
+
+ btwss = (blade_transport_wss_t *)data;
+
+ ks_log(KS_LOG_DEBUG, "Started\n");
+ while (!btwss->shutdown) {
+ // @todo take exact timeout from a setting in config_wss_endpoints
+ if (ks_poll(btwss->listeners_poll, btwss->listeners_count, 100) > 0) {
+ for (int32_t index = 0; index < btwss->listeners_count; ++index) {
+ ks_socket_t sock = KS_SOCK_INVALID;
+
+ if (btwss->listeners_poll[index].revents & POLLERR) {
+ // @todo: error handling, just skip the listener for now, it might recover, could skip X times before closing?
+ ks_log(KS_LOG_DEBUG, "POLLERR on index %d\n", index);
+ continue;
+ }
+ if (!(btwss->listeners_poll[index].revents & POLLIN)) continue;
+
+ if ((sock = accept(btwss->listeners_poll[index].fd, NULL, NULL)) == KS_SOCK_INVALID) {
+ // @todo: error handling, just skip the socket for now as most causes are because remote side became unreachable
+ ks_log(KS_LOG_DEBUG, "Accept failed on index %d\n", index);
+ continue;
+ }
+
+ // @todo getsockname and getpeername (getpeername can be skipped if passing to accept instead)
+
+ ks_log(KS_LOG_DEBUG, "Socket accepted\n", index);
+
+ // @todo make new function to wrap the following code all the way through assigning initial state to reuse in outbound connects
+ blade_connection_create(&bc, btwss->handle);
+ ks_assert(bc);
+
+ blade_transport_wss_link_create(&btwssl, blade_connection_pool_get(bc), btwss, sock, NULL);
+ ks_assert(btwssl);
+
+ blade_connection_transport_set(bc, btwssl, btwss->callbacks);
+
+ blade_connection_read_lock(bc, KS_TRUE);
+
+ if (blade_connection_startup(bc, BLADE_CONNECTION_DIRECTION_INBOUND) != KS_STATUS_SUCCESS) {
+ ks_log(KS_LOG_DEBUG, "Connection (%s) startup failed\n", blade_connection_id_get(bc));
+ blade_connection_read_unlock(bc);
+ blade_connection_destroy(&bc);
+ continue;
+ }
+ ks_log(KS_LOG_DEBUG, "Connection (%s) started\n", blade_connection_id_get(bc));
+
+ blade_handle_connections_add(bc);
+
+ blade_connection_state_set(bc, BLADE_CONNECTION_STATE_STARTUP);
+
+ blade_connection_read_unlock(bc);
+ // @todo end of reusable function, lock ensures it cannot be destroyed until this code finishes
+ }
+ }
+ }
+ ks_log(KS_LOG_DEBUG, "Stopped\n");
+
+ btwss->shutdown = KS_FALSE;
+
+ return NULL;
+}
+
+ks_status_t blade_transport_wss_onconnect(blade_connection_t **bcP, blade_transport_t *bt, blade_identity_t *target, const char *session_id)
+{
+ ks_status_t ret = KS_STATUS_SUCCESS;
+ blade_transport_wss_t *btwss = NULL;
+ ks_sockaddr_t addr;
+ ks_socket_t sock = KS_SOCK_INVALID;
+ int family = AF_INET;
+ const char *ip = NULL;
+ const char *portstr = NULL;
+ ks_port_t port = 1234;
+ blade_transport_wss_link_t *btwssl = NULL;
+ blade_connection_t *bc = NULL;
+
+ ks_assert(bcP);
+ ks_assert(bt);
+ ks_assert(target);
+
+ btwss = (blade_transport_wss_t *)blade_transport_data_get(bt);
+
+ *bcP = NULL;
+
+ ks_log(KS_LOG_DEBUG, "Connect Callback: %s\n", blade_identity_uri(target));
+
+ // @todo completely rework all of this once more is known about connecting when an identity has no explicit transport details but this transport
+ // has been choosen anyway
+ ip = blade_identity_parameter_get(target, "host");
+ portstr = blade_identity_parameter_get(target, "port");
+ if (!ip) {
+ // @todo: temporary, this should fall back on DNS SRV or whatever else can turn "a@b.com" into an ip (and port?) to connect to
+ // also need to deal with hostname lookup, so identities with wss transport need to have a host parameter that is an IP for the moment
+ ks_log(KS_LOG_DEBUG, "No host provided\n");
+ ret = KS_STATUS_FAIL;
+ goto done;
+ }
+
+ // @todo wrap this code to get address family from string IP between IPV4 and IPV6, and put it in libks somewhere
+ {
+ ks_size_t len = strlen(ip);
+
+ if (len <= 3) {
+ ks_log(KS_LOG_DEBUG, "Invalid host provided\n");
+ ret = KS_STATUS_FAIL;
+ goto done;
+ }
+ if (ip[1] == '.' || ip[2] == '.' || (len > 3 && ip[3] == '.')) family = AF_INET;
+ else family = AF_INET6;
+ }
+
+ if (portstr) {
+ int p = atoi(portstr);
+ if (p > 0 && p <= UINT16_MAX) port = p;
+ }
+
+ ks_log(KS_LOG_DEBUG, "Connecting to %s on port %d\n", ip, port);
+
+ ks_addr_set(&addr, ip, port, family);
+ if ((sock = ks_socket_connect(SOCK_STREAM, IPPROTO_TCP, &addr)) == KS_SOCK_INVALID) {
+ // @todo: error handling, just fail for now as most causes are because remote side became unreachable
+ ks_log(KS_LOG_DEBUG, "Connect failed\n");
+ ret = KS_STATUS_FAIL;
+ goto done;
+ }
+
+ ks_log(KS_LOG_DEBUG, "Socket connected\n");
+
+ // @todo see above listener code, make reusable function for the following code
+ blade_connection_create(&bc, btwss->handle);
+ ks_assert(bc);
+
+ blade_transport_wss_link_create(&btwssl, blade_connection_pool_get(bc), btwss, sock, session_id);
+ ks_assert(btwssl);
+
+ blade_connection_transport_set(bc, btwssl, btwss->callbacks);
+
+ blade_connection_read_lock(bc, KS_TRUE);
+
+ if (blade_connection_startup(bc, BLADE_CONNECTION_DIRECTION_OUTBOUND) != KS_STATUS_SUCCESS) {
+ ks_log(KS_LOG_DEBUG, "Connection (%s) startup failed\n", blade_connection_id_get(bc));
+ blade_connection_read_unlock(bc);
+ blade_connection_destroy(&bc);
+ ret = KS_STATUS_FAIL;
+ goto done;
+ }
+ ks_log(KS_LOG_DEBUG, "Connection (%s) started\n", blade_connection_id_get(bc));
+
+ blade_handle_connections_add(bc);
+
+ blade_connection_state_set(bc, BLADE_CONNECTION_STATE_STARTUP);
+
+ blade_connection_read_unlock(bc);
+
+ // @todo consider ramification of unlocking above, while returning the new connection object back to the framework, thread might run and disconnect quickly
+ // @todo have blade_handle_connect and blade_transport_wss_on_connect (and the abstracted callback) return a copy of the connection id (allocated from blade_handle_t's pool temporarily) rather than the connection pointer itself
+ // which will then require getting the connection and thus relock it for any further use, if it disconnects during that time the connection will be locked preventing obtaining and then return NULL if removed
+ *bcP = bc;
+
+ done:
+ return ret;
+}
+
+ks_status_t blade_transport_wss_link_write(blade_transport_wss_link_t *btwssl, cJSON *json)
+{
+ ks_status_t ret = KS_STATUS_SUCCESS;
+ char *json_str = NULL;
+ ks_size_t json_str_len = 0;
+
+ ks_assert(btwssl);
+ ks_assert(json);
+
+ json_str = cJSON_PrintUnformatted(json);
+ if (!json_str) {
+ ks_log(KS_LOG_DEBUG, "Failed to generate json string\n");
+ ret = KS_STATUS_FAIL;
+ goto done;
+ }
+ // @todo determine if WSOC_TEXT null terminates when read_frame is called, or if it's safe to include like this
+ json_str_len = strlen(json_str) + 1;
+ if ((ks_size_t)kws_write_frame(btwssl->kws, WSOC_TEXT, json_str, json_str_len) != json_str_len) {
+ ks_log(KS_LOG_DEBUG, "Failed to write frame\n");
+ ret = KS_STATUS_FAIL;
+ goto done;
+ }
+ ks_log(KS_LOG_DEBUG, "Frame written %d bytes\n", json_str_len);
+
+ done:
+ if (json_str) free(json_str);
+
+ return ret;
+}
+
+ks_status_t blade_transport_wss_onsend(blade_connection_t *bc, cJSON *json)
+{
+ blade_transport_wss_link_t *btwssl = NULL;
+
+ ks_assert(bc);
+ ks_assert(json);
+
+ btwssl = (blade_transport_wss_link_t *)blade_connection_transport_get(bc);
+
+ return blade_transport_wss_link_write(btwssl, json);
+}
+
+ks_status_t blade_transport_wss_link_read(blade_transport_wss_link_t *btwssl, cJSON **json)
+{
+ // @todo get exact timeout from service config?
+ int32_t poll_flags = 0;
+
+ ks_assert(btwssl);
+ ks_assert(json);
+
+ poll_flags = ks_wait_sock(btwssl->sock, 1, KS_POLL_READ); // | KS_POLL_ERROR);
+
+ *json = NULL;
+
+ if (poll_flags & KS_POLL_ERROR) {
+ ks_log(KS_LOG_DEBUG, "POLLERR\n");
+ return KS_STATUS_FAIL;
+ }
+ if (poll_flags & KS_POLL_READ) {
+ kws_opcode_t opcode;
+ uint8_t *frame_data = NULL;
+ ks_ssize_t frame_data_len = kws_read_frame(btwssl->kws, &opcode, &frame_data);
+
+ if (frame_data_len <= 0) {
+ // @todo error logging, strerror(ks_errno())
+ // 0 means socket closed with WS_NONE, which closes websocket with no additional reason
+ // -1 means socket closed with a general failure
+ // -2 means nonblocking wait
+ // other values are based on WS_XXX reasons
+ // negative values are based on reasons, except for -1 is but -2 is nonblocking wait, and
+ ks_log(KS_LOG_DEBUG, "Failed to read frame\n");
+ return KS_STATUS_FAIL;
+ }
+ ks_log(KS_LOG_DEBUG, "Frame read %d bytes\n", frame_data_len);
+
+ if (!(*json = cJSON_Parse((char *)frame_data))) {
+ ks_log(KS_LOG_DEBUG, "Failed to parse frame\n");
+ return KS_STATUS_FAIL;
+ }
+ }
+ return KS_STATUS_SUCCESS;
+}
+
+ks_status_t blade_transport_wss_onreceive(blade_connection_t *bc, cJSON **json)
+{
+ blade_transport_wss_link_t *btwssl = NULL;
+
+ ks_assert(bc);
+ ks_assert(json);
+
+ btwssl = (blade_transport_wss_link_t *)blade_connection_transport_get(bc);
+
+ 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 ret = KS_STATUS_SUCCESS;
+ blade_transport_wss_link_t *btwssl = NULL;
+ cJSON *json = NULL;
+
+ ks_assert(bc);
+ //ks_assert(id);
+ ks_assert(message);
+
+ btwssl = (blade_transport_wss_link_t *)blade_connection_transport_get(bc);
+
+ blade_jsonrpc_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");
+ ret = KS_STATUS_FAIL;
+ }
+
+ cJSON_Delete(json);
+ return ret;
+}
+
+
+blade_connection_state_hook_t blade_transport_wss_onstate_startup_inbound(blade_connection_t *bc, blade_connection_state_condition_t condition)
+{
+ blade_connection_state_hook_t ret = BLADE_CONNECTION_STATE_HOOK_SUCCESS;
+ blade_transport_wss_link_t *btwssl = NULL;
+ cJSON *json_req = NULL;
+ cJSON *json_res = NULL;
+ cJSON *json_params = NULL;
+ cJSON *json_result = NULL;
+ cJSON *json_result_identities = NULL;
+ cJSON *json_result_realms = NULL;
+ //cJSON *error = NULL;
+ blade_session_t *bs = NULL;
+ blade_handle_t *bh = NULL;
+ const char *jsonrpc = NULL;
+ const char *id = NULL;
+ const char *method = NULL;
+ const char *sid = NULL;
+ ks_time_t timeout;
+ ks_hash_iterator_t *it = NULL;
+ ks_hash_t *identities = NULL;
+ ks_hash_t *realms = NULL;
+
+ ks_assert(bc);
+
+ bh = blade_connection_handle_get(bc);
+ ks_assert(bh);
+
+ ks_log(KS_LOG_DEBUG, "State Callback: %d\n", (int32_t)condition);
+
+ if (condition == BLADE_CONNECTION_STATE_CONDITION_PRE) return BLADE_CONNECTION_STATE_HOOK_SUCCESS;
+
+ btwssl = (blade_transport_wss_link_t *)blade_connection_transport_get(bc);
+
+ // @todo: SSL init stuffs based on data from config to pass into kws_init
+ if (kws_init(&btwssl->kws, btwssl->sock, NULL, NULL, KWS_BLOCK, btwssl->pool) != KS_STATUS_SUCCESS) {
+ ks_log(KS_LOG_DEBUG, "Failed websocket init\n");
+ ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT;
+ goto done;
+ }
+
+ // @todo very temporary, really need monotonic clock and get timeout delay and sleep delay from config
+ timeout = ks_time_now() + (5 * KS_USEC_PER_SEC);
+ while (blade_transport_wss_link_read(btwssl, &json_req) == KS_STATUS_SUCCESS) {
+ if (json_req) break;
+ ks_sleep_ms(250);
+ if (ks_time_now() >= timeout) break;
+ }
+
+ 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");
+ ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT;
+ goto done;
+ }
+
+ // @todo start here for a reusable handler for "blade.connect" request jsonrpc 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");
+ ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT;
+ goto done;
+ }
+
+ 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");
+ ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT;
+ goto done;
+ }
+
+ 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");
+ ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT;
+ goto done;
+ }
+
+ json_params = cJSON_GetObjectItem(json_req, "params");
+ if (json_params) {
+ sid = cJSON_GetObjectCstr(json_params, "session-id");
+ if (sid) {
+ // @todo validate uuid format by parsing, not currently available in uuid functions, send -32602 (invalid params) if invalid
+ ks_log(KS_LOG_DEBUG, "Session (%s) requested\n", sid);
+ }
+ }
+
+ if (sid) {
+ bs = blade_handle_sessions_lookup(bh, sid); // bs comes out read locked if not null to prevent it being cleaned up before we are done
+ if (bs) {
+ if (blade_session_terminating(bs)) {
+ blade_session_read_unlock(bs);
+ ks_log(KS_LOG_DEBUG, "Session (%s) terminating\n", blade_session_id_get(bs));
+ bs = NULL;
+ } else {
+ ks_log(KS_LOG_DEBUG, "Session (%s) located\n", blade_session_id_get(bs));
+ }
+ }
+ }
+
+ if (!bs) {
+ ks_pool_t *pool = NULL;
+
+ blade_session_create(&bs, bh, NULL);
+ ks_assert(bs);
+
+ sid = blade_session_id_get(bs);
+ ks_log(KS_LOG_DEBUG, "Session (%s) created\n", sid);
+
+ blade_session_read_lock(bs, KS_TRUE); // this will be done by blade_handle_sessions_get() otherwise
+
+ if (blade_session_startup(bs) != KS_STATUS_SUCCESS) {
+ ks_log(KS_LOG_DEBUG, "Session (%s) startup failed\n", sid);
+ blade_transport_wss_jsonrpc_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;
+ goto done;
+ }
+
+ // This is an inbound connection, thus it is always creating a downstream session
+
+ ks_log(KS_LOG_DEBUG, "Session (%s) started\n", sid);
+ blade_handle_sessions_add(bs);
+
+ pool = blade_connection_pool_get(bc);
+
+ // iterate the realms from the handle ultimately provided by the master router node, and obtained when establishing upstream sessions (see outbound handler), for each of
+ // these realms an identity based on the sessionid will be created, in the future this process can be adjusted based on authentication which is currently skipped
+ // so for now if a master node provides more than a single realm, all provided realms will be used in addition to any additionally registered identities or entire subrealms
+ realms = blade_handle_realms_get(bh);
+ ks_hash_read_lock(realms);
+ for (it = ks_hash_first(realms, KS_UNLOCKED); it; it = ks_hash_next(&it)) {
+ void *key = NULL;
+ void *value = NULL;
+ char *identity = NULL;
+
+ ks_hash_this(it, &key, NULL, &value);
+
+ identity = ks_psprintf(pool, "%s@%s", sid, (const char *)key);
+
+ // @note This is where routing gets complicated, lots of stuff has to be tracked for different reasons and different perspectives, and a lot of it is determined and passed during this
+ // initial "blade.connect" message handler. As this is a downstream session connecting inbound, this node is responsible for giving the new node identities to be known by, the realms
+ // which the new node is permitted to register or route additional new identities under, and making sure messages for these new identities can be routed to the correct downstream session
+ // when they arrive on this node, this includes making sure upstream nodes are notified of routing changes.
+
+ // This tracks the identities that are specifically for the remote node of this session NOT including further downstream sessions, the remote node calls blade_handle_identity_register()
+ // when these are given to it, these would also include additional explicitly registered identities via "blade.register", but not those received via "blade.route" for new identities
+ blade_session_identity_add(bs, identity);
+ // This tracks the realms that are permitted for the remote node of this session to register or route new identities, these include realms provided from upstream as implicit initial realms
+ // that this downstream session may register or route additional identities under, the remote node calls blade_handle_realm_register() for these, additional explicit subrealm registrations
+ // from "blade.register" would appear in here as well, and "blade.route" has no impact on these
+ blade_session_realm_add(bs, (const char *)key);
+ // This is primarily to cleanup the routes added to the blade_handle for main routing when a session terminates, these don't have a lot of use otherwise but it will keep the main route table
+ // from having long running write locks when a session cleans up
+ blade_session_route_add(bs, identity);
+ // This is the main routing entry to make an identity routable through a session when a message is received for a given identity in this table, these allow efficiently determine which session
+ // a message should pass through when it does not match the local node identities from blade_handle_identity_register(), and must be matched with a call to blade_session_route_add() for cleanup,
+ // additionally when a "blade.route" is received the identity it carries affects these routes along with the sessionid of the downstream session it came through, and "blade.register" would also
+ // result in the new identities being added as routes however new entire wildcard subrealm registration would require a special process for matching any identities from those subrealms
+ blade_handle_route_add(bh, identity, sid);
+
+ ks_pool_free(pool, &identity);
+ }
+ ks_hash_read_unlock(realms);
+ }
+
+ blade_jsonrpc_response_raw_create(&json_res, &json_result, id);
+ ks_assert(json_res);
+
+ cJSON_AddStringToObject(json_result, "session-id", sid);
+
+ // add the list of actual identities the local node will recognize the remote node, this is the same list that the remote side would be adding to the handle with blade_handle_identity_add()
+ // and may contain additional identities that are explicitly registered by the remote node, this ensures upon reconnect that the same list of identities gets provided to the remote node to refresh
+ // the remote nodes local identities on the edge case that the session times out on the remote end while reconnecting
+
+ json_result_identities = cJSON_CreateArray();
+ cJSON_AddItemToObject(json_result, "identities", json_result_identities);
+
+ identities = blade_session_identities_get(bs);
+ ks_hash_read_lock(identities);
+ for (it = ks_hash_first(identities, KS_UNLOCKED); it; it = ks_hash_next(&it)) {
+ void *key = NULL;
+ void *value = NULL;
+
+ ks_hash_this(it, &key, NULL, &value);
+
+ cJSON_AddItemToArray(json_result_identities, cJSON_CreateString((const char *)key));
+ }
+ ks_hash_read_unlock(identities);
+
+ json_result_realms = cJSON_CreateArray();
+ cJSON_AddItemToObject(json_result, "realms", json_result_realms);
+
+ // add the list of actual realms the local node will permit the remote node to register or route, this is the same list that the remote side would be adding to the handle with blade_handle_realm_add()
+ // and may contain additional subrealms that are explicitly registered by the remote node, this ensures upon reconnect that the same list of realms gets provided to the remote node to refresh
+ // the remote nodes local realms on the edge case that the session times out on the remote end while reconnecting
+
+ realms = blade_session_realms_get(bs);
+ ks_hash_read_lock(realms);
+ for (it = ks_hash_first(realms, KS_UNLOCKED); it; it = ks_hash_next(&it)) {
+ void *key = NULL;
+ void *value = NULL;
+
+ ks_hash_this(it, &key, NULL, &value);
+
+ cJSON_AddItemToArray(json_result_realms, cJSON_CreateString((const char *)key));
+ }
+ ks_hash_read_unlock(realms);
+
+ // This starts the final process for associating the connection to the session, including for reconnecting to an existing session, this simply
+ // associates the session to this connection, upon return the remainder of the association for the session to the connection is handled along
+ // with making sure both this connection and the session state machines are in running states
+ blade_connection_session_set(bc, sid);
+
+ // @todo end of reusable handler for "blade.connect" request
+
+ if (blade_transport_wss_link_write(btwssl, json_res) != KS_STATUS_SUCCESS) {
+ ks_log(KS_LOG_DEBUG, "Failed to write response message\n");
+ ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT;
+ goto done;
+ }
+
+ done:
+ // @note the state machine expects if we return SUCCESS, that the session assigned to the connection will be read locked to ensure that the state
+ // machine can finish attaching the session, if you BYPASS then you can handle everything here in the callback, but this should be fairly standard
+ // behaviour to simply go as far as assigning a session to the connection and let the system handle the rest
+ if (json_req) cJSON_Delete(json_req);
+ if (json_res) cJSON_Delete(json_res);
+
+
+ return ret;
+}
+
+blade_connection_state_hook_t blade_transport_wss_onstate_startup_outbound(blade_connection_t *bc, blade_connection_state_condition_t condition)
+{
+ blade_connection_state_hook_t ret = BLADE_CONNECTION_STATE_HOOK_SUCCESS;
+ blade_handle_t *bh = NULL;
+ blade_transport_wss_link_t *btwssl = NULL;
+ ks_pool_t *pool = NULL;
+ cJSON *json_req = NULL;
+ cJSON *json_params = NULL;
+ cJSON *json_res = NULL;
+ const char *mid = NULL;
+ ks_time_t timeout;
+ const char *jsonrpc = NULL;
+ const char *id = NULL;
+ cJSON *json_error = NULL;
+ cJSON *json_result = NULL;
+ cJSON *json_result_identities = NULL;
+ int json_result_identities_size = 0;
+ cJSON *json_result_realms = NULL;
+ int json_result_realms_size = 0;
+ const char *sid = NULL;
+ blade_session_t *bs = NULL;
+
+ ks_assert(bc);
+
+ ks_log(KS_LOG_DEBUG, "State Callback: %d\n", (int32_t)condition);
+
+ if (condition == BLADE_CONNECTION_STATE_CONDITION_PRE) return BLADE_CONNECTION_STATE_HOOK_SUCCESS;
+
+ bh = blade_connection_handle_get(bc);
+ btwssl = (blade_transport_wss_link_t *)blade_connection_transport_get(bc);
+ pool = blade_handle_pool_get(bh);
+
+ // @todo: SSL init stuffs based on data from config to pass into kws_init
+ if (kws_init(&btwssl->kws, btwssl->sock, NULL, "/blade:blade.invalid:blade", KWS_BLOCK, btwssl->pool) != KS_STATUS_SUCCESS) {
+ ks_log(KS_LOG_DEBUG, "Failed websocket init\n");
+ ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT;
+ goto done;
+ }
+
+ blade_jsonrpc_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);
+
+ ks_log(KS_LOG_DEBUG, "Session (%s) requested\n", (btwssl->session_id ? btwssl->session_id : "none"));
+
+ if (blade_transport_wss_link_write(btwssl, json_req) != KS_STATUS_SUCCESS) {
+ ks_log(KS_LOG_DEBUG, "Failed to write request message\n");
+ ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT;
+ goto done;
+ }
+
+
+ timeout = ks_time_now() + (5 * KS_USEC_PER_SEC);
+ while (blade_transport_wss_link_read(btwssl, &json_res) == KS_STATUS_SUCCESS) {
+ if (json_res) break;
+ ks_sleep_ms(250);
+ if (ks_time_now() >= timeout) break;
+ }
+
+ if (!json_res) {
+ ks_log(KS_LOG_DEBUG, "Failed to receive message before timeout\n");
+ ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT;
+ goto done;
+ }
+
+ // @todo start here for a reusable handler for "blade.connect" response jsonrpc 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")) {
+ ks_log(KS_LOG_DEBUG, "Received message is not the expected protocol\n");
+ ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT;
+ goto done;
+ }
+
+ id = cJSON_GetObjectCstr(json_res, "id"); // @todo switch to number if we are not using a uuid for message id
+ if (!id || strcasecmp(mid, id)) {
+ ks_log(KS_LOG_DEBUG, "Received message has missing or unexpected 'id'\n");
+ ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT;
+ goto done;
+ }
+
+ json_error = cJSON_GetObjectItem(json_res, "error");
+ if (json_error) {
+ ks_log(KS_LOG_DEBUG, "Error message ... add the details\n");
+ ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT;
+ goto done;
+ }
+
+ json_result = cJSON_GetObjectItem(json_res, "result");
+ if (!json_result) {
+ ks_log(KS_LOG_DEBUG, "Received message is missing 'result'\n");
+ ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT;
+ goto done;
+ }
+
+ sid = cJSON_GetObjectCstr(json_result, "session-id");
+ if (!sid) {
+ ks_log(KS_LOG_DEBUG, "Received message 'result' is missing 'session-id'\n");
+ ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT;
+ goto done;
+ }
+
+ json_result_identities = cJSON_GetObjectItem(json_result, "identities");
+ if (!json_result_identities || json_result_identities->type != cJSON_Array || (json_result_identities_size = cJSON_GetArraySize(json_result_identities)) <= 0) {
+ ks_log(KS_LOG_DEBUG, "Received message is missing 'identities'\n");
+ ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT;
+ goto done;
+ }
+
+ json_result_realms = cJSON_GetObjectItem(json_result, "realms");
+ if (!json_result_realms || json_result_realms->type != cJSON_Array || (json_result_realms_size = cJSON_GetArraySize(json_result_realms)) <= 0) {
+ ks_log(KS_LOG_DEBUG, "Received message is missing 'realms'\n");
+ ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT;
+ goto done;
+ }
+
+ if (sid) {
+ // @todo validate uuid format by parsing, not currently available in uuid functions
+ bs = blade_handle_sessions_lookup(bh, sid); // bs comes out read locked if not null to prevent it being cleaned up before we are done
+ if (bs) {
+ ks_log(KS_LOG_DEBUG, "Session (%s) located\n", blade_session_id_get(bs));
+ }
+ }
+
+ if (!bs) {
+ blade_session_create(&bs, bh, sid);
+ ks_assert(bs);
+
+ ks_log(KS_LOG_DEBUG, "Session (%s) created\n", blade_session_id_get(bs));
+
+ blade_session_read_lock(bs, KS_TRUE); // this will be done by blade_handle_sessions_get() otherwise
+
+ if (blade_session_startup(bs) != KS_STATUS_SUCCESS) {
+ ks_log(KS_LOG_DEBUG, "Session (%s) startup failed\n", blade_session_id_get(bs));
+ blade_session_read_unlock(bs);
+ blade_session_destroy(&bs);
+ ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT;
+ goto done;
+ }
+
+ // This is an outbound connection, thus it is always creating an upstream session
+
+ if (blade_handle_upstream_set(bh, sid) != KS_STATUS_SUCCESS) {
+ ks_log(KS_LOG_DEBUG, "Session (%s) abandoned, upstream already available\n", blade_session_id_get(bs));
+ blade_session_read_unlock(bs);
+ blade_session_hangup(bs);
+ ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT;
+ goto done;
+ }
+
+ ks_log(KS_LOG_DEBUG, "Session (%s) started\n", blade_session_id_get(bs));
+
+ blade_handle_sessions_add(bs);
+
+ // new upstream sessions register the realms and local identities based on the realms and identities of the response, however
+ // upstream sessions do not register any routes and thus do not track any routes on the session
+
+ // iterate identities and register to handle as local node identities
+ for (int index = 0; index < json_result_identities_size; ++index) {
+ cJSON *elem = cJSON_GetArrayItem(json_result_identities, index);
+ blade_handle_identity_register(bh, elem->valuestring);
+ }
+
+ // iterate realms and register to handle as permitted realms for future registrations
+ for (int index = 0; index < json_result_realms_size; ++index) {
+ cJSON *elem = cJSON_GetArrayItem(json_result_realms, index);
+ blade_handle_realm_register(bh, elem->valuestring);
+ }
+ }
+
+ blade_connection_session_set(bc, blade_session_id_get(bs));
+
+ // @todo end of reusable handler for "blade.connect" response
+
+ done:
+ if (json_req) cJSON_Delete(json_req);
+ if (json_res) cJSON_Delete(json_res);
+
+ return ret;
+}
+
+blade_connection_state_hook_t blade_transport_wss_onstate_shutdown(blade_connection_t *bc, blade_connection_state_condition_t condition)
+{
+ ks_assert(bc);
+
+ ks_log(KS_LOG_DEBUG, "State Callback: %d\n", (int32_t)condition);
+
+ if (condition == BLADE_CONNECTION_STATE_CONDITION_PRE) return BLADE_CONNECTION_STATE_HOOK_SUCCESS;
+
+ return BLADE_CONNECTION_STATE_HOOK_SUCCESS;
+}
+
+blade_connection_state_hook_t blade_transport_wss_onstate_run_inbound(blade_connection_t *bc, blade_connection_state_condition_t condition)
+{
+ ks_assert(bc);
+
+ if (condition == BLADE_CONNECTION_STATE_CONDITION_PRE) {
+ ks_log(KS_LOG_DEBUG, "State Callback: %d\n", (int32_t)condition);
+ }
+
+ return BLADE_CONNECTION_STATE_HOOK_SUCCESS;
+}
+
+blade_connection_state_hook_t blade_transport_wss_onstate_run_outbound(blade_connection_t *bc, blade_connection_state_condition_t condition)
+{
+ ks_assert(bc);
+
+ if (condition == BLADE_CONNECTION_STATE_CONDITION_PRE) {
+ ks_log(KS_LOG_DEBUG, "State Callback: %d\n", (int32_t)condition);
+ }
+
+ return BLADE_CONNECTION_STATE_HOOK_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/include/blade.h b/libs/libblade/src/include/blade.h
index ce92ad7296..5e6c277abd 100644
--- a/libs/libblade/src/include/blade.h
+++ b/libs/libblade/src/include/blade.h
@@ -34,28 +34,25 @@
#ifndef _BLADE_H_
#define _BLADE_H_
#include
-#include
#include
#include
#include "unqlite.h"
#include "blade_types.h"
#include "blade_stack.h"
#include "blade_identity.h"
-#include "blade_module.h"
+#include "blade_transport.h"
+#include "blade_jsonrpc.h"
#include "blade_connection.h"
#include "blade_session.h"
-#include "blade_protocol.h"
-#include "blade_datastore.h"
-#include "blade_space.h"
-#include "blade_method.h"
#include "ks_dht.h"
#include "ks_bencode.h"
-#include "blade_module_wss.h"
+#include "blade_transport_wss.h"
KS_BEGIN_EXTERN_C
#ifdef _WIN32
+// @todo look into why the tarball build has a different function name from the debian package
#define config_lookup_from config_setting_lookup
#endif
diff --git a/libs/libblade/src/include/blade_connection.h b/libs/libblade/src/include/blade_connection.h
index c2643a7783..f7a0225f59 100644
--- a/libs/libblade/src/include/blade_connection.h
+++ b/libs/libblade/src/include/blade_connection.h
@@ -52,7 +52,6 @@ KS_DECLARE(void) blade_connection_transport_set(blade_connection_t *bc, void *tr
KS_DECLARE(void) blade_connection_state_set(blade_connection_t *bc, blade_connection_state_t state);
KS_DECLARE(blade_connection_state_t) blade_connection_state_get(blade_connection_t *bc);
KS_DECLARE(void) blade_connection_disconnect(blade_connection_t *bc);
-KS_DECLARE(blade_connection_rank_t) blade_connection_rank(blade_connection_t *bc, blade_identity_t *target);
KS_DECLARE(ks_status_t) blade_connection_sending_push(blade_connection_t *bc, cJSON *json);
KS_DECLARE(ks_status_t) blade_connection_sending_pop(blade_connection_t *bc, cJSON **json);
KS_DECLARE(const char *) blade_connection_session_get(blade_connection_t *bc);
diff --git a/libs/libblade/src/include/blade_datastore.h b/libs/libblade/src/include/blade_datastore.h
deleted file mode 100644
index b42ce736ee..0000000000
--- a/libs/libblade/src/include/blade_datastore.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (c) 2007-2014, Anthony Minessale II
- * 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_DATASTORE_H_
-#define _BLADE_DATASTORE_H_
-#include
-
-KS_BEGIN_EXTERN_C
-KS_DECLARE(ks_status_t) blade_datastore_create(blade_datastore_t **bdsP, ks_pool_t *pool, ks_thread_pool_t *tpool);
-KS_DECLARE(ks_status_t) blade_datastore_destroy(blade_datastore_t **bdsP);
-KS_DECLARE(ks_status_t) blade_datastore_startup(blade_datastore_t *bds, config_setting_t *config);
-KS_DECLARE(ks_status_t) blade_datastore_shutdown(blade_datastore_t *bds);
-
-KS_DECLARE(void) blade_datastore_error(blade_datastore_t *bds, const char **buffer, int32_t *buffer_length);
-KS_DECLARE(ks_status_t) blade_datastore_store(blade_datastore_t *bds, const void *key, int32_t key_length, const void *data, int64_t data_length);
-KS_DECLARE(ks_status_t) blade_datastore_fetch(blade_datastore_t *bds,
- blade_datastore_fetch_callback_t callback,
- const void *key,
- int32_t key_length,
- void *userdata);
-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_jsonrpc.h b/libs/libblade/src/include/blade_jsonrpc.h
new file mode 100644
index 0000000000..7ad66ea82c
--- /dev/null
+++ b/libs/libblade/src/include/blade_jsonrpc.h
@@ -0,0 +1,80 @@
+/*
+ * 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_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(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_method.h b/libs/libblade/src/include/blade_module_master.h
similarity index 84%
rename from libs/libblade/src/include/blade_method.h
rename to libs/libblade/src/include/blade_module_master.h
index f2ab8ab548..ea896f270b 100644
--- a/libs/libblade/src/include/blade_method.h
+++ b/libs/libblade/src/include/blade_module_master.h
@@ -31,14 +31,17 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef _BLADE_METHOD_H_
-#define _BLADE_METHOD_H_
+#ifndef _BLADE_MODULE_MASTER_H_
+#define _BLADE_MODULE_MASTER_H_
#include
KS_BEGIN_EXTERN_C
-KS_DECLARE(ks_status_t) blade_method_create(blade_method_t **bmP, blade_space_t *bs, const char *name, blade_request_callback_t callback);
-KS_DECLARE(const char *) blade_method_name_get(blade_method_t *bm);
-KS_DECLARE(blade_request_callback_t) blade_method_callback_get(blade_method_t *bm);
+
+KS_DECLARE(ks_status_t) blade_module_master_create(blade_module_t **bmP, blade_handle_t *bh);
+
+KS_DECLARE(ks_status_t) blade_module_master_on_startup(blade_module_t *bm, config_setting_t *config);
+KS_DECLARE(ks_status_t) blade_module_master_on_shutdown(blade_module_t *bm);
+
KS_END_EXTERN_C
#endif
diff --git a/libs/libblade/src/include/blade_protocol.h b/libs/libblade/src/include/blade_protocol.h
deleted file mode 100644
index 29c8814d38..0000000000
--- a/libs/libblade/src/include/blade_protocol.h
+++ /dev/null
@@ -1,67 +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_PROTOCOL_H_
-#define _BLADE_PROTOCOL_H_
-#include
-
-KS_BEGIN_EXTERN_C
-KS_DECLARE(ks_status_t) blade_request_create(blade_request_t **breqP,
- blade_handle_t *bh,
- ks_pool_t *pool,
- const char *session_id,
- cJSON *json,
- blade_response_callback_t callback);
-KS_DECLARE(ks_status_t) blade_request_destroy(blade_request_t **breqP);
-KS_DECLARE(ks_status_t) blade_response_create(blade_response_t **bresP, blade_handle_t *bh, ks_pool_t *pool, const char *session_id, blade_request_t *breq, cJSON *json);
-KS_DECLARE(ks_status_t) blade_response_destroy(blade_response_t **bresP);
-KS_DECLARE(ks_status_t) blade_event_create(blade_event_t **bevP, blade_handle_t *bh, ks_pool_t *pool, const char *session_id, cJSON *json);
-KS_DECLARE(ks_status_t) blade_event_destroy(blade_event_t **bevP);
-KS_DECLARE(ks_status_t) blade_rpc_request_create(ks_pool_t *pool, cJSON **json, cJSON **params, const char **id, const char *method);
-KS_DECLARE(ks_status_t) blade_rpc_response_create(cJSON **json, cJSON **result, const char *id);
-KS_DECLARE(ks_status_t) blade_rpc_error_create(cJSON **json, cJSON **error, const char *id, int32_t code, const char *message);
-KS_DECLARE(ks_status_t) blade_rpc_event_create(cJSON **json, cJSON **result, const char *event);
-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 bfb3967b95..fc69be7196 100644
--- a/libs/libblade/src/include/blade_session.h
+++ b/libs/libblade/src/include/blade_session.h
@@ -36,13 +36,21 @@
#include
KS_BEGIN_EXTERN_C
-KS_DECLARE(ks_status_t) blade_session_create(blade_session_t **bsP, blade_handle_t *bh, const char *sid);
+KS_DECLARE(ks_status_t) blade_session_create(blade_session_t **bsP, blade_handle_t *bh, const char *id);
KS_DECLARE(ks_status_t) blade_session_destroy(blade_session_t **bsP);
KS_DECLARE(ks_status_t) blade_session_startup(blade_session_t *bs);
KS_DECLARE(ks_status_t) blade_session_shutdown(blade_session_t *bs);
KS_DECLARE(blade_handle_t *) blade_session_handle_get(blade_session_t *bs);
KS_DECLARE(const char *) blade_session_id_get(blade_session_t *bs);
KS_DECLARE(blade_session_state_t) blade_session_state_get(blade_session_t *bs);
+KS_DECLARE(ks_status_t) blade_session_identity_add(blade_session_t *bs, const char *identity);
+KS_DECLARE(ks_status_t) blade_session_identity_remove(blade_session_t *bs, const char *identity);
+KS_DECLARE(ks_hash_t *) blade_session_identities_get(blade_session_t *bs);
+KS_DECLARE(ks_status_t) blade_session_realm_add(blade_session_t *bs, const char *realm);
+KS_DECLARE(ks_status_t) blade_session_realm_remove(blade_session_t *bs, const char *realm);
+KS_DECLARE(ks_hash_t *) blade_session_realms_get(blade_session_t *bs);
+KS_DECLARE(ks_status_t) blade_session_route_add(blade_session_t *bs, const char *identity);
+KS_DECLARE(ks_status_t) blade_session_route_remove(blade_session_t *bs, const char *identity);
KS_DECLARE(cJSON *) blade_session_properties_get(blade_session_t *bs);
KS_DECLARE(ks_status_t) blade_session_read_lock(blade_session_t *bs, ks_bool_t block);
KS_DECLARE(ks_status_t) blade_session_read_unlock(blade_session_t *bs);
@@ -55,9 +63,9 @@ KS_DECLARE(ks_status_t) blade_session_properties_write_unlock(blade_session_t *b
KS_DECLARE(void) blade_session_state_set(blade_session_t *bs, blade_session_state_t state);
KS_DECLARE(void) blade_session_hangup(blade_session_t *bs);
KS_DECLARE(ks_bool_t) blade_session_terminating(blade_session_t *bs);
-KS_DECLARE(ks_status_t) blade_session_connections_add(blade_session_t *bs, const char *id);
-KS_DECLARE(ks_status_t) blade_session_connections_remove(blade_session_t *bs, const char *id);
-KS_DECLARE(ks_status_t) blade_session_send(blade_session_t *bs, cJSON *json, blade_response_callback_t callback);
+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_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_space.h b/libs/libblade/src/include/blade_space.h
deleted file mode 100644
index 0165a3fa68..0000000000
--- a/libs/libblade/src/include/blade_space.h
+++ /dev/null
@@ -1,60 +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_SPACE_H_
-#define _BLADE_SPACE_H_
-#include
-
-KS_BEGIN_EXTERN_C
-KS_DECLARE(ks_status_t) blade_space_create(blade_space_t **bsP, blade_handle_t *bh, blade_module_t *bm, const char *path);
-KS_DECLARE(blade_handle_t *) blade_space_handle_get(blade_space_t *bs);
-KS_DECLARE(ks_pool_t *) blade_space_pool_get(blade_space_t *bs);
-KS_DECLARE(blade_module_t *) blade_space_module_get(blade_space_t *bs);
-KS_DECLARE(const char *) blade_space_path_get(blade_space_t *bs);
-KS_DECLARE(ks_status_t) blade_space_methods_add(blade_space_t *bs, blade_method_t *bm);
-KS_DECLARE(ks_status_t) blade_space_methods_remove(blade_space_t *bs, blade_method_t *bm);
-KS_DECLARE(blade_method_t *) blade_space_methods_get(blade_space_t *bs, const char *name);
-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_stack.h b/libs/libblade/src/include/blade_stack.h
index e8c10fbc84..2d25970f93 100644
--- a/libs/libblade/src/include/blade_stack.h
+++ b/libs/libblade/src/include/blade_stack.h
@@ -48,45 +48,46 @@ KS_DECLARE(ks_status_t) blade_handle_shutdown(blade_handle_t *bh);
KS_DECLARE(ks_pool_t *) blade_handle_pool_get(blade_handle_t *bh);
KS_DECLARE(ks_thread_pool_t *) blade_handle_tpool_get(blade_handle_t *bh);
-KS_DECLARE(ks_status_t) blade_handle_module_register(blade_module_t *bm);
-//KS_DECLARE(ks_status_t) blade_handle_module_unregister(blade_module_t *bm);
+KS_DECLARE(ks_status_t) blade_handle_identity_register(blade_handle_t *bh, const char *identity);
+KS_DECLARE(ks_status_t) blade_handle_identity_unregister(blade_handle_t *bh, const char *identity);
-KS_DECLARE(ks_status_t) blade_handle_transport_register(blade_handle_t *bh, blade_module_t *bm, const char *name, blade_transport_callbacks_t *callbacks);
-KS_DECLARE(ks_status_t) blade_handle_transport_unregister(blade_handle_t *bh, const char *name);
+KS_DECLARE(ks_status_t) blade_handle_realm_register(blade_handle_t *bh, const char *realm);
+KS_DECLARE(ks_status_t) blade_handle_realm_unregister(blade_handle_t *bh, const char *realm);
+KS_DECLARE(ks_hash_t *) blade_handle_realms_get(blade_handle_t *bh);
-KS_DECLARE(ks_status_t) blade_handle_space_register(blade_space_t *bs);
-KS_DECLARE(ks_status_t) blade_handle_space_unregister(blade_space_t *bs);
-KS_DECLARE(blade_space_t *) blade_handle_space_lookup(blade_handle_t *bh, const char *path);
+KS_DECLARE(ks_status_t) blade_handle_route_add(blade_handle_t *bh, const char *identity, const char *id);
+KS_DECLARE(ks_status_t) blade_handle_route_remove(blade_handle_t *bh, const char *identity);
+KS_DECLARE(blade_session_t *) blade_handle_route_lookup(blade_handle_t *bh, const char *identity);
+
+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_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_event_register(blade_handle_t *bh, const char *event, blade_event_callback_t callback);
-KS_DECLARE(ks_status_t) blade_handle_event_unregister(blade_handle_t *bh, const char *event);
-KS_DECLARE(blade_event_callback_t) blade_handle_event_lookup(blade_handle_t *bh, const char *event);
KS_DECLARE(ks_status_t) blade_handle_connect(blade_handle_t *bh, blade_connection_t **bcP, blade_identity_t *target, const char *session_id);
-KS_DECLARE(blade_connection_t *) blade_handle_connections_get(blade_handle_t *bh, const char *cid);
KS_DECLARE(ks_status_t) blade_handle_connections_add(blade_connection_t *bc);
KS_DECLARE(ks_status_t) blade_handle_connections_remove(blade_connection_t *bc);
+KS_DECLARE(blade_connection_t *) blade_handle_connections_lookup(blade_handle_t *bh, const char *id);
-KS_DECLARE(blade_session_t *) blade_handle_sessions_get(blade_handle_t *bh, const char *sid);
KS_DECLARE(ks_status_t) blade_handle_sessions_add(blade_session_t *bs);
KS_DECLARE(ks_status_t) blade_handle_sessions_remove(blade_session_t *bs);
+KS_DECLARE(blade_session_t *) blade_handle_sessions_lookup(blade_handle_t *bh, const char *id);
+
+KS_DECLARE(ks_status_t) blade_handle_upstream_set(blade_handle_t *bh, const char *id);
+
KS_DECLARE(void) blade_handle_sessions_send(blade_handle_t *bh, ks_list_t *sessions, const char *exclude, cJSON *json);
KS_DECLARE(ks_status_t) blade_handle_session_state_callback_register(blade_handle_t *bh, void *data, blade_session_state_callback_t callback, const char **id);
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(blade_request_t *) blade_handle_requests_get(blade_handle_t *bh, const char *mid);
-KS_DECLARE(ks_status_t) blade_handle_requests_add(blade_request_t *br);
-KS_DECLARE(ks_status_t) blade_handle_requests_remove(blade_request_t *br);
-
-KS_DECLARE(ks_bool_t) blade_handle_datastore_available(blade_handle_t *bh);
-KS_DECLARE(ks_status_t) blade_handle_datastore_store(blade_handle_t *bh, const void *key, int32_t key_length, const void *data, int64_t data_length);
-KS_DECLARE(ks_status_t) blade_handle_datastore_fetch(blade_handle_t *bh,
- blade_datastore_fetch_callback_t callback,
- const void *key,
- int32_t key_length,
- void *userdata);
KS_END_EXTERN_C
#endif
diff --git a/libs/libblade/src/include/blade_module.h b/libs/libblade/src/include/blade_transport.h
similarity index 73%
rename from libs/libblade/src/include/blade_module.h
rename to libs/libblade/src/include/blade_transport.h
index 20f905b7ea..7b90202ca0 100644
--- a/libs/libblade/src/include/blade_module.h
+++ b/libs/libblade/src/include/blade_transport.h
@@ -1,23 +1,23 @@
/*
* 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
@@ -31,20 +31,17 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef _BLADE_MODULE_H_
-#define _BLADE_MODULE_H_
+#ifndef _BLADE_TRANSPORT_H_
+#define _BLADE_TRANSPORT_H_
#include
KS_BEGIN_EXTERN_C
-
-KS_DECLARE(ks_status_t) blade_module_create(blade_module_t **bmP, blade_handle_t *bh, ks_pool_t *pool, void *module_data, blade_module_callbacks_t *module_callbacks);
-KS_DECLARE(ks_status_t) blade_module_destroy(blade_module_t **bmP);
-KS_DECLARE(blade_handle_t *) blade_module_handle_get(blade_module_t *bm);
-KS_DECLARE(ks_pool_t *) blade_module_pool_get(blade_module_t *bm);
-KS_DECLARE(const char *) blade_module_id_get(blade_module_t *bm);
-KS_DECLARE(void *) blade_module_data_get(blade_module_t *bm);
-KS_DECLARE(blade_module_callbacks_t *) blade_module_callbacks_get(blade_module_t *bm);
-
+KS_DECLARE(ks_status_t) blade_transport_create(blade_transport_t **btP, blade_handle_t *bh, ks_pool_t *pool, const char *name, void *data, blade_transport_callbacks_t *callbacks);
+KS_DECLARE(ks_status_t) blade_transport_destroy(blade_transport_t **btP);
+KS_DECLARE(blade_handle_t *) blade_transport_handle_get(blade_transport_t *bt);
+KS_DECLARE(const char *) blade_transport_name_get(blade_transport_t *bt);
+KS_DECLARE(void *) blade_transport_data_get(blade_transport_t *bt);
+KS_DECLARE(blade_transport_callbacks_t *) blade_transport_callbacks_get(blade_transport_t *bt);
KS_END_EXTERN_C
#endif
diff --git a/libs/libblade/src/include/blade_module_wss.h b/libs/libblade/src/include/blade_transport_wss.h
similarity index 87%
rename from libs/libblade/src/include/blade_module_wss.h
rename to libs/libblade/src/include/blade_transport_wss.h
index fba23a5964..624d706b80 100644
--- a/libs/libblade/src/include/blade_module_wss.h
+++ b/libs/libblade/src/include/blade_transport_wss.h
@@ -37,10 +37,7 @@
KS_BEGIN_EXTERN_C
-KS_DECLARE(ks_status_t) blade_module_wss_create(blade_module_t **bmP, blade_handle_t *bh);
-
-KS_DECLARE(ks_status_t) blade_module_wss_on_startup(blade_module_t *bm, config_setting_t *config);
-KS_DECLARE(ks_status_t) blade_module_wss_on_shutdown(blade_module_t *bm);
+KS_DECLARE(ks_status_t) blade_transport_wss_create(blade_transport_t **btP, blade_handle_t *bh);
KS_END_EXTERN_C
diff --git a/libs/libblade/src/include/blade_types.h b/libs/libblade/src/include/blade_types.h
index 0146a9aa5e..5e10b28ade 100644
--- a/libs/libblade/src/include/blade_types.h
+++ b/libs/libblade/src/include/blade_types.h
@@ -40,25 +40,22 @@ KS_BEGIN_EXTERN_C
typedef struct blade_handle_s blade_handle_t;
typedef struct blade_identity_s blade_identity_t;
-typedef struct blade_module_s blade_module_t;
-typedef struct blade_module_callbacks_s blade_module_callbacks_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_session_callbacks_s blade_session_callbacks_t;
typedef struct blade_connection_s blade_connection_t;
typedef struct blade_session_s blade_session_t;
-typedef struct blade_request_s blade_request_t;
-typedef struct blade_response_s blade_response_t;
-typedef struct blade_event_s blade_event_t;
-typedef struct blade_space_s blade_space_t;
-typedef struct blade_method_s blade_method_t;
+typedef struct blade_application_s blade_application_t;
typedef struct blade_datastore_s blade_datastore_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_request_callback_t)(blade_module_t *bm, blade_request_t *breq);
-typedef ks_bool_t (*blade_response_callback_t)(blade_response_t *bres);
-typedef ks_bool_t (*blade_event_callback_t)(blade_event_t *bev);
typedef ks_bool_t (*blade_datastore_fetch_callback_t)(blade_datastore_t *bds, const void *data, uint32_t data_length, void *userdata);
@@ -66,12 +63,9 @@ typedef ks_bool_t (*blade_datastore_fetch_callback_t)(blade_datastore_t *bds, co
typedef enum {
BLADE_CONNECTION_STATE_NONE,
BLADE_CONNECTION_STATE_CLEANUP,
- BLADE_CONNECTION_STATE_DISCONNECT,
- BLADE_CONNECTION_STATE_NEW,
- BLADE_CONNECTION_STATE_CONNECT,
- BLADE_CONNECTION_STATE_ATTACH,
- BLADE_CONNECTION_STATE_DETACH,
- BLADE_CONNECTION_STATE_READY,
+ BLADE_CONNECTION_STATE_STARTUP,
+ BLADE_CONNECTION_STATE_SHUTDOWN,
+ BLADE_CONNECTION_STATE_RUN,
} blade_connection_state_t;
typedef enum {
@@ -90,13 +84,6 @@ typedef enum {
BLADE_CONNECTION_STATE_HOOK_BYPASS,
} blade_connection_state_hook_t;
-typedef enum {
- BLADE_CONNECTION_RANK_POOR,
- BLADE_CONNECTION_RANK_AVERAGE,
- BLADE_CONNECTION_RANK_GOOD,
- BLADE_CONNECTION_RANK_GREAT,
-} blade_connection_rank_t;
-
typedef enum {
BLADE_SESSION_STATE_CONDITION_PRE,
@@ -106,83 +93,41 @@ typedef enum {
typedef enum {
BLADE_SESSION_STATE_NONE,
BLADE_SESSION_STATE_CLEANUP,
- BLADE_SESSION_STATE_DESTROY,
- BLADE_SESSION_STATE_HANGUP,
- BLADE_SESSION_STATE_CONNECT,
- BLADE_SESSION_STATE_ATTACH,
- BLADE_SESSION_STATE_DETACH,
- BLADE_SESSION_STATE_READY,
+ BLADE_SESSION_STATE_STARTUP,
+ BLADE_SESSION_STATE_SHUTDOWN,
+ BLADE_SESSION_STATE_RUN,
} blade_session_state_t;
-typedef ks_status_t (*blade_module_startup_callback_t)(blade_module_t *bm, config_setting_t *config);
-typedef ks_status_t(*blade_module_shutdown_callback_t)(blade_module_t *bm);
-struct blade_module_callbacks_s {
- blade_module_startup_callback_t onstartup;
- blade_module_shutdown_callback_t onshutdown;
-};
-
-
-typedef ks_status_t (*blade_transport_connect_callback_t)(blade_connection_t **bcP, blade_module_t *bm, blade_identity_t *target, const char *session_id);
-typedef blade_connection_rank_t (*blade_transport_rank_callback_t)(blade_connection_t *bc, blade_identity_t *target);
+typedef ks_status_t (*blade_transport_startup_callback_t)(blade_transport_t *bt, config_setting_t *config);
+typedef ks_status_t (*blade_transport_shutdown_callback_t)(blade_transport_t *bt);
+typedef ks_status_t (*blade_transport_connect_callback_t)(blade_connection_t **bcP, blade_transport_t *bt, blade_identity_t *target, const char *session_id);
typedef ks_status_t (*blade_transport_send_callback_t)(blade_connection_t *bc, cJSON *json);
typedef ks_status_t (*blade_transport_receive_callback_t)(blade_connection_t *bc, cJSON **json);
typedef blade_connection_state_hook_t (*blade_transport_state_callback_t)(blade_connection_t *bc, blade_connection_state_condition_t condition);
struct blade_transport_callbacks_s {
+ blade_transport_startup_callback_t onstartup;
+ blade_transport_shutdown_callback_t onshutdown;
+
blade_transport_connect_callback_t onconnect;
- blade_transport_rank_callback_t onrank;
+
blade_transport_send_callback_t onsend;
blade_transport_receive_callback_t onreceive;
- blade_transport_state_callback_t onstate_disconnect_inbound;
- blade_transport_state_callback_t onstate_disconnect_outbound;
- blade_transport_state_callback_t onstate_new_inbound;
- blade_transport_state_callback_t onstate_new_outbound;
- blade_transport_state_callback_t onstate_connect_inbound;
- blade_transport_state_callback_t onstate_connect_outbound;
- blade_transport_state_callback_t onstate_attach_inbound;
- blade_transport_state_callback_t onstate_attach_outbound;
- blade_transport_state_callback_t onstate_detach_inbound;
- blade_transport_state_callback_t onstate_detach_outbound;
- blade_transport_state_callback_t onstate_ready_inbound;
- blade_transport_state_callback_t onstate_ready_outbound;
+ blade_transport_state_callback_t onstate_startup_inbound;
+ blade_transport_state_callback_t onstate_startup_outbound;
+ blade_transport_state_callback_t onstate_shutdown_inbound;
+ blade_transport_state_callback_t onstate_shutdown_outbound;
+ blade_transport_state_callback_t onstate_run_inbound;
+ blade_transport_state_callback_t onstate_run_outbound;
};
typedef void (*blade_session_state_callback_t)(blade_session_t *bs, blade_session_state_condition_t condition, void *data);
-struct blade_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_response_callback_t callback;
- // @todo ttl to wait for response before injecting an error response locally
- // @todo rpc response callback
-};
-
-struct blade_response_s {
- blade_handle_t *handle;
- ks_pool_t *pool;
- const char *session_id;
- blade_request_t *request;
-
- cJSON *message;
-};
-
-struct blade_event_s {
- blade_handle_t *handle;
- ks_pool_t *pool;
- const char *session_id;
-
- cJSON *message;
-};
-
KS_END_EXTERN_C
#endif
diff --git a/libs/libblade/switchblade/Makefile.am b/libs/libblade/switchblade/Makefile.am
new file mode 100644
index 0000000000..70742bc69d
--- /dev/null
+++ b/libs/libblade/switchblade/Makefile.am
@@ -0,0 +1,5 @@
+switchblade_SOURCES = switchblade.c
+switchblade_CFLAGS = $(AM_CFLAGS) -I$(abs_top_srcdir)/src/include -g -ggdb -O0
+switchblade_LDADD = $(abs_top_builddir)/libblade.la -lconfig -lm -lpthread
+
+all: switchblade
diff --git a/libs/libblade/switchblade/switchblade.c b/libs/libblade/switchblade/switchblade.c
new file mode 100644
index 0000000000..6fee65bbfd
--- /dev/null
+++ b/libs/libblade/switchblade/switchblade.c
@@ -0,0 +1,73 @@
+#include "blade.h"
+
+// @todo switch to wait condition once something is being done with the main thread during runtime
+ks_bool_t g_shutdown = KS_FALSE;
+
+void idle(blade_handle_t *bh);
+
+int main(int argc, char **argv)
+{
+ blade_handle_t *bh = NULL;
+ config_t config;
+ config_setting_t *config_blade = NULL;
+ const char *cfgpath = "switchblade.cfg";
+
+ ks_global_set_default_logger(KS_LOG_LEVEL_DEBUG);
+
+ blade_init();
+
+ blade_handle_create(&bh);
+
+ config_init(&config);
+ if (!config_read_file(&config, cfgpath)) {
+ ks_log(KS_LOG_ERROR, "%s:%d - %s\n", config_error_file(&config), config_error_line(&config), config_error_text(&config));
+ config_destroy(&config);
+ return EXIT_FAILURE;
+ }
+ config_blade = config_lookup(&config, "blade");
+ if (!config_blade) {
+ ks_log(KS_LOG_ERROR, "Missing 'blade' config group\n");
+ config_destroy(&config);
+ return EXIT_FAILURE;
+ }
+ if (config_setting_type(config_blade) != CONFIG_TYPE_GROUP) {
+ ks_log(KS_LOG_ERROR, "The 'blade' config setting is not a group\n");
+ return EXIT_FAILURE;
+ }
+
+ if (blade_handle_startup(bh, config_blade) != KS_STATUS_SUCCESS) {
+ ks_log(KS_LOG_ERROR, "Blade startup failed\n");
+ return EXIT_FAILURE;
+ }
+
+ // @todo portable process signal handler (SIGINT, SIGHUP, etc)
+
+ idle(bh);
+
+ blade_handle_destroy(&bh);
+
+ config_destroy(&config);
+
+ blade_shutdown();
+
+ return 0;
+}
+
+void idle(blade_handle_t *bh)
+{
+ while (!g_shutdown) {
+ ks_sleep_ms(1000);
+ }
+}
+
+
+/* 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/switchblade/switchblade.cfg b/libs/libblade/switchblade/switchblade.cfg
new file mode 100644
index 0000000000..583c39da8d
--- /dev/null
+++ b/libs/libblade/switchblade/switchblade.cfg
@@ -0,0 +1,18 @@
+blade:
+{
+ identity = "master1@yourdomain.com";
+ wss:
+ {
+ endpoints:
+ {
+ ipv4 = ( { address = "0.0.0.0", port = 2100 } );
+ ipv6 = ( { address = "::", port = 2100 } );
+ backlog = 128;
+ };
+ # SSL group is optional, disabled when absent
+ ssl:
+ {
+ # todo: server SSL stuffs here
+ };
+ };
+};
diff --git a/libs/libblade/switchblade/switchblade.vcxproj b/libs/libblade/switchblade/switchblade.vcxproj
new file mode 100644
index 0000000000..63dde1a502
--- /dev/null
+++ b/libs/libblade/switchblade/switchblade.vcxproj
@@ -0,0 +1,214 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ {8330E669-77F3-4F70-A275-6F7BABE050A7}
+ Win32Proj
+ switchblade
+ 8.1
+
+
+
+ Application
+ true
+ v140
+ Unicode
+
+
+ Application
+ false
+ v140
+ true
+ Unicode
+
+
+ Application
+ true
+ v140
+ Unicode
+
+
+ Application
+ false
+ v140
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(Platform)\$(Configuration)\$(ProjectName)\
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(SolutionDir);$(SolutionDir)..\libks\src\include;$(SolutionDir)..\libsodium-$(SodiumVersion)\src\libsodium\include;$(SolutionDir)..\libconfig-$(ConfigVersion)\lib;$(SolutionDir)\openssl\include;$(IncludePath)
+ $(LibraryPath)
+
+
+ true
+ $(Platform)\$(Configuration)\$(ProjectName)\
+ $(SolutionDir);$(SolutionDir)..\libks\src\include;$(SolutionDir)..\libsodium-$(SodiumVersion)\src\libsodium\include;$(SolutionDir)..\libconfig-$(ConfigVersion)\lib;$(SolutionDir)\openssl\include64;$(IncludePath)
+ $(LibraryPath)
+
+
+ false
+ $(Platform)\$(Configuration)\$(ProjectName)\
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(SolutionDir);$(SolutionDir)..\libks\src\include;$(SolutionDir)..\libsodium-$(SodiumVersion)\src\libsodium\include;$(SolutionDir)..\libconfig-$(ConfigVersion)\lib;$(SolutionDir)\openssl\include;$(IncludePath)
+ $(LibraryPath)
+
+
+ false
+ $(Platform)\$(Configuration)\$(ProjectName)\
+ $(SolutionDir);$(SolutionDir)..\libks\src\include;$(SolutionDir)..\libsodium-$(SodiumVersion)\src\libsodium\include;$(SolutionDir)..\libconfig-$(ConfigVersion)\lib;$(SolutionDir)\openssl\include64;$(IncludePath)
+ $(LibraryPath)
+
+
+
+
+
+ Level3
+ Disabled
+ _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ $(SolutionDir)..\win32\openssl\include;$(SolutionDir)..\win32\openssl\include_x86;../src/include;.
+ 4090
+ true
+ false
+
+
+ Console
+ true
+
+
+
+
+
+
+ Level3
+ Disabled
+ _CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ $(SolutionDir)..\win32\openssl\include;$(SolutionDir)..\win32\openssl\include_x64;../src/include;.
+ 4090
+ true
+ false
+
+
+ Console
+ true
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ $(SolutionDir)..\win32\openssl\include;$(SolutionDir)..\win32\openssl\include_x86;../src/include;.
+ 4090
+ true
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ _CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ $(SolutionDir)..\win32\openssl\include;$(SolutionDir)..\win32\openssl\include_x64;../src/include;.
+ 4090
+ true
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+
+
+
+ {70d178d8-1100-4152-86c0-809a91cff832}
+
+
+ {1a234565-926d-49b2-83e4-d56e0c38c9f2}
+
+
+ {a185b162-6cb6-4502-b03f-b56f7699a8d9}
+
+
+ {d331904d-a00a-4694-a5a3-fcff64ab5dbe}
+
+
+ {b4b62169-5ad4-4559-8707-3d933ac5db39}
+
+
+ {a89d6d18-6203-4149-9051-f8e798e7a3e7}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/libs/libblade/test/bladec.c b/libs/libblade/test/bladec.c
index 831eaced4d..dc5fb8949f 100644
--- a/libs/libblade/test/bladec.c
+++ b/libs/libblade/test/bladec.c
@@ -17,19 +17,19 @@ 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_chat(blade_handle_t *bh, char *args);
static const struct command_def_s command_defs[] = {
{ "quit", command_quit },
{ "connect", command_connect },
- { "chat", command_chat },
+// { "chat", command_chat },
{ 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 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);
int main(int argc, char **argv)
{
@@ -71,8 +71,8 @@ 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);
+ //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;
@@ -84,7 +84,7 @@ int main(int argc, char **argv)
blade_identity_destroy(&target);
- ks_sleep_ms(2000);
+ ks_sleep_ms(5000);
} else loop(bh);
//blade_handle_session_state_callback_unregister(bh, session_state_callback_id);
@@ -98,37 +98,37 @@ 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_rpc_request_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);
- }
- }
-}
+//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)
{
@@ -210,77 +210,77 @@ void command_connect(blade_handle_t *bh, char *args)
blade_identity_destroy(&target);
}
-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_rpc_request_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_rpc_request_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);
- }
-}
+//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);
+// }
+//}
diff --git a/libs/libblade/test/bladec.cfg b/libs/libblade/test/bladec.cfg
index 14582ed3ab..6d7e93b5a0 100644
--- a/libs/libblade/test/bladec.cfg
+++ b/libs/libblade/test/bladec.cfg
@@ -1,11 +1,3 @@
blade:
{
- identity = "peer@domain";
- datastore:
- {
- database:
- {
- path = ":mem:";
- };
- };
};
diff --git a/libs/libblade/test/blades.c b/libs/libblade/test/blades.c
index 35e2ef34f6..c380df9f09 100644
--- a/libs/libblade/test/blades.c
+++ b/libs/libblade/test/blades.c
@@ -25,34 +25,34 @@ static const struct command_def_s command_defs[] = {
-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_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,
+//};
int main(int argc, char **argv)
@@ -60,7 +60,7 @@ 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_module_t *mod_chat = NULL;
//blade_identity_t *id = NULL;
const char *cfgpath = "blades.cfg";
@@ -90,8 +90,8 @@ int main(int argc, char **argv)
}
// must occur before startup
- blade_module_chat_create(&mod_chat, bh);
- blade_handle_module_register(mod_chat);
+ //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");
@@ -177,328 +177,328 @@ void command_quit(blade_handle_t *bh, char *args)
-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;
-}
+//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:
diff --git a/libs/libblade/test/blades.cfg b/libs/libblade/test/blades.cfg
index 3420d74ff2..442e103cd3 100644
--- a/libs/libblade/test/blades.cfg
+++ b/libs/libblade/test/blades.cfg
@@ -1,28 +1,26 @@
blade:
{
- identity = "service@domain";
- directory:
- {
- };
- datastore:
- {
- database:
- {
- path = ":mem:";
- };
- };
- wss:
- {
- endpoints:
- {
- ipv4 = ( { address = "0.0.0.0", port = 2100 } );
- ipv6 = ( { address = "::", port = 2100 } );
- backlog = 128;
- };
- # SSL group is optional, disabled when absent
- ssl:
- {
- # todo: server SSL stuffs here
- };
- };
+ master:
+ {
+ enabled = true;
+ user = "00000000-0000-0000-0000-000000000000";
+ realms = ( "mydomain.com" );
+ };
+ transport:
+ {
+ wss:
+ {
+ endpoints:
+ {
+ ipv4 = ( { address = "0.0.0.0", port = 2100 } );
+ ipv6 = ( { address = "::", port = 2100 } );
+ backlog = 128;
+ };
+ # SSL group is optional, disabled when absent
+ ssl:
+ {
+ # todo: server SSL stuffs here
+ };
+ };
+ };
};