mod_v8: Added new extension class that makes it possible to subscribe to FS events. Wiki will be updated soon.

This commit is contained in:
Peter Olsson 2014-02-01 18:20:04 +01:00
parent ab2bc7c689
commit 04005dfa68
10 changed files with 875 additions and 19 deletions

View File

@ -90,7 +90,8 @@ mod_v8_la_SOURCES = \
src/fssocket.cpp \
src/fsteletone.cpp \
src/fsxml.cpp \
src/fsfile.cpp
src/fsfile.cpp \
src/fseventhandler.cpp
mod_v8_la_CFLAGS = $(AM_CFLAGS) $(LIBCURL_CPPFLAGS) -I$(switch_srcdir)/libs/libteletone/src
mod_v8_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBCURL_CPPFLAGS) -I$(switch_srcdir)/libs/libteletone/src

View File

@ -0,0 +1,94 @@
/*
* 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.hpp -- JavaScript EventHandler class header
*
*/
#ifndef FS_EVENTHANDLER_H
#define FS_EVENTHANDLER_H
#include "mod_v8.h"
/* Macros for easier V8 callback definitions */
#define JS_EVENTHANDLER_GET_PROPERTY_DEF(method_name) JS_GET_PROPERTY_DEF(method_name, FSEventHandler)
#define JS_EVENTHANDLER_SET_PROPERTY_DEF(method_name) JS_SET_PROPERTY_DEF(method_name, FSEventHandler)
#define JS_EVENTHANDLER_FUNCTION_DEF(method_name) JS_FUNCTION_DEF(method_name, FSEventHandler)
#define JS_EVENTHANDLER_GET_PROPERTY_IMPL(method_name) JS_GET_PROPERTY_IMPL(method_name, FSEventHandler)
#define JS_EVENTHANDLER_SET_PROPERTY_IMPL(method_name) JS_SET_PROPERTY_IMPL(method_name, FSEventHandler)
#define JS_EVENTHANDLER_FUNCTION_IMPL(method_name) JS_FUNCTION_IMPL(method_name, FSEventHandler)
#define JS_EVENTHANDLER_FUNCTION_IMPL_STATIC(method_name) JS_FUNCTION_IMPL_STATIC(method_name, FSEventHandler)
#define JS_EVENTHANDLER_GET_PROPERTY_IMPL_STATIC(method_name) JS_GET_PROPERTY_IMPL_STATIC(method_name, FSEventHandler)
class FSEventHandler : public JSBase
{
private:
switch_mutex_t *_mutex;
switch_memory_pool_t *_pool;
switch_hash_t *_event_hash;
switch_queue_t *_event_queue;
uint8_t _event_list[SWITCH_EVENT_ALL + 1];
switch_event_t *_filters;
void Init();
void DoSubscribe(const v8::FunctionCallbackInfo<v8::Value>& info);
public:
FSEventHandler(JSMain *owner) : JSBase(owner) { Init(); }
FSEventHandler(const v8::FunctionCallbackInfo<v8::Value>& info) : JSBase(info) { Init(); }
virtual ~FSEventHandler(void);
virtual std::string GetJSClassName();
static const v8_mod_interface_t *GetModuleInterface();
/* Public method to queue an event to this instance */
void QueueEvent(switch_event_t *event);
/* Methods available from JavaScript */
static void *Construct(const v8::FunctionCallbackInfo<v8::Value>& info);
JS_EVENTHANDLER_FUNCTION_DEF(Subscribe);
JS_EVENTHANDLER_FUNCTION_DEF(UnSubscribe);
JS_EVENTHANDLER_FUNCTION_DEF(AddFilter);
JS_EVENTHANDLER_FUNCTION_DEF(DeleteFilter);
JS_EVENTHANDLER_FUNCTION_DEF(GetEvent);
JS_EVENTHANDLER_FUNCTION_DEF(SendEvent);
JS_EVENTHANDLER_FUNCTION_DEF(ExecuteApi);
JS_EVENTHANDLER_FUNCTION_DEF(ExecuteBgApi);
JS_FUNCTION_DEF_STATIC(Destroy);
JS_GET_PROPERTY_DEF_STATIC(GetReadyProperty);
};
#endif /* FS_EVENTHANDLER_H */
/* 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:
*/

View File

@ -178,6 +178,7 @@
<ClCompile Include=".\src\fsglobal.cpp" />
<ClCompile Include=".\src\fsteletone.cpp" />
<ClCompile Include="mod_v8.cpp" />
<ClCompile Include="src\fseventhandler.cpp" />
<ClCompile Include="src\fsfile.cpp" />
<ClCompile Include="src\fsxml.cpp" />
</ItemGroup>
@ -195,6 +196,7 @@
<ClInclude Include=".\include\fssocket.hpp" />
<ClInclude Include=".\include\fsglobal.hpp" />
<ClInclude Include=".\include\fsteletone.hpp" />
<ClInclude Include="include\fseventhandler.hpp" />
<ClInclude Include="include\fsfile.hpp" />
<ClInclude Include="include\fsxml.hpp" />
<ClInclude Include="mod_v8.h" />

View File

@ -50,6 +50,9 @@
<ClCompile Include="src\fsxml.cpp">
<Filter>FSClasses</Filter>
</ClCompile>
<ClCompile Include="src\fseventhandler.cpp">
<Filter>FSClasses</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="mod_v8.h" />
@ -98,6 +101,9 @@
<ClInclude Include="include\fsxml.hpp">
<Filter>FSClasses\include</Filter>
</ClInclude>
<ClInclude Include="include\fseventhandler.hpp">
<Filter>FSClasses\include</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="BaseClasses">

View File

@ -182,6 +182,7 @@
<ClCompile Include=".\src\fsglobal.cpp" />
<ClCompile Include=".\src\fsteletone.cpp" />
<ClCompile Include="mod_v8.cpp" />
<ClCompile Include="src\fseventhandler.cpp" />
<ClCompile Include="src\fsfile.cpp" />
<ClCompile Include="src\fsxml.cpp" />
</ItemGroup>
@ -199,6 +200,7 @@
<ClInclude Include=".\include\fssocket.hpp" />
<ClInclude Include=".\include\fsglobal.hpp" />
<ClInclude Include=".\include\fsteletone.hpp" />
<ClInclude Include="include\fseventhandler.hpp" />
<ClInclude Include="include\fsfile.hpp" />
<ClInclude Include="include\fsxml.hpp" />
<ClInclude Include="mod_v8.h" />

View File

@ -50,6 +50,9 @@
<ClCompile Include="src\fsxml.cpp">
<Filter>FSClasses</Filter>
</ClCompile>
<ClCompile Include="src\fseventhandler.cpp">
<Filter>FSClasses</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="mod_v8.h" />
@ -98,6 +101,9 @@
<ClInclude Include="include\fsxml.hpp">
<Filter>FSClasses\include</Filter>
</ClInclude>
<ClInclude Include="include\fseventhandler.hpp">
<Filter>FSClasses\include</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="BaseClasses">

View File

@ -34,20 +34,21 @@
* 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.
*
@ -73,7 +74,7 @@
#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"
@ -88,6 +89,9 @@
#include "fsodbc.hpp"
#include "fsxml.hpp"
#include "fsfile.hpp"
#include "fseventhandler.hpp"
#include <set>
using namespace std;
using namespace v8;
@ -106,7 +110,17 @@ static switch_api_interface_t *jsapi_interface = NULL;
/* 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;
@ -258,7 +272,6 @@ static switch_status_t load_modules(void)
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);
@ -688,8 +701,53 @@ static void v8_thread_launch(const char *text)
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;
@ -769,6 +827,19 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_v8_load)
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;
}
@ -786,6 +857,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_v8_load)
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);
@ -802,6 +874,12 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_v8_load)
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;

View File

@ -40,15 +40,19 @@ SWITCH_BEGIN_EXTERN_C
#define JS_BUFFER_SIZE 1024 * 32
#define JS_BLOCK_SIZE JS_BUFFER_SIZE
/* Function definition for initialization of an extension module */
typedef switch_status_t (*v8_mod_load_t) (const v8::FunctionCallbackInfo<v8::Value>& info);
/* Extension module interface, stored inside the load_hash */
typedef struct {
const char *name;
v8_mod_load_t v8_mod_load;
} v8_mod_interface_t;
/* Function definition for external extension module */
typedef switch_status_t (*v8_mod_init_t) (const v8_mod_interface_t **module_interface);
/* Struct that holds information about loadable extension modules */
typedef struct {
switch_hash_t *load_hash;
switch_memory_pool_t *pool;
@ -58,6 +62,9 @@ extern module_manager_t module_manager;
SWITCH_END_EXTERN_C
void v8_add_event_handler(void *event_handler);
void v8_remove_event_handler(void *event_handler);
#endif /* MOD_V8_H */
/* For Emacs:

View File

@ -0,0 +1,660 @@
/*
* 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 {
char *cmd;
char *arg;
char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1];
int ack;
switch_memory_pool_t *pool;
} api_command_struct_t;
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]) {
send = 1;
} else if ((_event_list[event->event_id])) {
if (event->event_id != SWITCH_EVENT_CUSTOM || !event->subclass_name || (switch_core_hash_find(_event_hash, event->subclass_name))) {
send = 1;
}
}
if (send) {
if (_filters && _filters->headers) {
switch_event_header_t *hp;
const char *hval;
send = 0;
for (hp = _filters->headers; hp; hp = hp->next) {
if ((hval = switch_event_get_header(event, hp->name))) {
const char *comp_to = hp->value;
int pos = 1, cmp = 0;
while (comp_to && *comp_to) {
if (*comp_to == '+') {
pos = 1;
} else if (*comp_to == '-') {
pos = 0;
} else if (*comp_to != ' ') {
break;
}
comp_to++;
}
if (send && pos) {
continue;
}
if (!comp_to) {
continue;
}
if (*hp->value == '/') {
switch_regex_t *re = NULL;
int ovector[30];
cmp = !!switch_regex_perform(hval, comp_to, &re, ovector, sizeof(ovector) / sizeof(ovector[0]));
switch_regex_safe_free(re);
} else {
cmp = !strcasecmp(hval, comp_to);
}
if (cmp) {
if (pos) {
send = 1;
} else {
send = 0;
break;
}
}
}
}
}
}
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) {
switch_mutex_lock(_mutex);
switch_core_hash_insert(_event_hash, js_safe_str(*str), MARKER);
switch_mutex_unlock(_mutex);
} else if (switch_name_event(js_safe_str(*str), &etype) == SWITCH_STATUS_SUCCESS) {
ret = true;
if (etype == SWITCH_EVENT_ALL) {
uint32_t x = 0;
for (x = 0; x < SWITCH_EVENT_ALL; x++) {
_event_list[x] = 1;
}
}
if (etype <= SWITCH_EVENT_ALL) {
_event_list[etype] = 1;
}
if (etype == SWITCH_EVENT_CUSTOM) {
custom++;
}
}
}
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) {
switch_mutex_lock(_mutex);
switch_core_hash_delete(_event_hash, js_safe_str(*str));
switch_mutex_unlock(_mutex);
} else if (switch_name_event(js_safe_str(*str), &etype) == SWITCH_STATUS_SUCCESS) {
uint32_t x = 0;
ret = true;
if (etype == SWITCH_EVENT_CUSTOM) {
custom++;
} else if (etype == SWITCH_EVENT_ALL) {
for (x = 0; x <= SWITCH_EVENT_ALL; x++) {
_event_list[x] = 0;
}
} else {
if (_event_list[SWITCH_EVENT_ALL]) {
_event_list[SWITCH_EVENT_ALL] = 0;
for (x = 0; x < SWITCH_EVENT_ALL; x++) {
_event_list[x] = 1;
}
}
_event_list[etype] = 0;
}
}
}
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)) {
info.GetReturnValue().Set(false);
return;
}
switch_mutex_lock(_mutex);
if (!_filters) {
switch_event_create_plain(&_filters, SWITCH_EVENT_CLONE);
}
if (!strcasecmp(headerName, "all")) {
switch_event_destroy(&_filters);
switch_event_create_plain(&_filters, SWITCH_EVENT_CLONE);
} else {
switch_event_del_header(_filters, headerName);
}
info.GetReturnValue().Set(true);
switch_mutex_unlock(_mutex);
}
}
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)) {
info.GetReturnValue().Set(false);
return;
}
switch_mutex_lock(_mutex);
if (!_filters) {
switch_event_create_plain(&_filters, SWITCH_EVENT_CLONE);
}
switch_event_add_header_string(_filters, SWITCH_STACK_BOTTOM, headerName, headerVal);
info.GetReturnValue().Set(true);
switch_mutex_unlock(_mutex);
}
}
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()))) {
if ((status = switch_core_session_queue_private_event(session, event, SWITCH_FALSE)) == SWITCH_STATUS_SUCCESS) {
info.GetReturnValue().Set(true);
} else {
info.GetReturnValue().Set(false);
}
switch_core_session_rwunlock(session);
} else {
info.GetReturnValue().Set(false);
// TODO LOGGING
//switch_snprintf(reply, reply_len, "-ERR invalid session id [%s]", switch_str_nil(uuid));
}
} 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)
{
api_command_struct_t *acs = (api_command_struct_t *) obj;
switch_stream_handle_t stream = { 0 };
char *reply, *freply = NULL;
switch_status_t status;
switch_event_t *event;
if (!acs) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Internal error.\n");
return NULL;
}
acs->ack = 1;
SWITCH_STANDARD_STREAM(stream);
status = switch_api_execute(acs->cmd, acs->arg, NULL, &stream);
if (status == SWITCH_STATUS_SUCCESS) {
reply = (char *)stream.data;
} else {
freply = switch_mprintf("-ERR %s Command not found!\n", acs->cmd);
reply = freply;
}
if (!reply) {
reply = "Command returned no output!";
}
if (switch_event_create(&event, SWITCH_EVENT_BACKGROUND_JOB) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Job-UUID", acs->uuid_str);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Job-Command", acs->cmd);
if (acs->arg) {
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Job-Command-Arg", acs->arg);
}
switch_event_add_body(event, "%s", reply);
switch_event_fire(&event);
}
switch_safe_free(stream.data);
switch_safe_free(freply);
switch_memory_pool_t *pool = acs->pool;
if (acs->ack == -1) {
int sanity = 2000;
while (acs->ack == -1) {
switch_cond_next();
if (--sanity <= 0)
break;
}
}
acs = NULL;
switch_core_destroy_memory_pool(&pool);
pool = NULL;
return NULL;
}
JS_EVENTHANDLER_FUNCTION_IMPL(ExecuteBgApi)
{
string cmd;
string arg;
string jobuuid;
api_command_struct_t *acs = NULL;
switch_memory_pool_t *pool;
switch_thread_t *thread;
switch_threadattr_t *thd_attr = NULL;
switch_uuid_t uuid;
int sanity = 2000;
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;
}
switch_core_new_memory_pool(&pool);
acs = (api_command_struct_t *)switch_core_alloc(pool, sizeof(*acs));
switch_assert(acs);
acs->pool = pool;
acs->cmd = switch_core_strdup(acs->pool, cmd.c_str());
if (arg.c_str()) {
acs->arg = switch_core_strdup(acs->pool, arg.c_str());
}
switch_threadattr_create(&thd_attr, acs->pool);
switch_threadattr_detach_set(thd_attr, 1);
switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
if (jobuuid.length() > 0) {
switch_copy_string(acs->uuid_str, jobuuid.c_str(), sizeof(acs->uuid_str));
} else {
switch_uuid_get(&uuid);
switch_uuid_format(acs->uuid_str, &uuid);
}
info.GetReturnValue().Set(String::NewFromUtf8(info.GetIsolate(), acs->uuid_str));
switch_thread_create(&thread, thd_attr, api_exec, acs, acs->pool);
while (!acs->ack) {
switch_cond_next();
if (--sanity <= 0)
break;
}
if (acs->ack == -1) {
acs->ack--;
}
}
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:
*/

View File

@ -69,7 +69,7 @@ JSBase::~JSBase(void)
}
/* If the object is still alive inside V8, set the internal field to NULL. But only if we're actually inside a JS context */
if (!persistentHandle->IsNearDeath() && !GetIsolate()->GetCurrentContext().IsEmpty()) {
if (!persistentHandle->IsNearDeath() && !GetIsolate()->GetCurrentContext().IsEmpty() && (!js || !js->GetForcedTermination())) {
Handle<Object> jsObj = GetJavaScriptObject();
jsObj->SetInternalField(0, Null(GetIsolate()));
}