#include "blade.h" #include "tap.h" #define CONSOLE_INPUT_MAX 512 ks_bool_t g_shutdown = KS_FALSE; 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 } }; //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) { blade_handle_t *bh = NULL; config_t config; config_setting_t *config_blade = NULL; //blade_module_t *mod_chat = NULL; //blade_identity_t *id = NULL; const char *cfgpath = "blades.cfg"; ks_global_set_default_logger(KS_LOG_LEVEL_DEBUG); blade_init(); blade_handle_create(&bh); //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; } // must occur before startup //blade_module_chat_create(&mod_chat, bh); //blade_handle_module_register(mod_chat); if (blade_handle_startup(bh, config_blade) != KS_STATUS_SUCCESS) { ks_log(KS_LOG_ERROR, "Blade startup failed\n"); return EXIT_FAILURE; } loop(bh); blade_handle_destroy(&bh); config_destroy(&config); blade_shutdown(); return 0; } void loop(blade_handle_t *bh) { char buf[CONSOLE_INPUT_MAX]; while (!g_shutdown) { if (!fgets(buf, CONSOLE_INPUT_MAX, stdin)) break; for (int index = 0; buf[index]; ++index) { if (buf[index] == '\r' || buf[index] == '\n') { buf[index] = '\0'; break; } } process_console_input(bh, buf); } } 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; } //static void blade_module_chat_cleanup(ks_pool_t *pool, void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type) //{ // blade_module_chat_t *bm_chat = (blade_module_chat_t *)ptr; // // ks_assert(bm_chat); // // switch (action) { // case KS_MPCL_ANNOUNCE: // break; // case KS_MPCL_TEARDOWN: // break; // case KS_MPCL_DESTROY: // break; // } //} // // //ks_status_t blade_module_chat_create(blade_module_t **bmP, blade_handle_t *bh) //{ // blade_module_chat_t *bm_chat = NULL; // ks_pool_t *pool = NULL; // // ks_assert(bmP); // ks_assert(bh); // // ks_pool_open(&pool); // ks_assert(pool); // // bm_chat = ks_pool_alloc(pool, sizeof(blade_module_chat_t)); // bm_chat->handle = bh; // bm_chat->pool = pool; // bm_chat->tpool = blade_handle_tpool_get(bh); // bm_chat->session_state_callback_id = NULL; // // ks_list_create(&bm_chat->participants, pool); // ks_assert(bm_chat->participants); // // blade_module_create(&bm_chat->module, bh, pool, bm_chat, &g_module_chat_callbacks); // ks_assert(bm_chat->module); // // ks_pool_set_cleanup(pool, bm_chat, NULL, blade_module_chat_cleanup); // // ks_log(KS_LOG_DEBUG, "Created\n"); // // *bmP = bm_chat->module; // // return KS_STATUS_SUCCESS; //} // // //ks_status_t blade_module_chat_config(blade_module_chat_t *bm_chat, config_setting_t *config) //{ // config_setting_t *chat = NULL; // // ks_assert(bm_chat); // ks_assert(config); // // if (!config_setting_is_group(config)) { // ks_log(KS_LOG_DEBUG, "!config_setting_is_group(config)\n"); // return KS_STATUS_FAIL; // } // // chat = config_setting_get_member(config, "chat"); // if (chat) { // } // // // // Configuration is valid, now assign it to the variables that are used // // If the configuration was invalid, then this does not get changed // // ks_log(KS_LOG_DEBUG, "Configured\n"); // // return KS_STATUS_SUCCESS; //} // //ks_status_t blade_module_chat_on_startup(blade_module_t *bm, config_setting_t *config) //{ // blade_module_chat_t *bm_chat = NULL; // blade_space_t *space = NULL; // blade_method_t *method = NULL; // // ks_assert(bm); // ks_assert(config); // // bm_chat = (blade_module_chat_t *)blade_module_data_get(bm); // // if (blade_module_chat_config(bm_chat, config) != KS_STATUS_SUCCESS) { // ks_log(KS_LOG_DEBUG, "blade_module_chat_config failed\n"); // return KS_STATUS_FAIL; // } // // blade_space_create(&space, bm_chat->handle, bm, "blade.chat"); // ks_assert(space); // // bm_chat->blade_chat_space = space; // // blade_method_create(&method, space, "join", blade_chat_join_request_handler); // ks_assert(method); // blade_space_methods_add(space, method); // // blade_method_create(&method, space, "leave", blade_chat_leave_request_handler); // ks_assert(method); // blade_space_methods_add(space, method); // // blade_method_create(&method, space, "send", blade_chat_send_request_handler); // ks_assert(method); // blade_space_methods_add(space, method); // // blade_handle_space_register(space); // // blade_handle_session_state_callback_register(blade_module_handle_get(bm), bm, blade_module_chat_on_session_state, &bm_chat->session_state_callback_id); // // ks_log(KS_LOG_DEBUG, "Started\n"); // // return KS_STATUS_SUCCESS; //} // //ks_status_t blade_module_chat_on_shutdown(blade_module_t *bm) //{ // blade_module_chat_t *bm_chat = NULL; // // ks_assert(bm); // // bm_chat = (blade_module_chat_t *)blade_module_data_get(bm); // ks_assert(bm_chat); // // if (bm_chat->session_state_callback_id) blade_handle_session_state_callback_unregister(blade_module_handle_get(bm), bm_chat->session_state_callback_id); // bm_chat->session_state_callback_id = NULL; // // if (bm_chat->blade_chat_space) blade_handle_space_unregister(bm_chat->blade_chat_space); // // ks_log(KS_LOG_DEBUG, "Stopped\n"); // // return KS_STATUS_SUCCESS; //} // //void blade_module_chat_on_session_state(blade_session_t *bs, blade_session_state_condition_t condition, void *data) //{ // blade_module_t *bm = NULL; // blade_module_chat_t *bm_chat = NULL; // // ks_assert(bs); // ks_assert(data); // // bm = (blade_module_t *)data; // bm_chat = (blade_module_chat_t *)blade_module_data_get(bm); // ks_assert(bm_chat); // // if (blade_session_state_get(bs) == BLADE_SESSION_STATE_HANGUP && condition == BLADE_SESSION_STATE_CONDITION_PRE) { // cJSON *props = NULL; // // ks_log(KS_LOG_DEBUG, "Removing session from chat participants if present\n"); // // props = blade_session_properties_get(bs); // ks_assert(props); // // cJSON_DeleteItemFromObject(props, "blade.chat.participant"); // // ks_list_delete(bm_chat->participants, blade_session_id_get(bs)); // @todo make copy of session id instead and search manually, also free the id // } //} // //ks_bool_t blade_chat_join_request_handler(blade_module_t *bm, blade_request_t *breq) //{ // blade_module_chat_t *bm_chat = NULL; // blade_session_t *bs = NULL; // cJSON *res = NULL; // cJSON *props = NULL; // cJSON *props_participant = NULL; // // ks_assert(bm); // ks_assert(breq); // // ks_log(KS_LOG_DEBUG, "Request Received!\n"); // // bm_chat = (blade_module_chat_t *)blade_module_data_get(bm); // ks_assert(bm_chat); // // bs = blade_handle_sessions_get(breq->handle, breq->session_id); // ks_assert(bs); // // // @todo properties only used to demonstrate a flexible container for session data, should just rely on the participants list/hash // blade_session_properties_write_lock(bs, KS_TRUE); // // props = blade_session_properties_get(bs); // ks_assert(props); // // props_participant = cJSON_GetObjectItem(props, "blade.chat.participant"); // if (props_participant && props_participant->type == cJSON_True) { // ks_log(KS_LOG_DEBUG, "Session (%s) attempted to join chat but is already a participant\n", blade_session_id_get(bs)); // blade_rpc_error_create(&res, NULL, breq->message_id, -10000, "Already a participant of chat"); // } // else { // ks_log(KS_LOG_DEBUG, "Session (%s) joined chat\n", blade_session_id_get(bs)); // // if (props_participant) props_participant->type = cJSON_True; // else cJSON_AddTrueToObject(props, "blade.chat.participant"); // // ks_list_append(bm_chat->participants, blade_session_id_get(bs)); // @todo make copy of session id instead and cleanup when removed // // blade_rpc_response_create(&res, NULL, breq->message_id); // // // @todo create an event to send to participants when a session joins and leaves, send after main response though // } // // blade_session_properties_write_unlock(bs); // // blade_session_send(bs, res, NULL); // // blade_session_read_unlock(bs); // // cJSON_Delete(res); // // return KS_FALSE; //} // //ks_bool_t blade_chat_leave_request_handler(blade_module_t *bm, blade_request_t *breq) //{ // blade_module_chat_t *bm_chat = NULL; // blade_session_t *bs = NULL; // cJSON *res = NULL; // cJSON *props = NULL; // cJSON *props_participant = NULL; // // ks_assert(bm); // ks_assert(breq); // // ks_log(KS_LOG_DEBUG, "Request Received!\n"); // // bm_chat = (blade_module_chat_t *)blade_module_data_get(bm); // ks_assert(bm_chat); // // bs = blade_handle_sessions_get(breq->handle, breq->session_id); // ks_assert(bs); // // blade_session_properties_write_lock(bs, KS_TRUE); // // props = blade_session_properties_get(bs); // ks_assert(props); // // props_participant = cJSON_GetObjectItem(props, "blade.chat.participant"); // if (!props_participant || props_participant->type == cJSON_False) { // ks_log(KS_LOG_DEBUG, "Session (%s) attempted to leave chat but is not a participant\n", blade_session_id_get(bs)); // blade_rpc_error_create(&res, NULL, breq->message_id, -10000, "Not a participant of chat"); // } // else { // ks_log(KS_LOG_DEBUG, "Session (%s) left chat\n", blade_session_id_get(bs)); // // cJSON_DeleteItemFromObject(props, "blade.chat.participant"); // // ks_list_delete(bm_chat->participants, blade_session_id_get(bs)); // @todo make copy of session id instead and search manually, also free the id // // blade_rpc_response_create(&res, NULL, breq->message_id); // // // @todo create an event to send to participants when a session joins and leaves, send after main response though // } // // blade_session_properties_write_unlock(bs); // // blade_session_send(bs, res, NULL); // // blade_session_read_unlock(bs); // // cJSON_Delete(res); // // return KS_FALSE; //} // //ks_bool_t blade_chat_send_request_handler(blade_module_t *bm, blade_request_t *breq) //{ // blade_module_chat_t *bm_chat = NULL; // blade_session_t *bs = NULL; // cJSON *params = NULL; // cJSON *res = NULL; // cJSON *event = NULL; // const char *message = NULL; // ks_bool_t sendevent = KS_FALSE; // // ks_assert(bm); // ks_assert(breq); // // ks_log(KS_LOG_DEBUG, "Request Received!\n"); // // bm_chat = (blade_module_chat_t *)blade_module_data_get(bm); // ks_assert(bm_chat); // // params = cJSON_GetObjectItem(breq->message, "params"); // @todo cache this in blade_request_t for quicker/easier access // if (!params) { // ks_log(KS_LOG_DEBUG, "Session (%s) attempted to send chat message with no 'params' object\n", blade_session_id_get(bs)); // blade_rpc_error_create(&res, NULL, breq->message_id, -32602, "Missing params object"); // } // else if (!(message = cJSON_GetObjectCstr(params, "message"))) { // ks_log(KS_LOG_DEBUG, "Session (%s) attempted to send chat message with no 'message'\n", blade_session_id_get(bs)); // blade_rpc_error_create(&res, NULL, breq->message_id, -32602, "Missing params message string"); // } // // bs = blade_handle_sessions_get(breq->handle, breq->session_id); // ks_assert(bs); // // if (!res) { // blade_rpc_response_create(&res, NULL, breq->message_id); // sendevent = KS_TRUE; // } // blade_session_send(bs, res, NULL); // // blade_session_read_unlock(bs); // // cJSON_Delete(res); // // if (sendevent) { // blade_rpc_event_create(&event, &res, "blade.chat.message"); // ks_assert(event); // cJSON_AddStringToObject(res, "from", breq->session_id); // @todo should really be the identity, but we don't have that in place yet // cJSON_AddStringToObject(res, "message", message); // // blade_handle_sessions_send(breq->handle, bm_chat->participants, NULL, event); // // cJSON_Delete(event); // } // // return KS_FALSE; //} /* For Emacs: * Local Variables: * 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: */