From 612e1754fc830c972bb65a00f0743f009597fab3 Mon Sep 17 00:00:00 2001 From: Stefan Sayer Date: Wed, 21 Oct 2009 22:35:27 +0000 Subject: [PATCH] support for live reloading of DSM scripts, preloading of modules, registering of applications, listing DSMs git-svn-id: http://svn.berlios.de/svnroot/repos/sems/trunk@1551 8eb893ce-cfd4-0310-b710-fb5ebe64c474 --- apps/dsm/DSM.cpp | 264 ++++++++++++++++++++++--- apps/dsm/DSM.h | 15 +- apps/dsm/DSMStateDiagramCollection.cpp | 8 + apps/dsm/DSMStateDiagramCollection.h | 1 + apps/dsm/doc/Readme.dsm.txt | 39 ++++ 5 files changed, 302 insertions(+), 25 deletions(-) diff --git a/apps/dsm/DSM.cpp b/apps/dsm/DSM.cpp index d84ba0c1..29522aa0 100644 --- a/apps/dsm/DSM.cpp +++ b/apps/dsm/DSM.cpp @@ -77,6 +77,8 @@ DSMFactory::DSMFactory(const string& _app_name) loaded(false) { AmEventDispatcher::instance()->addEventQueue("dsm", this); + + diags = new DSMStateDiagramCollection(); } void DSMFactory::postEvent(AmEvent* e) { @@ -183,32 +185,20 @@ int DSMFactory::onLoad() string ModPath = cfg.getParameter("mod_path"); - string preload_mods = cfg.getParameter("preload_mods"); - vector preload_names = explode(preload_mods, ","); - if (preload_names.size()) { - for (vector::iterator it= - preload_names.begin(); it != preload_names.end(); it++) { - DBG("preloading '%s'...\n", it->c_str()); - if (!preload_reader.importModule("import("+*it+")", ModPath)) { - ERROR("importing module '%s' for preload\n", it->c_str()); - return -1; - } - DSMModule* last_loaded = preload_reader.mods.back(); - if (last_loaded) { - if (last_loaded->preload()) { - DBG("Error while preloading '%s'\n", it->c_str()); - return -1; - } - } - } + string err; + int res = preloadModules(cfg, err, ModPath); + if (res<0) { + ERROR("%s\n", err.c_str()); + return res; } + // todo: pass preloaded mods to chart reader string LoadDiags = cfg.getParameter("load_diags"); vector diags_names = explode(LoadDiags, ","); for (vector::iterator it= diags_names.begin(); it != diags_names.end(); it++) { - if (!diags.loadFile(DiagPath+*it+".dsm", *it, ModPath)) { + if (!diags->loadFile(DiagPath+*it+".dsm", *it, ModPath)) { ERROR("loading %s from %s\n", it->c_str(), (DiagPath+*it+".dsm").c_str()); return -1; @@ -219,7 +209,7 @@ int DSMFactory::onLoad() vector register_names = explode(RegisterDiags, ","); for (vector::iterator it= register_names.begin(); it != register_names.end(); it++) { - if (diags.hasDiagram(*it)) { + if (diags->hasDiagram(*it)) { bool res = AmPlugIn::instance()->registerFactory4App(*it,this); if(res) INFO("DSM state machine registered: %s.\n", @@ -448,7 +438,10 @@ AmSession* DSMFactory::onInvite(const AmSipRequest& req) } else { start_diag = req.cmd; } - DSMCall* s = new DSMCall(&prompts, diags, start_diag, NULL); + diags_mut.lock(); + DSMCall* s = new DSMCall(&prompts, *diags, start_diag, NULL); + diags_mut.unlock(); + prepareSession(s); addVariables(s, "config.", config); @@ -503,7 +496,7 @@ AmSession* DSMFactory::onInvite(const AmSipRequest& req, AmArg2DSMStrMap(session_params, vars); } - DSMCall* s = new DSMCall(&prompts, diags, start_diag, cred); + DSMCall* s = new DSMCall(&prompts, *diags, start_diag, cred); prepareSession(s); addVariables(s, "config.", config); @@ -532,11 +525,206 @@ AmSession* DSMFactory::onInvite(const AmSipRequest& req, return s; } +void DSMFactory::reloadDSMs(const AmArg& args, AmArg& ret) { + DSMStateDiagramCollection* new_diags = new DSMStateDiagramCollection(); + + AmConfigReader cfg; + if(cfg.loadFile(AmConfig::ModConfigPath + string(MOD_NAME ".conf"))) { + ret.push(500); + ret.push("loading config file " +AmConfig::ModConfigPath + string(MOD_NAME ".conf")); + return ; + } + + string DiagPath = cfg.getParameter("diag_path"); + if (DiagPath.length() && DiagPath[DiagPath.length()-1] != '/') + DiagPath += '/'; + + string ModPath = cfg.getParameter("mod_path"); + + string LoadDiags = cfg.getParameter("load_diags"); + vector diags_names = explode(LoadDiags, ","); + for (vector::iterator it= + diags_names.begin(); it != diags_names.end(); it++) { + if (!new_diags->loadFile(DiagPath+*it+".dsm", *it, ModPath)) { + ERROR("loading %s from %s\n", + it->c_str(), (DiagPath+*it+".dsm").c_str()); + ret.push(500); + ret.push("loading " +*it+ " from "+ DiagPath+*it+".dsm"); + return; + } + } + diags_mut.lock(); + DSMStateDiagramCollection* old_diags = diags; + diags = new_diags; + diags_mut.unlock(); + + DBG("deleting old diagram collection\n"); + delete old_diags; + + ret.push(200); + ret.push("DSMs reloaded"); +} + + +int DSMFactory::preloadModules(AmConfigReader& cfg, string& res, const string& ModPath) { + string preload_mods = cfg.getParameter("preload_mods"); + vector preload_names = explode(preload_mods, ","); + if (preload_names.size()) { + for (vector::iterator it= + preload_names.begin(); it != preload_names.end(); it++) { + DBG("preloading '%s'...\n", it->c_str()); + if (!preload_reader.importModule("import("+*it+")", ModPath)) { + res = "importing module '"+*it+"' for preload\n"; + return -1; + } + DSMModule* last_loaded = preload_reader.mods.back(); + if (last_loaded) { + if (last_loaded->preload()) { + res = "Error while preloading '"+*it+"'\n"; + return -1; + } + } + } + } + + return 0; +} + +void DSMFactory::preloadModules(const AmArg& args, AmArg& ret) { + AmConfigReader cfg; + if(cfg.loadFile(AmConfig::ModConfigPath + string(MOD_NAME ".conf"))) { + ret.push(500); + ret.push("loading config file " +AmConfig::ModConfigPath + string(MOD_NAME ".conf")); + return ; + } + string err; + + string ModPath = cfg.getParameter("mod_path"); + + int res = preloadModules(cfg, err, ModPath); + if (res<0) { + ret.push(500); + ret.push(err); + } else { + ret.push(200); + ret.push("modules preloaded"); + } +} + +void DSMFactory::preloadModule(const AmArg& args, AmArg& ret) { + string mod_name = args.get(0).asCStr(); + string mod_path = args.get(1).asCStr(); + + if (!preload_reader.importModule("import("+mod_name+")", mod_path)) { + ret.push(500); + ret.push("importing module '"+mod_name+"' for preload"); + return; + } + DSMModule* last_loaded = preload_reader.mods.back(); + if (last_loaded) { + if (last_loaded->preload()) { + ret.push(500); + ret.push("Error while preloading '"+mod_name+"'"); + return; + } + } + ret.push(200); + ret.push("module preloaded."); + return; +} + +void DSMFactory::listDSMs(const AmArg& args, AmArg& ret) { + diags_mut.lock(); + vector names = diags->getDiagramNames(); + diags_mut.unlock(); + for (vector::iterator it= + names.begin(); it != names.end(); it++) { + ret.push(*it); + } +} + +void DSMFactory::hasDSM(const AmArg& args, AmArg& ret) { + diags_mut.lock(); + bool res = diags->hasDiagram(args.get(0).asCStr()); + diags_mut.unlock(); + if (res) + ret.push("1"); + else + ret.push("0"); +} + +void DSMFactory::registerApplication(const AmArg& args, AmArg& ret) { + string diag_name = args.get(0).asCStr(); + diags_mut.lock(); + bool has_diag = diags->hasDiagram(diag_name); + diags_mut.unlock(); + if (!has_diag) { + ret.push(400); + ret.push("unknown application (DSM)"); + return; + } + + bool res = AmPlugIn::instance()->registerFactory4App(diag_name,this); + if(res) { + INFO("DSM state machine registered: %s.\n",diag_name.c_str()); + ret.push(200); + ret.push("registered DSM application"); + } else { + ret.push(500); + ret.push("Error registering DSM application (already registered?)"); + } +} + +void DSMFactory::loadDSM(const AmArg& args, AmArg& ret) { + string dsm_name = args.get(0).asCStr(); + + AmConfigReader cfg; + if(cfg.loadFile(AmConfig::ModConfigPath + string(MOD_NAME ".conf"))) { + ret.push(500); + ret.push("loading config file " +AmConfig::ModConfigPath + string(MOD_NAME ".conf")); + return ; + } + + string DiagPath = cfg.getParameter("diag_path"); + if (DiagPath.length() && DiagPath[DiagPath.length()-1] != '/') + DiagPath += '/'; + + string ModPath = cfg.getParameter("mod_path"); + + string dsm_file_name = DiagPath+dsm_name+".dsm"; + string res = "OK"; + diags_mut.lock(); + if (!diags->loadFile(dsm_file_name, dsm_name, ModPath)) { + ret.push(500); + ret.push("error loading "+dsm_name+" from "+ dsm_file_name); + } else { + ret.push(200); + ret.push("loaded "+dsm_name+" from "+ dsm_file_name); + } + diags_mut.unlock(); +} + +void DSMFactory::loadDSMWithPaths(const AmArg& args, AmArg& ret) { + string dsm_name = args.get(0).asCStr(); + string diag_path = args.get(1).asCStr(); + string mod_path = args.get(2).asCStr(); + + string res = "OK"; + diags_mut.lock(); + if (!diags->loadFile(diag_path+dsm_name+".dsm", dsm_name, mod_path)) { + ret.push(500); + ret.push("error loading "+dsm_name+" from "+ diag_path+dsm_name+".dsm"); + } else { + ret.push(200); + ret.push("loaded "+dsm_name+" from "+ diag_path+dsm_name+".dsm"); + } + diags_mut.unlock(); +} void DSMFactory::invoke(const string& method, const AmArg& args, AmArg& ret) { - if(method == "postDSMEvent"){ + if (method == "postDSMEvent"){ assertArgCStr(args.get(0)) DSMEvent* ev = new DSMEvent(); @@ -550,9 +738,37 @@ void DSMFactory::invoke(const string& method, const AmArg& args, ret.push(AmArg(404)); ret.push(AmArg("Session not found")); } - + } else if (method == "reloadDSMs"){ + reloadDSMs(args,ret); + } else if (method == "loadDSM"){ + args.assertArrayFmt("s"); + loadDSM(args,ret); + } else if (method == "loadDSMWithPath"){ + args.assertArrayFmt("sss"); + loadDSMWithPaths(args,ret); + } else if (method == "preloadModules"){ + preloadModules(args,ret); + } else if (method == "preloadModule"){ + args.assertArrayFmt("ss"); + preloadModule(args,ret); + } else if (method == "hasDSM"){ + args.assertArrayFmt("s"); + hasDSM(args,ret); + } else if (method == "listDSMs"){ + listDSMs(args,ret); + } else if (method == "registerApplication"){ + args.assertArrayFmt("s"); + registerApplication(args,ret); } else if(method == "_list"){ ret.push(AmArg("postDSMEvent")); + ret.push(AmArg("reloadDSMs")); + ret.push(AmArg("loadDSM")); + ret.push(AmArg("loadDSMWithPaths")); + ret.push(AmArg("preloadModules")); + ret.push(AmArg("preloadModule")); + ret.push(AmArg("hasDSM")); + ret.push(AmArg("listDSMs")); + ret.push(AmArg("registerApplication")); } else throw AmDynInvoke::NotImplemented(method); } diff --git a/apps/dsm/DSM.h b/apps/dsm/DSM.h index cce1baf6..eb70f999 100644 --- a/apps/dsm/DSM.h +++ b/apps/dsm/DSM.h @@ -60,7 +60,8 @@ class DSMFactory public AmEventQueueInterface { AmPromptCollection prompts; - DSMStateDiagramCollection diags; + DSMStateDiagramCollection* diags; + AmMutex diags_mut; static string InboundStartDiag; static string OutboundStartDiag; @@ -83,6 +84,18 @@ class DSMFactory void addParams(DSMCall* s, const string& hdrs); DSMChartReader preload_reader; + + void listDSMs(const AmArg& args, AmArg& ret); + void hasDSM(const AmArg& args, AmArg& ret); + void reloadDSMs(const AmArg& args, AmArg& ret); + void preloadModules(const AmArg& args, AmArg& ret); + void preloadModule(const AmArg& args, AmArg& ret); + void loadDSM(const AmArg& args, AmArg& ret); + void loadDSMWithPaths(const AmArg& args, AmArg& ret); + void registerApplication(const AmArg& args, AmArg& ret); + + int preloadModules(AmConfigReader& cfg, string& res, const string& ModPath); + public: static DSMFactory* instance(); diff --git a/apps/dsm/DSMStateDiagramCollection.cpp b/apps/dsm/DSMStateDiagramCollection.cpp index d2dc4955..210b9cb4 100644 --- a/apps/dsm/DSMStateDiagramCollection.cpp +++ b/apps/dsm/DSMStateDiagramCollection.cpp @@ -78,6 +78,14 @@ bool DSMStateDiagramCollection::hasDiagram(const string& name) { return false; } +vector DSMStateDiagramCollection::getDiagramNames() { + vector res; + for (vector::iterator it= + diags.begin(); it != diags.end(); it++) + res.push_back(it->getName()); + return res; +} + void DSMStateDiagramCollection::addToEngine(DSMStateEngine* e) { DBG("adding %zd diags to engine\n", diags.size()); for (vector ::iterator it = diff --git a/apps/dsm/DSMStateDiagramCollection.h b/apps/dsm/DSMStateDiagramCollection.h index 899e2658..51446f1d 100644 --- a/apps/dsm/DSMStateDiagramCollection.h +++ b/apps/dsm/DSMStateDiagramCollection.h @@ -46,6 +46,7 @@ class DSMStateDiagramCollection bool loadFile(const string& filename, const string& name, const string& mod_path); void addToEngine(DSMStateEngine* e); bool hasDiagram(const string& name); + vector getDiagramNames(); }; #endif diff --git a/apps/dsm/doc/Readme.dsm.txt b/apps/dsm/doc/Readme.dsm.txt index 4ec54d0b..2c4a5944 100644 --- a/apps/dsm/doc/Readme.dsm.txt +++ b/apps/dsm/doc/Readme.dsm.txt @@ -44,10 +44,49 @@ 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. +DI commands +=========== + +postDSMEvent(string call_id, [ [[param0,val0],[param1,val1],...] ] + post a DSM event into a call. can be used to interact with running + calls in DSM. See DSM + monitoring + DI example in + examples/dsm_di_monit. + + Example: + s.postDSMEvent(call_id, [['action', 'take'],['roomname', 'realworld']]) + + +reloadDSMs() + reload all DSMs from config file (load_diags) + +loadDSM(string diag_name) + load DSM with name diag_name, paths are taken from config file + +loadDSMWithPaths(string diag_name, string diag_path, string mod_path) + load DSM with specified paths + +preloadModules() + preload all modules specified in config file (preload_mods) + +preloadModule(string mod_name, string mod_path) + preload module from specific path + +hasDSM(string diag_name) + returns 1 if DSM with diag_name is loaded, 0 if not + +listDSMs() + return list of loaded DSMs + +registerApplication(string diag_name) + register DSM with name diag_name as application in SEMS + (e.g. to be used with application=$(apphdr), $(ruri.param) + or $(ruri.user) + More info ========= o doc/dsm_syntax.txt has a quick reference for dsm syntax o doc/examples/ and lib/ some example DSMs + o doc/examples/dsm_di_monit example on interfacing with DSM o mods/ (will) have modules Internals