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:
parent
ab2bc7c689
commit
04005dfa68
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
*/
|
|
@ -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" />
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
*/
|
|
@ -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()));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue