state-server: Initial implementation of /info/ RPC calls

Nothing is published yet, but data is successfully passed to the state server

+ usages of scheduler replaced with executor

Change-Id: I9da9182edc4efe8e896e2452ef4f9f0d98a03da1
diff --git a/src/state-server.cc b/src/state-server.cc
index 98830d0..6f73950 100644
--- a/src/state-server.cc
+++ b/src/state-server.cc
@@ -45,7 +45,7 @@
   , m_objectManager (objectManager)
   , m_rootDir(rootDir)
   , m_freshness(freshness)
-  , m_scheduler (new Scheduler())
+  , m_executor (1)
   , m_userName (userName)
   , m_sharedFolderName (sharedFolderName)
   , m_appName (appName)
@@ -53,19 +53,19 @@
   // may be later /localhost should be replaced with /%C1.M.S.localhost
 
   // <PREFIX_INFO> = /localhost/<user's-device-name>/"chronoshare"/"info"
-  m_PREFIX_INFO = Name ("/localhost")(m_userName)("chronoshare")("info");
+  m_PREFIX_INFO = Name ("/localhost")(m_userName)("chronoshare")(m_sharedFolderName)("info");
 
   // <PREFIX_CMD> = /localhost/<user's-device-name>/"chronoshare"/"cmd"
-  m_PREFIX_CMD = Name ("/localhost")(m_userName)("chronoshare")("cmd");
+  m_PREFIX_CMD = Name ("/localhost")(m_userName)("chronoshare")(m_sharedFolderName)("cmd");
 
-  m_scheduler->start ();
+  m_executor.start ();
 
   registerPrefixes ();
 }
 
 StateServer::~StateServer()
 {
-  m_scheduler->shutdown ();
+  m_executor.shutdown ();
 
   deregisterPrefixes ();
 }
@@ -77,10 +77,10 @@
   // will be extended to support all planned commands later
 
   // <PREFIX_INFO>/"actions"/"all"/<nonce>/<segment>  get list of all actions
-  m_ccnx->setInterestFilter (Name (m_PREFIX_INFO)("actions")("all"), bind(&StateServer::info_actions_all, this, _1));
+  m_ccnx->setInterestFilter (Name (m_PREFIX_INFO)("actions")("folder"), bind(&StateServer::info_actions_folder, this, _1));
 
-  // // <PREFIX_INFO>/"filestate"/"all"/<nonce>/<segment>
-  // m_ccnx->setInterestFilter (Name (m_PREFIX_INFO)("filestate")("all"), bind(&StateServer::info_filestate_all, this, _1));
+  // <PREFIX_INFO>/"filestate"/"all"/<nonce>/<segment>
+  m_ccnx->setInterestFilter (Name (m_PREFIX_INFO)("filestate")("folder"), bind(&StateServer::info_filestate_folder, this, _1));
 
   // <PREFIX_CMD>/"restore"/"file"/<one-component-relative-file-name>/<version>/<file-hash>
   m_ccnx->setInterestFilter (Name (m_PREFIX_CMD)("restore")("file"), bind(&StateServer::cmd_restore_file, this, _1));
@@ -89,34 +89,77 @@
 void
 StateServer::deregisterPrefixes ()
 {
-  m_ccnx->clearInterestFilter (Name (m_PREFIX_INFO)("actions")("all"));
-  m_ccnx->clearInterestFilter (Name (m_PREFIX_INFO)("filestate")("all"));
+  m_ccnx->clearInterestFilter (Name (m_PREFIX_INFO)("actions")("folder"));
+  m_ccnx->clearInterestFilter (Name (m_PREFIX_INFO)("filestate")("folder"));
   m_ccnx->clearInterestFilter (Name (m_PREFIX_CMD) ("restore")("file"));
 }
 
-void
-StateServer::info_actions_all (const Name &interest)
+// void
+// StateServer::info_actions_all (const Name &interest)
+// {
+//   _LOG_DEBUG (">> info_actions_all: " << interest);
+//   m_executor.execute (bind (&StateServer::info_actions_all_Execute, this, interest));
+// }
+
+// void
+// StateServer::info_actions_all_Execute (const Name &interest)
+// {
+//   // <PREFIX_INFO>/"actions"/"all"/<nonce>/<offset>  get list of all actions
+
+//   try
+//     {
+//       int offset = interest.getCompFromBackAsInt (0);
+
+//       // LookupActionsInFolderRecursively
+//       /// @todo !!! add security checking
+//       m_ccnx->publishData (interest, "FAIL: Not implemented", 1);
+//     }
+//   catch (Ccnx::NameException &ne)
+//     {
+//       // ignore any unexpected interests and errors
+//       _LOG_ERROR (*boost::get_error_info<Ccnx::error_info_str>(ne));
+//     }
+// }
+
+void debugAction (const Ccnx::Name &name, sqlite3_int64 seq_no, const ActionItem &action)
 {
-  _LOG_DEBUG (">> info_actions_all: " << interest);
-  m_scheduler->scheduleOneTimeTask (m_scheduler, 0, bind (&StateServer::info_actions_all_Execute, this, interest), boost::lexical_cast<string>(interest));
+  std::cout << name << ", " << seq_no << ", " << action.filename () << std::endl;
 }
 
 void
-StateServer::info_actions_all_Execute (const Name &interest)
+StateServer::info_actions_folder (const Name &interest)
 {
-  // <PREFIX_INFO>/"actions"/"all"/<nonce>/<segment>  get list of all actions
+  if (interest.size () - m_PREFIX_INFO.size () != 4 &&
+      interest.size () - m_PREFIX_INFO.size () != 5)
+    {
+      _LOG_DEBUG ("Invalid interest: " << interest);
+      return;
+    }
+
+  _LOG_DEBUG (">> info_actions_all: " << interest);
+  m_executor.execute (bind (&StateServer::info_actions_folder_Execute, this, interest));
+}
+
+void
+StateServer::info_actions_folder_Execute (const Name &interest)
+{
+  // <PREFIX_INFO>/"actions"/"folder"/<folder>/<nonce>/<offset>  get list of all actions
 
   try
     {
-      int segment = interest.getCompFromBackAsInt (0);
-      if (segment != 0)
-        {
-          // ignore anything except segment 0, other stuff should be cached.. if not, then good luck
-          return;
-        }
+      int offset = interest.getCompFromBackAsInt (0);
 
       /// @todo !!! add security checking
-      m_ccnx->publishData (interest, "FAIL: Not implemented", 1);
+
+      string folder;
+      if (interest.size () - m_PREFIX_INFO.size () == 5)
+        folder = interest.getCompFromBackAsString (2);
+      else // == 4
+        folder = "";
+
+      m_actionLog->LookupActionsInFolderRecursively (debugAction, folder, offset*100, 100);
+
+      // m_ccnx->publishData (interest, "FAIL: Not implemented", 1);
     }
   catch (Ccnx::NameException &ne)
     {
@@ -125,11 +168,67 @@
     }
 }
 
+void debugFileState (const FileItem &file)
+{
+  std::cout << file.filename () << std::endl;
+}
+
+void
+StateServer::info_filestate_folder (const Ccnx::Name &interest)
+{
+  if (interest.size () - m_PREFIX_INFO.size () != 4 &&
+      interest.size () - m_PREFIX_INFO.size () != 5)
+    {
+      _LOG_DEBUG ("Invalid interest: " << interest << ", " << interest.size () - m_PREFIX_INFO.size ());
+      return;
+    }
+
+  _LOG_DEBUG (">> info_filestate_folder: " << interest);
+  m_executor.execute (bind (&StateServer::info_filestate_folder_Execute, this, interest));
+}
+
+
+void
+StateServer::info_filestate_folder_Execute (const Ccnx::Name &interest)
+{
+  // <PREFIX_INFO>/"filestate"/"folder"/<one-component-relative-folder-name>/<nonce>/<offset>
+  try
+    {
+      int offset = interest.getCompFromBackAsInt (0);
+
+      // /// @todo !!! add security checking
+
+      string folder;
+      if (interest.size () - m_PREFIX_INFO.size () == 5)
+        folder = interest.getCompFromBackAsString (2);
+      else // == 4
+        folder = "";
+
+      FileStatePtr fileState = m_actionLog->GetFileState ();
+      fileState->LookupFilesInFolderRecursively (debugFileState, folder, offset*100, 100);
+
+      // m_ccnx->publishData (interest, "FAIL: Not implemented", 1);
+    }
+  catch (Ccnx::NameException &ne)
+    {
+      // ignore any unexpected interests and errors
+      _LOG_ERROR (*boost::get_error_info<Ccnx::error_info_str>(ne));
+    }
+}
+
+
 void
 StateServer::cmd_restore_file (const Ccnx::Name &interest)
 {
+  if (interest.size () - m_PREFIX_CMD.size () != 4 &&
+      interest.size () - m_PREFIX_CMD.size () != 5)
+    {
+      _LOG_DEBUG ("Invalid interest: " << interest);
+      return;
+    }
+
   _LOG_DEBUG (">> cmd_restore_file: " << interest);
-  m_scheduler->scheduleOneTimeTask (m_scheduler, 0, bind (&StateServer::cmd_restore_file_Execute, this, interest), boost::lexical_cast<string>(interest));
+  m_executor.execute (bind (&StateServer::cmd_restore_file_Execute, this, interest));
 }
 
 void
@@ -141,25 +240,45 @@
 
   try
     {
-      Hash hash (head(interest.getCompFromBack (0)), interest.getCompFromBack (0).size());
-      int64_t version = interest.getCompFromBackAsInt (1);
-      string  filename = interest.getCompFromBackAsString (2); // should be safe even with full relative path
+      FileItemPtr file;
 
-      FileItemPtr file = m_actionLog->LookupAction (filename, version, hash);
+      if (interest.size () - m_PREFIX_CMD.size () == 5)
+        {
+          Hash hash (head(interest.getCompFromBack (0)), interest.getCompFromBack (0).size());
+          int64_t version = interest.getCompFromBackAsInt (1);
+          string  filename = interest.getCompFromBackAsString (2); // should be safe even with full relative path
+
+          file = m_actionLog->LookupAction (filename, version, hash);
+          if (!file)
+            {
+              _LOG_ERROR ("Requested file is not found: [" << filename << "] version [" << version << "] hash [" << hash.shortHash () << "]");
+            }
+        }
+      else
+        {
+          int64_t version = interest.getCompFromBackAsInt (0);
+          string  filename = interest.getCompFromBackAsString (1); // should be safe even with full relative path
+
+          file = m_actionLog->LookupAction (filename, version, Hash (0,0));
+          if (!file)
+            {
+              _LOG_ERROR ("Requested file is not found: [" << filename << "] version [" << version << "]");
+            }
+        }
+
       if (!file)
         {
           m_ccnx->publishData (interest, "FAIL: Requested file is not found", 1);
-          _LOG_ERROR ("Requested file is not found: [" << filename << "] version [" << version << "] hash [" << hash.shortHash () << "]");
           return;
         }
 
-      hash = Hash (file->file_hash ().c_str (), file->file_hash ().size ());
+      Hash hash = Hash (file->file_hash ().c_str (), file->file_hash ().size ());
 
       ///////////////////
       // now the magic //
       ///////////////////
 
-      boost::filesystem::path filePath = m_rootDir / filename;
+      boost::filesystem::path filePath = m_rootDir / file->filename ();
       Name deviceName (file->device_name ().c_str (), file->device_name ().size ());
 
       try