summaryrefslogtreecommitdiffstats
path: root/src/uscxml/plugins/invoker/filesystem
diff options
context:
space:
mode:
authorStefan Radomski <radomski@tk.informatik.tu-darmstadt.de>2013-03-06 18:23:17 (GMT)
committerStefan Radomski <radomski@tk.informatik.tu-darmstadt.de>2013-03-06 18:23:17 (GMT)
commite1a31a44c946d58a1b4654e5daa2d10d9c6f881d (patch)
tree7ce434b9bfb30c2de74cfe1f226c2ceda4ee8178 /src/uscxml/plugins/invoker/filesystem
parent8c4977361f9e7998da298b9648f3ad4be5e772ff (diff)
downloaduscxml-e1a31a44c946d58a1b4654e5daa2d10d9c6f881d.zip
uscxml-e1a31a44c946d58a1b4654e5daa2d10d9c6f881d.tar.gz
uscxml-e1a31a44c946d58a1b4654e5daa2d10d9c6f881d.tar.bz2
Changed directory monitor to polling behaviour :(
Diffstat (limited to 'src/uscxml/plugins/invoker/filesystem')
-rw-r--r--src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.cpp423
-rw-r--r--src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.h59
-rw-r--r--src/uscxml/plugins/invoker/filesystem/dirmon/FileWatcher/FileWatcherOSX.cpp62
-rw-r--r--src/uscxml/plugins/invoker/filesystem/dirmon/FileWatcher/FileWatcherOSX.h3
4 files changed, 359 insertions, 188 deletions
diff --git a/src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.cpp b/src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.cpp
index 37be3e0..675135a 100644
--- a/src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.cpp
+++ b/src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.cpp
@@ -25,10 +25,10 @@ bool connect(pluma::Host& host) {
#endif
DirMonInvoker::DirMonInvoker() :
- _reportExisting(true),
- _reportHidden(false),
- _recurse(false),
- _thread(NULL) {
+ _reportExisting(true),
+ _reportHidden(false),
+ _recurse(false),
+ _thread(NULL) {
}
DirMonInvoker::~DirMonInvoker() {
@@ -55,222 +55,329 @@ 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, "false"))
+ if (req.params.find("dir") == req.params.end()) {
+ LOG(ERROR) << "No dir param given";
+ return;
+ }
+
+ if (boost::iequals(req.params.find("reportexisting")->second, "false"))
_reportExisting = false;
- if (req.params.find("recurse") != req.params.end() && boost::iequals(req.params.find("recurse")->second, "true"))
+ if (req.params.find("recurse") != req.params.end() &&
+ boost::iequals(req.params.find("recurse")->second, "true"))
_recurse = true;
- if (req.params.find("reporthidden") != req.params.end() && boost::iequals(req.params.find("reporthidden")->second, "true"))
+ if (req.params.find("reporthidden") != req.params.end() &&
+ boost::iequals(req.params.find("reporthidden")->second, "true"))
_reportHidden = true;
-
- std::string suffixList;
- if (req.params.find("suffix") != req.params.end()) {
- suffixList = req.params.find("suffix")->second;
- } else if (req.params.find("suffixes") != req.params.end()) {
- suffixList = req.params.find("suffixes")->second;
- }
-
- 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::string suffixList;
+ if (req.params.find("suffix") != req.params.end()) {
+ suffixList = req.params.find("suffix")->second;
+ } else if (req.params.find("suffixes") != req.params.end()) {
+ suffixList = req.params.find("suffixes")->second;
+ }
+
+ 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, 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)));
+ _dir = url.path();
}
- dirIter++;
+ break;
}
+
+ _watcher = new DirectoryWatch(_dir, _recurse);
+ _watcher->addMonitor(this);
+ _watcher->updateEntries(true);
+
_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();
+ while(((DirMonInvoker*)instance)->_isRunning) {
+ ((DirMonInvoker*)instance)->_watcher->updateEntries();
+ tthread::this_thread::sleep_for(tthread::chrono::milliseconds(20));
+ }
}
-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::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));
-void DirMonInvoker::handleFileAction(FW::WatchID watchid, const FW::String& dir, const FW::String& filename, FW::Action action) {
-
- std::string path;
- if (!boost::algorithm::starts_with(filename, dir)) {
- path = dir + filename;
- } else {
- path = filename;
- }
-
- 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;
- }
+ // 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 FW::Actions::Existing:
+ case DirectoryWatch::EXISTING:
event.name = "file.existing";
break;
- case FW::Actions::Add:
+ case DirectoryWatch::ADDED:
event.name = "file.added";
break;
- case FW::Actions::Delete:
+ case DirectoryWatch::DELETED:
event.name = "file.deleted";
break;
- case FW::Actions::Modified:
+ case DirectoryWatch::MODIFIED:
event.name = "file.modified";
break;
default:
break;
}
- // basename is the filename with suffix
- std::string basename;
- size_t lastSep;
- if ((lastSep = path.find_last_of(PATH_SEPERATOR)) != std::string::npos) {
- lastSep++;
- basename = path.substr(lastSep, path.length() - lastSep);
- event.data.compound["file"].compound["name"] = Data(basename, Data::VERBATIM);
- }
-
- // return if this is a hidden file
- if (boost::algorithm::starts_with(basename, ".") && !_reportHidden)
- return;
-
- struct stat fileStat;
- if (action != FW::Actions::Delete) {
- if (stat(path.c_str(), &fileStat) != 0) {
- LOG(ERROR) << "Error with stat on directory entry " << path << ": " << strerror(errno);
- return;
- } else {
- event.data.compound["file"].compound["mtime"] = toStr(fileStat.st_mtime);
- event.data.compound["file"].compound["ctime"] = toStr(fileStat.st_ctime);
- event.data.compound["file"].compound["atime"] = toStr(fileStat.st_atime);
- event.data.compound["file"].compound["size"] = toStr(fileStat.st_size);
- }
- }
-
- // extension is the suffix and strippedName the basename without the suffix
- size_t lastDot;
- if ((lastDot = basename.find_last_of(".")) != std::string::npos) {
- std::string extension = basename.substr(lastDot + 1);
- event.data.compound["file"].compound["extension"] = Data(extension, Data::VERBATIM);
- std::string strippedName = basename.substr(0, lastDot);
- event.data.compound["file"].compound["strippedName"] = Data(strippedName, Data::VERBATIM);
- }
-
- // relpath is the path to the file relative to the dir
- if (boost::algorithm::starts_with(filename, dir)) {
- std::string relPath = filename.substr(dir.length());
- event.data.compound["file"].compound["relPath"] = Data(relPath, Data::VERBATIM);
-
- // relDir is the relpath without the basename
- if ((lastSep = relPath.find_last_of(PATH_SEPERATOR)) != std::string::npos) {
- lastSep++;
- std::string relDir = relPath.substr(0, lastSep);
- event.data.compound["file"].compound["relDir"] = Data(relDir, Data::VERBATIM);
- }
+ if (action != DirectoryWatch::DELETED) {
+ event.data.compound["file"].compound["mtime"] = toStr(fileStat.st_mtime);
+ event.data.compound["file"].compound["ctime"] = toStr(fileStat.st_ctime);
+ event.data.compound["file"].compound["atime"] = toStr(fileStat.st_atime);
+ event.data.compound["file"].compound["size"] = toStr(fileStat.st_size);
}
+ 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);
returnEvent(event);
}
-bool DirMonInvoker::filter(const std::string filename) {
- return true;
+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->first);
+ fileIter++;
+ }
+ assert(_knownDirs.size() == 0);
+ assert(_knownEntries.size() == 0);
}
-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);
+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;
}
- // iterate all entries and see what changed
- struct dirent* entry;
- while((entry = readdir(dp))) {
- std::string dname = entry->d_name;
+
+ if ((unsigned)dirStat.st_mtime >= (unsigned)_lastChecked) {
+ // 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;
+ 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 {
+ string dname = ffd.cFileName;
#endif
- if (boost::iequals(dname, ".") || boost::iequals(dname, ".."))
- continue;
+ // see if the file was changed
+ char* filename;
+ asprintf(&filename, "%s/%s", (_dir + _relDir).c_str(), dname.c_str());
- char* filename = (char*)malloc(dir.size() + dname.size() + 2);
- sprintf(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;
+ }
- 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 (boost::equals(dname, ".") || boost::equals(dname, "..")) {
+ free(filename);
+ continue; // do not report . or ..
+ }
+ }
- if (fileStat.st_mode & S_IFDIR) {
- if (_recurse) {
- reportExistingIn(filename, watchid);
+ 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 {
- free(filename);
- continue;
+ // 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++;
+ }
+ }
}
- }
- if (!filter(dname)) {
free(filename);
- continue;
+ _knownEntries[dname] = fileStat; // gets copied on insertion
+#ifndef WIN32
}
-
- handleFileAction(watchid, dir, filename, FW::Actions::Existing);
+ 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->first);
+ }
+ fileIter++;
+ }
+ // remember when we last checked the directory for modifications
#ifndef WIN32
- }
- closedir(dp);
+ time(&_lastChecked);
#else
- }
- while (FindNextFile(hFind, &ffd) != 0);
- FindClose(hFind);
+ // 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/filesystem/dirmon/DirMonInvoker.h b/src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.h
index 04e670d..3fd9258 100644
--- a/src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.h
+++ b/src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.h
@@ -2,8 +2,8 @@
#define DIRMONINVOKER_H_W09J90F0
#include <uscxml/Interpreter.h>
-#include "FileWatcher/FileWatcher.h"
#include <map>
+#include <sys/stat.h>
#ifdef BUILD_AS_PLUGINS
#include "uscxml/plugins/Plugins.h"
@@ -11,7 +11,48 @@
namespace uscxml {
-class DirMonInvoker : public InvokerImpl, public FW::FileWatchListener {
+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) {}
+
+ void addMonitor(DirectoryWatchMonitor* monitor) {
+ _monitors.insert(monitor);
+ }
+ void removeMonitor(DirectoryWatchMonitor* monitor) {
+ _monitors.erase(monitor);
+ }
+ void updateEntries(bool reportAsExisting = false);
+ void reportAsDeleted();
+
+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();
@@ -30,10 +71,7 @@ public:
virtual void cancel(const std::string sendId);
virtual void invoke(const InvokeRequest& req);
- void handleFileAction(FW::WatchID watchid, const FW::String& dir, const FW::String& filename, FW::Action action);
- void reportExisting();
- void reportExistingIn(const std::string dir, FW::WatchID watchid);
- virtual bool filter(const std::string filename);
+ virtual void handleChanges(DirectoryWatch::Action action, const std::string dir, const std::string file, struct stat fileStat);
static void run(void* instance);
@@ -41,12 +79,15 @@ protected:
bool _reportExisting;
bool _reportHidden;
bool _recurse;
- std::set<std::string> _suffixes;
+
+ std::string _dir;
+ std::set<std::string> _suffixes;
bool _isRunning;
tthread::thread* _thread;
- FW::FileWatcher _fileWatcher;
- std::multimap<std::string, FW::WatchID> _watchIds;
+ tthread::recursive_mutex _mutex;
+
+ DirectoryWatch* _watcher;
};
#ifdef BUILD_AS_PLUGINS
diff --git a/src/uscxml/plugins/invoker/filesystem/dirmon/FileWatcher/FileWatcherOSX.cpp b/src/uscxml/plugins/invoker/filesystem/dirmon/FileWatcher/FileWatcherOSX.cpp
index e1634b0..a47d635 100644
--- a/src/uscxml/plugins/invoker/filesystem/dirmon/FileWatcher/FileWatcherOSX.cpp
+++ b/src/uscxml/plugins/invoker/filesystem/dirmon/FileWatcher/FileWatcherOSX.cpp
@@ -35,6 +35,7 @@
#include <stdlib.h>
#include <dirent.h>
#include <string.h>
+#include <iostream>
// this is more suited:
// https://developer.apple.com/library/mac/#documentation/Darwin/Conceptual/FSEvents_ProgGuide/UsingtheFSEventsFramework/UsingtheFSEventsFramework.html
@@ -71,18 +72,20 @@ struct WatchStruct {
WatchID mWatchID;
String mDirName;
FileWatchListener* mListener;
+ FileWatcherOSX* mWatcher;
+ bool mRecursive;
// index 0 is always the directory
KEvent mChangeList[MAX_CHANGE_EVENT_SIZE];
size_t mChangeListCount;
- WatchStruct(WatchID watchid, const String& dirname, FileWatchListener* listener)
- : mWatchID(watchid), mDirName(dirname), mListener(listener) {
+ WatchStruct(WatchID watchid, const String& dirname, FileWatchListener* listener, FileWatcherOSX* watcher, bool recursive = false)
+ : mWatchID(watchid), mDirName(dirname), mListener(listener), mWatcher(watcher), mRecursive(recursive) {
mChangeListCount = 0;
addAll();
}
- void addFile(const String& name, bool imitEvents = true) {
+ void addFile(const String& name, bool emitEvents = true) {
//fprintf(stderr, "ADDED: %s\n", name.c_str());
// create entry
@@ -104,18 +107,18 @@ struct WatchStruct {
// set the event data at the end of the list
EV_SET(&mChangeList[mChangeListCount], fd, EVFILT_VNODE,
EV_ADD | EV_ENABLE | EV_ONESHOT,
- NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_ATTRIB,
+ NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_ATTRIB | NOTE_RENAME,
0, (void*)entry);
// qsort
qsort(mChangeList + 1, mChangeListCount, sizeof(KEvent), comparator);
// handle action
- if(imitEvents)
+ if(emitEvents)
handleAction(name, Actions::Add);
}
- void removeFile(const String& name, bool imitEvents = true) {
+ void removeFile(const String& name, bool emitEvents = true) {
// bsearch
KEvent target;
EntryStruct tempEntry(name.c_str(), 0);
@@ -140,7 +143,7 @@ struct WatchStruct {
qsort(mChangeList + 1, mChangeListCount, sizeof(KEvent), comparator);
// handle action
- if(imitEvents)
+ if(emitEvents)
handleAction(name, Actions::Delete);
}
@@ -207,7 +210,7 @@ struct WatchStruct {
int fd = open(mDirName.c_str(), O_RDONLY);
EV_SET(&mChangeList[0], fd, EVFILT_VNODE,
EV_ADD | EV_ENABLE | EV_ONESHOT,
- NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_ATTRIB,
+ NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_ATTRIB | NOTE_RENAME,
0, 0);
//fprintf(stderr, "ADDED: %s\n", mDirName.c_str());
@@ -222,11 +225,13 @@ struct WatchStruct {
while((entry = readdir(dir)) != NULL) {
String fname = (mDirName + "/" + String(entry->d_name));
stat(fname.c_str(), &attrib);
- if(S_ISREG(attrib.st_mode))
+ if(S_ISREG(attrib.st_mode)) {
addFile(fname, false);
- //else
- // fprintf(stderr, "NOT ADDED: %s (%d)\n", fname.c_str(), attrib.st_mode);
-
+ } else if(S_IFDIR && mRecursive && entry->d_name[0] != '.') {
+ mWatcher->addWatch(fname, mListener, mRecursive);
+ } else {
+ fprintf(stderr, "NOT ADDED: %s (%d)\n", fname.c_str(), attrib.st_mode);
+ }
}//end while
closedir(dir);
@@ -263,19 +268,33 @@ void FileWatcherOSX::update() {
if(nev == -1)
perror("kevent");
else {
+ if (event.fflags & NOTE_DELETE) {
+ fprintf(stderr, "NOTE_DELETE ");
+ }
+ if (event.fflags & NOTE_EXTEND) {
+ fprintf(stderr, "NOTE_EXTEND ");
+ }
+ if (event.fflags & NOTE_WRITE) {
+ fprintf(stderr, "NOTE_WRITE ");
+ }
+ if (event.fflags & NOTE_ATTRIB) {
+ fprintf(stderr, "NOTE_ATTRIB ");
+ }
+ if (event.fflags & NOTE_RENAME) {
+ fprintf(stderr, "NOTE_RENAME ");
+ }
+
EntryStruct* entry = 0;
if((entry = (EntryStruct*)event.udata) != 0) {
- //fprintf(stderr, "File: %s -- ", (char*)entry->mFilename);
+ fprintf(stderr, " to %s -- \n", (char*)entry->mFilename);
if(event.fflags & NOTE_DELETE) {
- //fprintf(stderr, "File deleted\n");
//watch->handleAction(entry->mFilename, Action::Delete);
watch->removeFile(entry->mFilename);
}
if(event.fflags & NOTE_EXTEND ||
event.fflags & NOTE_WRITE ||
event.fflags & NOTE_ATTRIB) {
- //fprintf(stderr, "modified\n");
//watch->rescan();
struct stat attrib;
stat(entry->mFilename, &attrib);
@@ -283,7 +302,7 @@ void FileWatcherOSX::update() {
watch->handleAction(entry->mFilename, FW::Actions::Modified);
}
} else {
- //fprintf(stderr, "Dir: %s -- rescanning\n", watch->mDirName.c_str());
+ fprintf(stderr, " in %s -- rescanning\n", watch->mDirName.c_str());
watch->rescan();
}
}
@@ -295,7 +314,7 @@ void FileWatcherOSX::update() {
FileWatcherOSX::FileWatcherOSX() {
mDescriptor = kqueue();
mTimeOut.tv_sec = 0;
- mTimeOut.tv_nsec = 2000000;
+ mTimeOut.tv_nsec = 20000000;
}
//--------
@@ -322,9 +341,12 @@ WatchID FileWatcherOSX::addWatch(const String& directory, FileWatchListener* wat
0, (void*)"testing");
*/
- WatchStruct* watch = new WatchStruct(++mLastWatchID, directory, watcher);
- mWatches.insert(std::make_pair(mLastWatchID, watch));
- return mLastWatchID;
+ std::cout << "Adding watch for " << directory << std::endl;
+
+ WatchID currWatch = ++mLastWatchID;
+ WatchStruct* watch = new WatchStruct(currWatch, directory, watcher, this, recursive);
+ mWatches.insert(std::make_pair(currWatch, watch));
+ return currWatch;
}
//--------
diff --git a/src/uscxml/plugins/invoker/filesystem/dirmon/FileWatcher/FileWatcherOSX.h b/src/uscxml/plugins/invoker/filesystem/dirmon/FileWatcher/FileWatcherOSX.h
index 39f411c..92e3957 100644
--- a/src/uscxml/plugins/invoker/filesystem/dirmon/FileWatcher/FileWatcherOSX.h
+++ b/src/uscxml/plugins/invoker/filesystem/dirmon/FileWatcher/FileWatcherOSX.h
@@ -54,7 +54,7 @@ public:
/// Add a directory watch
/// @exception FileNotFoundException Thrown when the requested directory does not exist
- WatchID addWatch(const String& directory, FileWatchListener* watcher, bool recursive);
+ WatchID addWatch(const String& directory, FileWatchListener* watcher, bool recursive = false);
/// Remove a directory watch. This is a brute force lazy search O(nlogn).
void removeWatch(const String& directory);
@@ -78,6 +78,7 @@ private:
/// WatchID allocator
int mLastWatchID;
+ friend class WatchStruct;
};//end FileWatcherOSX
};//namespace FW