fs-watcher: Switch code to use ndn-cxx

Implementation moved to ndn::chronoshare namespace

Change-Id: I78a7f08dc2aafe7a2d578f78d99c72db7ea414b6
diff --git a/fs-watcher/fs-watcher.cpp b/fs-watcher/fs-watcher.cpp
index 65305a4..6e637cf 100644
--- a/fs-watcher/fs-watcher.cpp
+++ b/fs-watcher/fs-watcher.cpp
@@ -19,24 +19,23 @@
  */
 
 #include "fs-watcher.hpp"
-#include "db-helper.hpp"
-#include "logging.hpp"
-
-#include <boost/bind.hpp>
+#include "core/logging.hpp"
 
 #include <QDirIterator>
 #include <QRegExp>
 
-using namespace std;
-using namespace boost;
+namespace ndn {
+namespace chronoshare {
 
 _LOG_INIT(FsWatcher);
 
-FsWatcher::FsWatcher(QString dirPath, LocalFile_Change_Callback onChange,
+namespace fs = boost::filesystem;
+
+FsWatcher::FsWatcher(boost::asio::io_service& io, QString dirPath, LocalFile_Change_Callback onChange,
                      LocalFile_Change_Callback onDelete, QObject* parent)
   : QObject(parent)
-  , m_watcher(new QFileSystemWatcher())
-  , m_scheduler(new Scheduler())
+  , m_watcher(new QFileSystemWatcher(this))
+  , m_scheduler(io)
   , m_dirPath(dirPath)
   , m_onChange(onChange)
   , m_onDelete(onDelete)
@@ -48,61 +47,56 @@
 
   m_watcher->addPath(m_dirPath);
 
-  // register signals (callback functions)
+  // register signals(callback functions)
   connect(m_watcher, SIGNAL(directoryChanged(QString)), this, SLOT(DidDirectoryChanged(QString)));
   connect(m_watcher, SIGNAL(fileChanged(QString)), this, SLOT(DidFileChanged(QString)));
 
-  m_scheduler->start();
+  rescheduleEvent("rescan", m_dirPath.toStdString(), time::seconds(0),
+                  bind(&FsWatcher::ScanDirectory_NotifyUpdates_Execute, this, m_dirPath));
 
-  Scheduler::scheduleOneTimeTask(m_scheduler, 0,
-                                 bind(&FsWatcher::ScanDirectory_NotifyRemovals_Execute, this,
-                                      m_dirPath),
-                                 "rescan-r-" +
-                                   m_dirPath.toStdString()); // only one task will be scheduled per directory
-
-  Scheduler::scheduleOneTimeTask(m_scheduler, 0, bind(&FsWatcher::ScanDirectory_NotifyUpdates_Execute,
-                                                      this, m_dirPath),
-                                 "rescan-" +
-                                   m_dirPath.toStdString()); // only one task will be scheduled per directory
+  rescheduleEvent("rescan-r", m_dirPath.toStdString(), time::seconds(0),
+                  bind(&FsWatcher::ScanDirectory_NotifyRemovals_Execute, this, m_dirPath));
 }
 
 FsWatcher::~FsWatcher()
 {
-  m_scheduler->shutdown();
   sqlite3_close(m_db);
 }
 
 void
+FsWatcher::rescheduleEvent(const std::string& eventType, const std::string& path,
+                           const time::milliseconds& period, const Scheduler::Event& callback)
+{
+  util::scheduler::ScopedEventId event(m_scheduler);
+  event = m_scheduler.scheduleEvent(period, callback);
+
+  // only one task per directory/file
+  std::string key = eventType + ":" + path;
+  m_events.erase(key);
+  m_events.insert(std::make_pair(key, std::move(event)));
+}
+
+void
 FsWatcher::DidDirectoryChanged(QString dirPath)
 {
   _LOG_DEBUG("Triggered DirPath: " << dirPath.toStdString());
 
-  filesystem::path absPathTriggeredDir(dirPath.toStdString());
-  if (!filesystem::exists(filesystem::path(absPathTriggeredDir))) {
-    Scheduler::scheduleOneTimeTask(m_scheduler, 0.5,
-                                   bind(&FsWatcher::ScanDirectory_NotifyRemovals_Execute, this,
-                                        dirPath),
-                                   "r-" + dirPath.toStdString()); // only one task will be scheduled per directory
+  fs::path absPathTriggeredDir(dirPath.toStdString());
+  if (!fs::exists(fs::path(absPathTriggeredDir))) {
+    rescheduleEvent("r-", dirPath.toStdString(), time::milliseconds(500),
+                    bind(&FsWatcher::ScanDirectory_NotifyRemovals_Execute, this, dirPath));
   }
   else {
-    // m_executor.execute (bind (&FsWatcher::ScanDirectory_NotifyUpdates_Execute, this, dirPath));
-    Scheduler::scheduleOneTimeTask(m_scheduler, 0.5,
-                                   bind(&FsWatcher::ScanDirectory_NotifyUpdates_Execute, this,
-                                        dirPath),
-                                   dirPath.toStdString()); // only one task will be scheduled per directory
+    rescheduleEvent("", dirPath.toStdString(), time::milliseconds(500),
+                    bind(&FsWatcher::ScanDirectory_NotifyUpdates_Execute, this, dirPath));
 
-    // m_executor.execute (bind (&FsWatcher::ScanDirectory_NotifyUpdates_Execute, this, dirPath));
-    Scheduler::scheduleOneTimeTask(m_scheduler, 300,
-                                   bind(&FsWatcher::ScanDirectory_NotifyUpdates_Execute, this,
-                                        dirPath),
-                                   "rescan-" +
-                                     dirPath.toStdString()); // only one task will be scheduled per directory
+    // rescan updated folder for updates
+    rescheduleEvent("rescan", dirPath.toStdString(), time::seconds(300),
+                    bind(&FsWatcher::ScanDirectory_NotifyUpdates_Execute, this, dirPath));
 
-    Scheduler::scheduleOneTimeTask(m_scheduler, 300,
-                                   bind(&FsWatcher::ScanDirectory_NotifyRemovals_Execute, this,
-                                        m_dirPath),
-                                   "rescan-r-" +
-                                     m_dirPath.toStdString()); // only one task will be scheduled per directory
+    // rescan whole folder for deletions
+    rescheduleEvent("rescan-r", m_dirPath.toStdString(), time::seconds(300),
+                    bind(&FsWatcher::ScanDirectory_NotifyRemovals_Execute, this, m_dirPath));
   }
 }
 
@@ -116,29 +110,30 @@
   }
   QString absFilePath = filePath;
 
-  filesystem::path absPathTriggeredFile(filePath.toStdString());
+  fs::path absPathTriggeredFile(filePath.toStdString());
   filePath.remove(0, m_dirPath.size());
 
-  filesystem::path triggeredFile(filePath.toStdString());
-  if (filesystem::exists(filesystem::path(absPathTriggeredFile))) {
+  fs::path triggeredFile(filePath.toStdString());
+  if (fs::exists(fs::path(absPathTriggeredFile))) {
     _LOG_DEBUG("Triggered UPDATE of file:  " << triggeredFile.relative_path().generic_string());
-    // m_onChange (triggeredFile.relative_path ());
+    // m_onChange(triggeredFile.relative_path());
 
     m_watcher->removePath(absFilePath);
     m_watcher->addPath(absFilePath);
 
-    Scheduler::scheduleOneTimeTask(m_scheduler, 0.5, bind(m_onChange, triggeredFile.relative_path()),
-                                   triggeredFile.relative_path().string());
+    rescheduleEvent("", triggeredFile.relative_path().string(), time::milliseconds(500),
+                    bind(m_onChange, triggeredFile.relative_path()));
   }
   else {
     _LOG_DEBUG("Triggered DELETE of file: " << triggeredFile.relative_path().generic_string());
-    // m_onDelete (triggeredFile.relative_path ());
+    // m_onDelete(triggeredFile.relative_path());
 
     m_watcher->removePath(absFilePath);
 
     deleteFile(triggeredFile.relative_path());
-    Scheduler::scheduleOneTimeTask(m_scheduler, 0.5, bind(m_onDelete, triggeredFile.relative_path()),
-                                   "r-" + triggeredFile.relative_path().string());
+
+    rescheduleEvent("r", triggeredFile.relative_path().string(), time::milliseconds(500),
+                    bind(m_onDelete, triggeredFile.relative_path()));
   }
 }
 
@@ -147,13 +142,13 @@
 {
   _LOG_TRACE(" >> ScanDirectory_NotifyUpdates_Execute");
 
-  // exclude working only on last component, not the full path; iterating through all directories, even excluded from monitoring
+  // exclude working only on last component, not the full path; iterating through all directories,
+  // even excluded from monitoring
   QRegExp exclude("^(\\.|\\.\\.|\\.chronoshare|.*~|.*\\.swp)$");
 
-  QDirIterator dirIterator(dirPath,
-                           QDir::Dirs | QDir::Files | /*QDir::Hidden |*/ QDir::NoSymLinks |
-                             QDir::NoDotAndDotDot,
-                           QDirIterator::Subdirectories); // directory iterator (recursive)
+  QDirIterator dirIterator(dirPath, QDir::Dirs | QDir::Files | /*QDir::Hidden |*/ QDir::NoSymLinks |
+                                      QDir::NoDotAndDotDot,
+                           QDirIterator::Subdirectories); // directory iterator(recursive)
 
   // iterate through directory recursively
   while (dirIterator.hasNext()) {
@@ -169,17 +164,18 @@
       _LOG_DEBUG("Not excluded file/dir: " << fileInfo.absoluteFilePath().toStdString());
       QString absFilePath = fileInfo.absoluteFilePath();
 
-      // _LOG_DEBUG ("Attempt to add path to watcher: " << absFilePath.toStdString ());
+      // _LOG_DEBUG("Attempt to add path to watcher: " << absFilePath.toStdString());
       m_watcher->removePath(absFilePath);
       m_watcher->addPath(absFilePath);
 
       if (fileInfo.isFile()) {
         QString relFile = absFilePath;
         relFile.remove(0, m_dirPath.size());
-        filesystem::path aFile(relFile.toStdString());
+        fs::path aFile(relFile.toStdString());
 
         if (
-          //!m_fileState->LookupFile (aFile.relative_path ().generic_string ()) /* file does not exist there, but exists locally: added */)
+          //!m_fileState->LookupFile(aFile.relative_path().generic_string())
+          ///* file does not exist there, but exists locally: added */)
           !fileExists(aFile.relative_path()) /*file does not exist in db, but exists in fs: add */) {
           addFile(aFile.relative_path());
           DidFileChanged(absFilePath);
@@ -187,7 +183,7 @@
       }
     }
     else {
-      // _LOG_DEBUG ("Excluded file/dir: " << fileInfo.filePath ().toStdString ());
+      // _LOG_DEBUG("Excluded file/dir: " << fileInfo.filePath().toStdString());
     }
   }
 }
@@ -198,73 +194,71 @@
 {
   _LOG_DEBUG("Triggered DirPath: " << dirPath.toStdString());
 
-  filesystem::path absPathTriggeredDir(dirPath.toStdString());
+  fs::path absPathTriggeredDir(dirPath.toStdString());
   dirPath.remove(0, m_dirPath.size());
 
-  filesystem::path triggeredDir(dirPath.toStdString());
+  fs::path triggeredDir(dirPath.toStdString());
 
   /*
-  FileItemsPtr files = m_fileState->LookupFilesInFolderRecursively (triggeredDir.relative_path ().generic_string ());
-  for (std::list<FileItem>::iterator file = files->begin (); file != files->end (); file ++)
+  FileItemsPtr files = m_fileState->LookupFilesInFolderRecursively(triggeredDir.relative_path().generic_string());
+  for (std::list<FileItem>::iterator file = files->begin(); file != files->end(); file ++)
     {
-      filesystem::path testFile = filesystem::path (m_dirPath.toStdString ()) / file->filename ();
-      _LOG_DEBUG ("Check file for deletion [" << testFile.generic_string () << "]");
+      fs::path testFile = fs::path(m_dirPath.toStdString()) / file->filename();
+      _LOG_DEBUG("Check file for deletion [" << testFile.generic_string() << "]");
 
-      if (!filesystem::exists (testFile))
+      if (!fs::exists(testFile))
         {
-          if (removeIncomplete || file->is_complete ())
+          if (removeIncomplete || file->is_complete())
             {
-              _LOG_DEBUG ("Notifying about removed file [" << file->filename () << "]");
-              m_onDelete (file->filename ());
+              _LOG_DEBUG("Notifying about removed file [" << file->filename() << "]");
+              m_onDelete(file->filename());
             }
         }
     }
     */
 
-  vector<string> files;
+  std::vector<std::string> files;
   getFilesInDir(triggeredDir.relative_path(), files);
-  for (vector<string>::iterator file = files.begin(); file != files.end(); file++) {
-    filesystem::path targetFile = filesystem::path(m_dirPath.toStdString()) / *file;
-    if (!filesystem::exists(targetFile)) {
+  for (std::vector<std::string>::iterator file = files.begin(); file != files.end(); file++) {
+    fs::path targetFile = fs::path(m_dirPath.toStdString()) / *file;
+    if (!fs::exists(targetFile)) {
       deleteFile(*file);
       m_onDelete(*file);
     }
   }
 }
 
-const string INIT_DATABASE = "\
-CREATE TABLE IF NOT EXISTS                                      \n\
-    Files(                                                      \n\
-    filename      TEXT NOT NULL,                                \n\
-    PRIMARY KEY (filename)                                      \n\
-);                                                              \n\
-CREATE INDEX filename_index ON Files (filename);                \n\
+const std::string INIT_DATABASE = "\
+CREATE TABLE IF NOT EXISTS                                     \n\
+    Files(                                                     \n\
+    filename      TEXT NOT NULL,                               \n\
+    PRIMARY KEY(filename)                                      \n\
+);                                                             \n\
+CREATE INDEX IF NOT EXISTS filename_index ON Files(filename);  \n\
 ";
 
 void
 FsWatcher::initFileStateDb()
 {
-  filesystem::path dbFolder =
-    filesystem::path(m_dirPath.toStdString()) / ".chronoshare" / "fs_watcher";
-  filesystem::create_directories(dbFolder);
+  fs::path dbFolder = fs::path(m_dirPath.toStdString()) / ".chronoshare" / "fs_watcher";
+  fs::create_directories(dbFolder);
 
   int res = sqlite3_open((dbFolder / "filestate.db").string().c_str(), &m_db);
   if (res != SQLITE_OK) {
-    BOOST_THROW_EXCEPTION(Error::Db() << errmsg_info_str("Cannot open database: " +
-                                                         (dbFolder / "filestate.db").string()));
+    BOOST_THROW_EXCEPTION(Error("Cannot open database: " + (dbFolder / "filestate.db").string()));
   }
 
   char* errmsg = 0;
   res = sqlite3_exec(m_db, INIT_DATABASE.c_str(), NULL, NULL, &errmsg);
   if (res != SQLITE_OK && errmsg != 0) {
-    // _LOG_TRACE ("Init \"error\": " << errmsg);
-    cout << "FS-Watcher DB error: " << errmsg << endl;
+    // _LOG_TRACE("Init \"error\": " << errmsg);
+    std::cout << "FS-Watcher DB error: " << errmsg << std::endl;
     sqlite3_free(errmsg);
   }
 }
 
 bool
-FsWatcher::fileExists(const filesystem::path& filename)
+FsWatcher::fileExists(const fs::path& filename)
 {
   sqlite3_stmt* stmt;
   sqlite3_prepare_v2(m_db, "SELECT * FROM Files WHERE filename = ?;", -1, &stmt, 0);
@@ -279,17 +273,17 @@
 }
 
 void
-FsWatcher::addFile(const filesystem::path& filename)
+FsWatcher::addFile(const fs::path& filename)
 {
   sqlite3_stmt* stmt;
-  sqlite3_prepare_v2(m_db, "INSERT OR IGNORE INTO Files (filename) VALUES (?);", -1, &stmt, 0);
+  sqlite3_prepare_v2(m_db, "INSERT OR IGNORE INTO Files(filename) VALUES(?);", -1, &stmt, 0);
   sqlite3_bind_text(stmt, 1, filename.c_str(), -1, SQLITE_STATIC);
   sqlite3_step(stmt);
   sqlite3_finalize(stmt);
 }
 
 void
-FsWatcher::deleteFile(const filesystem::path& filename)
+FsWatcher::deleteFile(const fs::path& filename)
 {
   sqlite3_stmt* stmt;
   sqlite3_prepare_v2(m_db, "DELETE FROM Files WHERE filename = ?;", -1, &stmt, 0);
@@ -299,14 +293,14 @@
 }
 
 void
-FsWatcher::getFilesInDir(const filesystem::path& dir, vector<string>& files)
+FsWatcher::getFilesInDir(const fs::path& dir, std::vector<std::string>& files)
 {
   sqlite3_stmt* stmt;
   sqlite3_prepare_v2(m_db, "SELECT * FROM Files WHERE filename LIKE ?;", -1, &stmt, 0);
 
-  string dirStr = dir.string();
-  ostringstream escapedDir;
-  for (string::const_iterator ch = dirStr.begin(); ch != dirStr.end(); ch++) {
+  std::string dirStr = dir.string();
+  std::ostringstream escapedDir;
+  for (std::string::const_iterator ch = dirStr.begin(); ch != dirStr.end(); ch++) {
     if (*ch == '%')
       escapedDir << "\\%";
     else
@@ -314,19 +308,22 @@
   }
   escapedDir << "/"
              << "%";
-  string escapedDirStr = escapedDir.str();
+  std::string escapedDirStr = escapedDir.str();
   sqlite3_bind_text(stmt, 1, escapedDirStr.c_str(), escapedDirStr.size(), SQLITE_STATIC);
 
   while (sqlite3_step(stmt) == SQLITE_ROW) {
-    string filename(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0)),
-                    sqlite3_column_bytes(stmt, 0));
+    std::string filename(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0)),
+                         sqlite3_column_bytes(stmt, 0));
     files.push_back(filename);
   }
 
   sqlite3_finalize(stmt);
 }
 
-#if WAF
-#include "fs-watcher.cc.moc"
+} // namespace chronoshare
+} // namespace ndn
+
+#ifdef WAF
 #include "fs-watcher.moc"
+// #include "fs-watcher.cpp.moc"
 #endif