FS-9952: Initial implementation of a very basic text chat system which introduced a number of supporting subsystems
This commit is contained in:
parent
75ee45395d
commit
7742dffae4
|
@ -15,7 +15,7 @@ libblade_la_SOURCES = src/blade.c src/blade_stack.c
|
||||||
libblade_la_SOURCES += src/blade_datastore.c
|
libblade_la_SOURCES += src/blade_datastore.c
|
||||||
libblade_la_SOURCES += src/blade_identity.c src/blade_module.c src/blade_connection.c
|
libblade_la_SOURCES += src/blade_identity.c src/blade_module.c src/blade_connection.c
|
||||||
libblade_la_SOURCES += src/blade_session.c src/blade_protocol.c src/blade_space.c src/blade_method.c
|
libblade_la_SOURCES += src/blade_session.c src/blade_protocol.c src/blade_space.c src/blade_method.c
|
||||||
libblade_la_SOURCES += src/blade_module_wss.c
|
libblade_la_SOURCES += src/blade_module_wss.c src/blade_module_chat.c
|
||||||
libblade_la_CFLAGS = $(AM_CFLAGS) $(AM_CPPFLAGS)
|
libblade_la_CFLAGS = $(AM_CFLAGS) $(AM_CPPFLAGS)
|
||||||
libblade_la_LDFLAGS = -version-info 0:1:0 -lncurses -lpthread -lm -lconfig $(AM_LDFLAGS)
|
libblade_la_LDFLAGS = -version-info 0:1:0 -lncurses -lpthread -lm -lconfig $(AM_LDFLAGS)
|
||||||
libblade_la_LIBADD = libunqlite.la
|
libblade_la_LIBADD = libunqlite.la
|
||||||
|
|
|
@ -532,6 +532,7 @@ ks_status_t blade_connection_state_on_ready(blade_connection_t *bc)
|
||||||
if (callback) hook = callback(bc, BLADE_CONNECTION_STATE_CONDITION_POST);
|
if (callback) hook = callback(bc, BLADE_CONNECTION_STATE_CONDITION_POST);
|
||||||
|
|
||||||
if (hook == BLADE_CONNECTION_STATE_HOOK_DISCONNECT) blade_connection_disconnect(bc);
|
if (hook == BLADE_CONNECTION_STATE_HOOK_DISCONNECT) blade_connection_disconnect(bc);
|
||||||
|
else ks_sleep_ms(1);
|
||||||
|
|
||||||
return KS_STATUS_SUCCESS;
|
return KS_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,6 +78,13 @@ KS_DECLARE(ks_status_t) blade_module_destroy(blade_module_t **bmP)
|
||||||
return KS_STATUS_SUCCESS;
|
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(void *) blade_module_data_get(blade_module_t *bm)
|
KS_DECLARE(void *) blade_module_data_get(blade_module_t *bm)
|
||||||
{
|
{
|
||||||
ks_assert(bm);
|
ks_assert(bm);
|
||||||
|
|
|
@ -0,0 +1,432 @@
|
||||||
|
/*
|
||||||
|
* 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_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;
|
||||||
|
|
||||||
|
const char *session_state_callback_id;
|
||||||
|
list_t participants;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
ks_status_t blade_module_chat_create(blade_module_chat_t **bm_chatP, blade_handle_t *bh);
|
||||||
|
ks_status_t blade_module_chat_destroy(blade_module_chat_t **bm_chatP);
|
||||||
|
|
||||||
|
// @todo remove exporting this, it's only temporary until DSO loading is in place so wss module can be loaded
|
||||||
|
KS_DECLARE(ks_status_t) blade_module_chat_on_load(blade_module_t **bmP, blade_handle_t *bh);
|
||||||
|
KS_DECLARE(ks_status_t) blade_module_chat_on_unload(blade_module_t *bm);
|
||||||
|
KS_DECLARE(ks_status_t) blade_module_chat_on_startup(blade_module_t *bm, config_setting_t *config);
|
||||||
|
KS_DECLARE(ks_status_t) blade_module_chat_on_shutdown(blade_module_t *bm);
|
||||||
|
|
||||||
|
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_load,
|
||||||
|
blade_module_chat_on_unload,
|
||||||
|
blade_module_chat_on_startup,
|
||||||
|
blade_module_chat_on_shutdown,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ks_status_t blade_module_chat_create(blade_module_chat_t **bm_chatP, blade_handle_t *bh)
|
||||||
|
{
|
||||||
|
blade_module_chat_t *bm_chat = NULL;
|
||||||
|
ks_pool_t *pool = NULL;
|
||||||
|
|
||||||
|
ks_assert(bm_chatP);
|
||||||
|
ks_assert(bh);
|
||||||
|
|
||||||
|
pool = blade_handle_pool_get(bh);
|
||||||
|
|
||||||
|
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;
|
||||||
|
list_init(&bm_chat->participants);
|
||||||
|
|
||||||
|
blade_module_create(&bm_chat->module, bh, bm_chat, &g_module_chat_callbacks);
|
||||||
|
bm_chat->module_callbacks = &g_module_chat_callbacks;
|
||||||
|
|
||||||
|
*bm_chatP = bm_chat;
|
||||||
|
|
||||||
|
ks_log(KS_LOG_DEBUG, "Created\n");
|
||||||
|
|
||||||
|
return KS_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
ks_status_t blade_module_chat_destroy(blade_module_chat_t **bm_chatP)
|
||||||
|
{
|
||||||
|
blade_module_chat_t *bm_chat = NULL;
|
||||||
|
|
||||||
|
ks_assert(bm_chatP);
|
||||||
|
ks_assert(*bm_chatP);
|
||||||
|
|
||||||
|
bm_chat = *bm_chatP;
|
||||||
|
|
||||||
|
blade_module_chat_on_shutdown(bm_chat->module);
|
||||||
|
|
||||||
|
list_destroy(&bm_chat->participants);
|
||||||
|
|
||||||
|
blade_module_destroy(&bm_chat->module);
|
||||||
|
|
||||||
|
ks_pool_free(bm_chat->pool, bm_chatP);
|
||||||
|
|
||||||
|
ks_log(KS_LOG_DEBUG, "Destroyed\n");
|
||||||
|
|
||||||
|
return KS_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
KS_DECLARE(ks_status_t) blade_module_chat_on_load(blade_module_t **bmP, blade_handle_t *bh)
|
||||||
|
{
|
||||||
|
blade_module_chat_t *bm_chat = NULL;
|
||||||
|
|
||||||
|
ks_assert(bmP);
|
||||||
|
ks_assert(bh);
|
||||||
|
|
||||||
|
blade_module_chat_create(&bm_chat, bh);
|
||||||
|
ks_assert(bm_chat);
|
||||||
|
|
||||||
|
*bmP = bm_chat->module;
|
||||||
|
|
||||||
|
ks_log(KS_LOG_DEBUG, "Loaded\n");
|
||||||
|
|
||||||
|
return KS_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
KS_DECLARE(ks_status_t) blade_module_chat_on_unload(blade_module_t *bm)
|
||||||
|
{
|
||||||
|
blade_module_chat_t *bm_chat = NULL;
|
||||||
|
|
||||||
|
ks_assert(bm);
|
||||||
|
|
||||||
|
bm_chat = blade_module_data_get(bm);
|
||||||
|
|
||||||
|
blade_module_chat_destroy(&bm_chat);
|
||||||
|
|
||||||
|
ks_log(KS_LOG_DEBUG, "Unloaded\n");
|
||||||
|
|
||||||
|
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_DECLARE(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);
|
||||||
|
|
||||||
|
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_DECLARE(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;
|
||||||
|
|
||||||
|
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");
|
||||||
|
|
||||||
|
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(breq->pool, &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");
|
||||||
|
|
||||||
|
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(breq->pool, &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(breq->pool, &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");
|
||||||
|
|
||||||
|
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(breq->pool, &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(breq->pool, &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(breq->pool, &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(breq->pool, &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(breq->pool, &event, &res, "blade.chat.message");
|
||||||
|
ks_assert(event);
|
||||||
|
cJSON_AddStringToObject(res, "from", breq->session_id); // @todo should really be the identity, but we don't have that in place yet
|
||||||
|
cJSON_AddStringToObject(res, "message", message);
|
||||||
|
|
||||||
|
blade_handle_sessions_send(breq->handle, &bm_chat->participants, NULL, event);
|
||||||
|
|
||||||
|
cJSON_Delete(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
return KS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* For Emacs:
|
||||||
|
* Local Variables:
|
||||||
|
* 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:
|
||||||
|
*/
|
|
@ -122,7 +122,7 @@ ks_status_t blade_transport_wss_init_create(blade_transport_wss_init_t **bt_wssi
|
||||||
ks_status_t blade_transport_wss_init_destroy(blade_transport_wss_init_t **bt_wssiP);
|
ks_status_t blade_transport_wss_init_destroy(blade_transport_wss_init_t **bt_wssiP);
|
||||||
|
|
||||||
|
|
||||||
ks_bool_t blade_test_echo_request_handler(blade_request_t *breq);
|
ks_bool_t blade_test_echo_request_handler(blade_module_t *bm, blade_request_t *breq);
|
||||||
ks_bool_t blade_test_echo_response_handler(blade_response_t *bres);
|
ks_bool_t blade_test_echo_response_handler(blade_response_t *bres);
|
||||||
|
|
||||||
|
|
||||||
|
@ -427,7 +427,7 @@ KS_DECLARE(ks_status_t) blade_module_wss_on_startup(blade_module_t *bm, config_s
|
||||||
blade_handle_transport_register(bm_wss->handle, bm, BLADE_MODULE_WSS_TRANSPORT_NAME, bm_wss->transport_callbacks);
|
blade_handle_transport_register(bm_wss->handle, bm, BLADE_MODULE_WSS_TRANSPORT_NAME, bm_wss->transport_callbacks);
|
||||||
|
|
||||||
|
|
||||||
blade_space_create(&space, bm_wss->handle, "blade.test");
|
blade_space_create(&space, bm_wss->handle, bm, "blade.test");
|
||||||
ks_assert(space);
|
ks_assert(space);
|
||||||
|
|
||||||
blade_method_create(&method, space, "echo", blade_test_echo_request_handler);
|
blade_method_create(&method, space, "echo", blade_test_echo_request_handler);
|
||||||
|
@ -1248,9 +1248,10 @@ blade_connection_state_hook_t blade_transport_wss_on_state_ready_inbound(blade_c
|
||||||
{
|
{
|
||||||
ks_assert(bc);
|
ks_assert(bc);
|
||||||
|
|
||||||
ks_log(KS_LOG_DEBUG, "State Callback: %d\n", (int32_t)condition);
|
if (condition == BLADE_CONNECTION_STATE_CONDITION_PRE) {
|
||||||
|
ks_log(KS_LOG_DEBUG, "State Callback: %d\n", (int32_t)condition);
|
||||||
|
}
|
||||||
|
|
||||||
ks_sleep_ms(1000);
|
|
||||||
return BLADE_CONNECTION_STATE_HOOK_SUCCESS;
|
return BLADE_CONNECTION_STATE_HOOK_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1258,12 +1259,12 @@ blade_connection_state_hook_t blade_transport_wss_on_state_ready_outbound(blade_
|
||||||
{
|
{
|
||||||
ks_assert(bc);
|
ks_assert(bc);
|
||||||
|
|
||||||
ks_log(KS_LOG_DEBUG, "State Callback: %d\n", (int32_t)condition);
|
|
||||||
|
|
||||||
if (condition == BLADE_CONNECTION_STATE_CONDITION_PRE) {
|
if (condition == BLADE_CONNECTION_STATE_CONDITION_PRE) {
|
||||||
blade_session_t *bs = NULL;
|
blade_session_t *bs = NULL;
|
||||||
cJSON *req = NULL;
|
cJSON *req = NULL;
|
||||||
|
|
||||||
|
ks_log(KS_LOG_DEBUG, "State Callback: %d\n", (int32_t)condition);
|
||||||
|
|
||||||
bs = blade_handle_sessions_get(blade_connection_handle_get(bc), blade_connection_session_get(bc));
|
bs = blade_handle_sessions_get(blade_connection_handle_get(bc), blade_connection_session_get(bc));
|
||||||
ks_assert(bs);
|
ks_assert(bs);
|
||||||
|
|
||||||
|
@ -1273,17 +1274,17 @@ blade_connection_state_hook_t blade_transport_wss_on_state_ready_outbound(blade_
|
||||||
blade_session_read_unlock(bs);
|
blade_session_read_unlock(bs);
|
||||||
}
|
}
|
||||||
|
|
||||||
ks_sleep_ms(1000);
|
|
||||||
return BLADE_CONNECTION_STATE_HOOK_SUCCESS;
|
return BLADE_CONNECTION_STATE_HOOK_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ks_bool_t blade_test_echo_request_handler(blade_request_t *breq)
|
ks_bool_t blade_test_echo_request_handler(blade_module_t *bm, blade_request_t *breq)
|
||||||
{
|
{
|
||||||
blade_session_t *bs = NULL;
|
blade_session_t *bs = NULL;
|
||||||
cJSON *res = NULL;
|
cJSON *res = NULL;
|
||||||
|
|
||||||
|
ks_assert(bm);
|
||||||
ks_assert(breq);
|
ks_assert(breq);
|
||||||
|
|
||||||
ks_log(KS_LOG_DEBUG, "Request Received!\n");
|
ks_log(KS_LOG_DEBUG, "Request Received!\n");
|
||||||
|
|
|
@ -55,7 +55,7 @@ KS_DECLARE(ks_status_t) blade_request_create(blade_request_t **breqP,
|
||||||
breq->pool = pool;
|
breq->pool = pool;
|
||||||
breq->session_id = ks_pstrdup(pool, session_id);
|
breq->session_id = ks_pstrdup(pool, session_id);
|
||||||
breq->message = cJSON_Duplicate(json, 1);
|
breq->message = cJSON_Duplicate(json, 1);
|
||||||
breq->message_id = cJSON_GetObjectCstr(json, "id");
|
breq->message_id = cJSON_GetObjectCstr(breq->message, "id");
|
||||||
breq->callback = callback;
|
breq->callback = callback;
|
||||||
|
|
||||||
*breqP = breq;
|
*breqP = breq;
|
||||||
|
@ -81,7 +81,11 @@ 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, const char *session_id, blade_request_t *breq, cJSON *json)
|
KS_DECLARE(ks_status_t) blade_response_create(blade_response_t **bresP,
|
||||||
|
blade_handle_t *bh,
|
||||||
|
const char *session_id,
|
||||||
|
blade_request_t *breq,
|
||||||
|
cJSON *json)
|
||||||
{
|
{
|
||||||
blade_response_t *bres = NULL;
|
blade_response_t *bres = NULL;
|
||||||
ks_pool_t *pool = NULL;
|
ks_pool_t *pool = NULL;
|
||||||
|
@ -125,6 +129,50 @@ KS_DECLARE(ks_status_t) blade_response_destroy(blade_response_t **bresP)
|
||||||
return KS_STATUS_SUCCESS;
|
return KS_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KS_DECLARE(ks_status_t) blade_event_create(blade_event_t **bevP,
|
||||||
|
blade_handle_t *bh,
|
||||||
|
const char *session_id,
|
||||||
|
cJSON *json)
|
||||||
|
{
|
||||||
|
blade_event_t *bev = NULL;
|
||||||
|
ks_pool_t *pool = NULL;
|
||||||
|
|
||||||
|
ks_assert(bevP);
|
||||||
|
ks_assert(bh);
|
||||||
|
ks_assert(session_id);
|
||||||
|
ks_assert(json);
|
||||||
|
|
||||||
|
pool = blade_handle_pool_get(bh);
|
||||||
|
ks_assert(pool);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
*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, (void **)&bev->session_id);
|
||||||
|
cJSON_Delete(bev->message);
|
||||||
|
|
||||||
|
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)
|
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 *root = NULL;
|
||||||
|
@ -208,6 +256,35 @@ KS_DECLARE(ks_status_t) blade_rpc_error_create(ks_pool_t *pool, cJSON **json, cJ
|
||||||
return KS_STATUS_SUCCESS;
|
return KS_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KS_DECLARE(ks_status_t) blade_rpc_event_create(ks_pool_t *pool, cJSON **json, cJSON **result, const char *event)
|
||||||
|
{
|
||||||
|
cJSON *root = NULL;
|
||||||
|
cJSON *b = NULL;
|
||||||
|
cJSON *r = NULL;
|
||||||
|
|
||||||
|
ks_assert(pool);
|
||||||
|
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:
|
/* For Emacs:
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* mode:c
|
* mode:c
|
||||||
|
|
|
@ -48,6 +48,9 @@ struct blade_session_s {
|
||||||
|
|
||||||
ks_q_t *sending;
|
ks_q_t *sending;
|
||||||
ks_q_t *receiving;
|
ks_q_t *receiving;
|
||||||
|
|
||||||
|
cJSON *properties;
|
||||||
|
ks_rwl_t *properties_lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
void *blade_session_state_thread(ks_thread_t *thread, void *data);
|
void *blade_session_state_thread(ks_thread_t *thread, void *data);
|
||||||
|
@ -83,6 +86,11 @@ KS_DECLARE(ks_status_t) blade_session_create(blade_session_t **bsP, blade_handle
|
||||||
ks_q_create(&bs->receiving, pool, 0);
|
ks_q_create(&bs->receiving, pool, 0);
|
||||||
ks_assert(bs->receiving);
|
ks_assert(bs->receiving);
|
||||||
|
|
||||||
|
bs->properties = cJSON_CreateObject();
|
||||||
|
ks_assert(bs->properties);
|
||||||
|
ks_rwl_create(&bs->properties_lock, pool);
|
||||||
|
ks_assert(bs->properties_lock);
|
||||||
|
|
||||||
*bsP = bs;
|
*bsP = bs;
|
||||||
|
|
||||||
ks_log(KS_LOG_DEBUG, "Created\n");
|
ks_log(KS_LOG_DEBUG, "Created\n");
|
||||||
|
@ -101,6 +109,10 @@ KS_DECLARE(ks_status_t) blade_session_destroy(blade_session_t **bsP)
|
||||||
|
|
||||||
blade_session_shutdown(bs);
|
blade_session_shutdown(bs);
|
||||||
|
|
||||||
|
cJSON_Delete(bs->properties);
|
||||||
|
bs->properties = NULL;
|
||||||
|
ks_rwl_destroy(&bs->properties_lock);
|
||||||
|
|
||||||
list_destroy(&bs->connections);
|
list_destroy(&bs->connections);
|
||||||
ks_q_destroy(&bs->receiving);
|
ks_q_destroy(&bs->receiving);
|
||||||
ks_q_destroy(&bs->sending);
|
ks_q_destroy(&bs->sending);
|
||||||
|
@ -174,6 +186,13 @@ KS_DECLARE(blade_handle_t *) blade_session_handle_get(blade_session_t *bs)
|
||||||
return bs->handle;
|
return bs->handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KS_DECLARE(ks_pool_t *) blade_session_pool_get(blade_session_t *bs)
|
||||||
|
{
|
||||||
|
ks_assert(bs);
|
||||||
|
|
||||||
|
return bs->pool;
|
||||||
|
}
|
||||||
|
|
||||||
KS_DECLARE(const char *) blade_session_id_get(blade_session_t *bs)
|
KS_DECLARE(const char *) blade_session_id_get(blade_session_t *bs)
|
||||||
{
|
{
|
||||||
ks_assert(bs);
|
ks_assert(bs);
|
||||||
|
@ -190,6 +209,20 @@ KS_DECLARE(void) blade_session_id_set(blade_session_t *bs, const char *id)
|
||||||
bs->id = ks_pstrdup(bs->pool, id);
|
bs->id = ks_pstrdup(bs->pool, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KS_DECLARE(blade_session_state_t) blade_session_state_get(blade_session_t *bs)
|
||||||
|
{
|
||||||
|
ks_assert(bs);
|
||||||
|
|
||||||
|
return bs->state;
|
||||||
|
}
|
||||||
|
|
||||||
|
KS_DECLARE(cJSON *) blade_session_properties_get(blade_session_t *bs)
|
||||||
|
{
|
||||||
|
ks_assert(bs);
|
||||||
|
|
||||||
|
return bs->properties;
|
||||||
|
}
|
||||||
|
|
||||||
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_lock(blade_session_t *bs, ks_bool_t block)
|
||||||
{
|
{
|
||||||
ks_status_t ret = KS_STATUS_SUCCESS;
|
ks_status_t ret = KS_STATUS_SUCCESS;
|
||||||
|
@ -227,11 +260,50 @@ KS_DECLARE(ks_status_t) blade_session_write_unlock(blade_session_t *bs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
KS_DECLARE(ks_status_t) blade_session_properties_read_lock(blade_session_t *bs, ks_bool_t block)
|
||||||
|
{
|
||||||
|
ks_status_t ret = KS_STATUS_SUCCESS;
|
||||||
|
|
||||||
|
ks_assert(bs);
|
||||||
|
|
||||||
|
if (block) ret = ks_rwl_read_lock(bs->properties_lock);
|
||||||
|
else ret = ks_rwl_try_read_lock(bs->properties_lock);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
KS_DECLARE(ks_status_t) blade_session_properties_read_unlock(blade_session_t *bs)
|
||||||
|
{
|
||||||
|
ks_assert(bs);
|
||||||
|
|
||||||
|
return ks_rwl_read_unlock(bs->properties_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
KS_DECLARE(ks_status_t) blade_session_properties_write_lock(blade_session_t *bs, ks_bool_t block)
|
||||||
|
{
|
||||||
|
ks_status_t ret = KS_STATUS_SUCCESS;
|
||||||
|
|
||||||
|
ks_assert(bs);
|
||||||
|
|
||||||
|
if (block) ret = ks_rwl_write_lock(bs->properties_lock);
|
||||||
|
else ret = ks_rwl_try_write_lock(bs->properties_lock);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
KS_DECLARE(ks_status_t) blade_session_properties_write_unlock(blade_session_t *bs)
|
||||||
|
{
|
||||||
|
ks_assert(bs);
|
||||||
|
|
||||||
|
return ks_rwl_write_unlock(bs->properties_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
KS_DECLARE(void) blade_session_state_set(blade_session_t *bs, blade_session_state_t state)
|
KS_DECLARE(void) blade_session_state_set(blade_session_t *bs, blade_session_state_t state)
|
||||||
{
|
{
|
||||||
ks_assert(bs);
|
ks_assert(bs);
|
||||||
|
|
||||||
bs->state = state;
|
bs->state = state;
|
||||||
|
|
||||||
|
blade_handle_session_state_callbacks_execute(bs, BLADE_SESSION_STATE_CONDITION_PRE);
|
||||||
}
|
}
|
||||||
|
|
||||||
KS_DECLARE(void) blade_session_hangup(blade_session_t *bs)
|
KS_DECLARE(void) blade_session_hangup(blade_session_t *bs)
|
||||||
|
@ -387,6 +459,8 @@ void *blade_session_state_thread(ks_thread_t *thread, void *data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
blade_handle_session_state_callbacks_execute(bs, BLADE_SESSION_STATE_CONDITION_POST);
|
||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case BLADE_SESSION_STATE_DESTROY:
|
case BLADE_SESSION_STATE_DESTROY:
|
||||||
blade_session_state_on_destroy(bs);
|
blade_session_state_on_destroy(bs);
|
||||||
|
@ -468,7 +542,7 @@ ks_status_t blade_session_state_on_ready(blade_session_t *bs)
|
||||||
|
|
||||||
ks_assert(bs);
|
ks_assert(bs);
|
||||||
|
|
||||||
ks_log(KS_LOG_DEBUG, "Session (%s) state ready\n", bs->id);
|
//ks_log(KS_LOG_DEBUG, "Session (%s) state ready\n", bs->id);
|
||||||
|
|
||||||
// @todo for now only process messages if there is a connection available
|
// @todo for now only process messages if there is a connection available
|
||||||
if (list_size(&bs->connections) > 0) {
|
if (list_size(&bs->connections) > 0) {
|
||||||
|
@ -479,7 +553,7 @@ ks_status_t blade_session_state_on_ready(blade_session_t *bs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ks_sleep_ms(1000);
|
ks_sleep_ms(1);
|
||||||
return KS_STATUS_SUCCESS;
|
return KS_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -495,7 +569,15 @@ KS_DECLARE(ks_status_t) blade_session_send(blade_session_t *bs, cJSON *json, bla
|
||||||
|
|
||||||
method = cJSON_GetObjectCstr(json, "method");
|
method = cJSON_GetObjectCstr(json, "method");
|
||||||
id = cJSON_GetObjectCstr(json, "id");
|
id = cJSON_GetObjectCstr(json, "id");
|
||||||
if (method) {
|
if (!id) {
|
||||||
|
cJSON *blade = NULL;
|
||||||
|
const char *event = NULL;
|
||||||
|
|
||||||
|
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) {
|
||||||
// @note This is scenario 1
|
// @note This is scenario 1
|
||||||
// 1) Sending a request (client: method caller or consumer)
|
// 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);
|
ks_log(KS_LOG_DEBUG, "Session (%s) sending request (%s) for %s\n", bs->id, id, method);
|
||||||
|
@ -529,7 +611,10 @@ ks_status_t blade_session_process(blade_session_t *bs, cJSON *json)
|
||||||
{
|
{
|
||||||
blade_request_t *breq = NULL;
|
blade_request_t *breq = NULL;
|
||||||
blade_response_t *bres = NULL;
|
blade_response_t *bres = NULL;
|
||||||
|
blade_event_t *bev = NULL;
|
||||||
const char *jsonrpc = NULL;
|
const char *jsonrpc = NULL;
|
||||||
|
cJSON *blade = NULL;
|
||||||
|
const char *blade_event = NULL;
|
||||||
const char *id = NULL;
|
const char *id = NULL;
|
||||||
const char *method = NULL;
|
const char *method = NULL;
|
||||||
ks_bool_t disconnect = KS_FALSE;
|
ks_bool_t disconnect = KS_FALSE;
|
||||||
|
@ -548,73 +633,99 @@ ks_status_t blade_session_process(blade_session_t *bs, cJSON *json)
|
||||||
return KS_STATUS_FAIL;
|
return KS_STATUS_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
id = cJSON_GetObjectCstr(json, "id");
|
blade = cJSON_GetObjectItem(json, "blade");
|
||||||
if (!id) {
|
if (blade) {
|
||||||
ks_log(KS_LOG_DEBUG, "Received message is missing 'id'\n");
|
blade_event = cJSON_GetObjectCstr(blade, "event");
|
||||||
// @todo send error response, code = -32600 (invalid request)
|
|
||||||
// @todo hangup session entirely?
|
|
||||||
return KS_STATUS_FAIL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
method = cJSON_GetObjectCstr(json, "method");
|
if (blade_event) {
|
||||||
if (method) {
|
blade_event_callback_t callback = blade_handle_event_lookup(blade_session_handle_get(bs), blade_event);
|
||||||
// @note This is scenario 2
|
if (!callback) {
|
||||||
// 2) Receiving a request (server: method callee or provider)
|
ks_log(KS_LOG_DEBUG, "Received event message with no event callback '%s'\n", blade_event);
|
||||||
blade_space_t *tmp_space = NULL;
|
} else {
|
||||||
blade_method_t *tmp_method = NULL;
|
ks_log(KS_LOG_DEBUG, "Session (%s) processing event %s\n", bs->id, blade_event);
|
||||||
blade_request_callback_t callback = NULL;
|
|
||||||
char *space_name = ks_pstrdup(bs->pool, method);
|
|
||||||
char *method_name = strrchr(space_name, '.');
|
|
||||||
|
|
||||||
ks_log(KS_LOG_DEBUG, "Session (%s) receiving request (%s) for %s\n", bs->id, id, method);
|
blade_event_create(&bev, bs->handle, bs->id, json);
|
||||||
|
ks_assert(bev);
|
||||||
|
|
||||||
if (!method_name || method_name == space_name) {
|
disconnect = callback(bev);
|
||||||
ks_pool_free(bs->pool, (void **)&space_name);
|
|
||||||
// @todo send error response, code = -32601 (method not found)
|
blade_event_destroy(&bev);
|
||||||
// @todo hangup session entirely?
|
|
||||||
return KS_STATUS_FAIL;
|
|
||||||
}
|
}
|
||||||
*method_name = '\0';
|
|
||||||
method_name++; // @todo check if can be postfixed safely on previous assignment, can't recall
|
|
||||||
|
|
||||||
tmp_space = blade_handle_space_lookup(bs->handle, space_name);
|
|
||||||
if (tmp_space) tmp_method = blade_space_methods_get(tmp_space, method_name);
|
|
||||||
|
|
||||||
ks_pool_free(bs->pool, (void **)&space_name);
|
|
||||||
|
|
||||||
if (!tmp_method) {
|
|
||||||
// @todo send error response, code = -32601 (method not found)
|
|
||||||
// @todo hangup session entirely?
|
|
||||||
return KS_STATUS_FAIL;
|
|
||||||
}
|
|
||||||
callback = blade_method_callback_get(tmp_method);
|
|
||||||
ks_assert(callback);
|
|
||||||
|
|
||||||
blade_request_create(&breq, bs->handle, bs->id, json, NULL);
|
|
||||||
ks_assert(breq);
|
|
||||||
|
|
||||||
disconnect = callback(breq);
|
|
||||||
|
|
||||||
blade_request_destroy(&breq);
|
|
||||||
} else {
|
} else {
|
||||||
// @note This is scenario 4
|
id = cJSON_GetObjectCstr(json, "id");
|
||||||
// 4) Receiving a response or error (client: method caller or consumer)
|
if (!id) {
|
||||||
|
ks_log(KS_LOG_DEBUG, "Received non-event message is missing 'id'\n");
|
||||||
ks_log(KS_LOG_DEBUG, "Session (%s) receiving response (%s)\n", bs->id, id);
|
// @todo send error response, code = -32600 (invalid request)
|
||||||
|
|
||||||
breq = blade_handle_requests_get(bs->handle, id);
|
|
||||||
if (!breq) {
|
|
||||||
// @todo hangup session entirely?
|
// @todo hangup session entirely?
|
||||||
return KS_STATUS_FAIL;
|
return KS_STATUS_FAIL;
|
||||||
}
|
}
|
||||||
blade_handle_requests_remove(breq);
|
|
||||||
|
|
||||||
blade_response_create(&bres, bs->handle, bs->id, breq, json);
|
method = cJSON_GetObjectCstr(json, "method");
|
||||||
ks_assert(bres);
|
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, '.');
|
||||||
|
|
||||||
disconnect = breq->callback(bres);
|
ks_log(KS_LOG_DEBUG, "Session (%s) receiving request (%s) for %s\n", bs->id, id, method);
|
||||||
|
|
||||||
blade_response_destroy(&bres);
|
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
|
||||||
|
|
||||||
|
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, 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->id, breq, json);
|
||||||
|
ks_assert(bres);
|
||||||
|
|
||||||
|
disconnect = breq->callback(bres);
|
||||||
|
|
||||||
|
blade_response_destroy(&bres);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (disconnect) {
|
if (disconnect) {
|
||||||
|
|
|
@ -36,13 +36,14 @@
|
||||||
struct blade_space_s {
|
struct blade_space_s {
|
||||||
blade_handle_t *handle;
|
blade_handle_t *handle;
|
||||||
ks_pool_t *pool;
|
ks_pool_t *pool;
|
||||||
|
blade_module_t *module;
|
||||||
|
|
||||||
const char *path;
|
const char *path;
|
||||||
ks_hash_t *methods;
|
ks_hash_t *methods;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
KS_DECLARE(ks_status_t) blade_space_create(blade_space_t **bsP, blade_handle_t *bh, const char *path)
|
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;
|
blade_space_t *bs = NULL;
|
||||||
ks_pool_t *pool = NULL;
|
ks_pool_t *pool = NULL;
|
||||||
|
@ -56,6 +57,7 @@ KS_DECLARE(ks_status_t) blade_space_create(blade_space_t **bsP, blade_handle_t *
|
||||||
bs = ks_pool_alloc(pool, sizeof(blade_space_t));
|
bs = ks_pool_alloc(pool, sizeof(blade_space_t));
|
||||||
bs->handle = bh;
|
bs->handle = bh;
|
||||||
bs->pool = pool;
|
bs->pool = pool;
|
||||||
|
bs->module = bm;
|
||||||
bs->path = path; // @todo dup and keep copy? should mostly be literals
|
bs->path = path; // @todo dup and keep copy? should mostly be literals
|
||||||
ks_hash_create(&bs->methods, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_NOLOCK | KS_HASH_FLAG_DUP_CHECK, bs->pool);
|
ks_hash_create(&bs->methods, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_NOLOCK | KS_HASH_FLAG_DUP_CHECK, bs->pool);
|
||||||
ks_assert(bs);
|
ks_assert(bs);
|
||||||
|
@ -101,6 +103,13 @@ KS_DECLARE(blade_handle_t *) blade_space_handle_get(blade_space_t *bs)
|
||||||
return bs->handle;
|
return bs->handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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_DECLARE(const char *) blade_space_path_get(blade_space_t *bs)
|
||||||
{
|
{
|
||||||
ks_assert(bs);
|
ks_assert(bs);
|
||||||
|
|
|
@ -49,14 +49,21 @@ struct blade_handle_s {
|
||||||
|
|
||||||
ks_hash_t *transports; // registered transports exposed by modules, NOT active connections
|
ks_hash_t *transports; // registered transports exposed by modules, NOT active connections
|
||||||
ks_hash_t *spaces; // registered method spaces exposed by modules
|
ks_hash_t *spaces; // registered method spaces exposed by modules
|
||||||
|
// 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
|
||||||
|
ks_hash_t *events;
|
||||||
|
|
||||||
//blade_identity_t *identity;
|
//blade_identity_t *identity;
|
||||||
blade_datastore_t *datastore;
|
blade_datastore_t *datastore;
|
||||||
|
|
||||||
// @todo insert on connection creations, remove on connection destructions, key based on a UUID for the connection
|
// @todo insert on connection creations, remove on connection destructions, key based on a UUID for the connection
|
||||||
ks_hash_t *connections; // active connections keyed by connection id
|
ks_hash_t *connections; // active connections keyed by connection id
|
||||||
|
|
||||||
// @todo insert on session creations, remove on session destructions, key based on a UUID for the session
|
// @todo insert on session creations, remove on session destructions, key based on a UUID for the session
|
||||||
ks_hash_t *sessions; // active sessions keyed by session id
|
ks_hash_t *sessions; // active sessions keyed by session id
|
||||||
|
ks_hash_t *session_state_callbacks;
|
||||||
|
|
||||||
// @todo another hash with sessions keyed by the remote identity without parameters for quick lookup by target identity on sending?
|
// @todo another hash with sessions keyed by the remote identity without parameters for quick lookup by target identity on sending?
|
||||||
ks_hash_t *requests; // outgoing requests waiting for a response keyed by the message id
|
ks_hash_t *requests; // outgoing requests waiting for a response keyed by the message id
|
||||||
};
|
};
|
||||||
|
@ -70,7 +77,6 @@ struct blade_handle_transport_registration_s {
|
||||||
blade_transport_callbacks_t *callbacks;
|
blade_transport_callbacks_t *callbacks;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
KS_DECLARE(ks_status_t) blade_handle_transport_registration_create(blade_handle_transport_registration_t **bhtrP,
|
KS_DECLARE(ks_status_t) blade_handle_transport_registration_create(blade_handle_transport_registration_t **bhtrP,
|
||||||
ks_pool_t *pool,
|
ks_pool_t *pool,
|
||||||
blade_module_t *module,
|
blade_module_t *module,
|
||||||
|
@ -110,6 +116,59 @@ KS_DECLARE(ks_status_t) blade_handle_transport_registration_destroy(blade_handle
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct blade_handle_session_state_callback_registration_s blade_handle_session_state_callback_registration_t;
|
||||||
|
struct blade_handle_session_state_callback_registration_s {
|
||||||
|
ks_pool_t *pool;
|
||||||
|
|
||||||
|
const char *id;
|
||||||
|
void *data;
|
||||||
|
blade_session_state_callback_t callback;
|
||||||
|
};
|
||||||
|
|
||||||
|
ks_status_t blade_handle_session_state_callback_registration_create(blade_handle_session_state_callback_registration_t **bhsscrP,
|
||||||
|
ks_pool_t *pool,
|
||||||
|
void *data,
|
||||||
|
blade_session_state_callback_t callback)
|
||||||
|
{
|
||||||
|
blade_handle_session_state_callback_registration_t *bhsscr = NULL;
|
||||||
|
uuid_t uuid;
|
||||||
|
|
||||||
|
ks_assert(bhsscrP);
|
||||||
|
ks_assert(pool);
|
||||||
|
ks_assert(callback);
|
||||||
|
|
||||||
|
ks_uuid(&uuid);
|
||||||
|
|
||||||
|
bhsscr = ks_pool_alloc(pool, sizeof(blade_handle_session_state_callback_registration_t));
|
||||||
|
bhsscr->pool = pool;
|
||||||
|
bhsscr->id = ks_uuid_str(pool, &uuid);
|
||||||
|
bhsscr->data = data;
|
||||||
|
bhsscr->callback = callback;
|
||||||
|
|
||||||
|
*bhsscrP = bhsscr;
|
||||||
|
|
||||||
|
return KS_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
ks_status_t blade_handle_session_state_callback_registration_destroy(blade_handle_session_state_callback_registration_t **bhsscrP)
|
||||||
|
{
|
||||||
|
blade_handle_session_state_callback_registration_t *bhsscr = NULL;
|
||||||
|
|
||||||
|
ks_assert(bhsscrP);
|
||||||
|
|
||||||
|
bhsscr = *bhsscrP;
|
||||||
|
*bhsscrP = NULL;
|
||||||
|
|
||||||
|
ks_assert(bhsscr);
|
||||||
|
|
||||||
|
ks_pool_free(bhsscr->pool, &bhsscr->id);
|
||||||
|
|
||||||
|
ks_pool_free(bhsscr->pool, &bhsscr);
|
||||||
|
|
||||||
|
return KS_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
KS_DECLARE(ks_status_t) blade_handle_create(blade_handle_t **bhP, ks_pool_t *pool, ks_thread_pool_t *tpool)
|
KS_DECLARE(ks_status_t) blade_handle_create(blade_handle_t **bhP, ks_pool_t *pool, ks_thread_pool_t *tpool)
|
||||||
{
|
{
|
||||||
|
@ -137,12 +196,17 @@ KS_DECLARE(ks_status_t) blade_handle_create(blade_handle_t **bhP, ks_pool_t *poo
|
||||||
ks_assert(bh->transports);
|
ks_assert(bh->transports);
|
||||||
ks_hash_create(&bh->spaces, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_NOLOCK | KS_HASH_FLAG_DUP_CHECK, bh->pool);
|
ks_hash_create(&bh->spaces, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_NOLOCK | KS_HASH_FLAG_DUP_CHECK, bh->pool);
|
||||||
ks_assert(bh->spaces);
|
ks_assert(bh->spaces);
|
||||||
|
ks_hash_create(&bh->events, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_NOLOCK | KS_HASH_FLAG_DUP_CHECK, bh->pool);
|
||||||
|
ks_assert(bh->events);
|
||||||
|
|
||||||
ks_hash_create(&bh->connections, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_NOLOCK | KS_HASH_FLAG_DUP_CHECK, bh->pool);
|
ks_hash_create(&bh->connections, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_NOLOCK | KS_HASH_FLAG_DUP_CHECK, bh->pool);
|
||||||
ks_assert(bh->connections);
|
ks_assert(bh->connections);
|
||||||
|
|
||||||
ks_hash_create(&bh->sessions, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_NOLOCK | KS_HASH_FLAG_DUP_CHECK, bh->pool);
|
ks_hash_create(&bh->sessions, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_NOLOCK | KS_HASH_FLAG_DUP_CHECK, bh->pool);
|
||||||
ks_assert(bh->sessions);
|
ks_assert(bh->sessions);
|
||||||
// @todo decide if this is uint32_t or uuid string, prefer uuid string to avoid needing another lock and variable for next id
|
ks_hash_create(&bh->session_state_callbacks, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_NOLOCK | KS_HASH_FLAG_DUP_CHECK, bh->pool);
|
||||||
|
ks_assert(bh->session_state_callbacks);
|
||||||
|
|
||||||
ks_hash_create(&bh->requests, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_NOLOCK | KS_HASH_FLAG_DUP_CHECK, bh->pool);
|
ks_hash_create(&bh->requests, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_NOLOCK | KS_HASH_FLAG_DUP_CHECK, bh->pool);
|
||||||
ks_assert(bh->requests);
|
ks_assert(bh->requests);
|
||||||
|
|
||||||
|
@ -172,8 +236,10 @@ KS_DECLARE(ks_status_t) blade_handle_destroy(blade_handle_t **bhP)
|
||||||
blade_handle_shutdown(bh);
|
blade_handle_shutdown(bh);
|
||||||
|
|
||||||
ks_hash_destroy(&bh->requests);
|
ks_hash_destroy(&bh->requests);
|
||||||
|
ks_hash_destroy(&bh->session_state_callbacks);
|
||||||
ks_hash_destroy(&bh->sessions);
|
ks_hash_destroy(&bh->sessions);
|
||||||
ks_hash_destroy(&bh->connections);
|
ks_hash_destroy(&bh->connections);
|
||||||
|
ks_hash_destroy(&bh->events);
|
||||||
ks_hash_destroy(&bh->spaces);
|
ks_hash_destroy(&bh->spaces);
|
||||||
ks_hash_destroy(&bh->transports);
|
ks_hash_destroy(&bh->transports);
|
||||||
|
|
||||||
|
@ -267,6 +333,14 @@ KS_DECLARE(ks_status_t) blade_handle_shutdown(blade_handle_t *bh)
|
||||||
// @todo call onshutdown and onunload callbacks for modules from DSOs, which will unregister transports and spaces, and will disconnect remaining
|
// @todo call onshutdown and onunload callbacks for modules from DSOs, which will unregister transports and spaces, and will disconnect remaining
|
||||||
// unattached connections
|
// unattached connections
|
||||||
|
|
||||||
|
for (it = ks_hash_first(bh->events, KS_UNLOCKED); it; it = ks_hash_next(&it)) {
|
||||||
|
void *key = NULL;
|
||||||
|
blade_event_callback_t *value = NULL;
|
||||||
|
|
||||||
|
ks_hash_this(it, (const void **)&key, NULL, (void **)&value);
|
||||||
|
blade_handle_event_unregister(bh, (const char *)key);
|
||||||
|
}
|
||||||
|
|
||||||
for (it = ks_hash_first(bh->spaces, KS_UNLOCKED); it; it = ks_hash_next(&it)) {
|
for (it = ks_hash_first(bh->spaces, KS_UNLOCKED); it; it = ks_hash_next(&it)) {
|
||||||
void *key = NULL;
|
void *key = NULL;
|
||||||
blade_space_t *value = NULL;
|
blade_space_t *value = NULL;
|
||||||
|
@ -409,6 +483,53 @@ KS_DECLARE(blade_space_t *) blade_handle_space_lookup(blade_handle_t *bh, const
|
||||||
return bs;
|
return bs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KS_DECLARE(ks_status_t) blade_handle_event_register(blade_handle_t *bh, const char *event, blade_event_callback_t callback)
|
||||||
|
{
|
||||||
|
ks_assert(bh);
|
||||||
|
ks_assert(event);
|
||||||
|
ks_assert(callback);
|
||||||
|
|
||||||
|
ks_hash_write_lock(bh->events);
|
||||||
|
ks_hash_insert(bh->events, (void *)event, (void *)(intptr_t)callback);
|
||||||
|
ks_hash_write_unlock(bh->events);
|
||||||
|
|
||||||
|
ks_log(KS_LOG_DEBUG, "Event Registered: %s\n", event);
|
||||||
|
|
||||||
|
return KS_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
KS_DECLARE(ks_status_t) blade_handle_event_unregister(blade_handle_t *bh, const char *event)
|
||||||
|
{
|
||||||
|
ks_bool_t removed = KS_FALSE;
|
||||||
|
|
||||||
|
ks_assert(bh);
|
||||||
|
ks_assert(event);
|
||||||
|
|
||||||
|
ks_hash_write_lock(bh->events);
|
||||||
|
if (ks_hash_remove(bh->events, (void *)event)) removed = KS_TRUE;
|
||||||
|
ks_hash_write_unlock(bh->events);
|
||||||
|
|
||||||
|
if (removed) {
|
||||||
|
ks_log(KS_LOG_DEBUG, "Event Unregistered: %s\n", event);
|
||||||
|
}
|
||||||
|
|
||||||
|
return KS_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
KS_DECLARE(blade_event_callback_t) blade_handle_event_lookup(blade_handle_t *bh, const char *event)
|
||||||
|
{
|
||||||
|
blade_event_callback_t callback = NULL;
|
||||||
|
|
||||||
|
ks_assert(bh);
|
||||||
|
ks_assert(event);
|
||||||
|
|
||||||
|
ks_hash_read_lock(bh->events);
|
||||||
|
callback = (blade_event_callback_t)(intptr_t)ks_hash_search(bh->events, (void *)event, KS_UNLOCKED);
|
||||||
|
ks_hash_read_unlock(bh->events);
|
||||||
|
|
||||||
|
return callback;
|
||||||
|
}
|
||||||
|
|
||||||
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(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;
|
ks_status_t ret = KS_STATUS_SUCCESS;
|
||||||
|
@ -512,10 +633,11 @@ KS_DECLARE(ks_status_t) blade_handle_connections_remove(blade_connection_t *bc)
|
||||||
|
|
||||||
blade_connection_write_unlock(bc);
|
blade_connection_write_unlock(bc);
|
||||||
|
|
||||||
|
// @todo call bh->connection_callbacks
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
KS_DECLARE(blade_session_t *) blade_handle_sessions_get(blade_handle_t *bh, const char *sid)
|
KS_DECLARE(blade_session_t *) blade_handle_sessions_get(blade_handle_t *bh, const char *sid)
|
||||||
{
|
{
|
||||||
blade_session_t *bs = NULL;
|
blade_session_t *bs = NULL;
|
||||||
|
@ -569,6 +691,92 @@ KS_DECLARE(ks_status_t) blade_handle_sessions_remove(blade_session_t *bs)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KS_DECLARE(void) blade_handle_sessions_send(blade_handle_t *bh, list_t *sessions, const char *exclude, cJSON *json)
|
||||||
|
{
|
||||||
|
blade_session_t *bs = NULL;
|
||||||
|
|
||||||
|
ks_assert(bh);
|
||||||
|
ks_assert(sessions);
|
||||||
|
ks_assert(json);
|
||||||
|
|
||||||
|
list_iterator_start(sessions);
|
||||||
|
while (list_iterator_hasnext(sessions)) {
|
||||||
|
const char *sessionid = list_iterator_next(sessions);
|
||||||
|
if (exclude && !strcmp(exclude, sessionid)) continue;
|
||||||
|
bs = blade_handle_sessions_get(bh, sessionid);
|
||||||
|
if (!bs) {
|
||||||
|
ks_log(KS_LOG_DEBUG, "This should not happen\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
blade_session_send(bs, json, NULL);
|
||||||
|
blade_session_read_unlock(bs);
|
||||||
|
}
|
||||||
|
list_iterator_stop(sessions);
|
||||||
|
}
|
||||||
|
|
||||||
|
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_status_t ret = KS_STATUS_SUCCESS;
|
||||||
|
blade_handle_session_state_callback_registration_t *bhsscr = NULL;
|
||||||
|
|
||||||
|
ks_assert(bh);
|
||||||
|
ks_assert(callback);
|
||||||
|
ks_assert(id);
|
||||||
|
|
||||||
|
blade_handle_session_state_callback_registration_create(&bhsscr, blade_handle_pool_get(bh), data, callback);
|
||||||
|
ks_assert(bhsscr);
|
||||||
|
|
||||||
|
ks_hash_write_lock(bh->session_state_callbacks);
|
||||||
|
ret = ks_hash_insert(bh->session_state_callbacks, (void *)bhsscr->id, bhsscr);
|
||||||
|
ks_hash_write_unlock(bh->session_state_callbacks);
|
||||||
|
|
||||||
|
*id = bhsscr->id;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
KS_DECLARE(ks_status_t) blade_handle_session_state_callback_unregister(blade_handle_t *bh, const char *id)
|
||||||
|
{
|
||||||
|
ks_status_t ret = KS_STATUS_SUCCESS;
|
||||||
|
blade_handle_session_state_callback_registration_t *bhsscr = NULL;
|
||||||
|
|
||||||
|
ks_assert(bh);
|
||||||
|
ks_assert(id);
|
||||||
|
|
||||||
|
ks_hash_write_lock(bh->session_state_callbacks);
|
||||||
|
bhsscr = (blade_handle_session_state_callback_registration_t *)ks_hash_remove(bh->session_state_callbacks, (void *)id);
|
||||||
|
if (!bhsscr) ret = KS_STATUS_FAIL;
|
||||||
|
ks_hash_write_lock(bh->session_state_callbacks);
|
||||||
|
|
||||||
|
if (bhsscr) blade_handle_session_state_callback_registration_destroy(&bhsscr);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
KS_DECLARE(void) blade_handle_session_state_callbacks_execute(blade_session_t *bs, blade_session_state_condition_t condition)
|
||||||
|
{
|
||||||
|
blade_handle_t *bh = NULL;
|
||||||
|
ks_hash_iterator_t *it = NULL;
|
||||||
|
|
||||||
|
ks_assert(bs);
|
||||||
|
|
||||||
|
if (blade_session_state_get(bs) == BLADE_SESSION_STATE_NONE) return;
|
||||||
|
|
||||||
|
bh = blade_session_handle_get(bs);
|
||||||
|
ks_assert(bh);
|
||||||
|
|
||||||
|
ks_hash_read_lock(bh->session_state_callbacks);
|
||||||
|
for (it = ks_hash_first(bh->session_state_callbacks, KS_UNLOCKED); it; it = ks_hash_next(&it)) {
|
||||||
|
void *key = NULL;
|
||||||
|
blade_handle_session_state_callback_registration_t *value = NULL;
|
||||||
|
|
||||||
|
ks_hash_this(it, (const void **)&key, NULL, (void **)&value);
|
||||||
|
|
||||||
|
value->callback(bs, condition, value->data);
|
||||||
|
}
|
||||||
|
ks_hash_read_unlock(bh->session_state_callbacks);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
KS_DECLARE(blade_request_t *) blade_handle_requests_get(blade_handle_t *bh, const char *mid)
|
KS_DECLARE(blade_request_t *) blade_handle_requests_get(blade_handle_t *bh, const char *mid)
|
||||||
{
|
{
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
KS_BEGIN_EXTERN_C
|
KS_BEGIN_EXTERN_C
|
||||||
KS_DECLARE(ks_status_t) blade_module_create(blade_module_t **bmP, blade_handle_t *bh, void *module_data, blade_module_callbacks_t *module_callbacks);
|
KS_DECLARE(ks_status_t) blade_module_create(blade_module_t **bmP, blade_handle_t *bh, void *module_data, blade_module_callbacks_t *module_callbacks);
|
||||||
KS_DECLARE(ks_status_t) blade_module_destroy(blade_module_t **bmP);
|
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(void *) blade_module_data_get(blade_module_t *bm);
|
KS_DECLARE(void *) blade_module_data_get(blade_module_t *bm);
|
||||||
|
|
||||||
// @todo very temporary, this is just here to get the wss module loaded until DSO is in place
|
// @todo very temporary, this is just here to get the wss module loaded until DSO is in place
|
||||||
|
@ -45,6 +46,11 @@ KS_DECLARE(ks_status_t) blade_module_wss_on_load(blade_module_t **bmP, blade_han
|
||||||
KS_DECLARE(ks_status_t) blade_module_wss_on_unload(blade_module_t *bm);
|
KS_DECLARE(ks_status_t) blade_module_wss_on_unload(blade_module_t *bm);
|
||||||
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_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_module_wss_on_shutdown(blade_module_t *bm);
|
||||||
|
|
||||||
|
KS_DECLARE(ks_status_t) blade_module_chat_on_load(blade_module_t **bmP, blade_handle_t *bh);
|
||||||
|
KS_DECLARE(ks_status_t) blade_module_chat_on_unload(blade_module_t *bm);
|
||||||
|
KS_DECLARE(ks_status_t) blade_module_chat_on_startup(blade_module_t *bm, config_setting_t *config);
|
||||||
|
KS_DECLARE(ks_status_t) blade_module_chat_on_shutdown(blade_module_t *bm);
|
||||||
KS_END_EXTERN_C
|
KS_END_EXTERN_C
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -44,9 +44,12 @@ KS_DECLARE(ks_status_t) blade_request_create(blade_request_t **breqP,
|
||||||
KS_DECLARE(ks_status_t) blade_request_destroy(blade_request_t **breqP);
|
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, const char *session_id, blade_request_t *breq, cJSON *json);
|
KS_DECLARE(ks_status_t) blade_response_create(blade_response_t **bresP, blade_handle_t *bh, 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_response_destroy(blade_response_t **bresP);
|
||||||
|
KS_DECLARE(ks_status_t) blade_event_create(blade_event_t **bevP, blade_handle_t *bh, 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_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(ks_pool_t *pool, cJSON **json, cJSON **result, const char *id);
|
KS_DECLARE(ks_status_t) blade_rpc_response_create(ks_pool_t *pool, cJSON **json, cJSON **result, const char *id);
|
||||||
KS_DECLARE(ks_status_t) blade_rpc_error_create(ks_pool_t *pool, cJSON **json, cJSON **error, const char *id, int32_t code, const char *message);
|
KS_DECLARE(ks_status_t) blade_rpc_error_create(ks_pool_t *pool, cJSON **json, cJSON **error, const char *id, int32_t code, const char *message);
|
||||||
|
KS_DECLARE(ks_status_t) blade_rpc_event_create(ks_pool_t *pool, cJSON **json, cJSON **result, const char *event);
|
||||||
KS_END_EXTERN_C
|
KS_END_EXTERN_C
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -41,12 +41,19 @@ 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_startup(blade_session_t *bs);
|
||||||
KS_DECLARE(ks_status_t) blade_session_shutdown(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(blade_handle_t *) blade_session_handle_get(blade_session_t *bs);
|
||||||
|
KS_DECLARE(ks_pool_t *) blade_session_pool_get(blade_session_t *bs);
|
||||||
KS_DECLARE(const char *) blade_session_id_get(blade_session_t *bs);
|
KS_DECLARE(const char *) blade_session_id_get(blade_session_t *bs);
|
||||||
KS_DECLARE(void) blade_session_id_set(blade_session_t *bs, const char *id);
|
KS_DECLARE(void) blade_session_id_set(blade_session_t *bs, const char *id);
|
||||||
|
KS_DECLARE(blade_session_state_t) blade_session_state_get(blade_session_t *bs);
|
||||||
|
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_lock(blade_session_t *bs, ks_bool_t block);
|
||||||
KS_DECLARE(ks_status_t) blade_session_read_unlock(blade_session_t *bs);
|
KS_DECLARE(ks_status_t) blade_session_read_unlock(blade_session_t *bs);
|
||||||
KS_DECLARE(ks_status_t) blade_session_write_lock(blade_session_t *bs, ks_bool_t block);
|
KS_DECLARE(ks_status_t) blade_session_write_lock(blade_session_t *bs, ks_bool_t block);
|
||||||
KS_DECLARE(ks_status_t) blade_session_write_unlock(blade_session_t *bs);
|
KS_DECLARE(ks_status_t) blade_session_write_unlock(blade_session_t *bs);
|
||||||
|
KS_DECLARE(ks_status_t) blade_session_properties_read_lock(blade_session_t *bs, ks_bool_t block);
|
||||||
|
KS_DECLARE(ks_status_t) blade_session_properties_read_unlock(blade_session_t *bs);
|
||||||
|
KS_DECLARE(ks_status_t) blade_session_properties_write_lock(blade_session_t *bs, ks_bool_t block);
|
||||||
|
KS_DECLARE(ks_status_t) blade_session_properties_write_unlock(blade_session_t *bs);
|
||||||
KS_DECLARE(void) blade_session_state_set(blade_session_t *bs, blade_session_state_t state);
|
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(void) blade_session_hangup(blade_session_t *bs);
|
||||||
KS_DECLARE(ks_bool_t) blade_session_terminating(blade_session_t *bs);
|
KS_DECLARE(ks_bool_t) blade_session_terminating(blade_session_t *bs);
|
||||||
|
|
|
@ -36,9 +36,10 @@
|
||||||
#include <blade.h>
|
#include <blade.h>
|
||||||
|
|
||||||
KS_BEGIN_EXTERN_C
|
KS_BEGIN_EXTERN_C
|
||||||
KS_DECLARE(ks_status_t) blade_space_create(blade_space_t **bsP, blade_handle_t *bh, const char *path);
|
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(ks_status_t) blade_space_destroy(blade_space_t **bsP);
|
KS_DECLARE(ks_status_t) blade_space_destroy(blade_space_t **bsP);
|
||||||
KS_DECLARE(blade_handle_t *) blade_space_handle_get(blade_space_t *bs);
|
KS_DECLARE(blade_handle_t *) blade_space_handle_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(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_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(ks_status_t) blade_space_methods_remove(blade_space_t *bs, blade_method_t *bm);
|
||||||
|
|
|
@ -55,6 +55,10 @@ 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(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(blade_space_t *) blade_handle_space_lookup(blade_handle_t *bh, const char *path);
|
||||||
|
|
||||||
|
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(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(blade_connection_t *) blade_handle_connections_get(blade_handle_t *bh, const char *cid);
|
||||||
|
@ -64,6 +68,10 @@ KS_DECLARE(ks_status_t) blade_handle_connections_remove(blade_connection_t *bc);
|
||||||
KS_DECLARE(blade_session_t *) blade_handle_sessions_get(blade_handle_t *bh, const char *sid);
|
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_add(blade_session_t *bs);
|
||||||
KS_DECLARE(ks_status_t) blade_handle_sessions_remove(blade_session_t *bs);
|
KS_DECLARE(ks_status_t) blade_handle_sessions_remove(blade_session_t *bs);
|
||||||
|
KS_DECLARE(void) blade_handle_sessions_send(blade_handle_t *bh, 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(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_add(blade_request_t *br);
|
||||||
|
|
|
@ -43,21 +43,24 @@ typedef struct blade_identity_s blade_identity_t;
|
||||||
typedef struct blade_module_s blade_module_t;
|
typedef struct blade_module_s blade_module_t;
|
||||||
typedef struct blade_module_callbacks_s blade_module_callbacks_t;
|
typedef struct blade_module_callbacks_s blade_module_callbacks_t;
|
||||||
typedef struct blade_transport_callbacks_s blade_transport_callbacks_t;
|
typedef struct blade_transport_callbacks_s blade_transport_callbacks_t;
|
||||||
|
typedef struct blade_session_callbacks_s blade_session_callbacks_t;
|
||||||
typedef struct blade_connection_s blade_connection_t;
|
typedef struct blade_connection_s blade_connection_t;
|
||||||
typedef struct blade_session_s blade_session_t;
|
typedef struct blade_session_s blade_session_t;
|
||||||
typedef struct blade_request_s blade_request_t;
|
typedef struct blade_request_s blade_request_t;
|
||||||
typedef struct blade_response_s blade_response_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_space_s blade_space_t;
|
||||||
typedef struct blade_method_s blade_method_t;
|
typedef struct blade_method_s blade_method_t;
|
||||||
|
|
||||||
|
|
||||||
typedef ks_bool_t (*blade_request_callback_t)(blade_request_t *breq);
|
|
||||||
typedef ks_bool_t (*blade_response_callback_t)(blade_response_t *bres);
|
|
||||||
|
|
||||||
typedef struct blade_datastore_s blade_datastore_t;
|
typedef struct blade_datastore_s blade_datastore_t;
|
||||||
|
|
||||||
typedef ks_bool_t (*blade_datastore_fetch_callback_t)(blade_datastore_t *bds, const void *data, uint32_t data_length, void *userdata);
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -94,6 +97,11 @@ typedef enum {
|
||||||
} blade_connection_rank_t;
|
} blade_connection_rank_t;
|
||||||
|
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
BLADE_SESSION_STATE_CONDITION_PRE,
|
||||||
|
BLADE_SESSION_STATE_CONDITION_POST,
|
||||||
|
} blade_session_state_condition_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
BLADE_SESSION_STATE_NONE,
|
BLADE_SESSION_STATE_NONE,
|
||||||
BLADE_SESSION_STATE_DESTROY,
|
BLADE_SESSION_STATE_DESTROY,
|
||||||
|
@ -145,6 +153,8 @@ struct blade_transport_callbacks_s {
|
||||||
blade_transport_state_callback_t onstate_ready_outbound;
|
blade_transport_state_callback_t onstate_ready_outbound;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef void (*blade_session_state_callback_t)(blade_session_t *bs, blade_session_state_condition_t condition, void *data);
|
||||||
|
|
||||||
|
|
||||||
struct blade_request_s {
|
struct blade_request_s {
|
||||||
blade_handle_t *handle;
|
blade_handle_t *handle;
|
||||||
|
@ -167,6 +177,14 @@ struct blade_response_s {
|
||||||
cJSON *message;
|
cJSON *message;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct blade_event_s {
|
||||||
|
blade_handle_t *handle;
|
||||||
|
ks_pool_t *pool;
|
||||||
|
const char *session_id;
|
||||||
|
|
||||||
|
cJSON *message;
|
||||||
|
};
|
||||||
|
|
||||||
KS_END_EXTERN_C
|
KS_END_EXTERN_C
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -13,6 +13,11 @@ bladec_SOURCES = bladec.c tap.c
|
||||||
bladec_CFLAGS = $(AM_CFLAGS)
|
bladec_CFLAGS = $(AM_CFLAGS)
|
||||||
bladec_LDADD = $(TEST_LDADD)
|
bladec_LDADD = $(TEST_LDADD)
|
||||||
|
|
||||||
|
check_PROGRAMS += blades
|
||||||
|
blades_SOURCES = blades.c tap.c
|
||||||
|
blades_CFLAGS = $(AM_CFLAGS)
|
||||||
|
blades_LDADD = $(TEST_LDADD)
|
||||||
|
|
||||||
|
|
||||||
TESTS=$(check_PROGRAMS)
|
TESTS=$(check_PROGRAMS)
|
||||||
|
|
||||||
|
|
|
@ -26,22 +26,22 @@ struct command_def_s {
|
||||||
command_callback callback;
|
command_callback callback;
|
||||||
};
|
};
|
||||||
|
|
||||||
void command_test(blade_handle_t *bh, char *args);
|
|
||||||
void command_quit(blade_handle_t *bh, char *args);
|
void command_quit(blade_handle_t *bh, char *args);
|
||||||
void command_store(blade_handle_t *bh, char *args);
|
|
||||||
void command_fetch(blade_handle_t *bh, char *args);
|
|
||||||
void command_connect(blade_handle_t *bh, char *args);
|
void command_connect(blade_handle_t *bh, char *args);
|
||||||
|
void command_chat(blade_handle_t *bh, char *args);
|
||||||
|
|
||||||
static const struct command_def_s command_defs[] = {
|
static const struct command_def_s command_defs[] = {
|
||||||
{ "test", command_test },
|
|
||||||
{ "quit", command_quit },
|
{ "quit", command_quit },
|
||||||
{ "store", command_store },
|
|
||||||
{ "fetch", command_fetch },
|
|
||||||
{ "connect", command_connect },
|
{ "connect", command_connect },
|
||||||
|
{ "chat", command_chat },
|
||||||
|
|
||||||
{ NULL, NULL }
|
{ 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);
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
blade_handle_t *bh = NULL;
|
blade_handle_t *bh = NULL;
|
||||||
|
@ -50,7 +50,7 @@ int main(int argc, char **argv)
|
||||||
blade_module_t *mod_wss = NULL;
|
blade_module_t *mod_wss = NULL;
|
||||||
//blade_identity_t *id = NULL;
|
//blade_identity_t *id = NULL;
|
||||||
const char *cfgpath = "bladec.cfg";
|
const char *cfgpath = "bladec.cfg";
|
||||||
|
const char *session_state_callback_id = NULL;
|
||||||
|
|
||||||
ks_global_set_default_logger(KS_LOG_LEVEL_DEBUG);
|
ks_global_set_default_logger(KS_LOG_LEVEL_DEBUG);
|
||||||
|
|
||||||
|
@ -91,8 +91,13 @@ int main(int argc, char **argv)
|
||||||
return EXIT_FAILURE;
|
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);
|
||||||
|
|
||||||
loop(bh);
|
loop(bh);
|
||||||
|
|
||||||
|
blade_handle_session_state_callback_unregister(bh, session_state_callback_id);
|
||||||
|
|
||||||
blade_module_wss_on_shutdown(mod_wss);
|
blade_module_wss_on_shutdown(mod_wss);
|
||||||
|
|
||||||
blade_module_wss_on_unload(mod_wss);
|
blade_module_wss_on_unload(mod_wss);
|
||||||
|
@ -104,7 +109,37 @@ int main(int argc, char **argv)
|
||||||
return 0;
|
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_session_pool_get(bs), &req, NULL, NULL, "blade.chat.join");
|
||||||
|
blade_session_send(bs, req, on_blade_chat_join_response);
|
||||||
|
cJSON_Delete(req);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void buffer_console_input(void)
|
void buffer_console_input(void)
|
||||||
{
|
{
|
||||||
|
@ -199,11 +234,6 @@ void process_console_input(blade_handle_t *bh, char *line)
|
||||||
if (!found) ks_log(KS_LOG_INFO, "Command '%s' unknown.\n", cmd);
|
if (!found) ks_log(KS_LOG_INFO, "Command '%s' unknown.\n", cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void command_test(blade_handle_t *bh, char *args)
|
|
||||||
{
|
|
||||||
ks_log(KS_LOG_DEBUG, "Hello World!\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void command_quit(blade_handle_t *bh, char *args)
|
void command_quit(blade_handle_t *bh, char *args)
|
||||||
{
|
{
|
||||||
ks_assert(bh);
|
ks_assert(bh);
|
||||||
|
@ -213,36 +243,6 @@ void command_quit(blade_handle_t *bh, char *args)
|
||||||
g_shutdown = KS_TRUE;
|
g_shutdown = KS_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void command_store(blade_handle_t *bh, char *args)
|
|
||||||
{
|
|
||||||
char *key;
|
|
||||||
char *data;
|
|
||||||
|
|
||||||
ks_assert(args);
|
|
||||||
|
|
||||||
parse_argument(&args, &key, ' ');
|
|
||||||
parse_argument(&args, &data, ' ');
|
|
||||||
|
|
||||||
blade_handle_datastore_store(bh, key, strlen(key), data, strlen(data) + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
ks_bool_t blade_datastore_fetch_callback(blade_datastore_t *bds, const void *data, uint32_t data_length, void *userdata)
|
|
||||||
{
|
|
||||||
ks_log(KS_LOG_INFO, "%s\n", data);
|
|
||||||
return KS_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void command_fetch(blade_handle_t *bh, char *args)
|
|
||||||
{
|
|
||||||
char *key;
|
|
||||||
|
|
||||||
ks_assert(args);
|
|
||||||
|
|
||||||
parse_argument(&args, &key, ' ');
|
|
||||||
|
|
||||||
blade_handle_datastore_fetch(bh, blade_datastore_fetch_callback, key, strlen(key), bh);
|
|
||||||
}
|
|
||||||
|
|
||||||
void command_connect(blade_handle_t *bh, char *args)
|
void command_connect(blade_handle_t *bh, char *args)
|
||||||
{
|
{
|
||||||
blade_connection_t *bc = NULL;
|
blade_connection_t *bc = NULL;
|
||||||
|
@ -257,3 +257,55 @@ void command_connect(blade_handle_t *bh, char *args)
|
||||||
|
|
||||||
blade_identity_destroy(&target);
|
blade_identity_destroy(&target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
{
|
||||||
|
ks_log(KS_LOG_DEBUG, "Received Chat Join Response!\n");
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
blade:
|
blade:
|
||||||
{
|
{
|
||||||
identity = "directory@domain";
|
identity = "peer@domain";
|
||||||
directory:
|
|
||||||
{
|
|
||||||
};
|
|
||||||
datastore:
|
datastore:
|
||||||
{
|
{
|
||||||
database:
|
database:
|
||||||
|
@ -11,18 +8,4 @@ blade:
|
||||||
path = ":mem:";
|
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
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
blade:
|
|
||||||
{
|
|
||||||
identity = "peer@domain";
|
|
||||||
datastore:
|
|
||||||
{
|
|
||||||
database:
|
|
||||||
{
|
|
||||||
path = ":mem:";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -0,0 +1,207 @@
|
||||||
|
#include "blade.h"
|
||||||
|
#include "tap.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define STDIO_FD(_fs) _fileno(_fs)
|
||||||
|
#define READ(_fd, _buffer, _count) _read(_fd, _buffer, _count)
|
||||||
|
#else
|
||||||
|
#define STDIO_FD(_fs) fileno(_fs)
|
||||||
|
#define READ(_fd, _buffer, _count) read(_fd, _buffer, _count)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define CONSOLE_INPUT_MAX 512
|
||||||
|
|
||||||
|
ks_bool_t g_shutdown = KS_FALSE;
|
||||||
|
char g_console_input[CONSOLE_INPUT_MAX];
|
||||||
|
size_t g_console_input_length = 0;
|
||||||
|
size_t g_console_input_eol = 0;
|
||||||
|
|
||||||
|
void loop(blade_handle_t *bh);
|
||||||
|
void process_console_input(blade_handle_t *bh, char *line);
|
||||||
|
|
||||||
|
typedef void (*command_callback)(blade_handle_t *bh, char *args);
|
||||||
|
|
||||||
|
struct command_def_s {
|
||||||
|
const char *cmd;
|
||||||
|
command_callback callback;
|
||||||
|
};
|
||||||
|
|
||||||
|
void command_quit(blade_handle_t *bh, char *args);
|
||||||
|
|
||||||
|
static const struct command_def_s command_defs[] = {
|
||||||
|
{ "quit", command_quit },
|
||||||
|
|
||||||
|
{ NULL, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
blade_handle_t *bh = NULL;
|
||||||
|
config_t config;
|
||||||
|
config_setting_t *config_blade = NULL;
|
||||||
|
blade_module_t *mod_wss = NULL;
|
||||||
|
blade_module_t *mod_chat = NULL;
|
||||||
|
//blade_identity_t *id = NULL;
|
||||||
|
const char *cfgpath = "blades.cfg";
|
||||||
|
|
||||||
|
ks_global_set_default_logger(KS_LOG_LEVEL_DEBUG);
|
||||||
|
|
||||||
|
blade_init();
|
||||||
|
|
||||||
|
blade_handle_create(&bh, NULL, NULL);
|
||||||
|
|
||||||
|
if (argc > 1) cfgpath = argv[1];
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blade_module_wss_on_load(&mod_wss, bh) != KS_STATUS_SUCCESS) {
|
||||||
|
ks_log(KS_LOG_ERROR, "Blade WSS module load failed\n");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
if (blade_module_wss_on_startup(mod_wss, config_blade) != KS_STATUS_SUCCESS) {
|
||||||
|
ks_log(KS_LOG_ERROR, "Blade WSS module startup failed\n");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
blade_module_chat_on_load(&mod_chat, bh);
|
||||||
|
blade_module_chat_on_startup(mod_chat, config_blade);
|
||||||
|
|
||||||
|
loop(bh);
|
||||||
|
|
||||||
|
blade_module_chat_on_shutdown(mod_chat);
|
||||||
|
blade_module_chat_on_unload(mod_chat);
|
||||||
|
|
||||||
|
blade_module_wss_on_shutdown(mod_wss);
|
||||||
|
|
||||||
|
blade_module_wss_on_unload(mod_wss);
|
||||||
|
|
||||||
|
blade_handle_destroy(&bh);
|
||||||
|
|
||||||
|
blade_shutdown();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void buffer_console_input(void)
|
||||||
|
{
|
||||||
|
ssize_t bytes = 0;
|
||||||
|
struct pollfd poll[1];
|
||||||
|
poll[0].fd = STDIO_FD(stdin);
|
||||||
|
poll[0].events = POLLIN | POLLERR;
|
||||||
|
|
||||||
|
if (ks_poll(poll, 1, 1) > 0) {
|
||||||
|
if (poll[0].revents & POLLIN) {
|
||||||
|
if ((bytes = READ(poll[0].fd, g_console_input + g_console_input_length, CONSOLE_INPUT_MAX - g_console_input_length)) <= 0) {
|
||||||
|
// @todo error
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
g_console_input_length += bytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop(blade_handle_t *bh)
|
||||||
|
{
|
||||||
|
while (!g_shutdown) {
|
||||||
|
ks_bool_t eol = KS_FALSE;
|
||||||
|
buffer_console_input();
|
||||||
|
|
||||||
|
for (; g_console_input_eol < g_console_input_length; ++g_console_input_eol) {
|
||||||
|
char c = g_console_input[g_console_input_eol];
|
||||||
|
if (c == '\r' || c == '\n') {
|
||||||
|
eol = KS_TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (eol) {
|
||||||
|
g_console_input[g_console_input_eol] = '\0';
|
||||||
|
process_console_input(bh, g_console_input);
|
||||||
|
g_console_input_eol++;
|
||||||
|
for (; g_console_input_eol < g_console_input_length; ++g_console_input_eol) {
|
||||||
|
char c = g_console_input[g_console_input_eol];
|
||||||
|
if (c != '\r' && c != '\n') break;
|
||||||
|
}
|
||||||
|
if (g_console_input_eol == g_console_input_length) g_console_input_eol = g_console_input_length = 0;
|
||||||
|
else {
|
||||||
|
memcpy(g_console_input, g_console_input + g_console_input_eol, g_console_input_length - g_console_input_eol);
|
||||||
|
g_console_input_length -= g_console_input_eol;
|
||||||
|
g_console_input_eol = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (g_console_input_length == CONSOLE_INPUT_MAX) {
|
||||||
|
// @todo lines must not exceed 512 bytes, treat as error and ignore buffer until next new line?
|
||||||
|
ks_assert(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void parse_argument(char **input, char **arg, char terminator)
|
||||||
|
{
|
||||||
|
char *tmp;
|
||||||
|
|
||||||
|
ks_assert(input);
|
||||||
|
ks_assert(*input);
|
||||||
|
ks_assert(arg);
|
||||||
|
|
||||||
|
tmp = *input;
|
||||||
|
*arg = tmp;
|
||||||
|
|
||||||
|
while (*tmp && *tmp != terminator) ++tmp;
|
||||||
|
if (*tmp == terminator) {
|
||||||
|
*tmp = '\0';
|
||||||
|
++tmp;
|
||||||
|
}
|
||||||
|
*input = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void process_console_input(blade_handle_t *bh, char *line)
|
||||||
|
{
|
||||||
|
char *args = line;
|
||||||
|
char *cmd = NULL;
|
||||||
|
ks_bool_t found = KS_FALSE;
|
||||||
|
|
||||||
|
ks_log(KS_LOG_DEBUG, "Output: %s\n", line);
|
||||||
|
|
||||||
|
parse_argument(&args, &cmd, ' ');
|
||||||
|
|
||||||
|
ks_log(KS_LOG_DEBUG, "Command: %s, Args: %s\n", cmd, args);
|
||||||
|
|
||||||
|
for (int32_t index = 0; command_defs[index].cmd; ++index) {
|
||||||
|
if (!strcmp(command_defs[index].cmd, cmd)) {
|
||||||
|
found = KS_TRUE;
|
||||||
|
command_defs[index].callback(bh, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) ks_log(KS_LOG_INFO, "Command '%s' unknown.\n", cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void command_quit(blade_handle_t *bh, char *args)
|
||||||
|
{
|
||||||
|
ks_assert(bh);
|
||||||
|
ks_assert(args);
|
||||||
|
|
||||||
|
ks_log(KS_LOG_DEBUG, "Shutting down\n");
|
||||||
|
g_shutdown = KS_TRUE;
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
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
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
Loading…
Reference in New Issue