From 40af0d1777a1585c11d496de8beb0d9078d9718a Mon Sep 17 00:00:00 2001 From: Stefan Sayer Date: Tue, 6 Jul 2010 23:30:20 +0200 Subject: [PATCH] DSM: add system DSMs, DSMs unrelated to calls --- apps/dsm/DSM.cpp | 72 ++++++++++- apps/dsm/DSM.h | 5 + apps/dsm/DSMCall.cpp | 3 +- apps/dsm/DSMCoreModule.cpp | 34 ++++- apps/dsm/DSMCoreModule.h | 5 +- apps/dsm/DSMStateEngine.cpp | 10 +- apps/dsm/DSMStateEngine.h | 5 +- apps/dsm/SystemDSM.cpp | 181 +++++++++++++++++++++++++++ apps/dsm/SystemDSM.h | 100 +++++++++++++++ apps/dsm/etc/dsm.conf | 7 +- doc/dsm/Readme.dsm.txt | 25 ++++ doc/dsm/dsm_syntax.txt | 26 +++- doc/dsm/examples/test_system_dsm.dsm | 37 ++++++ 13 files changed, 492 insertions(+), 18 deletions(-) create mode 100644 apps/dsm/SystemDSM.cpp create mode 100644 apps/dsm/SystemDSM.h create mode 100644 doc/dsm/examples/test_system_dsm.dsm diff --git a/apps/dsm/DSM.cpp b/apps/dsm/DSM.cpp index 31689dc4..ae1f2d95 100644 --- a/apps/dsm/DSM.cpp +++ b/apps/dsm/DSM.cpp @@ -37,6 +37,7 @@ #include "DSMChartReader.h" #include "AmSipHeaders.h" #include "AmEventDispatcher.h" +#include "SystemDSM.h" #include #include @@ -164,6 +165,17 @@ int DSMFactory::onLoad() MainScriptConfig.SetParamVariables = cfg.getParameter("set_param_variables")=="yes"; + vector system_dsms = explode(cfg.getParameter("run_system_dsms"), ","); + for (vector::iterator it=system_dsms.begin(); it != system_dsms.end(); it++) { + string status; + if (createSystemDSM("main", *it, false /* reload */, status)) { + DBG("created SystemDSM '%s'\n", it->c_str()); + } else { + ERROR("creating system DSM '%s': '%s'\n", it->c_str(), status.c_str()); + return -1; + } + } + #ifdef USE_MONITORING string monitoring_full_callgraph = cfg.getParameter("monitoring_full_stategraph"); MonitoringFullCallgraph = monitoring_full_callgraph == "yes"; @@ -420,6 +432,7 @@ bool DSMFactory::loadConfig(const string& conf_file_name, const string& conf_nam ScriptConfigs_mut.lock(); try { + Name2ScriptConfig[script_name] = script_config; // set ScriptConfig to this for all registered apps' names for (vector::iterator reg_app_it= registered_apps.begin(); reg_app_it != registered_apps.end(); reg_app_it++) { @@ -442,7 +455,19 @@ bool DSMFactory::loadConfig(const string& conf_file_name, const string& conf_nam } ScriptConfigs_mut.unlock(); - return true; + bool res = true; + + vector system_dsms = explode(cfg.getParameter("run_system_dsms"), ","); + for (vector::iterator it=system_dsms.begin(); it != system_dsms.end(); it++) { + string status; + if (createSystemDSM(script_name, *it, live_reload, status)) { + } else { + ERROR("creating system DSM '%s': '%s'\n", it->c_str(), status.c_str()); + res = false; + } + } + + return res; } @@ -726,6 +751,39 @@ AmSession* DSMFactory::onInvite(const AmSipRequest& req, return s; } +bool DSMFactory::createSystemDSM(const string& config_name, const string& start_diag, bool reload, string& status) { + bool res = true; + + DSMScriptConfig* script_config = NULL; + ScriptConfigs_mut.lock(); + if (config_name == "main") + script_config = &MainScriptConfig; + else { + map::iterator it = Name2ScriptConfig.find(config_name); + if (it != Name2ScriptConfig.end()) + script_config = &it->second; + } + if (script_config==NULL) { + status = "Error: Script config '"+config_name+"' not found, in ["; + for (map::iterator it = + Name2ScriptConfig.begin(); it != Name2ScriptConfig.end(); it++) { + if (it != Name2ScriptConfig.begin()) + status+=", "; + status += it->first; + } + status += "]"; + res = false; + } else { + SystemDSM* s = new SystemDSM(*script_config, start_diag, reload); + s->start(); + // add to garbage collector + AmThreadWatcher::instance()->add(s); + status = "OK"; + } + ScriptConfigs_mut.unlock(); + return res; +} + void DSMFactory::reloadDSMs(const AmArg& args, AmArg& ret) { DSMStateDiagramCollection* new_diags = new DSMStateDiagramCollection(); @@ -1035,6 +1093,16 @@ void DSMFactory::invoke(const string& method, const AmArg& args, } else if (method == "loadConfig"){ args.assertArrayFmt("ss"); loadConfig(args,ret); + } else if (method == "runSystemDSM"){ + args.assertArrayFmt("ss"); + string status; + if (createSystemDSM(args.get(0).asCStr(), args.get(1).asCStr(), false, status)) { + ret.push(200); + ret.push(status); + } else { + ret.push(500); + ret.push(status); + } } else if(method == "_list"){ ret.push(AmArg("postDSMEvent")); ret.push(AmArg("reloadDSMs")); @@ -1046,6 +1114,8 @@ void DSMFactory::invoke(const string& method, const AmArg& args, ret.push(AmArg("hasDSM")); ret.push(AmArg("listDSMs")); ret.push(AmArg("registerApplication")); + ret.push(AmArg("runSystemDSM")); } else throw AmDynInvoke::NotImplemented(method); } + diff --git a/apps/dsm/DSM.h b/apps/dsm/DSM.h index f5bee93c..1815c74e 100644 --- a/apps/dsm/DSM.h +++ b/apps/dsm/DSM.h @@ -73,7 +73,10 @@ class DSMFactory static string OutboundStartDiag; DSMScriptConfig MainScriptConfig; + // script name -> config map ScriptConfigs; + // config name -> config + map Name2ScriptConfig; AmMutex ScriptConfigs_mut; #ifdef USE_MONITORING @@ -108,6 +111,8 @@ class DSMFactory DSMChartReader preload_reader; + bool createSystemDSM(const string& config_name, const string& start_diag, bool reload, string& status); + void listDSMs(const AmArg& args, AmArg& ret); void hasDSM(const AmArg& args, AmArg& ret); void reloadDSMs(const AmArg& args, AmArg& ret); diff --git a/apps/dsm/DSMCall.cpp b/apps/dsm/DSMCall.cpp index b3477534..14e4b76c 100644 --- a/apps/dsm/DSMCall.cpp +++ b/apps/dsm/DSMCall.cpp @@ -340,8 +340,7 @@ void DSMCall::process(AmEvent* event) if (dsm_event) { engine.runEvent(this, this, DSMCondition::DSMEvent, &dsm_event->params); return; - } - + } } AmAudioEvent* audio_event = dynamic_cast(event); diff --git a/apps/dsm/DSMCoreModule.cpp b/apps/dsm/DSMCoreModule.cpp index 8b0947a3..b322c55d 100644 --- a/apps/dsm/DSMCoreModule.cpp +++ b/apps/dsm/DSMCoreModule.cpp @@ -31,6 +31,7 @@ #include "AmSession.h" #include "AmSessionContainer.h" #include "AmUtils.h" +#include "AmEventDispatcher.h" #include "jsonArg.h" @@ -94,6 +95,9 @@ DSMAction* DSMCoreModule::getAction(const string& from_str) { DEF_CMD("postEvent", SCPostEventAction); + DEF_CMD("registerEventQueue", SCRegisterEventQueueAction); + DEF_CMD("unregisterEventQueue", SCUnregisterEventQueueAction); + if (cmd == "DI") { SCDIAction * a = new SCDIAction(params, false); a->name = from_str; @@ -183,6 +187,15 @@ DSMCondition* DSMCoreModule::getCondition(const string& from_str) { if (cmd == "jsonRpcResponse") return new TestDSMCondition(params, DSMCondition::JsonRpcResponse); + if (cmd == "startup") + return new TestDSMCondition(params, DSMCondition::Startup); + + if (cmd == "reload") + return new TestDSMCondition(params, DSMCondition::Reload); + + if (cmd == "system") + return new TestDSMCondition(params, DSMCondition::System); + return NULL; } @@ -843,7 +856,7 @@ TestDSMCondition::TestDSMCondition(const string& expr, DSMCondition::EventType e name = expr; } -bool TestDSMCondition::match(AmSession* sess, DSMCondition::EventType event, +bool TestDSMCondition::match(AmSession* sess, DSMSession* sc_sess, DSMCondition::EventType event, map* event_params) { if (ttype == None || (type != DSMCondition::Any && type != event)) return false; @@ -851,7 +864,6 @@ bool TestDSMCondition::match(AmSession* sess, DSMCondition::EventType event, if (ttype == Always) return true; - DSMSession* sc_sess = dynamic_cast(sess); if (!sc_sess) { ERROR("wrong session type\n"); return false; @@ -1189,3 +1201,21 @@ EXEC_ACTION_START(SCSendDTMFAction) { sess->sendDtmf(event_i, duration_i); } EXEC_ACTION_END; + +EXEC_ACTION_START(SCRegisterEventQueueAction) { + string q_name = resolveVars(arg, sess, sc_sess, event_params); + DBG("Registering event queue '%s'\n", q_name.c_str()); + if (q_name.empty()) { + WARN("Registering empty event queue name!\n"); + } + AmEventDispatcher::instance()->addEventQueue(q_name, sess); +} EXEC_ACTION_END; + +EXEC_ACTION_START(SCUnregisterEventQueueAction) { + string q_name = resolveVars(arg, sess, sc_sess, event_params); + DBG("Unregistering event queue '%s'\n", q_name.c_str()); + if (q_name.empty()) { + WARN("Unregistering empty event queue name!\n"); + } + AmEventDispatcher::instance()->delEventQueue(q_name); +} EXEC_ACTION_END; diff --git a/apps/dsm/DSMCoreModule.h b/apps/dsm/DSMCoreModule.h index 6f13f0dd..28c18d01 100644 --- a/apps/dsm/DSMCoreModule.h +++ b/apps/dsm/DSMCoreModule.h @@ -104,6 +104,9 @@ DEF_ACTION_1P(SCB2BAddHeaderAction); DEF_ACTION_1P(SCB2BClearHeadersAction); DEF_ACTION_2P(SCB2BSetHeadersAction); +DEF_ACTION_1P(SCRegisterEventQueueAction); +DEF_ACTION_1P(SCUnregisterEventQueueAction); + class SCDIAction : public DSMAction { vector params; @@ -132,7 +135,7 @@ class TestDSMCondition public: TestDSMCondition(const string& expr, DSMCondition::EventType e); - bool match(AmSession* sess, DSMCondition::EventType event, + bool match(AmSession* sess, DSMSession* sc_sess, DSMCondition::EventType event, map* event_params); }; diff --git a/apps/dsm/DSMStateEngine.cpp b/apps/dsm/DSMStateEngine.cpp index 8b12798e..e8839991 100644 --- a/apps/dsm/DSMStateEngine.cpp +++ b/apps/dsm/DSMStateEngine.cpp @@ -290,15 +290,15 @@ bool DSMStateEngine::init(AmSession* sess, DSMSession* sc_sess, } bool DSMCondition::_match(AmSession* sess, DSMSession* sc_sess, - DSMCondition::EventType event, - map* event_params) { + DSMCondition::EventType event, + map* event_params) { // or xor - return invert?(!match(sess,sc_sess,event,event_params)):match(sess, sc_sess, event, event_params); + return invert? (!match(sess,sc_sess,event,event_params)) : match(sess, sc_sess, event, event_params); } bool DSMCondition::match(AmSession* sess, DSMSession* sc_sess, - DSMCondition::EventType event, - map* event_params) { + DSMCondition::EventType event, + map* event_params) { if ((type != Any) && (event != type)) return false; diff --git a/apps/dsm/DSMStateEngine.h b/apps/dsm/DSMStateEngine.h index 89731b1f..961b8b3d 100644 --- a/apps/dsm/DSMStateEngine.h +++ b/apps/dsm/DSMStateEngine.h @@ -86,8 +86,11 @@ class DSMCondition XmlrpcResponse, JsonRpcResponse, - JsonRpcRequest + JsonRpcRequest, + Startup, + Reload, + System }; bool invert; diff --git a/apps/dsm/SystemDSM.cpp b/apps/dsm/SystemDSM.cpp new file mode 100644 index 00000000..775c40a5 --- /dev/null +++ b/apps/dsm/SystemDSM.cpp @@ -0,0 +1,181 @@ + +#include "SystemDSM.h" +#include "log.h" +#include "AmUtils.h" +#include "AmEventDispatcher.h" + +#include "DSMStateDiagramCollection.h" +#include "../apps/jsonrpc/JsonRPCEvents.h" // todo! + +SystemDSM::SystemDSM(const DSMScriptConfig& config, + const string& startDiagName, + bool reload) + : stop_requested(false), AmEventQueue(this), + startDiagName(startDiagName), dummy_session(this), + reload(reload) +{ + config.diags->addToEngine(&engine); + + for (map::const_iterator it = + config.config_vars.begin(); it != config.config_vars.end(); it++) + var["config."+it->first] = it->second; + + // register our event queue + string our_id = "SystemDSM_"+AmSession::getNewId(); + dummy_session.setLocalTag(our_id); + AmEventDispatcher::instance()->addEventQueue(our_id, this); +} + +SystemDSM::~SystemDSM() { +} + +void SystemDSM::run() { + DBG("SystemDSM thread starting...\n"); + + DBG("Running init of SystemDSM...\n"); + if (!engine.init(&dummy_session, this, startDiagName, + reload ? DSMCondition::Reload : DSMCondition::Startup)) { + WARN("Initialization failed for SystemDSM\n"); + AmEventDispatcher::instance()->delEventQueue(dummy_session.getLocalTag()); + return; + } + + while (!stop_requested.get() && !dummy_session.getStopped()) { + waitForEvent(); + processEvents(); + } + + AmEventDispatcher::instance()->delEventQueue(dummy_session.getLocalTag()); + DBG("SystemDSM thread finished.\n"); +} + +void SystemDSM::on_stop() { + DBG("requesting stop of SystemDSM\n"); + stop_requested.set(true); +} + +void SystemDSM::process(AmEvent* event) { + + AmPluginEvent* plugin_event = dynamic_cast(event); + if(plugin_event && plugin_event->name == "timer_timeout") { + int timer_id = plugin_event->data.get(0).asInt(); + map params; + params["id"] = int2str(timer_id); + engine.runEvent(&dummy_session, this, DSMCondition::Timer, ¶ms); + } + + if (event->event_id == DSM_EVENT_ID) { + DSMEvent* dsm_event = dynamic_cast(event); + if (dsm_event) { + engine.runEvent(&dummy_session, this, DSMCondition::DSMEvent, &dsm_event->params); + return; + } + } + // todo: give modules the possibility to define/process events + JsonRpcEvent* jsonrpc_ev = dynamic_cast(event); + if (jsonrpc_ev) { + DBG("received jsonrpc event\n"); + + JsonRpcResponseEvent* resp_ev = + dynamic_cast(jsonrpc_ev); + if (resp_ev) { + map params; + params["ev_type"] = "JsonRpcResponse"; + params["id"] = resp_ev->response.id; + params["is_error"] = resp_ev->response.is_error ? + "true":"false"; + + // decode result for easy use from script + varPrintArg(resp_ev->response.data, params, resp_ev->response.is_error ? "error": "result"); + + // save reference to full parameters + avar[DSM_AVAR_JSONRPCRESPONEDATA] = AmArg(&resp_ev->response.data); + + engine.runEvent(&dummy_session, this, DSMCondition::JsonRpcResponse, ¶ms); + + avar.erase(DSM_AVAR_JSONRPCRESPONEDATA); + return; + } + + JsonRpcRequestEvent* req_ev = + dynamic_cast(jsonrpc_ev); + if (req_ev) { + map params; + params["ev_type"] = "JsonRpcRequest"; + params["is_notify"] = req_ev->isNotification() ? + "true" : "false"; + params["method"] = req_ev->method; + if (!req_ev->id.empty()) + params["id"] = req_ev->id; + + // decode request params result for easy use from script + varPrintArg(req_ev->params, params, "params"); + + // save reference to full parameters + avar[DSM_AVAR_JSONRPCREQUESTDATA] = AmArg(&req_ev->params); + + engine.runEvent(&dummy_session, this, DSMCondition::JsonRpcRequest, ¶ms); + + avar.erase(DSM_AVAR_JSONRPCREQUESTDATA); + return; + } + + } + + if (event->event_id == E_SYSTEM) { + AmSystemEvent* sys_ev = dynamic_cast(event); + if(sys_ev){ + DBG("SystemDSM received system Event\n"); + map params; + params["type"] = AmSystemEvent::getDescription(sys_ev->sys_event); + engine.runEvent(&dummy_session, this, DSMCondition::System, ¶ms); + // stop_requested.set(true); + return; + } + } + +} + +#define NOT_IMPLEMENTED(_func) \ +void SystemDSM::_func { \ + throw DSMException("core", "cause", "not implemented"); \ +} + +#define NOT_IMPLEMENTED_UINT(_func) \ + unsigned int SystemDSM::_func { \ + throw DSMException("core", "cause", "not implemented"); \ + } + +NOT_IMPLEMENTED(playPrompt(const string& name, bool loop)); +NOT_IMPLEMENTED(playFile(const string& name, bool loop, bool front)); +NOT_IMPLEMENTED(recordFile(const string& name)); +NOT_IMPLEMENTED_UINT(getRecordLength()); +NOT_IMPLEMENTED_UINT(getRecordDataSize()); +NOT_IMPLEMENTED(stopRecord()); +NOT_IMPLEMENTED(setInOutPlaylist()); +NOT_IMPLEMENTED(setInputPlaylist()); +NOT_IMPLEMENTED(setOutputPlaylist()); + +NOT_IMPLEMENTED(addToPlaylist(AmPlaylistItem* item)); +NOT_IMPLEMENTED(closePlaylist(bool notify)); +NOT_IMPLEMENTED(setPromptSet(const string& name)); +NOT_IMPLEMENTED(addSeparator(const string& name, bool front)); +NOT_IMPLEMENTED(connectMedia()); +NOT_IMPLEMENTED(disconnectMedia()); +NOT_IMPLEMENTED(mute()); +NOT_IMPLEMENTED(unmute()); + +/** B2BUA functions */ +NOT_IMPLEMENTED(B2BconnectCallee(const string& remote_party, + const string& remote_uri, + bool relayed_invite)); +NOT_IMPLEMENTED(B2BterminateOtherLeg()); +NOT_IMPLEMENTED(B2BaddReceivedRequest(const AmSipRequest& req)); +NOT_IMPLEMENTED(B2BsetHeaders(const string& hdr, bool replaceCRLF)); +NOT_IMPLEMENTED(B2BclearHeaders()); +NOT_IMPLEMENTED(B2BaddHeader(const string& hdr)); +NOT_IMPLEMENTED(transferOwnership(DSMDisposable* d)); +NOT_IMPLEMENTED(releaseOwnership(DSMDisposable* d)); + +#undef NOT_IMPLEMENTED +#undef NOT_IMPLEMENTED_UINT diff --git a/apps/dsm/SystemDSM.h b/apps/dsm/SystemDSM.h new file mode 100644 index 00000000..cb8b2eb7 --- /dev/null +++ b/apps/dsm/SystemDSM.h @@ -0,0 +1,100 @@ +#ifndef _SystemDSM_h_ +#define _SystemDSM_h_ + +#include "AmThread.h" +#include "AmEventQueue.h" +#include "DSMSession.h" +#include "AmSession.h" +#include "DSMStateEngine.h" + +#include + +using std::string; + + +class EventProxySession +: public AmSession +{ + AmEventQueueInterface* e; + public: + EventProxySession(AmEventQueueInterface* e) + : e(e) { assert(e); } + + void postEvent(AmEvent* event) { e->postEvent(event); } +}; + +class SystemDSM +: public AmThread, + public AmEventQueue, + public AmEventHandler, + public DSMSession + +{ + + EventProxySession dummy_session; + AmSharedVar stop_requested; + + DSMStateEngine engine; + string startDiagName; + bool reload; + + public: + + SystemDSM(const DSMScriptConfig& config, + const string& startDiagName, + bool reload); + ~SystemDSM(); + + void run(); + void on_stop(); + +// AmEventHandler interface + void process(AmEvent* event); + +// DSMSession interface + void playPrompt(const string& name, bool loop = false); + void playFile(const string& name, bool loop, bool front = false); + void recordFile(const string& name); + unsigned int getRecordLength(); + unsigned int getRecordDataSize(); + void stopRecord(); + void setInOutPlaylist(); + void setInputPlaylist(); + void setOutputPlaylist(); + + void addToPlaylist(AmPlaylistItem* item); + void closePlaylist(bool notify); + void setPromptSet(const string& name); + void addSeparator(const string& name, bool front = false); + void connectMedia(); + void disconnectMedia(); + void mute(); + void unmute(); + + /** B2BUA functions */ + void B2BconnectCallee(const string& remote_party, + const string& remote_uri, + bool relayed_invite = false); + void B2BterminateOtherLeg(); + + /** insert request in list of received ones */ + void B2BaddReceivedRequest(const AmSipRequest& req); + + /** set headers of outgoing INVITE */ + void B2BsetHeaders(const string& hdr, bool replaceCRLF); + + /** set headers of outgoing INVITE */ + void B2BclearHeaders(); + + /** add a header to the headers of outgoing INVITE */ + void B2BaddHeader(const string& hdr); + + /** transfer ownership of object to this session instance */ + void transferOwnership(DSMDisposable* d); + + /** release ownership of object from this session instance */ + void releaseOwnership(DSMDisposable* d); + +}; + +#endif diff --git a/apps/dsm/etc/dsm.conf b/apps/dsm/etc/dsm.conf index 102771ef..3f2a2fc7 100644 --- a/apps/dsm/etc/dsm.conf +++ b/apps/dsm/etc/dsm.conf @@ -55,6 +55,10 @@ load_prompts=/usr/local/etc/sems/dsm_in_prompts.conf,/usr/local/etc/sems/dsm_out # #set_param_variables=yes +# run these system DSMs on startup (system DSMs are DSMs executed without a call) +# +#run_system_dsms=system_dsm1,system_dsm2 + # monitoring_full_stategraph=[yes|no] # # Controls whether to log the full call graph (all states visited) @@ -118,7 +122,8 @@ load_prompts=/usr/local/etc/sems/dsm_in_prompts.conf,/usr/local/etc/sems/dsm_out # preload_mods= # run_invite_event= # set_param_variables= -# +# run_system_dsms= + # and additional configuration variables (as script variables) # # conf_dir=/usr/local/etc/sems/dsm/ diff --git a/doc/dsm/Readme.dsm.txt b/doc/dsm/Readme.dsm.txt index 49d1302d..412d51b1 100644 --- a/doc/dsm/Readme.dsm.txt +++ b/doc/dsm/Readme.dsm.txt @@ -53,6 +53,27 @@ A patch for fmsc 1.0.4 from the graphical FSM editor fsme (http://fsme.sf.net) is available, so DSMs can be defined in click-n-drag fashion and compiled to SEMS DSM diagrams. + +SystemDSMs +========== + +A system DSM is executed without a corresponding call. This can be useful +e.g. to execute something periodically, to make a call generator etc. + +Obviously, only limited functionality is available in System DSMs, all +call and media related functionality is not available (and will throw +exceptions with type 'core'). + +A system DSM receives the "startup" event on start of the server, or if +it is created via runSystemDSM DI call. It gets a "reload" event if the +system DSM is created by a live config reload. + +On server shutdown, a system DSM receives a "system" event with +"ServerShutdown" as type. + +See test_system_event.dsm example for an example how to handle server +start and reload. + DI commands =========== @@ -103,6 +124,10 @@ loadConfig(string conf_file_name, string conf_name) (re)load application configuration and script like a file in conf_dir +runSystemDSM(string conf_name, string start_diag) + run a system DSM (i.e. a DSM thread not connected to a session) + using scripts/configuration from conf_name. + conf_name=='main' for main scripts/main config (from dsm.conf) More info ========= diff --git a/doc/dsm/dsm_syntax.txt b/doc/dsm/dsm_syntax.txt index 30156ca1..0d9e97cd 100644 --- a/doc/dsm/dsm_syntax.txt +++ b/doc/dsm/dsm_syntax.txt @@ -187,6 +187,13 @@ sendDTMF(key [, duration_ms]) throwOnError() + registerEventQueue(queue_name) + register session to receive events under the name queue_name + WARNING: make sure to unregister the event queue before ending the session! + + unregisterEventQueue(queue_name) + unregister events queue queue_name + ============================= conditions: @@ -206,13 +213,13 @@ conditions: test(len($var) < len(@user)) -- like test(expr), but only on key press - keyTest(expr) - timerTest(expr) - noAudioTest(expr) - separatorTest(expr) + key or keyTest(expr) + timer or timerTest(expr) + noAudio or noAudioTest(expr) + separator or separatorTest(expr) e.g. separatorTest(#id == 5) - eventTest(expr) + event or eventTest(expr) keyPress(no) -- bye received: @@ -229,6 +236,15 @@ conditions: -- event is start of session (with run_invite_event, otherwise its always true): sessionStart + -- event is startup + startup + + -- event is reload + startup + + -- event is system event + system + B2B.otherReply Reply on other leg received (see AmB2BSession) #code - reply code diff --git a/doc/dsm/examples/test_system_dsm.dsm b/doc/dsm/examples/test_system_dsm.dsm new file mode 100644 index 00000000..12ba57c7 --- /dev/null +++ b/doc/dsm/examples/test_system_dsm.dsm @@ -0,0 +1,37 @@ +-- script to show how SystemDSM can be used +-- +-- on server startup (or via runSystemDSM), the "startup" event is processed. +-- on config reload, the "reload" event is processed; here we only send an +-- event to the main SystemDSM thread + +initial state START; + +transition "startup" START - startup / { + log(2, "Here we are!"); + logAll(2); + setTimer(1, 20); + -- register a friendlier name + registerEventQueue(system_dsm); +} -> RUNNING; + +-- this gets called when script config is reloaded +transition "reload" START - reload / { + set($cmd="reload"); + postEvent(system_dsm, cmd); + -- or: postEvent(system_dsm, var) to post all variables, + -- including changed config (#config.*) + stop(false); +} -> END; + +state RUNNING; +transition "timer hit" RUNNING - timer / log(2, "still there!"); setTimer(1, 20); -> RUNNING; + +transition "shutdown" RUNNING - system / unregisterEventQueue(system_dsm); stop(false) -> END; + +transition "stop cmd" RUNNING - eventTest(#cmd=="stop") / logAll(2); unregisterEventQueue(system_dsm); stop(false) } -> END; + +transition "reload cmd" RUNNING - eventTest(#cmd=="reload") / log(2, "got refresh"); logParams(2); -> RUNNING; + +transition "some other event" RUNNING - event / logAll(2) -> RUNNING; + +state END;