Singleton (separate) message handler context in Javascript
From Yate Documentation
(Difference between revisions)
(4 intermediate revisions by one user not shown) | |||
Line 2: | Line 2: | ||
A regular message handler callback is called by javascript when script context is unlocked.<br/> | A regular message handler callback is called by javascript when script context is unlocked.<br/> | ||
Script context is locked during message processing.<br/> | Script context is locked during message processing.<br/> | ||
− | Script global data is available in message handler callback function. | + | Script global data is available in message handler callback function.<br/> |
− | A singleton message handler may be used when application is expected to process a high number of messages and want to avoid contention due to javascript serialization. | + | A singleton message handler may be used when application is expected to process a high number of messages and want to avoid contention due to javascript serialization.<br/> |
− | When a singleton message handler is installed the javascript module will build and initialize a separate context.<br/> | + | When a singleton message handler is installed the javascript module will build and initialize a separate context each time a message is handled.<br/> |
− | + | Handler callback function is called in this context.<br/> | |
The context is deleted after message is handled.<br/> | The context is deleted after message is handled.<br/> | ||
− | Message | + | See [[Javascript Message|Message()]] for singleton functions availability. |
− | + | ||
− | + | ||
Line 25: | Line 23: | ||
// Increment some shared variable to be reported in status | // Increment some shared variable to be reported in status | ||
var perf = new Engine.SharedVars("handler_singleton_sample_perf"); | var perf = new Engine.SharedVars("handler_singleton_sample_perf"); | ||
− | + | perf.inc("handled_" + context); | |
if (!msg.called) | if (!msg.called) | ||
return false; | return false; | ||
Line 94: | Line 92: | ||
var str = ""; | var str = ""; | ||
var perf = new Engine.SharedVars("handler_singleton_sample_perf"); | var perf = new Engine.SharedVars("handler_singleton_sample_perf"); | ||
− | + | perf = perf.getVars(); | |
for (var name in perf) | for (var name in perf) | ||
str += "," + name + "=" + perf[name]; | str += "," + name + "=" + perf[name]; | ||
Line 124: | Line 122: | ||
Engine.output("Initializing module Sample Singleton Message Handler"); | Engine.output("Initializing module Sample Singleton Message Handler"); | ||
if (first) { | if (first) { | ||
− | |||
− | |||
if (!Message.installSingleton) { | if (!Message.installSingleton) { | ||
Engine.debug(Engine.DebugConf,"Refusing to start Sample Singleton Message Handler", | Engine.debug(Engine.DebugConf,"Refusing to start Sample Singleton Message Handler", |
Latest revision as of 08:54, 3 September 2024
A regular message handler callback is called by javascript when script context is unlocked.
Script context is locked during message processing.
Script global data is available in message handler callback function.
A singleton message handler may be used when application is expected to process a high number of messages and want to avoid contention due to javascript serialization.
When a singleton message handler is installed the javascript module will build and initialize a separate context each time a message is handled.
Handler callback function is called in this context.
The context is deleted after message is handled.
See Message() for singleton functions availability.
[edit] Sample
Engine.debugName("handler_singleton_sample"); Message.trackName("handler_singleton_sample"); // Callback for call.route. 'context' value is the second parameter passed to Message.installSingleton() function onCallRoute(msg,context) { if (debug) Engine.debug(Engine.DebugCall,"Singleton",msg.name(),"context=" + context); // Increment some shared variable to be reported in status var perf = new Engine.SharedVars("handler_singleton_sample_perf"); perf.inc("handled_" + context); if (!msg.called) return false; var shared_objects = new Engine.SharedObjects; var data = shared_objects.get("handler_singleton_sample_route_data"); if (!data) return false; if (data.local_route_called) { // Sample: route local using called party match var match = msg.called.match(data.local_route_called); if (match[1]) { perf.inc("routed_local_route_called"); msg.retValue("sip/sip:" + match[1] + "@127.0.0.1"); return true; } } if ("object" == typeof data.database) { // Sample: route local using database query var m = new Message("database",false,data.database); m.module = Engine.debugName(); if (m.dispatch(true) && !m.error) { var row = m.getRow(0); if (row.target) { perf.inc("routed_database"); msg.retValue(row.target); return true; } } else perf.inc("database_failure"); } return false; } function onTest(msg,context) { if (debug) { var shared_objects = new Engine.SharedObjects; var data = shared_objects.get("handler_singleton_sample_route_data"); var s = "\r\n-----\r\n" + Engine.dump_var_r(data) + "\r\n-----"; Engine.debug(Engine.DebugCall,"Singleton",msg.name(),"context=" + context,"route_data:" + s); } // Increment some shared variable to be reported in status perf = new Engine.SharedVars("handler_singleton_sample_perf"); perf.inc("handled_" + context); return true; } if (!Engine.scriptType) initialize(true); else if (Engine.ScriptTypeMsgHandler !== Engine.scriptType()) initialize(true); else { // We are in singleton message handler context // NOTE: debug (including level) is propagated from main script to singleton // context by javascript module debug = Engine.debugEnabled(); } // // From this point the code is used only if script is loaded as static script // function onStatus(msg) { if (msg.module && ("handler_singleton_sample" != msg.module)) return false; var str = ""; var perf = new Engine.SharedVars("handler_singleton_sample_perf"); perf = perf.getVars(); for (var name in perf) str += "," + name + "=" + perf[name]; msg.retValue(msg.retValue() + "name=handler_singleton_sample,type=misc;" + str.substr(1) + "\r\n"); return !!msg.module; } function onDebug(msg) { if (var dbg = msg.line) { Engine.setDebug(dbg); debug = Engine.debugEnabled(); } msg.retValue("Sample Singleton Message Handler debug " + Engine.debugEnabled() + " level " + Engine.debugLevel() + "\r\n"); return true; } function onReload(msg) { if (msg.plugin && ("handler_singleton_sample" != msg.plugin)) return false; initialize(); return !!msg.plugin; } function initialize(first) { Engine.output("Initializing module Sample Singleton Message Handler"); if (first) { if (!Message.installSingleton) { Engine.debug(Engine.DebugConf,"Refusing to start Sample Singleton Message Handler", "singleton handler install not available"); return; } // Initial debug Engine.setDebug("level 10"); debug = Engine.debugEnabled(); // Message.installSingleton(func,context,name[,priority[,filterName[,filterValue[,params]]]) // Do not load extensions (default: javascript.conf global setup) // Extensions are loaded using a script.init message. C++ modules may push javascript objects in script context var params = {load_extensions:false}; // Sample call.route filter. Handle if not explicitly disabled. Use Engine.MatchingItem var mi = {name:"handler_singleton_sample",value:/^$(true|yes|)$/}; var filter = new Engine.MatchingItem(mi); Message.installSingleton(onCallRoute,"call_route","call.route",30,filter,undefined,params); // Sample test filter. Handle if not explicitly disabled. Use basic Message.installSingleton(onTest,"test","test",70,"handler_singleton_sample",/^$(true|yes|)$/,params); // Module messages Message.install(onStatus,"engine.status"); Message.install(onDebug,"engine.debug",150,"module","handler_singleton_sample"); Message.install(onReload,"engine.init"); } // Init and set shared object holding route data var routeData = { local_route_called: /^(test|other)$/, database: {account:"some_db_account",query:"select target from route"}, }; var shared_objects = new Engine.SharedObjects; shared_objects.set("handler_singleton_sample_route_data",routeData); }
See also