* This module executes JavaScript using Google's V8 JavaScript engine.
*
* It extends the available JavaScript classes with the following FS related classes;
- * CoreDB Adds features to access the core DB (SQLite) in FreeSWITCH. (on request only)
- * CURL Adds some extra methods for CURL access. (on request only)
- * DTMF Object that holds information about a DTMF event.
- * Event Object that holds information about a FreeSWITCH event.
- * File Class to reflect the Spidermonkey built-in class "File". Not yet implemented! (on request only)
- * FileIO Simple class for basic file IO.
- * ODBC Adds features to access any ODBC available database in the system. (on request only)
- * PCRE Adds features to do regexp using the PCRE implementeation.
- * Request Class for extra features during API call from FS (using 'jsapi' function). This class cannot be constructed from JS code!
- * The Request class is only availble when started from 'jsapi' FS command, and only inside the predefined variable 'request'.
- * Session Main FS class, includes all functions to handle a session.
- * Socket Class for communicating over a TCP/IP socket. (on request only)
- * TeleTone Class used to play tones to a FS channel. (on request only)
- * XML XML parsing class, using the features from switch_xml. (on request only)
+ * CoreDB Adds features to access the core DB (SQLite) in FreeSWITCH. (on request only)
+ * CURL Adds some extra methods for CURL access. (on request only)
+ * DTMF Object that holds information about a DTMF event.
+ * Event Object that holds information about a FreeSWITCH event.
+ * EventHandler Features for handling FS events.
+ * File Class to reflect the Spidermonkey built-in class "File". Not yet implemented! (on request only)
+ * FileIO Simple class for basic file IO.
+ * ODBC Adds features to access any ODBC available database in the system. (on request only)
+ * PCRE Adds features to do regexp using the PCRE implementeation.
+ * Request Class for extra features during API call from FS (using 'jsapi' function). This class cannot be constructed from JS code!
+ * The Request class is only availble when started from 'jsapi' FS command, and only inside the predefined variable 'request'.
+ * Session Main FS class, includes all functions to handle a session.
+ * Socket Class for communicating over a TCP/IP socket. (on request only)
+ * TeleTone Class used to play tones to a FS channel. (on request only)
+ * XML XML parsing class, using the features from switch_xml. (on request only)
*
* Some of the classes above are available on request only, using the command [use('Class');] before using the class for the first time.
*
#include "fsglobal.hpp"
/* Common JavaScript classes */
-#include "fsrequest.hpp" /* Only loaded during 'jsapi' call */
+#include "fsrequest.hpp" /* Only loaded during 'jsapi' and 'jsjson' call */
#include "fspcre.hpp"
#include "fsevent.hpp"
#include "fssession.hpp"
#include "fsodbc.hpp"
#include "fsxml.hpp"
#include "fsfile.hpp"
+#include "fseventhandler.hpp"
+
+#include <set>
using namespace std;
using namespace v8;
/* Module manager for loadable modules */
module_manager_t module_manager = { 0 };
-/* Loadable module struct */
+/* Global data for this module */
+typedef struct {
+ switch_memory_pool_t *pool;
+ switch_mutex_t *event_mutex;
+ switch_event_node_t *event_node;
+ set<FSEventHandler *> *event_handlers;
+} mod_v8_global_t;
+
+mod_v8_global_t globals = { 0 };
+
+/* Loadable module struct, used for external extension modules */
typedef struct {
char *filename;
void *lib;
const char *EXT = ".SO";
#endif
- memset(&module_manager, 0, sizeof(module_manager));
switch_core_new_memory_pool(&module_manager.pool);
switch_core_hash_init(&module_manager.load_hash, module_manager.pool);
switch_thread_create(&thread, thd_attr, v8_thread_run, task, pool);
}
+void v8_add_event_handler(void *event_handler)
+{
+ FSEventHandler *eh = static_cast<FSEventHandler *>(event_handler);
+
+ if (eh) {
+ switch_mutex_lock(globals.event_mutex);
+ globals.event_handlers->insert(eh);
+ switch_mutex_unlock(globals.event_mutex);
+ }
+}
+
+void v8_remove_event_handler(void *event_handler)
+{
+ FSEventHandler *eh = static_cast<FSEventHandler *>(event_handler);
+
+ if (eh) {
+ switch_mutex_lock(globals.event_mutex);
+
+ set<FSEventHandler *>::iterator it = globals.event_handlers->find(eh);
+
+ if (it != globals.event_handlers->end()) {
+ globals.event_handlers->erase(it);
+ }
+
+ switch_mutex_unlock(globals.event_mutex);
+ }
+}
+
SWITCH_BEGIN_EXTERN_C
+static void event_handler(switch_event_t *event)
+{
+ if (event) {
+ switch_mutex_lock(globals.event_mutex);
+
+ set<FSEventHandler *>::iterator it;
+
+ for (it = globals.event_handlers->begin(); it != globals.event_handlers->end(); ++it) {
+ if (*it) {
+ (*it)->QueueEvent(event);
+ }
+ }
+
+ switch_mutex_unlock(globals.event_mutex);
+ }
+}
+
SWITCH_STANDARD_API(jsapi_function)
{
char *path_info = NULL;
switch_chat_application_interface_t *chat_app_interface;
switch_json_api_interface_t *json_api_interface;
+ if (switch_event_bind_removable(modname, SWITCH_EVENT_ALL, SWITCH_EVENT_SUBCLASS_ANY, event_handler, NULL, &globals.event_node) != SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind to events\n");
+ return SWITCH_STATUS_GENERR;
+ }
+
+ if (switch_core_new_memory_pool(&globals.pool) != SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "OH OH no pool\n");
+ return SWITCH_STATUS_GENERR;
+ }
+
+ switch_mutex_init(&globals.event_mutex, SWITCH_MUTEX_NESTED, globals.pool);
+ globals.event_handlers = new set<FSEventHandler *>();
+
if (load_modules() != SWITCH_STATUS_SUCCESS) {
return SWITCH_STATUS_FALSE;
}
v8_mod_init_built_in(FSTeleTone::GetModuleInterface());
v8_mod_init_built_in(FSXML::GetModuleInterface());
v8_mod_init_built_in(FSFile::GetModuleInterface());
+ v8_mod_init_built_in(FSEventHandler::GetModuleInterface());
/* connect my internal structure to the blank pointer passed to me */
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_v8_shutdown)
{
+ switch_event_unbind(&globals.event_node);
+
+ delete globals.event_handlers;
+ switch_mutex_destroy(globals.event_mutex);
+ switch_core_destroy_memory_pool(&globals.pool);
+
switch_core_hash_destroy(&module_manager.load_hash);
return SWITCH_STATUS_SUCCESS;
--- /dev/null
+/*
+ * mod_v8 for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2013-2014, Peter Olsson <peter@olssononline.se>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mod_v8 for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Peter Olsson <peter@olssononline.se>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Peter Olsson <peter@olssononline.se>
+ *
+ * fseventhandler.cpp -- JavaScript EventHandler class
+ *
+ */
+
+#include "fseventhandler.hpp"
+#include "fsevent.hpp"
+#include "fssession.hpp"
+
+#define MAX_QUEUE_LEN 100000
+
+using namespace std;
+using namespace v8;
+
+typedef struct {\r
+ char *cmd;\r
+ char *arg;\r
+ char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1];\r
+ int ack;\r
+ switch_memory_pool_t *pool;\r
+} api_command_struct_t;\r
+
+static const char js_class_name[] = "EventHandler";
+
+FSEventHandler::~FSEventHandler(void)
+{
+ v8_remove_event_handler(this);
+
+ if (_event_hash) switch_core_hash_destroy(&_event_hash);
+
+ if (_event_queue) {
+ void *pop;
+
+ while (switch_queue_trypop(_event_queue, &pop) == SWITCH_STATUS_SUCCESS) {
+ switch_event_t *pevent = (switch_event_t *) pop;
+ if (pevent) {
+ switch_event_destroy(&pevent);
+ }
+ }
+ }
+
+ if (_filters) switch_event_destroy(&_filters);
+ if (_mutex) switch_mutex_destroy(_mutex);
+ if (_pool) switch_core_destroy_memory_pool(&_pool);
+}
+
+void FSEventHandler::Init()
+{
+ if (switch_core_new_memory_pool(&_pool) != SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "OH OH no pool\n");
+ return;
+ }
+
+ switch_mutex_init(&_mutex, SWITCH_MUTEX_NESTED, _pool);
+ switch_core_hash_init(&_event_hash, _pool);
+ switch_queue_create(&_event_queue, MAX_QUEUE_LEN, _pool);
+
+ _filters = NULL;
+ memset(&_event_list, 0, sizeof(_event_list));
+
+ v8_add_event_handler(this);
+}
+
+string FSEventHandler::GetJSClassName()
+{
+ return js_class_name;
+}
+
+void FSEventHandler::QueueEvent(switch_event_t *event)
+{
+ switch_event_t *clone;
+ int send = 0;
+
+ switch_mutex_lock(_mutex);
+
+ if (_event_list[SWITCH_EVENT_ALL]) {\r
+ send = 1;\r
+ } else if ((_event_list[event->event_id])) {\r
+ if (event->event_id != SWITCH_EVENT_CUSTOM || !event->subclass_name || (switch_core_hash_find(_event_hash, event->subclass_name))) {\r
+ send = 1;\r
+ }\r
+ }\r
+\r
+ if (send) {\r
+ if (_filters && _filters->headers) {\r
+ switch_event_header_t *hp;\r
+ const char *hval;\r
+\r
+ send = 0;\r
+\r
+ for (hp = _filters->headers; hp; hp = hp->next) {\r
+ if ((hval = switch_event_get_header(event, hp->name))) {\r
+ const char *comp_to = hp->value;\r
+ int pos = 1, cmp = 0;\r
+\r
+ while (comp_to && *comp_to) {\r
+ if (*comp_to == '+') {\r
+ pos = 1;\r
+ } else if (*comp_to == '-') {\r
+ pos = 0;\r
+ } else if (*comp_to != ' ') {\r
+ break;\r
+ }\r
+ comp_to++;\r
+ }\r
+\r
+ if (send && pos) {\r
+ continue;\r
+ }\r
+\r
+ if (!comp_to) {\r
+ continue;\r
+ }\r
+\r
+ if (*hp->value == '/') {\r
+ switch_regex_t *re = NULL;\r
+ int ovector[30];\r
+ cmp = !!switch_regex_perform(hval, comp_to, &re, ovector, sizeof(ovector) / sizeof(ovector[0]));\r
+ switch_regex_safe_free(re);\r
+ } else {\r
+ cmp = !strcasecmp(hval, comp_to);\r
+ }\r
+\r
+ if (cmp) {\r
+ if (pos) {\r
+ send = 1;\r
+ } else {\r
+ send = 0;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ switch_mutex_unlock(_mutex);
+
+ if (send) {
+ if (switch_event_dup(&clone, event) == SWITCH_STATUS_SUCCESS) {
+
+ if (switch_queue_trypush(_event_queue, clone) == SWITCH_STATUS_SUCCESS) {
+ // TODO
+ /*if (l->lost_events) {
+ int le = l->lost_events;
+ l->lost_events = 0;
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(l->session), SWITCH_LOG_CRIT, "Lost %d events!\n", le);
+ }*/
+ } else {
+ /*if (++l->lost_events > MAX_MISSED) {
+ kill_listener(l, NULL);
+ }*/
+ switch_event_destroy(&clone);
+ }
+ } else {
+ ////switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(l->session), SWITCH_LOG_ERROR, "Memory Error!\n");
+ }
+ }
+}
+
+static char *MARKER = "1";
+
+void FSEventHandler::DoSubscribe(const v8::FunctionCallbackInfo<v8::Value>& info)
+{
+ int i, custom = 0;
+ bool ret = false;
+
+ for (i = 0; i < info.Length(); i++) {
+ String::Utf8Value str(info[i]);
+ switch_event_types_t etype;
+
+ if (custom) {\r
+ switch_mutex_lock(_mutex);\r
+ switch_core_hash_insert(_event_hash, js_safe_str(*str), MARKER);\r
+ switch_mutex_unlock(_mutex);\r
+ } else if (switch_name_event(js_safe_str(*str), &etype) == SWITCH_STATUS_SUCCESS) {\r
+ ret = true;\r
+\r
+ if (etype == SWITCH_EVENT_ALL) {\r
+ uint32_t x = 0;\r
+ for (x = 0; x < SWITCH_EVENT_ALL; x++) {\r
+ _event_list[x] = 1;\r
+ }\r
+ }\r
+\r
+ if (etype <= SWITCH_EVENT_ALL) {\r
+ _event_list[etype] = 1;\r
+ }\r
+\r
+ if (etype == SWITCH_EVENT_CUSTOM) {\r
+ custom++;\r
+ }\r
+ }\r
+ }
+
+ info.GetReturnValue().Set(ret);
+}
+
+void *FSEventHandler::Construct(const v8::FunctionCallbackInfo<v8::Value>& info)
+{
+ FSEventHandler *obj = new FSEventHandler(info);
+ obj->DoSubscribe(info);
+ return obj;
+}
+
+JS_EVENTHANDLER_FUNCTION_IMPL(Subscribe)
+{
+ DoSubscribe(info);
+}
+
+JS_EVENTHANDLER_FUNCTION_IMPL(UnSubscribe)
+{
+ int i, custom = 0;
+ bool ret = false;
+
+ for (i = 0; i < info.Length(); i++) {
+ String::Utf8Value str(info[i]);
+ switch_event_types_t etype;
+
+ if (custom) {\r
+ switch_mutex_lock(_mutex);\r
+ switch_core_hash_delete(_event_hash, js_safe_str(*str));\r
+ switch_mutex_unlock(_mutex);\r
+ } else if (switch_name_event(js_safe_str(*str), &etype) == SWITCH_STATUS_SUCCESS) {\r
+ uint32_t x = 0;\r
+ ret = true;\r
+\r
+ if (etype == SWITCH_EVENT_CUSTOM) {\r
+ custom++;\r
+ } else if (etype == SWITCH_EVENT_ALL) {\r
+ for (x = 0; x <= SWITCH_EVENT_ALL; x++) {\r
+ _event_list[x] = 0;\r
+ }\r
+ } else {\r
+ if (_event_list[SWITCH_EVENT_ALL]) {\r
+ _event_list[SWITCH_EVENT_ALL] = 0;\r
+ for (x = 0; x < SWITCH_EVENT_ALL; x++) {\r
+ _event_list[x] = 1;\r
+ }\r
+ }\r
+ _event_list[etype] = 0;\r
+ }\r
+ }\r
+ }
+
+ info.GetReturnValue().Set(ret);
+}
+
+JS_EVENTHANDLER_FUNCTION_IMPL(DeleteFilter)
+{
+ if (info.Length() < 1) {
+ info.GetReturnValue().Set(false);
+ } else {
+ String::Utf8Value str(info[0]);
+ const char *headerName = js_safe_str(*str);
+
+ if (zstr(headerName)) {\r
+ info.GetReturnValue().Set(false);\r
+ return;\r
+ }\r
+
+ switch_mutex_lock(_mutex);
+
+ if (!_filters) {\r
+ switch_event_create_plain(&_filters, SWITCH_EVENT_CLONE);\r
+ }\r
+\r
+ if (!strcasecmp(headerName, "all")) {\r
+ switch_event_destroy(&_filters);\r
+ switch_event_create_plain(&_filters, SWITCH_EVENT_CLONE);\r
+ } else {\r
+ switch_event_del_header(_filters, headerName);\r
+ }\r
+\r
+ info.GetReturnValue().Set(true);\r
+\r
+ switch_mutex_unlock(_mutex);\r
+ }
+}
+
+JS_EVENTHANDLER_FUNCTION_IMPL(AddFilter)
+{
+ if (info.Length() < 2) {
+ info.GetReturnValue().Set(false);
+ } else {
+ String::Utf8Value str1(info[0]);
+ String::Utf8Value str2(info[1]);
+ const char *headerName = js_safe_str(*str1);
+ const char *headerVal = js_safe_str(*str2);
+
+ if (zstr(headerName) || zstr(headerVal)) {\r
+ info.GetReturnValue().Set(false);\r
+ return;\r
+ }\r
+
+ switch_mutex_lock(_mutex);
+
+ if (!_filters) {\r
+ switch_event_create_plain(&_filters, SWITCH_EVENT_CLONE);\r
+ }\r
+\r
+ switch_event_add_header_string(_filters, SWITCH_STACK_BOTTOM, headerName, headerVal);\r
+\r
+ info.GetReturnValue().Set(true);\r
+\r
+ switch_mutex_unlock(_mutex);\r
+ }
+}
+
+JS_EVENTHANDLER_FUNCTION_IMPL(GetEvent)
+{
+ void *pop = NULL;
+ int timeout = 0;
+ switch_event_t *pevent = NULL;
+
+ if (info.Length() > 0 && !info[0].IsEmpty()) {
+ timeout = info[0]->Int32Value();
+ }
+
+ if (timeout > 0) {
+ if (switch_queue_pop_timeout(_event_queue, &pop, (switch_interval_time_t) timeout * 1000) == SWITCH_STATUS_SUCCESS && pop) {
+ pevent = (switch_event_t *) pop;
+ }
+ } else {
+ if (switch_queue_trypop(_event_queue, &pop) == SWITCH_STATUS_SUCCESS && pop) {
+ pevent = (switch_event_t *) pop;
+ }
+ }
+
+ if (pevent) {
+ FSEvent *evt = new FSEvent(info);
+ evt->SetEvent(pevent, 0);
+ evt->RegisterInstance(info.GetIsolate(), "", true);
+ info.GetReturnValue().Set(evt->GetJavaScriptObject());
+ } else {
+ info.GetReturnValue().Set(Null(info.GetIsolate()));
+ }
+}
+
+JS_EVENTHANDLER_FUNCTION_IMPL(SendEvent)
+{
+ if (info.Length() == 0) {
+ info.GetReturnValue().Set(false);
+ } else {
+ if (!info[0].IsEmpty() && info[0]->IsObject()) {
+ FSEvent *evt = JSBase::GetInstance<FSEvent>(info[0]->ToObject());
+ switch_event_t **event;
+
+ if (!evt || !(event = evt->GetEvent())) {
+ info.GetReturnValue().Set(false);
+ } else {
+ string session_uuid;
+
+ if (info.Length() > 1) {
+ if (!info[1].IsEmpty() && info[1]->IsObject()) {
+ /* The second argument is a session object */
+ FSSession *sess = JSBase::GetInstance<FSSession>(info[1]->ToObject());
+ switch_core_session_t *tmp;
+
+ if (sess && (tmp = sess->GetSession())) {
+ session_uuid = switch_core_session_get_uuid(tmp);
+ }
+ } else {
+ /* The second argument is a session uuid string */
+ String::Utf8Value str(info[1]);
+ session_uuid = js_safe_str(*str);
+ }
+ }
+
+ if (session_uuid.length() > 0) {
+ /* This is a session event */
+ switch_core_session_t *session;
+ switch_status_t status = SWITCH_STATUS_FALSE;
+
+ if ((session = switch_core_session_locate(session_uuid.c_str()))) {\r
+ if ((status = switch_core_session_queue_private_event(session, event, SWITCH_FALSE)) == SWITCH_STATUS_SUCCESS) {\r
+ info.GetReturnValue().Set(true);\r
+ } else {\r
+ info.GetReturnValue().Set(false);\r
+ }\r
+ switch_core_session_rwunlock(session);\r
+ } else {\r
+ info.GetReturnValue().Set(false);\r
+ // TODO LOGGING\r
+ //switch_snprintf(reply, reply_len, "-ERR invalid session id [%s]", switch_str_nil(uuid));\r
+ }\r
+ } else {
+ /* "Normal" event */
+ // TODO LOGGING
+ switch_event_fire(event);
+ }
+ }
+ }
+ }
+}
+
+JS_EVENTHANDLER_FUNCTION_IMPL(ExecuteApi)
+{
+ if (info.Length() > 0) {
+ String::Utf8Value str(info[0]);
+ const char *cmd = js_safe_str(*str);
+ string arg;
+ switch_stream_handle_t stream = { 0 };
+
+ if (!strcasecmp(cmd, "jsapi")) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Possible recursive API Call is not allowed\n");
+ info.GetReturnValue().Set(false);
+ return;
+ }
+
+ if (info.Length() > 1) {
+ String::Utf8Value str2(info[1]);
+ arg = js_safe_str(*str2);
+ }
+
+ SWITCH_STANDARD_STREAM(stream);
+ switch_api_execute(cmd, arg.c_str(), NULL, &stream);
+
+ info.GetReturnValue().Set(String::NewFromUtf8(info.GetIsolate(), switch_str_nil((char *) stream.data)));
+ switch_safe_free(stream.data);
+ } else {
+ info.GetReturnValue().Set(String::NewFromUtf8(info.GetIsolate(), "-ERR"));
+ }
+}
+
+static void *SWITCH_THREAD_FUNC api_exec(switch_thread_t *thread, void *obj)\r
+{\r
+ api_command_struct_t *acs = (api_command_struct_t *) obj;\r
+ switch_stream_handle_t stream = { 0 };\r
+ char *reply, *freply = NULL;\r
+ switch_status_t status;\r
+ switch_event_t *event;\r
+\r
+ if (!acs) {\r
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Internal error.\n");\r
+ return NULL;\r
+ }\r
+\r
+ acs->ack = 1;\r
+\r
+ SWITCH_STANDARD_STREAM(stream);\r
+\r
+ status = switch_api_execute(acs->cmd, acs->arg, NULL, &stream);\r
+\r
+ if (status == SWITCH_STATUS_SUCCESS) {\r
+ reply = (char *)stream.data;\r
+ } else {\r
+ freply = switch_mprintf("-ERR %s Command not found!\n", acs->cmd);\r
+ reply = freply;\r
+ }\r
+\r
+ if (!reply) {\r
+ reply = "Command returned no output!";\r
+ }\r
+\r
+ if (switch_event_create(&event, SWITCH_EVENT_BACKGROUND_JOB) == SWITCH_STATUS_SUCCESS) {\r
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Job-UUID", acs->uuid_str);\r
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Job-Command", acs->cmd);\r
+ if (acs->arg) {\r
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Job-Command-Arg", acs->arg);\r
+ }\r
+ switch_event_add_body(event, "%s", reply);\r
+ switch_event_fire(&event);\r
+ }\r
+\r
+ switch_safe_free(stream.data);\r
+ switch_safe_free(freply);\r
+\r
+ switch_memory_pool_t *pool = acs->pool;\r
+ if (acs->ack == -1) {\r
+ int sanity = 2000;\r
+ while (acs->ack == -1) {\r
+ switch_cond_next();\r
+ if (--sanity <= 0)\r
+ break;\r
+ }\r
+ }\r
+\r
+ acs = NULL;\r
+ switch_core_destroy_memory_pool(&pool);\r
+ pool = NULL;\r
+\r
+ return NULL;\r
+}\r
+
+JS_EVENTHANDLER_FUNCTION_IMPL(ExecuteBgApi)
+{
+ string cmd;\r
+ string arg;\r
+ string jobuuid;\r
+ api_command_struct_t *acs = NULL;\r
+ switch_memory_pool_t *pool;\r
+ switch_thread_t *thread;\r
+ switch_threadattr_t *thd_attr = NULL;\r
+ switch_uuid_t uuid;\r
+ int sanity = 2000;\r
+\r
+ if (info.Length() > 0) {
+ String::Utf8Value str(info[0]);
+ cmd = js_safe_str(*str);
+
+ if (info.Length() > 1) {
+ String::Utf8Value str2(info[1]);
+ arg = js_safe_str(*str2);
+ }
+
+ if (info.Length() > 2) {
+ String::Utf8Value str2(info[2]);
+ jobuuid = js_safe_str(*str2);
+ }
+ } else {
+ info.GetReturnValue().Set(false);
+ return;
+ }
+
+ if (cmd.length() == 0) {
+ info.GetReturnValue().Set(false);
+ return;
+ }
+\r
+ switch_core_new_memory_pool(&pool);\r
+ acs = (api_command_struct_t *)switch_core_alloc(pool, sizeof(*acs));\r
+ switch_assert(acs);\r
+ acs->pool = pool;\r
+\r
+ acs->cmd = switch_core_strdup(acs->pool, cmd.c_str());\r
+\r
+ if (arg.c_str()) {\r
+ acs->arg = switch_core_strdup(acs->pool, arg.c_str());\r
+ }\r
+\r
+ switch_threadattr_create(&thd_attr, acs->pool);\r
+ switch_threadattr_detach_set(thd_attr, 1);\r
+ switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);\r
+\r
+ if (jobuuid.length() > 0) {\r
+ switch_copy_string(acs->uuid_str, jobuuid.c_str(), sizeof(acs->uuid_str));\r
+ } else {\r
+ switch_uuid_get(&uuid);\r
+ switch_uuid_format(acs->uuid_str, &uuid);\r
+ }\r
+\r
+ info.GetReturnValue().Set(String::NewFromUtf8(info.GetIsolate(), acs->uuid_str));\r
+\r
+ switch_thread_create(&thread, thd_attr, api_exec, acs, acs->pool);\r
+\r
+ while (!acs->ack) {\r
+ switch_cond_next();\r
+ if (--sanity <= 0)\r
+ break;\r
+ }\r
+\r
+ if (acs->ack == -1) {\r
+ acs->ack--;\r
+ }\r
+}
+
+JS_EVENTHANDLER_FUNCTION_IMPL_STATIC(Destroy)
+{
+ JS_CHECK_SCRIPT_STATE();
+
+ FSEventHandler *obj = JSBase::GetInstance<FSEventHandler>(info.Holder());
+
+ if (obj) {
+ delete obj;
+ info.GetReturnValue().Set(true);
+ } else {
+ info.GetReturnValue().Set(false);
+ }
+}
+
+JS_EVENTHANDLER_GET_PROPERTY_IMPL_STATIC(GetReadyProperty)
+{
+ JS_CHECK_SCRIPT_STATE();
+
+ FSEventHandler *obj = JSBase::GetInstance<FSEventHandler>(info.Holder());
+
+ if (obj) {
+ info.GetReturnValue().Set(true);
+ } else {
+ info.GetReturnValue().Set(false);
+ }
+}
+
+static const js_function_t eventhandler_methods[] = {
+ {"subscribe", FSEventHandler::Subscribe},
+ {"unSubscribe", FSEventHandler::UnSubscribe},
+ {"addFilter", FSEventHandler::AddFilter},
+ {"deleteFilter", FSEventHandler::DeleteFilter},
+ {"getEvent", FSEventHandler::GetEvent},
+ {"sendEvent", FSEventHandler::SendEvent},
+ {"executeApi", FSEventHandler::ExecuteApi},
+ {"executeBgApi", FSEventHandler::ExecuteBgApi},
+ {"destroy", FSEventHandler::Destroy},
+ {0}
+};
+
+static const js_property_t eventhandler_props[] = {
+ {"ready", FSEventHandler::GetReadyProperty, JSBase::DefaultSetProperty},
+ {0}
+};
+
+static const js_class_definition_t eventhandler_desc = {
+ js_class_name,
+ FSEventHandler::Construct,
+ eventhandler_methods,
+ eventhandler_props
+};
+
+static switch_status_t eventhandler_load(const v8::FunctionCallbackInfo<Value>& info)
+{
+ JSBase::Register(info.GetIsolate(), &eventhandler_desc);
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static const v8_mod_interface_t eventhandler_module_interface = {
+ /*.name = */ js_class_name,
+ /*.js_mod_load */ eventhandler_load
+};
+
+const v8_mod_interface_t *FSEventHandler::GetModuleInterface()
+{
+ return &eventhandler_module_interface;
+}
+
+/* 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:
+ */