summaryrefslogtreecommitdiffstats
path: root/src/uscxml/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'src/uscxml/plugins')
-rw-r--r--src/uscxml/plugins/DataModelImpl.h1
-rw-r--r--src/uscxml/plugins/Factory.cpp117
-rw-r--r--src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp4
-rw-r--r--src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h2
-rw-r--r--src/uscxml/plugins/invoker/CMakeLists.txt24
-rw-r--r--src/uscxml/plugins/invoker/dirmon/DirMonInvoker.cpp449
-rw-r--r--src/uscxml/plugins/invoker/dirmon/DirMonInvoker.h140
-rw-r--r--src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h1
-rw-r--r--src/uscxml/plugins/ioprocessor/CMakeLists.txt33
-rw-r--r--src/uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.cpp6
10 files changed, 708 insertions, 69 deletions
diff --git a/src/uscxml/plugins/DataModelImpl.h b/src/uscxml/plugins/DataModelImpl.h
index 403a213..a151141 100644
--- a/src/uscxml/plugins/DataModelImpl.h
+++ b/src/uscxml/plugins/DataModelImpl.h
@@ -43,6 +43,7 @@ class DataModelImpl;
*/
class USCXML_API DataModelCallbacks {
public:
+ virtual ~DataModelCallbacks() {} ///< silence virtual destructor warning from swig
virtual const std::string& getName() = 0;
virtual const std::string& getSessionId() = 0;
virtual const std::map<std::string, IOProcessor>& getIOProcessors() = 0;
diff --git a/src/uscxml/plugins/Factory.cpp b/src/uscxml/plugins/Factory.cpp
index 3600dd1..e551a61 100644
--- a/src/uscxml/plugins/Factory.cpp
+++ b/src/uscxml/plugins/Factory.cpp
@@ -28,23 +28,38 @@
// see http://nadeausoftware.com/articles/2012/01/c_c_tip_how_use_compiler_predefined_macros_detect_operating_system
-// we will always include these in a build
+
+#ifdef WITH_IOPROC_SCXML
+# include "uscxml/plugins/ioprocessor/scxml/SCXMLIOProcessor.h"
+#endif
+
+#ifdef WITH_IOPROC_BASICHTTP
+# include "uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.h"
+#endif
+
+
#include "uscxml/plugins/datamodel/null/NULLDataModel.h"
-#include "uscxml/plugins/invoker/scxml/USCXMLInvoker.h"
-#include "uscxml/plugins/ioprocessor/scxml/SCXMLIOProcessor.h"
-#include "uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.h"
-# ifdef V8_FOUND
+#ifdef WITH_DM_ECMA_V8
# include "uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h"
-# endif
+#endif
-# ifdef JSC_FOUND
+#ifdef WITH_DM_ECMA_JSC
# include "uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.h"
-# endif
+#endif
-# ifdef LUA_FOUND
+#ifdef WITH_DM_LUA
# include "uscxml/plugins/datamodel/lua/LuaDataModel.h"
-# endif
+#endif
+
+
+#ifdef WITH_INV_SCXML
+# include "uscxml/plugins/invoker/scxml/USCXMLInvoker.h"
+#endif
+
+#ifdef WITH_INV_DIRMON
+# include "uscxml/plugins/invoker/dirmon/DirMonInvoker.h"
+#endif
namespace uscxml {
@@ -69,47 +84,61 @@ std::string Factory::getDefaultPluginPath() {
void Factory::registerPlugins() {
- {
- USCXMLInvoker* invoker = new USCXMLInvoker();
- registerInvoker(invoker);
- }
-
- {
- SCXMLIOProcessor* ioProcessor = new SCXMLIOProcessor();
- registerIOProcessor(ioProcessor);
- }
-
- {
- BasicHTTPIOProcessor* ioProcessor = new BasicHTTPIOProcessor();
- registerIOProcessor(ioProcessor);
- }
-
- {
- NULLDataModel* dataModel = new NULLDataModel();
- registerDataModel(dataModel);
- }
+#ifdef WITH_IOPROC_SCXML
+ {
+ SCXMLIOProcessor* ioProcessor = new SCXMLIOProcessor();
+ registerIOProcessor(ioProcessor);
+ }
+#endif
-#ifdef V8_FOUND
- {
- V8DataModel* dataModel = new V8DataModel();
- registerDataModel(dataModel);
- }
+#ifdef WITH_IOPROC_BASICHTTP
+ {
+ BasicHTTPIOProcessor* ioProcessor = new BasicHTTPIOProcessor();
+ registerIOProcessor(ioProcessor);
+ }
#endif
-#ifdef JSC_FOUND
- {
- JSCDataModel* dataModel = new JSCDataModel();
- registerDataModel(dataModel);
- }
+
+#ifdef WITH_DM_ECMA_V8
+ {
+ V8DataModel* dataModel = new V8DataModel();
+ registerDataModel(dataModel);
+ }
#endif
-#ifdef LUA_FOUND
- {
- LuaDataModel* dataModel = new LuaDataModel();
- registerDataModel(dataModel);
- }
+#ifdef WITH_DM_ECMA_JSC
+ {
+ JSCDataModel* dataModel = new JSCDataModel();
+ registerDataModel(dataModel);
+ }
+#endif
+
+#ifdef WITH_DM_LUA
+ {
+ LuaDataModel* dataModel = new LuaDataModel();
+ registerDataModel(dataModel);
+ }
#endif
+ {
+ NULLDataModel* dataModel = new NULLDataModel();
+ registerDataModel(dataModel);
+ }
+
+
+#ifdef WITH_INV_SCXML
+ {
+ USCXMLInvoker* invoker = new USCXMLInvoker();
+ registerInvoker(invoker);
+ }
+#endif
+
+#ifdef WITH_INV_DIRMON
+ {
+ DirMonInvoker* inv = new DirMonInvoker();
+ registerInvoker(inv);
+ }
+#endif
}
diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp
index 3ccadcd..1db4f45 100644
--- a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp
+++ b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp
@@ -415,7 +415,9 @@ void V8DataModel::setEvent(const Event& event) {
}
// we cannot make _event v8::ReadOnly as it will ignore subsequent setEvents
global->Set(v8::String::NewSymbol("_event"), eventObj);
- _event.Reset(_isolate, eventObj);
+
+// _event.Reset(_isolate, eventObj);
+// _event = eventObj;
}
Data V8DataModel::getAsData(const std::string& content) {
diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h
index 91ac48d..3b4d776 100644
--- a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h
+++ b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h
@@ -84,7 +84,7 @@ protected:
static void jsIn(const v8::FunctionCallbackInfo<v8::Value>& info);
static void jsPrint(const v8::FunctionCallbackInfo<v8::Value>& info);
- v8::Persistent<v8::Object> _event;
+ //v8::Local<v8::Object> _event; // Persistent events leak ..
v8::Persistent<v8::Context> _context;
static v8::Isolate* _isolate;
diff --git a/src/uscxml/plugins/invoker/CMakeLists.txt b/src/uscxml/plugins/invoker/CMakeLists.txt
index ec64899..5500e3f 100644
--- a/src/uscxml/plugins/invoker/CMakeLists.txt
+++ b/src/uscxml/plugins/invoker/CMakeLists.txt
@@ -1,11 +1,25 @@
# USCXML invoker
-set(USCXML_INVOKERS "scxml ${USCXML_INVOKERS}")
-file(GLOB_RECURSE USCXML_INVOKER
- scxml/*.cpp
- scxml/*.h)
- list (APPEND USCXML_FILES ${USCXML_INVOKER})
+OPTION(WITH_INV_SCXML "Build the SCXML invoker" ON)
+if (WITH_INV_SCXML)
+ set(USCXML_INVOKERS "scxml ${USCXML_INVOKERS}")
+ file(GLOB_RECURSE USCXML_INVOKER
+ scxml/*.cpp
+ scxml/*.h)
+ list (APPEND USCXML_FILES ${USCXML_INVOKER})
+endif()
+
+# Directoy Monitor
+OPTION(WITH_INV_DIRMON "Build the directory monitor invoker" ON)
+if (WITH_INV_DIRMON)
+ set(USCXML_INVOKERS "dirmon ${USCXML_INVOKERS}")
+ file(GLOB_RECURSE DIRMON_INVOKER
+ dirmon/*.cpp
+ dirmon/*.h)
+ list (APPEND USCXML_FILES ${DIRMON_INVOKER})
+endif()
+
set(USCXML_INCLUDE_DIRS ${USCXML_INCLUDE_DIRS} PARENT_SCOPE)
set(USCXML_FILES ${USCXML_FILES} PARENT_SCOPE)
set(USCXML_INVOKERS ${USCXML_INVOKERS} PARENT_SCOPE)
diff --git a/src/uscxml/plugins/invoker/dirmon/DirMonInvoker.cpp b/src/uscxml/plugins/invoker/dirmon/DirMonInvoker.cpp
new file mode 100644
index 0000000..f3b429f
--- /dev/null
+++ b/src/uscxml/plugins/invoker/dirmon/DirMonInvoker.cpp
@@ -0,0 +1,449 @@
+/**
+ * @file
+ * @author 2012-2013 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de)
+ * @copyright Simplified BSD
+ *
+ * @cond
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the FreeBSD license as published by the FreeBSD
+ * project.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * You should have received a copy of the FreeBSD license along with this
+ * program. If not, see <http://www.opensource.org/licenses/bsd-license>.
+ * @endcond
+ */
+
+#include "DirMonInvoker.h"
+
+#include "uscxml/config.h"
+
+#ifdef BUILD_AS_PLUGINS
+#include <Pluma/Connector.hpp>
+#endif
+
+#include <sys/stat.h>
+#ifndef WIN32
+#include <dirent.h>
+#else
+#include <strsafe.h>
+#endif
+
+#include <boost/algorithm/string.hpp>
+#include <easylogging++.h>
+
+namespace uscxml {
+
+#ifdef BUILD_AS_PLUGINS
+PLUMA_CONNECTOR
+bool pluginConnect(pluma::Host& host) {
+ host.add( new DirMonInvokerProvider() );
+ return true;
+}
+#endif
+
+DirMonInvoker::DirMonInvoker() :
+ _reportExisting(true),
+ _reportHidden(false),
+ _recurse(false),
+ _thread(NULL),
+ _watcher(NULL) {
+}
+
+DirMonInvoker::~DirMonInvoker() {
+ _isRunning = false;
+ if (_thread) {
+ _thread->join();
+ delete _thread;
+ }
+ if (_watcher)
+ delete(_watcher);
+};
+
+std::shared_ptr<InvokerImpl> DirMonInvoker::create(InterpreterImpl* interpreter) {
+ std::shared_ptr<DirMonInvoker> invoker(new DirMonInvoker());
+ invoker->_interpreter = interpreter;
+ return invoker;
+}
+
+Data DirMonInvoker::getDataModelVariables() {
+ std::lock_guard<std::recursive_mutex> lock(_mutex);
+
+ Data data;
+ data.compound["dir"] = Data(_dir, Data::VERBATIM);
+
+ std::set<std::string>::iterator suffixIter = _suffixes.begin();
+ while(suffixIter != _suffixes.end()) {
+ data.compound["suffixes"].array.push_back(Data(*suffixIter, Data::VERBATIM));
+ suffixIter++;
+ }
+
+ std::map<std::string, struct stat> entries = _watcher->getAllEntries();
+ std::map<std::string, struct stat>::iterator entryIter = entries.begin();
+ while(entryIter != entries.end()) {
+ data.compound["file"].compound[entryIter->first].compound["mtime"] = Data(toStr(entryIter->second.st_mtime), Data::INTERPRETED);
+ data.compound["file"].compound[entryIter->first].compound["ctime"] = Data(toStr(entryIter->second.st_mtime), Data::INTERPRETED);
+ data.compound["file"].compound[entryIter->first].compound["atime"] = Data(toStr(entryIter->second.st_mtime), Data::INTERPRETED);
+ data.compound["file"].compound[entryIter->first].compound["size"] = Data(toStr(entryIter->second.st_mtime), Data::INTERPRETED);
+ entryIter++;
+ }
+
+ return data;
+}
+
+void DirMonInvoker::eventFromSCXML(const Event& event) {
+}
+
+void DirMonInvoker::invoke(const std::string& source, const Event& req) {
+ if (req.params.find("dir") == req.params.end()) {
+ LOG(ERROR) << "No dir param given";
+ return;
+ }
+
+ if (req.params.find("reportexisting") != req.params.end() &&
+ iequals(req.params.find("reportexisting")->second.atom, "false"))
+ _reportExisting = false;
+ if (req.params.find("recurse") != req.params.end() &&
+ iequals(req.params.find("recurse")->second.atom, "true"))
+ _recurse = true;
+ if (req.params.find("reporthidden") != req.params.end() &&
+ iequals(req.params.find("reporthidden")->second.atom, "true"))
+ _reportHidden = true;
+
+ std::string suffixList;
+ if (req.params.find("suffix") != req.params.end()) {
+ suffixList = req.params.find("suffix")->second.atom;
+ } else if (req.params.find("suffixes") != req.params.end()) {
+ suffixList = req.params.find("suffixes")->second.atom;
+ }
+
+ if (suffixList.size() > 0) {
+ // seperate path into components
+ std::stringstream ss(suffixList);
+ std::string item;
+ while(std::getline(ss, item, ' ')) {
+ if (item.length() == 0)
+ continue;
+ _suffixes.insert(item);
+ }
+ }
+
+ std::multimap<std::string, Data>::const_iterator dirIter = req.params.find("dir");
+ while(dirIter != req.params.upper_bound("dir")) {
+ // this is simplified - Data might be more elaborate than a simple string atom
+ URL url = URL::resolve(dirIter->second.atom, _interpreter->getBaseURL());
+
+ if (!url.isAbsolute()) {
+ LOG(ERROR) << "Given directory '" << dirIter->second << "' cannot be transformed to absolute path";
+ } else {
+ _dir = url.path();
+ }
+ break;
+ }
+
+ _watcher = new DirectoryWatch(_dir, _recurse);
+ _watcher->addMonitor(this);
+ _watcher->updateEntries(true);
+
+ _isRunning = true;
+ _thread = new std::thread(DirMonInvoker::run, this);
+}
+
+void DirMonInvoker::uninvoke() {
+ _isRunning = false;
+ if (_thread) {
+ _thread->join();
+ delete _thread;
+ }
+}
+
+void DirMonInvoker::run(void* instance) {
+ while(((DirMonInvoker*)instance)->_isRunning) {
+ {
+ std::lock_guard<std::recursive_mutex> lock(((DirMonInvoker*)instance)->_mutex);
+ ((DirMonInvoker*)instance)->_watcher->updateEntries();
+ }
+ std::this_thread::sleep_for(std::chrono::milliseconds(20));
+ }
+}
+
+void DirMonInvoker::handleChanges(DirectoryWatch::Action action, const std::string reportedDir, const std::string reportedFilename, struct stat fileStat) {
+
+// std::cout << action << " on " << reportedFilename << std::endl;
+
+ std::string path; ///< complete path to the file including filename
+ std::string relPath; ///< path relative to monitored directory including filename
+ std::string dir; ///< the name of the directory we monitor
+ std::string relDir; ///< the directory from dir to the actual directory where we found a file
+ std::string basename; ///< filename including suffix
+ std::string strippedName; ///< filename without the suffix
+ std::string extension; ///< the extension
+
+ dir = reportedDir;
+
+ path = dir + reportedFilename;
+ boost::algorithm::replace_all(path, "\\", "/");
+ boost::algorithm::replace_all(path, "//", "/");
+
+ assert(boost::algorithm::starts_with(path, dir));
+ relPath = path.substr(dir.length());
+ assert(boost::equal(path, dir + relPath));
+
+ size_t lastSep;
+ if ((lastSep = path.find_last_of(PATH_SEPERATOR)) != std::string::npos) {
+ lastSep++;
+ basename = path.substr(lastSep, path.length() - lastSep);
+ } else {
+ assert(false);
+ }
+ assert(boost::algorithm::ends_with(relPath, basename));
+
+ // extension is the suffix and strippedName the basename without the suffix
+ size_t lastDot;
+ if ((lastDot = basename.find_last_of(".")) != std::string::npos) {
+ if (lastDot == 0) {
+ // hidden file
+ strippedName = basename;
+ } else {
+ extension = basename.substr(lastDot + 1);
+ strippedName = basename.substr(0, lastDot);
+ }
+ } else {
+ strippedName = basename;
+ }
+
+ relDir = relPath.substr(0, relPath.length() - basename.length());
+ assert(boost::equal(path, dir + relDir + basename));
+
+ // return if this is a hidden file
+ if (boost::algorithm::starts_with(basename, ".") && !_reportHidden)
+ return;
+
+ // ilter suffixes
+ if (_suffixes.size() > 0) {
+ bool validSuffix = false;
+ std::set<std::string>::iterator suffixIter = _suffixes.begin();
+ while(suffixIter != _suffixes.end()) {
+ if (boost::algorithm::ends_with(path, *suffixIter)) {
+ validSuffix = true;
+ break;
+ }
+ suffixIter++;
+ }
+ if (!validSuffix)
+ return;
+ }
+
+ Event event;
+ event.invokeid = _invokeId;
+
+ switch (action) {
+ case DirectoryWatch::EXISTING:
+ event.name = "file.existing";
+ break;
+ case DirectoryWatch::ADDED:
+ event.name = "file.added";
+ break;
+ case DirectoryWatch::DELETED:
+ event.name = "file.deleted";
+ break;
+ case DirectoryWatch::MODIFIED:
+ event.name = "file.modified";
+ break;
+ default:
+ break;
+ }
+
+ if (action != DirectoryWatch::DELETED) {
+ event.data.compound["file"].compound["mtime"] = Data(toStr(fileStat.st_mtime), Data::INTERPRETED);
+ event.data.compound["file"].compound["ctime"] = Data(toStr(fileStat.st_ctime), Data::INTERPRETED);
+ event.data.compound["file"].compound["atime"] = Data(toStr(fileStat.st_atime), Data::INTERPRETED);
+ event.data.compound["file"].compound["size"] = Data(toStr(fileStat.st_size), Data::INTERPRETED);
+ }
+
+ event.data.compound["file"].compound["name"] = Data(basename, Data::VERBATIM);
+ event.data.compound["file"].compound["extension"] = Data(extension, Data::VERBATIM);
+ event.data.compound["file"].compound["strippedName"] = Data(strippedName, Data::VERBATIM);
+ event.data.compound["file"].compound["relPath"] = Data(relPath, Data::VERBATIM);
+ event.data.compound["file"].compound["relDir"] = Data(relDir, Data::VERBATIM);
+ event.data.compound["file"].compound["path"] = Data(path, Data::VERBATIM);
+ event.data.compound["file"].compound["dir"] = Data(dir, Data::VERBATIM);
+
+ eventToSCXML(event, "dimon", "");
+}
+
+DirectoryWatch::~DirectoryWatch() {
+ std::map<std::string, DirectoryWatch*>::iterator dirIter = _knownDirs.begin();
+ while(dirIter != _knownDirs.end()) {
+ delete(dirIter->second);
+ dirIter++;
+ }
+
+}
+
+void DirectoryWatch::reportAsDeleted() {
+ std::map<std::string, struct stat>::iterator fileIter = _knownEntries.begin();
+ while(fileIter != _knownEntries.end()) {
+ if (fileIter->second.st_mode & S_IFDIR) {
+ _knownDirs[fileIter->first]->reportAsDeleted();
+ delete _knownDirs[fileIter->first];
+ _knownDirs.erase(fileIter->first);
+ } else {
+ _monitors_t::iterator monIter = _monitors.begin();
+ while(monIter != _monitors.end()) {
+ (*monIter)->handleChanges(DELETED, _dir, _relDir + PATH_SEPERATOR + fileIter->first, fileIter->second);
+ monIter++;
+ }
+ }
+ _knownEntries.erase(fileIter++);
+// fileIter++;
+ }
+ assert(_knownDirs.size() == 0);
+ assert(_knownEntries.size() == 0);
+}
+
+void DirectoryWatch::updateEntries(bool reportAsExisting) {
+ _monitors_t::iterator monIter;
+ if (_dir[_dir.length() - 1] == PATH_SEPERATOR)
+ _dir = _dir.substr(0, _dir.length() - 1);
+
+ // stat directory for modification date
+ struct stat dirStat;
+ if (stat((_dir + _relDir).c_str(), &dirStat) != 0) {
+ LOG(ERROR) << "Error with stat on directory " << _dir << ": " << strerror(errno);
+ return;
+ }
+
+ if ((unsigned)dirStat.st_mtime >= (unsigned)_lastChecked) {
+// std::cout << "dirStat.st_mtime: " << dirStat.st_mtime << " / _lastChecked: " << _lastChecked << std::endl;
+
+ // there are changes in the directory
+ std::set<std::string> currEntries;
+
+#ifndef WIN32
+ DIR *dp;
+ dp = opendir((_dir + _relDir).c_str());
+ if (dp == NULL) {
+ LOG(ERROR) << "Error opening directory " << _dir + _relDir << ": " << strerror(errno);
+ return;
+ }
+ // iterate all entries and see what changed
+ struct dirent* entry;
+ while((entry = readdir(dp))) {
+ std::string dname = entry->d_name;
+#else
+ WIN32_FIND_DATA ffd;
+ HANDLE hFind = INVALID_HANDLE_VALUE;
+ TCHAR szDir[MAX_PATH];
+ StringCchCopy(szDir, MAX_PATH, _dir.c_str());
+ StringCchCat(szDir, MAX_PATH, TEXT("\\*"));
+
+ hFind = FindFirstFile(szDir, &ffd);
+ do {
+ std::string dname = ffd.cFileName;
+#endif
+
+ // see if the file was changed
+ std::string filename = _dir + _relDir + "/" + dname;
+// asprintf(&filename, "%s/%s", (_dir + _relDir).c_str(), dname.c_str());
+
+ struct stat fileStat;
+ if (stat(filename.c_str(), &fileStat) != 0) {
+ LOG(ERROR) << "Error with stat on directory entry: " << filename << ": " << strerror(errno);
+ continue;
+ }
+
+ if (fileStat.st_mode & S_IFDIR) {
+ if (boost::equals(dname, ".") || boost::equals(dname, "..")) {
+ continue; // do not report . or ..
+ }
+ }
+
+ currEntries.insert(dname);
+
+ if (_knownEntries.find(dname) != _knownEntries.end()) {
+ // we have seen this entry before
+ struct stat oldStat = _knownEntries[dname];
+ if (oldStat.st_mtime < fileStat.st_mtime) {
+ monIter = _monitors.begin();
+ while(monIter != _monitors.end()) {
+ (*monIter)->handleChanges(MODIFIED, _dir, _relDir + PATH_SEPERATOR + dname, fileStat);
+ monIter++;
+ }
+ }
+ } else {
+ // we have not yet seen this entry
+ if (fileStat.st_mode & S_IFDIR) {
+ _knownDirs[dname] = new DirectoryWatch(_dir, _relDir + PATH_SEPERATOR + dname);
+ monIter = _monitors.begin();
+ while(monIter != _monitors.end()) {
+ _knownDirs[dname]->addMonitor(*monIter);
+ monIter++;
+ }
+ } else {
+ monIter = _monitors.begin();
+ while(monIter != _monitors.end()) {
+ if (reportAsExisting) {
+ (*monIter)->handleChanges(EXISTING, _dir, _relDir + PATH_SEPERATOR + dname, fileStat);
+ } else {
+ (*monIter)->handleChanges(ADDED, _dir, _relDir + PATH_SEPERATOR + dname, fileStat);
+ }
+ monIter++;
+ }
+ }
+ }
+
+ _knownEntries[dname] = fileStat; // gets copied on insertion
+#ifndef WIN32
+ }
+ closedir(dp);
+#else
+ }
+ while (FindNextFile(hFind, &ffd) != 0);
+ FindClose(hFind);
+#endif
+ // are there any known entries we have not seen this time around?
+ std::map<std::string, struct stat>::iterator fileIter = _knownEntries.begin();
+ while(fileIter != _knownEntries.end()) {
+ if (currEntries.find(fileIter->first) == currEntries.end()) {
+ // we used to know this file
+ if (fileIter->second.st_mode & S_IFDIR) {
+ if (_recurse) {
+ _knownDirs[fileIter->first]->reportAsDeleted();
+ delete _knownDirs[fileIter->first];
+ _knownDirs.erase(fileIter->first);
+ }
+ } else {
+ monIter = _monitors.begin();
+ while(monIter != _monitors.end()) {
+ (*monIter)->handleChanges(DELETED, _dir, _relDir + PATH_SEPERATOR + fileIter->first, fileIter->second);
+ monIter++;
+ }
+ }
+ _knownEntries.erase(fileIter++);
+ } else {
+ fileIter++;
+ }
+ }
+ // remember when we last checked the directory for modifications
+#ifndef WIN32
+ time(&_lastChecked);
+#else
+ // TODO: this will fail with sub-millisecond updates to the directory
+ _lastChecked = dirStat.st_mtime + 1;
+#endif
+ // update all directories
+ }
+ if (_recurse) {
+ std::map<std::string, DirectoryWatch*>::iterator dirIter = _knownDirs.begin();
+ while(dirIter != _knownDirs.end()) {
+ dirIter->second->updateEntries();
+ dirIter++;
+ }
+ }
+}
+
+} \ No newline at end of file
diff --git a/src/uscxml/plugins/invoker/dirmon/DirMonInvoker.h b/src/uscxml/plugins/invoker/dirmon/DirMonInvoker.h
new file mode 100644
index 0000000..be510d9
--- /dev/null
+++ b/src/uscxml/plugins/invoker/dirmon/DirMonInvoker.h
@@ -0,0 +1,140 @@
+/**
+ * @file
+ * @author 2012-2013 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de)
+ * @copyright Simplified BSD
+ *
+ * @cond
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the FreeBSD license as published by the FreeBSD
+ * project.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * You should have received a copy of the FreeBSD license along with this
+ * program. If not, see <http://www.opensource.org/licenses/bsd-license>.
+ * @endcond
+ */
+
+#ifndef DIRMONINVOKER_H_W09J90F0
+#define DIRMONINVOKER_H_W09J90F0
+
+#include "uscxml/plugins/InvokerImpl.h"
+
+#include <map>
+#include <set>
+#include <sys/stat.h>
+
+#ifdef BUILD_AS_PLUGINS
+#include "uscxml/plugins/Plugins.h"
+#endif
+
+namespace uscxml {
+
+class DirectoryWatchMonitor;
+
+class DirectoryWatch {
+public:
+ enum Action {
+ ADDED = 1,
+ MODIFIED = 2,
+ DELETED = 4,
+ EXISTING = 8
+ };
+
+ DirectoryWatch(const std::string& dir, bool recurse = false) : _dir(dir), _recurse(recurse), _lastChecked(0) {}
+ ~DirectoryWatch();
+
+ void addMonitor(DirectoryWatchMonitor* monitor) {
+ _monitors.insert(monitor);
+ }
+ void removeMonitor(DirectoryWatchMonitor* monitor) {
+ _monitors.erase(monitor);
+ }
+ void updateEntries(bool reportAsExisting = false);
+ void reportAsDeleted();
+
+ std::map<std::string, struct stat> getAllEntries() {
+ std::map<std::string, struct stat> entries;
+ entries.insert(_knownEntries.begin(), _knownEntries.end());
+
+ std::map<std::string, DirectoryWatch*>::iterator dirIter = _knownDirs.begin();
+ while(dirIter != _knownDirs.end()) {
+ std::map<std::string, struct stat> dirEntries = dirIter->second->getAllEntries();
+ std::map<std::string, struct stat>::iterator dirEntryIter = dirEntries.begin();
+ while(dirEntryIter != dirEntries.end()) {
+ entries[dirIter->first + '/' + dirEntryIter->first] = dirEntryIter->second;
+ dirEntryIter++;
+ }
+ dirIter++;
+ }
+
+ return entries;
+ }
+
+protected:
+ DirectoryWatch(const std::string& dir, const std::string& relDir) : _dir(dir), _relDir(relDir), _recurse(true), _lastChecked(0) {}
+
+ std::string _dir;
+ std::string _relDir;
+
+ bool _recurse;
+ std::map<std::string, struct stat> _knownEntries;
+ std::map<std::string, DirectoryWatch*> _knownDirs;
+ std::set<DirectoryWatchMonitor*> _monitors;
+ typedef std::set<DirectoryWatchMonitor*> _monitors_t;
+ time_t _lastChecked;
+};
+
+class DirectoryWatchMonitor {
+public:
+ virtual void handleChanges(DirectoryWatch::Action action, const std::string dir, const std::string file, struct stat fileStat) = 0;
+};
+
+class DirMonInvoker : public InvokerImpl, public DirectoryWatchMonitor {
+public:
+ DirMonInvoker();
+ virtual ~DirMonInvoker();
+ virtual std::shared_ptr<InvokerImpl> create(InterpreterImpl* interpreter);
+
+ virtual std::list<std::string> getNames() {
+ std::list<std::string> names;
+ names.push_back("dirmon");
+ names.push_back("DirectoryMonitor");
+ names.push_back("http://uscxml.tk.informatik.tu-darmstadt.de/#dirmon");
+ return names;
+ }
+
+ virtual Data getDataModelVariables();
+ virtual void eventFromSCXML(const Event& event);
+ virtual void invoke(const std::string& source, const Event& invokeEvent);
+ virtual void uninvoke();
+
+ virtual void handleChanges(DirectoryWatch::Action action, const std::string dir, const std::string file, struct stat fileStat);
+
+ static void run(void* instance);
+
+protected:
+ bool _reportExisting;
+ bool _reportHidden;
+ bool _recurse;
+
+ std::string _dir;
+ std::set<std::string> _suffixes;
+
+ bool _isRunning;
+ std::thread* _thread;
+ std::recursive_mutex _mutex;
+
+ DirectoryWatch* _watcher;
+};
+
+#ifdef BUILD_AS_PLUGINS
+PLUMA_INHERIT_PROVIDER(DirMonInvoker, InvokerImpl);
+#endif
+
+}
+
+
+#endif /* end of include guard: DIRMONINVOKER_H_W09J90F0 */
diff --git a/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h
index f896bac..9509de3 100644
--- a/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h
+++ b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h
@@ -23,7 +23,6 @@
#include "uscxml/interpreter/InterpreterImpl.h"
#include "uscxml/interpreter/BasicEventQueue.h"
-#include "uscxml/plugins/Invoker.h"
#include "uscxml/plugins/InvokerImpl.h"
#ifdef BUILD_AS_PLUGINS
diff --git a/src/uscxml/plugins/ioprocessor/CMakeLists.txt b/src/uscxml/plugins/ioprocessor/CMakeLists.txt
index 1171d73..3505920 100644
--- a/src/uscxml/plugins/ioprocessor/CMakeLists.txt
+++ b/src/uscxml/plugins/ioprocessor/CMakeLists.txt
@@ -1,20 +1,25 @@
# scxml ioprocessor
-set(USCXML_IOPROCESSORS "scxml ${USCXML_IOPROCESSORS}")
-file(GLOB_RECURSE SCXML_IOPROCESSOR
- scxml/*.cpp
- scxml/*.h
-)
-list (APPEND USCXML_FILES ${SCXML_IOPROCESSOR})
+OPTION(WITH_IOPROC_SCXML "Build the scxml i/o processor" ON)
+if (WITH_IOPROC_SCXML)
+ set(USCXML_IOPROCESSORS "scxml ${USCXML_IOPROCESSORS}")
+ file(GLOB_RECURSE SCXML_IOPROCESSOR
+ scxml/*.cpp
+ scxml/*.h
+ )
+ list (APPEND USCXML_FILES ${SCXML_IOPROCESSOR})
+endif()
-set(USCXML_IOPROCESSORS "basichttp ${USCXML_IOPROCESSORS}")
-file(GLOB_RECURSE BASICHTTP_IOPROCESSOR
- basichttp/*.cpp
- basichttp/*.h
-)
-list (APPEND BASICHTTP_IOPROCESSOR "")
-
-list (APPEND USCXML_FILES ${BASICHTTP_IOPROCESSOR})
+OPTION(WITH_IOPROC_BASICHTTP "Build the basichttp i/o processor" ON)
+if (WITH_IOPROC_BASICHTTP)
+ set(USCXML_IOPROCESSORS "basichttp ${USCXML_IOPROCESSORS}")
+ file(GLOB_RECURSE BASICHTTP_IOPROCESSOR
+ basichttp/*.cpp
+ basichttp/*.h
+ )
+ list (APPEND BASICHTTP_IOPROCESSOR "")
+ list (APPEND USCXML_FILES ${BASICHTTP_IOPROCESSOR})
+endif()
set(USCXML_INCLUDE_DIRS ${USCXML_INCLUDE_DIRS} PARENT_SCOPE)
set(USCXML_OPT_LIBS ${USCXML_OPT_LIBS} PARENT_SCOPE)
diff --git a/src/uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.cpp b/src/uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.cpp
index f81cf54..317b94c 100644
--- a/src/uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.cpp
+++ b/src/uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.cpp
@@ -199,9 +199,9 @@ void BasicHTTPIOProcessor::eventFromSCXML(const std::string& target, const Event
char* eventValueCStr = evhttp_encode_uri(event.name.c_str());
kvps << kvpSeperator << eventNameCStr << "=" << eventValueCStr;
kvpSeperator = "&";
- free(eventNameCStr);
- free(eventValueCStr);
- targetURL.addOutHeader("_scxmleventname", evhttp_encode_uri(event.name.c_str()));
+ targetURL.addOutHeader("_scxmleventname", eventValueCStr);
+ free(eventNameCStr);
+ free(eventValueCStr);
}
// event namelist