diff options
Diffstat (limited to 'RealtimeSync/watcher.cpp')
-rw-r--r-- | RealtimeSync/watcher.cpp | 151 |
1 files changed, 68 insertions, 83 deletions
diff --git a/RealtimeSync/watcher.cpp b/RealtimeSync/watcher.cpp index b17c63ba..37664d35 100644 --- a/RealtimeSync/watcher.cpp +++ b/RealtimeSync/watcher.cpp @@ -7,6 +7,7 @@ #include "watcher.h" #include "../shared/file_handling.h" #include "../shared/i18n.h" +#include "../shared/stl_tools.h" #include <set> #include <wx/timer.h> #include "../shared/resolve_path.h" @@ -32,112 +33,102 @@ bool rts::updateUiIsAllowed() return false; } - -class MonitorExistence //detect changes to directory availability +namespace { -public: - MonitorExistence() : allExisting_(true) {} - - //initialization - void addForMonitoring(const Zstring& dirName) - { - dirList.insert(dirName); - } - - bool allExisting() const //polling explicitly allowed! - { - const int UPDATE_INTERVAL = 1000; //1 second interval - - const wxLongLong current = wxGetLocalTimeMillis(); - if (current - lastCheck >= UPDATE_INTERVAL) - { - lastCheck = current; - allExisting_ = std::find_if(dirList.begin(), dirList.end(), std::not1(std::ptr_fun(&zen::dirExists))) == dirList.end(); - } - - return allExisting_; - } - -private: - mutable wxLongLong lastCheck; - mutable bool allExisting_; - - std::set<Zstring, LessFilename> dirList; //save avail. directories, avoid double-entries -}; - +const int CHECK_DIR_INTERVAL = 1000; //1 second interval +} -rts::WaitResult rts::waitForChanges(const std::vector<Zstring>& dirNames, WaitCallback* statusHandler) //throw(FileError) +rts::WaitResult rts::waitForChanges(const std::vector<Zstring>& dirNamesNonFmt, WaitCallback* statusHandler) //throw FileError { - if (dirNames.empty()) //pathological case, but check is needed nevertheless - throw zen::FileError(_("A directory input field is empty.")); + std::set<Zstring, LessFilename> dirNamesFmt; - //detect when volumes are removed/are not available anymore - MonitorExistence checkExist; - std::vector<std::shared_ptr<DirWatcher>> watches; - - for (std::vector<Zstring>::const_iterator i = dirNames.begin(); i != dirNames.end(); ++i) + std::for_each(dirNamesNonFmt.begin(), dirNamesNonFmt.end(), + [&](const Zstring& dirnameNonFmt) { - const Zstring formattedDir = zen::getFormattedDirectoryName(*i); + const Zstring& dirnameFmt = zen::getFormattedDirectoryName(dirnameNonFmt); - if (formattedDir.empty()) + if (dirnameFmt.empty()) throw zen::FileError(_("A directory input field is empty.")); + dirNamesFmt.insert(dirnameFmt); + }); + if (dirNamesFmt.empty()) //pathological case, but check is needed nevertheless + throw zen::FileError(_("A directory input field is empty.")); - checkExist.addForMonitoring(formattedDir); + //detect when volumes are removed/are not available anymore + std::vector<std::pair<Zstring, std::shared_ptr<DirWatcher>>> watches; + + for (auto iter = dirNamesFmt.begin(); iter != dirNamesFmt.end(); ++iter) + { + const Zstring& dirnameFmt = *iter; try { - watches.push_back(std::make_shared<DirWatcher>(formattedDir)); //throw FileError + watches.push_back(std::make_pair(dirnameFmt, std::make_shared<DirWatcher>(dirnameFmt))); //throw FileError } - catch (zen::FileError&) + catch (FileError&) { - if (!zen::dirExists(formattedDir)) //that's no good locking behavior, but better than nothing + //Note: checking for directory existence is NOT transactional!!! + if (!dirExists(dirnameFmt)) //that's no good locking behavior, but better than nothing return CHANGE_DIR_MISSING; throw; } } + wxLongLong lastCheck; while (true) { - //IMPORTANT CHECK: dirwatcher has problems detecting removal of top watched directories! - if (!checkExist.allExisting()) //check for removed devices: - return CHANGE_DIR_MISSING; + const bool checkDirExistNow = [&lastCheck]() -> bool //checking once per sec should suffice + { + const wxLongLong current = wxGetLocalTimeMillis(); + if (current - lastCheck >= CHECK_DIR_INTERVAL) + { + lastCheck = current; + return true; + } + return false; + }(); - try + + for (auto iter = watches.begin(); iter != watches.end(); ++iter) { - for (auto iter = watches.begin(); iter != watches.end(); ++iter) + const Zstring& dirname = iter->first; + DirWatcher& watcher = *(iter->second); + + //IMPORTANT CHECK: dirwatcher has problems detecting removal of top watched directories! + if (checkDirExistNow) + if (!dirExists(dirname)) //catch errors related to directory removal, e.g. ERROR_NETNAME_DELETED + return CHANGE_DIR_MISSING; + + try { - std::vector<Zstring> changedFiles = (*iter)->getChanges(); //throw FileError + std::vector<Zstring> changedFiles = watcher.getChanges(); //throw FileError //remove to be ignored changes - changedFiles.erase(std::remove_if(changedFiles.begin(), changedFiles.end(), - [](const Zstring& name) + vector_remove_if(changedFiles, [](const Zstring & name) { return endsWith(name, Zstr(".ffs_lock")) || //sync.ffs_lock, sync.Del.ffs_lock endsWith(name, Zstr(".ffs_db")); //sync.ffs_db, .sync.tmp.ffs_db //no need to ignore temporal recycle bin directory: this must be caused by a file deletion anyway - }), changedFiles.end()); + }); if (!changedFiles.empty()) { /* std::for_each(changedFiles.begin(), changedFiles.end(), [](const Zstring& fn) { wxMessageBox(toWx(fn));}); - - const wxString filename = toWx(changedFiles[0]); - ::wxSetEnv(wxT("RTS_CHANGE"), filename); */ - - return CHANGE_DETECTED; //directory change detected + return WaitResult(CHANGE_DETECTED, changedFiles[0]); //directory change detected } + + } + catch (FileError&) + { + //Note: checking for directory existence is NOT transactional!!! + if (!dirExists(dirname)) //catch errors related to directory removal, e.g. ERROR_NETNAME_DELETED + return CHANGE_DIR_MISSING; + throw; } - } - catch (FileError&) - { - //maybe some error is caused due to some unexpected removal/unavailability of a watched directory? If so we can remedy this error: - if (!checkExist.allExisting()) - return CHANGE_DIR_MISSING; - throw; } wxMilliSleep(rts::UI_UPDATE_INTERVAL); @@ -147,35 +138,29 @@ rts::WaitResult rts::waitForChanges(const std::vector<Zstring>& dirNames, WaitCa //support for monitoring newly connected directories volumes (e.g.: USB-sticks) -void rts::waitForMissingDirs(const std::vector<Zstring>& dirNames, WaitCallback* statusHandler) //throw(FileError) +void rts::waitForMissingDirs(const std::vector<Zstring>& dirNamesNonFmt, WaitCallback* statusHandler) //throw FileError { wxLongLong lastCheck; while (true) { - const int UPDATE_INTERVAL = 1000; //1 second interval const wxLongLong current = wxGetLocalTimeMillis(); - if (current - lastCheck >= UPDATE_INTERVAL) + if (current - lastCheck >= CHECK_DIR_INTERVAL) { lastCheck = current; - bool allExisting = true; - for (std::vector<Zstring>::const_iterator i = dirNames.begin(); i != dirNames.end(); ++i) - { - //support specifying volume by name => call getFormattedDirectoryName() repeatedly - const Zstring formattedDir = zen::getFormattedDirectoryName(*i); + if (std::find_if(dirNamesNonFmt.begin(), dirNamesNonFmt.end(), + [&](const Zstring& dirnameNonFmt) -> bool + { + //support specifying volume by name => call getFormattedDirectoryName() repeatedly + const Zstring formattedDir = zen::getFormattedDirectoryName(dirnameNonFmt); if (formattedDir.empty()) throw zen::FileError(_("A directory input field is empty.")); - if (!zen::dirExists(formattedDir)) - { - allExisting = false; - break; - } - } - if (allExisting) //check for newly arrived devices: - return; + return !dirExists(formattedDir); + }) == dirNamesNonFmt.end()) + return; } wxMilliSleep(rts::UI_UPDATE_INTERVAL); |