diff options
Diffstat (limited to 'src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.cpp')
-rw-r--r-- | src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.cpp | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.cpp b/src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.cpp new file mode 100644 index 0000000..8489d1d --- /dev/null +++ b/src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.cpp @@ -0,0 +1,197 @@ +#include "DirMonInvoker.h" +#include <glog/logging.h> + +#ifdef BUILD_AS_PLUGINS +#include <Pluma/Connector.hpp> +#endif + +#include <sys/stat.h> +#ifndef WIN32 +#include <dirent.h> +#else +#include <strsafe.h> +#endif + +namespace uscxml { + +#ifdef BUILD_AS_PLUGINS +PLUMA_CONNECTOR +bool connect(pluma::Host& host) { + host.add( new DirMonInvokerProvider() ); + return true; +} +#endif + +DirMonInvoker::DirMonInvoker() : _reportExisting(false), _recurse(false), _thread(NULL) { +} + +DirMonInvoker::~DirMonInvoker() { + _isRunning = false; + if (_thread) + _thread->join(); +}; + +boost::shared_ptr<IOProcessorImpl> DirMonInvoker::create(Interpreter* interpreter) { + boost::shared_ptr<DirMonInvoker> invoker = boost::shared_ptr<DirMonInvoker>(new DirMonInvoker()); + invoker->_interpreter = interpreter; + return invoker; +} + +Data DirMonInvoker::getDataModelVariables() { + Data data; + return data; +} + +void DirMonInvoker::send(const SendRequest& req) { +} + +void DirMonInvoker::cancel(const std::string sendId) { +} + +void DirMonInvoker::invoke(const InvokeRequest& req) { + if (req.params.find("dir") != req.params.end() && boost::iequals(req.params.find("reportexisting")->second, "true")) + _reportExisting = true; + if (req.params.find("recurse") != req.params.end() && boost::iequals(req.params.find("recurse")->second, "true")) + _recurse = true; + if (req.params.find("suffix") != req.params.end()) + _suffix = req.params.find("suffix")->second; + + std::multimap<std::string, std::string>::const_iterator dirIter = req.params.find("dir"); + while(dirIter != req.params.upper_bound("dir")) { + URL url(dirIter->second); + if (!_interpreter->toAbsoluteURI(url) || !boost::iequals(url.scheme(), "file")) { + LOG(ERROR) << "Given directory '" << dirIter->second << "' cannot be transformed to absolute path"; + } else { + _watchIds.insert(std::make_pair(url.path(), _fileWatcher.addWatch(url.path(), this, _recurse))); + } + dirIter++; + } + _isRunning = true; + _thread = new tthread::thread(DirMonInvoker::run, this); +} + +void DirMonInvoker::run(void* instance) { + if (((DirMonInvoker*)instance)->_reportExisting) + ((DirMonInvoker*)instance)->reportExisting(); + + while(((DirMonInvoker*)instance)->_isRunning) + ((DirMonInvoker*)instance)->_fileWatcher.update(); +} + +void DirMonInvoker::reportExisting() { + std::multimap<std::string, FW::WatchID>::iterator watchIter = _watchIds.begin(); + while(watchIter != _watchIds.end()) { + reportExistingIn(watchIter->first, watchIter->second); + watchIter++; + } +} + +void DirMonInvoker::handleFileAction(FW::WatchID watchid, const FW::String& dir, const FW::String& filename, FW::Action action) { + if (!boost::algorithm::ends_with(filename, _suffix)) + return; + + struct stat fileStat; + if (stat(filename.c_str(), &fileStat) != 0) { + LOG(ERROR) << "Error with stat on directory entry " << filename << ": " << strerror(errno); + return; + } + + Event event; + event.invokeid = _invokeId; + switch (action) { + case FW::Actions::Existing: + event.name = "file.existing"; + break; + case FW::Actions::Add: + event.name = "file.added"; + break; + case FW::Actions::Delete: + event.name = "file.deleted"; + break; + case FW::Actions::Modified: + event.name = "file.modified"; + break; + + default: + break; + } + + event.compound["file"].compound["name"] = Data(filename, Data::VERBATIM); + event.compound["file"].compound["dir"] = Data(dir, Data::VERBATIM); + + event.compound["file"].compound["mtime"] = toStr(fileStat.st_mtime); + event.compound["file"].compound["ctime"] = toStr(fileStat.st_ctime); + event.compound["file"].compound["atime"] = toStr(fileStat.st_atime); + event.compound["file"].compound["size"] = toStr(fileStat.st_size); + + returnEvent(event); +} + +bool DirMonInvoker::filter(const std::string filename) { + return true; +} + +void DirMonInvoker::reportExistingIn(const std::string dir, FW::WatchID watchid) { +#ifndef WIN32 + DIR *dp; + dp = opendir(dir.c_str()); + if (dp == NULL) { + LOG(ERROR) << "Error opening directory " << dir << ": " << 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 + + if (boost::iequals(dname, ".") || boost::iequals(dname, "..")) + continue; + + char* filename; + asprintf(&filename, "%s/%s", dir.c_str(), dname.c_str()); + + struct stat fileStat; + if (stat(filename, &fileStat) != 0) { + LOG(ERROR) << "Error with stat on directory entry " << filename << ": " << strerror(errno); + free(filename); + continue; + } + + if (fileStat.st_mode & S_IFDIR) { + if (_recurse) { + reportExistingIn(filename, watchid); + } else { + free(filename); + continue; + } + } + + if (!filter(dname)) { + free(filename); + continue; + } + + handleFileAction(watchid, dir, filename, FW::Actions::Existing); +#ifndef WIN32 + } + closedir(dp); +#else + } + while (FindNextFile(hFind, &ffd) != 0); + FindClose(hFind); +#endif + +} + +}
\ No newline at end of file |