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/action-log.cc b/src/action-log.cc
index 84c2779..14b30ca 100644
--- a/src/action-log.cc
+++ b/src/action-log.cc
@@ -37,6 +37,7 @@
\n\
action CHAR(1) NOT NULL, /* 0 for \"update\", 1 for \"delete\". */ \n\
filename TEXT NOT NULL, \n\
+ directory TEXT, \n\
\n\
version INTEGER NOT NULL, \n\
action_timestamp TIMESTAMP NOT NULL, \n\
@@ -258,6 +259,17 @@
sqlite3_finalize (stmt);
+ // I had a problem including directory_name assignment as part of the initial insert.
+ sqlite3_prepare_v2 (m_db, "UPDATE ActionLog SET directory=directory_name(filename) WHERE device_name=? AND seq_no=?", -1, &stmt, 0);
+ _LOG_DEBUG_COND (sqlite3_errcode (m_db) != SQLITE_OK, sqlite3_errmsg (m_db));
+
+ sqlite3_bind_blob (stmt, 1, device_name->buf (), device_name->length (), SQLITE_STATIC);
+ sqlite3_bind_int64 (stmt, 2, seq_no);
+ sqlite3_step (stmt);
+ _LOG_DEBUG_COND (sqlite3_errcode (m_db) != SQLITE_DONE, sqlite3_errmsg (m_db));
+
+ sqlite3_finalize (stmt);
+
sqlite3_exec (m_db, "END TRANSACTION;", 0,0,0);
// set complete for local file
@@ -362,6 +374,17 @@
sqlite3_finalize (stmt);
+ // I had a problem including directory_name assignment as part of the initial insert.
+ sqlite3_prepare_v2 (m_db, "UPDATE ActionLog SET directory=directory_name(filename) WHERE device_name=? AND seq_no=?", -1, &stmt, 0);
+ _LOG_DEBUG_COND (sqlite3_errcode (m_db) != SQLITE_OK, sqlite3_errmsg (m_db));
+
+ sqlite3_bind_blob (stmt, 1, device_name->buf (), device_name->length (), SQLITE_STATIC);
+ sqlite3_bind_int64 (stmt, 2, seq_no);
+ sqlite3_step (stmt);
+ _LOG_DEBUG_COND (sqlite3_errcode (m_db) != SQLITE_DONE, sqlite3_errmsg (m_db));
+
+ sqlite3_finalize (stmt);
+
sqlite3_exec (m_db, "END TRANSACTION;", 0,0,0);
return item;
@@ -554,6 +577,17 @@
sqlite3_finalize (stmt);
+ // I had a problem including directory_name assignment as part of the initial insert.
+ sqlite3_prepare_v2 (m_db, "UPDATE ActionLog SET directory=directory_name(filename) WHERE device_name=? AND seq_no=?", -1, &stmt, 0);
+ _LOG_DEBUG_COND (sqlite3_errcode (m_db) != SQLITE_OK, sqlite3_errmsg (m_db));
+
+ sqlite3_bind_blob (stmt, 1, device_name->buf (), device_name->length (), SQLITE_STATIC);
+ sqlite3_bind_int64 (stmt, 2, seqno);
+ sqlite3_step (stmt);
+ _LOG_DEBUG_COND (sqlite3_errcode (m_db) != SQLITE_DONE, sqlite3_errmsg (m_db));
+
+ sqlite3_finalize (stmt);
+
return action;
}
@@ -609,6 +643,82 @@
return retval;
}
+
+void
+ActionLog::LookupActionsInFolderRecursively (const boost::function<void (const Ccnx::Name &name, sqlite3_int64 seq_no, const ActionItem &)> &visitor,
+ const std::string &folder, int offset/*=0*/, int limit/*=-1*/)
+{
+ _LOG_DEBUG ("LookupActionsInFolderRecursively: [" << folder << "]");
+
+ sqlite3_stmt *stmt;
+ if (folder != "")
+ {
+ /// @todo Do something to improve efficiency of this query. Right now it is basically scanning the whole database
+
+ sqlite3_prepare_v2 (m_db,
+ "SELECT device_name,seq_no,action,filename,directory,version,action_timestamp, "
+ " file_hash,file_mtime,file_chmod,file_seg_num, "
+ " parent_device_name,parent_seq_no "
+ " FROM ActionLog "
+ " WHERE is_prefix (?, directory)=1 "
+ " ORDER BY action_timestamp DESC "
+ " LIMIT ? OFFSET ?", -1, &stmt, 0); // there is a small ambiguity with is_prefix matching, but should be ok for now
+ _LOG_DEBUG_COND (sqlite3_errcode (m_db) != SQLITE_OK, sqlite3_errmsg (m_db));
+
+ sqlite3_bind_text (stmt, 1, folder.c_str (), folder.size (), SQLITE_STATIC);
+ _LOG_DEBUG_COND (sqlite3_errcode (m_db) != SQLITE_OK, sqlite3_errmsg (m_db));
+
+ sqlite3_bind_int (stmt, 2, limit);
+ sqlite3_bind_int (stmt, 3, offset);
+ }
+ else
+ {
+ sqlite3_prepare_v2 (m_db,
+ "SELECT device_name,seq_no,action,filename,directory,version,action_timestamp, "
+ " file_hash,file_mtime,file_chmod,file_seg_num, "
+ " parent_device_name,parent_seq_no "
+ " FROM ActionLog "
+ " ORDER BY action_timestamp DESC "
+ " LIMIT ? OFFSET ?", -1, &stmt, 0);
+ sqlite3_bind_int (stmt, 1, limit);
+ sqlite3_bind_int (stmt, 2, offset);
+ }
+
+ _LOG_DEBUG_COND (sqlite3_errcode (m_db) != SQLITE_OK, sqlite3_errmsg (m_db));
+
+ while (sqlite3_step (stmt) == SQLITE_ROW)
+ {
+ ActionItem action;
+
+ Ccnx::Name device_name (sqlite3_column_blob (stmt, 0), sqlite3_column_bytes (stmt, 0));
+ sqlite3_int64 seq_no = sqlite3_column_int64 (stmt, 1);
+ action.set_action (static_cast<ActionItem_ActionType> (sqlite3_column_int (stmt, 2)));
+ action.set_filename (reinterpret_cast<const char *> (sqlite3_column_text (stmt, 3)), sqlite3_column_bytes (stmt, 3));
+ std::string directory (reinterpret_cast<const char *> (sqlite3_column_text (stmt, 4)), sqlite3_column_bytes (stmt, 4));
+ if (action.action () == 0)
+ {
+ action.set_version (sqlite3_column_int64 (stmt, 5));
+ action.set_timestamp (sqlite3_column_int64 (stmt, 6));
+ action.set_file_hash (sqlite3_column_blob (stmt, 7), sqlite3_column_bytes (stmt, 7));
+ action.set_mtime (sqlite3_column_int (stmt, 8));
+ action.set_mode (sqlite3_column_int (stmt, 9));
+ action.set_seg_num (sqlite3_column_int64 (stmt, 10));
+ }
+ if (sqlite3_column_bytes (stmt, 11) > 0)
+ {
+ action.set_parent_device_name (sqlite3_column_blob (stmt, 11), sqlite3_column_bytes (stmt, 11));
+ action.set_parent_seq_no (sqlite3_column_int64 (stmt, 12));
+ }
+
+ visitor (device_name, seq_no, action);
+ }
+
+ _LOG_DEBUG_COND (sqlite3_errcode (m_db) != SQLITE_DONE, sqlite3_errmsg (m_db));
+
+ sqlite3_finalize (stmt);
+}
+
+
///////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////
diff --git a/src/action-log.h b/src/action-log.h
index fe96f10..cfcaf7a 100644
--- a/src/action-log.h
+++ b/src/action-log.h
@@ -102,6 +102,13 @@
FileItemPtr
LookupAction (const std::string &filename, sqlite3_int64 version, const Hash &filehash);
+ /**
+ * @brief Lookup up to [limit] actions starting [offset] in decreasing order (by timestamp) and calling visitor(device_name,seqno,action) for each action
+ */
+ void
+ LookupActionsInFolderRecursively (const boost::function<void (const Ccnx::Name &name, sqlite3_int64 seq_no, const ActionItem &)> &visitor,
+ const std::string &folder, int offset=0, int limit=-1);
+
//
inline FileStatePtr
GetFileState ();
diff --git a/src/db-helper.cc b/src/db-helper.cc
index 33b0136..538e137 100644
--- a/src/db-helper.cc
+++ b/src/db-helper.cc
@@ -61,6 +61,13 @@
<< errmsg_info_str ("Cannot create function ``is_prefix''"));
}
+ res = sqlite3_create_function (m_db, "directory_name", -1, SQLITE_ANY, 0, DbHelper::directory_name_xFun, 0, 0);
+ if (res != SQLITE_OK)
+ {
+ BOOST_THROW_EXCEPTION (Error::Db ()
+ << errmsg_info_str ("Cannot create function ``directory_name''"));
+ }
+
// Alex: determine if tables initialized. if not, initialize... not sure what is the best way to go...
// for now, just attempt to create everything
sqlite3_exec (m_db, INIT_DATABASE.c_str (), NULL, NULL, NULL);
@@ -173,3 +180,31 @@
}
}
+void
+DbHelper::directory_name_xFun (sqlite3_context *context, int argc, sqlite3_value **argv)
+{
+ if (argc != 1)
+ {
+ sqlite3_result_error (context, "``directory_name'' expects 1 text argument", -1);
+ sqlite3_result_null (context);
+ return;
+ }
+
+ if (sqlite3_value_bytes (argv[0]) == 0)
+ {
+ sqlite3_result_null (context);
+ return;
+ }
+
+ boost::filesystem::path filePath (std::string (reinterpret_cast<const char*> (sqlite3_value_text (argv[0])), sqlite3_value_bytes (argv[0])));
+ std::string dirPath = filePath.parent_path ().generic_string ();
+ // _LOG_DEBUG ("directory_name FUN: " << dirPath);
+ if (dirPath.size () == 0)
+ {
+ sqlite3_result_null (context);
+ }
+ else
+ {
+ sqlite3_result_text (context, dirPath.c_str (), dirPath.size (), SQLITE_TRANSIENT);
+ }
+}
diff --git a/src/db-helper.h b/src/db-helper.h
index c15621c..0bc1a56 100644
--- a/src/db-helper.h
+++ b/src/db-helper.h
@@ -48,6 +48,9 @@
static void
is_prefix_xFun (sqlite3_context *context, int argc, sqlite3_value **argv);
+ static void
+ directory_name_xFun (sqlite3_context *context, int argc, sqlite3_value **argv);
+
protected:
sqlite3 *m_db;
};
diff --git a/src/file-state.cc b/src/file-state.cc
index fd982d9..63647c4 100644
--- a/src/file-state.cc
+++ b/src/file-state.cc
@@ -21,6 +21,7 @@
#include "file-state.h"
#include "logging.h"
+#include <boost/bind.hpp>
INIT_LOGGER ("FileState");
@@ -55,15 +56,6 @@
{
sqlite3_exec (m_db, INIT_DATABASE.c_str (), NULL, NULL, NULL);
_LOG_DEBUG_COND (sqlite3_errcode (m_db) != SQLITE_OK, sqlite3_errmsg (m_db));
-
- int res = sqlite3_create_function (m_db, "directory_name", -1, SQLITE_ANY, 0,
- FileState::directory_name_xFun,
- 0, 0);
- if (res != SQLITE_OK)
- {
- BOOST_THROW_EXCEPTION (Error::Db ()
- << errmsg_info_str ("Cannot create function ``directory_name''"));
- }
}
FileState::~FileState ()
@@ -242,21 +234,23 @@
return retval;
}
-
-FileItemsPtr
-FileState::LookupFilesInFolder (const std::string &folder)
+void
+FileState::LookupFilesInFolder (const boost::function<void (const FileItem&)> &visitor, const std::string &folder, int offset/*=0*/, int limit/*=-1*/)
{
sqlite3_stmt *stmt;
sqlite3_prepare_v2 (m_db,
"SELECT filename,device_name,seq_no,file_hash,strftime('%s', file_mtime),file_chmod,file_seg_num,is_complete "
" FROM FileState "
- " WHERE type = 0 AND directory = ?", -1, &stmt, 0);
+ " WHERE type = 0 AND directory = ?"
+ " LIMIT ? OFFSET ?", -1, &stmt, 0);
if (folder.size () == 0)
sqlite3_bind_null (stmt, 1);
else
sqlite3_bind_text (stmt, 1, folder.c_str (), folder.size (), SQLITE_STATIC);
- FileItemsPtr retval = make_shared<FileItems> ();
+ sqlite3_bind_int (stmt, 2, limit);
+ sqlite3_bind_int (stmt, 3, offset);
+
while (sqlite3_step (stmt) == SQLITE_ROW)
{
FileItem file;
@@ -269,58 +263,59 @@
file.set_seg_num (sqlite3_column_int64 (stmt, 6));
file.set_is_complete (sqlite3_column_int (stmt, 7));
- retval->push_back (file);
+ visitor (file);
}
_LOG_DEBUG_COND (sqlite3_errcode (m_db) != SQLITE_DONE, sqlite3_errmsg (m_db));
sqlite3_finalize (stmt);
+}
+
+FileItemsPtr
+FileState::LookupFilesInFolder (const std::string &folder, int offset/*=0*/, int limit/*=-1*/)
+{
+ FileItemsPtr retval = make_shared<FileItems> ();
+ LookupFilesInFolder (boost::bind (&FileItems::push_back, retval.get (), _1), folder, offset, limit);
return retval;
}
FileItemsPtr
-FileState::LookupFilesInFolderRecursively (const std::string &folder)
+FileState::LookupFilesInFolderRecursively (const boost::function<void (const FileItem&)> &visitor, const std::string &folder, int offset/*=0*/, int limit/*=-1*/)
{
_LOG_DEBUG ("LookupFilesInFolderRecursively: [" << folder << "]");
sqlite3_stmt *stmt;
if (folder != "")
{
+ /// @todo Do something to improve efficiency of this query. Right now it is basically scanning the whole database
+
sqlite3_prepare_v2 (m_db,
"SELECT filename,device_name,seq_no,file_hash,strftime('%s', file_mtime),file_chmod,file_seg_num,is_complete "
" FROM FileState "
- " WHERE type = 0 AND (directory = ? OR directory LIKE ?)", -1, &stmt, 0);
+ " WHERE type = 0 AND is_prefix (?, directory)=1 "
+ " LIMIT ? OFFSET ?", -1, &stmt, 0); // there is a small ambiguity with is_prefix matching, but should be ok for now
_LOG_DEBUG_COND (sqlite3_errcode (m_db) != SQLITE_OK, sqlite3_errmsg (m_db));
sqlite3_bind_text (stmt, 1, folder.c_str (), folder.size (), SQLITE_STATIC);
_LOG_DEBUG_COND (sqlite3_errcode (m_db) != SQLITE_OK, sqlite3_errmsg (m_db));
- ostringstream escapedFolder;
- for (string::const_iterator ch = folder.begin (); ch != folder.end (); ch ++)
- {
- if (*ch == '%')
- escapedFolder << "\\%";
- else
- escapedFolder << *ch;
- }
- escapedFolder << "/" << "%";
- string escapedFolderStr = escapedFolder.str ();
-
- sqlite3_bind_text (stmt, 2, escapedFolderStr.c_str (), escapedFolderStr.size (), SQLITE_STATIC);
- _LOG_DEBUG_COND (sqlite3_errcode (m_db) != SQLITE_OK, sqlite3_errmsg (m_db));
+ sqlite3_bind_int (stmt, 2, limit);
+ sqlite3_bind_int (stmt, 3, offset);
}
else
{
sqlite3_prepare_v2 (m_db,
"SELECT filename,device_name,seq_no,file_hash,strftime('%s', file_mtime),file_chmod,file_seg_num,is_complete "
" FROM FileState "
- " WHERE type = 0", -1, &stmt, 0);
+ " WHERE type = 0"
+ " LIMIT ? OFFSET ?", -1, &stmt, 0);
+ sqlite3_bind_int (stmt, 1, limit);
+ sqlite3_bind_int (stmt, 2, offset);
}
_LOG_DEBUG_COND (sqlite3_errcode (m_db) != SQLITE_OK, sqlite3_errmsg (m_db));
- FileItemsPtr retval = make_shared<FileItems> ();
while (sqlite3_step (stmt) == SQLITE_ROW)
{
FileItem file;
@@ -333,41 +328,19 @@
file.set_seg_num (sqlite3_column_int64 (stmt, 6));
file.set_is_complete (sqlite3_column_int (stmt, 7));
- retval->push_back (file);
+ visitor (file);
}
_LOG_DEBUG_COND (sqlite3_errcode (m_db) != SQLITE_DONE, sqlite3_errmsg (m_db));
sqlite3_finalize (stmt);
-
- return retval;
}
-void
-FileState::directory_name_xFun (sqlite3_context *context, int argc, sqlite3_value **argv)
+FileItemsPtr
+FileState::LookupFilesInFolderRecursively (const std::string &folder, int offset/*=0*/, int limit/*=-1*/)
{
- if (argc != 1)
- {
- sqlite3_result_error (context, "``directory_name'' expects 1 text argument", -1);
- sqlite3_result_null (context);
- return;
- }
+ FileItemsPtr retval = make_shared<FileItems> ();
+ LookupFilesInFolder (boost::bind (&FileItems::push_back, retval.get (), _1), folder, offset, limit);
- if (sqlite3_value_bytes (argv[0]) == 0)
- {
- sqlite3_result_null (context);
- return;
- }
-
- filesystem::path filePath (string (reinterpret_cast<const char*> (sqlite3_value_text (argv[0])), sqlite3_value_bytes (argv[0])));
- string dirPath = filePath.parent_path ().generic_string ();
- // _LOG_DEBUG ("directory_name FUN: " << dirPath);
- if (dirPath.size () == 0)
- {
- sqlite3_result_null (context);
- }
- else
- {
- sqlite3_result_text (context, dirPath.c_str (), dirPath.size (), SQLITE_TRANSIENT);
- }
+ return retval;
}
diff --git a/src/file-state.h b/src/file-state.h
index 91bb3d2..6c4ace2 100644
--- a/src/file-state.h
+++ b/src/file-state.h
@@ -78,20 +78,28 @@
LookupFilesForHash (const Hash &hash);
/**
- * @brief Lookup all files in the specified folder
+ * @brief Lookup all files in the specified folder and call visitor(file) for each file
*/
- FileItemsPtr
- LookupFilesInFolder (const std::string &folder);
+ void
+ LookupFilesInFolder (const boost::function<void (const FileItem&)> &visitor, const std::string &folder, int offset=0, int limit=-1);
/**
- * @brief Recursively lookup all files in the specified folder
+ * @brief Lookup all files in the specified folder (wrapper around the overloaded version)
*/
FileItemsPtr
- LookupFilesInFolderRecursively (const std::string &folder);
+ LookupFilesInFolder (const std::string &folder, int offset=0, int limit=-1);
-private:
- static void
- directory_name_xFun (sqlite3_context *context, int argc, sqlite3_value **argv);
+ /**
+ * @brief Recursively lookup all files in the specified folder and call visitor(file) for each file
+ */
+ FileItemsPtr
+ LookupFilesInFolderRecursively (const boost::function<void (const FileItem&)> &visitor, const std::string &folder, int offset=0, int limit=-1);
+
+ /**
+ * @brief Recursively lookup all files in the specified folder (wrapper around the overloaded version)
+ */
+ FileItemsPtr
+ LookupFilesInFolderRecursively (const std::string &folder, int offset=0, int limit=-1);
};
typedef boost::shared_ptr<FileState> FileStatePtr;
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
diff --git a/src/state-server.h b/src/state-server.h
index 3eec803..24c9b05 100644
--- a/src/state-server.h
+++ b/src/state-server.h
@@ -30,7 +30,7 @@
#include <map>
#include <boost/thread/shared_mutex.hpp>
#include <boost/thread/locks.hpp>
-#include "scheduler.h"
+#include "executor.h"
/**
* @brief Class serving state information from ChronoShare
@@ -39,7 +39,7 @@
*
* Information available:
*
- * For now serving only locally (using <PREFIX> = /localhost/<user's-device-name>/"chronoshare"/"info")
+ * For now serving only locally (using <PREFIX> = /localhost/<user's-device-name>/"chronoshare"/<FOLDER>/"info")
*
* - state: get list of SyncNodes, their sequence numbers, and forwarding hint (almost the same as RECOVERY interest)
*
@@ -47,28 +47,38 @@
*
* - action
*
- * <PREFIX_INFO>/"actions"/"all"/<nonce>/<segment> get list of all actions
- * <PREFIX_INFO>/"actions"/"file"/<nonce>/<segment> get list of actions for a file
+ * Get list of actions for a folder (for all files under this folder)
+ *
+ * <PREFIX_INFO>/"actions"/"folder"/<nonce>/<offset> (all actions)
+ * or
+ * <PREFIX_INFO>/"actions"/"folder"/<one-component-relative-file-name>/<nonce>/<offset>
*
* Actions are ordered in decreasing order (latest will go first).
- * Each data packet contains up to 100 actions. If there are more, they will be segmented. Data packet always
- * contains a segment number (even if there are less than 100 actions available).
*
- * Number of segments is indicated in FinalBlockID of the first data packet (in <PREFIX>/"action"/"all"/<nonce>/%00)
+ * Each data packet contains up to 100 actions.
+ * If more items are available, application data will specify URL for the next packet
+ *
+ * @todo SPECIFY FORMAT OF THIS FIELD
*
* - file
*
- * <PREFIX_INFO>/"filestate"/"all"/<nonce>/<segment>
+ * <PREFIX_INFO>/"filestate"/"folder"/<nonce>/<offset> (full filestate)
+ * or
+ * <PREFIX_INFO>/"filestate"/"folder"/<one-component-relative-folder-name>/<nonce>/<offset>
*
- * Each Data packets contains a list of up to 100 files, the rest is published in other segments.
- * Number of segments is indicated in FinalBlockID of the first data packet (in <PREFIX>/"file"/"all"/<nonce>/%00).
+ * Each Data packets contains a list of up to 100 files.
+ * If more items are available, application data will specify URL for the next packet
+ *
+ * @todo SPECIFY FORMAT OF THIS FIELD
*
* Commands available:
*
- * For now serving only locally (using <PREFIX_CMD> = /localhost/<user's-device-name>/"chronoshare"/"cmd")
+ * For now serving only locally (using <PREFIX_CMD> = /localhost/<user's-device-name>/"chronoshare"/<FOLDER>/"cmd")
*
* - restore version of the file
*
+ * <PREFIX_CMD>/"restore"/"file"/<one-component-relative-file-name>/<version>
+ * or
* <PREFIX_CMD>/"restore"/"file"/<one-component-relative-file-name>/<version>/<file-hash>
*
* - clean state log
@@ -86,10 +96,16 @@
private:
void
- info_actions_all (const Ccnx::Name &interest);
+ info_actions_folder (const Ccnx::Name &interest);
void
- info_actions_all_Execute (const Ccnx::Name &interest);
+ info_actions_folder_Execute (const Ccnx::Name &interest);
+
+ void
+ info_filestate_folder (const Ccnx::Name &interest);
+
+ void
+ info_filestate_folder_Execute (const Ccnx::Name &interest);
void
cmd_restore_file (const Ccnx::Name &interest);
@@ -115,7 +131,7 @@
boost::filesystem::path m_rootDir;
int m_freshness;
- SchedulerPtr m_scheduler;
+ Executor m_executor;
Ccnx::Name m_userName;
std::string m_sharedFolderName;