state server
Change-Id: Ie9365d7c7c62da8c3ef51088364c8af08751cfba
diff --git a/src/dispatcher.cpp b/src/dispatcher.cpp
index a554454..bf0856e 100644
--- a/src/dispatcher.cpp
+++ b/src/dispatcher.cpp
@@ -66,8 +66,8 @@
m_server->registerPrefix(Name("/"));
m_server->registerPrefix(Name(BROADCAST_DOMAIN));
- //m_stateServer = make_unique<StateServer>(m_face, m_actionLog, rootDir, m_localUserName, m_sharedFolder,
- // CHRONOSHARE_APP, m_objectManager, m_keyChair);
+ m_stateServer = make_unique<StateServer>(m_face, m_actionLog, rootDir, m_localUserName, m_sharedFolder,
+ CHRONOSHARE_APP, m_objectManager, m_keyChain);
m_core = make_unique<SyncCore>(m_face, m_syncLog, localUserName, Name("/"), syncPrefix,
bind(&Dispatcher::Did_SyncLog_StateChange, this, _1),
diff --git a/src/dispatcher.hpp b/src/dispatcher.hpp
index dcc73e4..45d6718 100644
--- a/src/dispatcher.hpp
+++ b/src/dispatcher.hpp
@@ -25,6 +25,7 @@
#include "action-log.hpp"
#include "content-server.hpp"
+#include "state-server.hpp"
#include "fetch-manager.hpp"
#include "object-db.hpp"
#include "object-manager.hpp"
@@ -216,7 +217,7 @@
std::string m_sharedFolder;
unique_ptr<ContentServer> m_server;
- //unique_ptr<StateServer> m_stateServer;
+ unique_ptr<StateServer> m_stateServer;
bool m_enablePrefixDiscovery;
FetchManagerPtr m_actionFetcher;
diff --git a/src/state-server.cpp b/src/state-server.cpp
index f84cdea..ecec125 100644
--- a/src/state-server.cpp
+++ b/src/state-server.cpp
@@ -18,53 +18,54 @@
* See AUTHORS.md for complete list of ChronoShare authors and contributors.
*/
-#include "state-server.h"
-#include "logging.h"
-#include "periodic-task.h"
-#include "simple-interval-generator.h"
-#include "task.h"
+#include "state-server.hpp"
+#include "core/logging.hpp"
+
+#include <ndn-cxx/util/digest.hpp>
+#include <ndn-cxx/util/string-helper.hpp>
+
+#include <boost/asio/io_service.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/filesystem/fstream.hpp>
#include <boost/lexical_cast.hpp>
-#include <boost/make_shared.hpp>
-#include <utility>
+
+namespace ndn {
+namespace chronoshare {
_LOG_INIT(StateServer);
-using namespace Ndnx;
-using namespace std;
-using namespace boost;
+namespace fs = boost::filesystem;
-StateServer::StateServer(CcnxWrapperPtr ccnx, ActionLogPtr actionLog,
- const boost::filesystem::path& rootDir, const Ccnx::Name& userName,
- const std::string& sharedFolderName, const std::string& appName,
- ObjectManager& objectManager, int freshness /* = -1*/)
- : m_ccnx(ccnx)
+StateServer::StateServer(Face& face, ActionLogPtr actionLog, const fs::path& rootDir,
+ const Name& userName, const std::string& sharedFolderName,
+ const name::Component& appName, ObjectManager& objectManager,
+ KeyChain& keyChain, time::milliseconds freshness)
+ : m_face(face)
, m_actionLog(actionLog)
, m_objectManager(objectManager)
, m_rootDir(rootDir)
, m_freshness(freshness)
- , m_executor(1)
, m_userName(userName)
, m_sharedFolderName(sharedFolderName)
, m_appName(appName)
+ , m_keyChain(keyChain)
+ , m_ioService(m_face.getIoService())
{
- // may be later /localhost should be replaced with /%C1.M.S.localhost
+ // may be later /localhop 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")(m_sharedFolderName)("info");
+ // <PREFIX_INFO> = /localhop/<user's-device-name>/"chronoshare"/"info"
+ m_PREFIX_INFO = Name("/localhop");
+ m_PREFIX_INFO.append(m_userName).append(m_appName).append(m_sharedFolderName).append("info");
- // <PREFIX_CMD> = /localhost/<user's-device-name>/"chronoshare"/"cmd"
- m_PREFIX_CMD = Name("/localhost")(m_userName)("chronoshare")(m_sharedFolderName)("cmd");
-
- m_executor.start();
+ // <PREFIX_CMD> = /localhop/<user's-device-name>/"chronoshare"/"cmd"
+ m_PREFIX_CMD = Name("/localhop");
+ m_PREFIX_CMD.append(m_userName).append(m_appName).append(m_sharedFolderName).append("cmd");
registerPrefixes();
}
StateServer::~StateServer()
{
- m_executor.shutdown();
-
deregisterPrefixes();
}
@@ -75,59 +76,84 @@
// will be extended to support all planned commands later
// <PREFIX_INFO>/"actions"/"all"/<segment> get list of all actions
- m_ccnx->setInterestFilter(Name(m_PREFIX_INFO)("actions")("folder"),
- bind(&StateServer::info_actions_folder, this, _1));
- m_ccnx->setInterestFilter(Name(m_PREFIX_INFO)("actions")("file"),
- bind(&StateServer::info_actions_file, this, _1));
+ Name actionsFolder = Name(m_PREFIX_INFO);
+ actionsFolder.append("actions").append("folder");
+ actionsFolderId =
+ m_face.setInterestFilter(InterestFilter(actionsFolder),
+ bind(&StateServer::info_actions_folder, this, _1, _2),
+ RegisterPrefixSuccessCallback(), RegisterPrefixFailureCallback());
+
+ _LOG_DEBUG("Register Prefix: " << actionsFolder);
+
+ Name actionsFile = Name(m_PREFIX_INFO);
+ actionsFile.append("actions").append("file");
+ actionsFileId =
+ m_face.setInterestFilter(InterestFilter(actionsFile),
+ bind(&StateServer::info_actions_file, this, _1, _2),
+ RegisterPrefixSuccessCallback(), RegisterPrefixFailureCallback());
+
+ _LOG_DEBUG("Register Prefix: " << actionsFile);
// <PREFIX_INFO>/"filestate"/"all"/<segment>
- m_ccnx->setInterestFilter(Name(m_PREFIX_INFO)("files")("folder"),
- bind(&StateServer::info_files_folder, this, _1));
+ Name filesFolder = Name(m_PREFIX_INFO);
+ filesFolder.append("files").append("folder");
+ filesFolderId =
+ m_face.setInterestFilter(InterestFilter(filesFolder),
+ bind(&StateServer::info_files_folder, this, _1, _2),
+ RegisterPrefixSuccessCallback(), RegisterPrefixFailureCallback());
+
+ _LOG_DEBUG("Register Prefix: " << filesFolder);
// <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));
+ Name restoreFile = Name(m_PREFIX_CMD);
+ restoreFile.append("restore").append("file");
+ restoreFileId =
+ m_face.setInterestFilter(InterestFilter(restoreFile),
+ bind(&StateServer::cmd_restore_file, this, _1, _2),
+ RegisterPrefixSuccessCallback(), RegisterPrefixFailureCallback());
+
+ _LOG_DEBUG("Register Prefix: " << restoreFile);
}
void
StateServer::deregisterPrefixes()
{
- m_ccnx->clearInterestFilter(Name(m_PREFIX_INFO)("actions")("folder"));
- m_ccnx->clearInterestFilter(Name(m_PREFIX_INFO)("actions")("file"));
- m_ccnx->clearInterestFilter(Name(m_PREFIX_INFO)("files")("folder"));
- m_ccnx->clearInterestFilter(Name(m_PREFIX_CMD)("restore")("file"));
+ m_face.unsetInterestFilter(actionsFolderId);
+ m_face.unsetInterestFilter(actionsFileId);
+ m_face.unsetInterestFilter(filesFolderId);
+ m_face.unsetInterestFilter(restoreFileId);
}
void
-StateServer::formatActionJson(json_spirit::Array& actions, const Ccnx::Name& name,
- sqlite3_int64 seq_no, const ActionItem& action)
+StateServer::formatActionJson(json_spirit::Array& actions, const Name& name, sqlite3_int64 seq_no,
+ const ActionItem& action)
{
/*
- * {
- * "id": {
- * "userName": "<NDN-NAME-OF-THE-USER>",
- * "seqNo": "<SEQ_NO_OF_THE_ACTION>"
- * },
- * "timestamp": "<ACTION-TIMESTAMP>",
- * "filename": "<FILENAME>",
- *
- * "action": "UPDATE | DELETE",
- *
- * // only if update
- * "update": {
- * "hash": "<FILE-HASH>",
- * "timestamp": "<FILE-TIMESTAMP>",
- * "chmod": "<FILE-MODE>",
- * "segNum": "<NUMBER-OF-SEGMENTS (~file size)>"
- * },
- *
- * // if parent_device_name is set
- * "parentId": {
- * "userName": "<NDN-NAME-OF-THE-USER>",
- * "seqNo": "<SEQ_NO_OF_THE_ACTION>"
- * }
- * }
- */
+ * {
+ * "id": {
+ * "userName": "<NDN-NAME-OF-THE-USER>",
+ * "seqNo": "<SEQ_NO_OF_THE_ACTION>"
+ * },
+ * "timestamp": "<ACTION-TIMESTAMP>",
+ * "filename": "<FILENAME>",
+ *
+ * "action": "UPDATE | DELETE",
+ *
+ * // only if update
+ * "update": {
+ * "hash": "<FILE-HASH>",
+ * "timestamp": "<FILE-TIMESTAMP>",
+ * "chmod": "<FILE-MODE>",
+ * "segNum": "<NUMBER-OF-SEGMENTS(~file size)>"
+ * },
+ *
+ * // if parent_device_name is set
+ * "parentId": {
+ * "userName": "<NDN-NAME-OF-THE-USER>",
+ * "seqNo": "<SEQ_NO_OF_THE_ACTION>"
+ * }
+ * }
+ */
using namespace json_spirit;
using namespace boost::posix_time;
@@ -135,7 +161,7 @@
Object json;
Object id;
- id.push_back(Pair("userName", boost::lexical_cast<string>(name)));
+ id.push_back(Pair("userName", boost::lexical_cast<std::string>(name)));
id.push_back(Pair("seqNo", static_cast<int64_t>(seq_no)));
json.push_back(Pair("id", id));
@@ -147,12 +173,12 @@
if (action.action() == 0) {
Object update;
- update.push_back(Pair("hash", boost::lexical_cast<string>(
- Hash(action.file_hash().c_str(), action.file_hash().size()))));
+ const Buffer hash(action.file_hash().c_str(), action.file_hash().size());
+ update.push_back(Pair("hash", toHex(hash)));
update.push_back(Pair("timestamp", to_iso_extended_string(from_time_t(action.mtime()))));
- ostringstream chmod;
- chmod << setbase(8) << setfill('0') << setw(4) << action.mode();
+ std::ostringstream chmod;
+ chmod << std::setbase(8) << std::setfill('0') << std::setw(4) << action.mode();
update.push_back(Pair("chmod", chmod.str()));
update.push_back(Pair("segNum", action.seg_num()));
@@ -161,9 +187,8 @@
if (action.has_parent_device_name()) {
Object parentId;
- Ccnx::Name parent_device_name(action.parent_device_name().c_str(),
- action.parent_device_name().size());
- id.push_back(Pair("userName", boost::lexical_cast<string>(parent_device_name)));
+ Name parent_device_name(action.parent_device_name());
+ id.push_back(Pair("userName", boost::lexical_cast<std::string>(parent_device_name)));
id.push_back(Pair("seqNo", action.parent_seq_no()));
json.push_back(Pair("parentId", parentId));
@@ -173,115 +198,120 @@
}
void
-StateServer::info_actions_folder(const Name& interest)
+StateServer::info_actions_folder(const InterestFilter& interesFilter, const Interest& interestTrue)
{
+ Name interest = interestTrue.getName();
+ _LOG_DEBUG(">> info_actions_folder: " << interest);
if (interest.size() - m_PREFIX_INFO.size() != 3 && interest.size() - m_PREFIX_INFO.size() != 4) {
_LOG_DEBUG("Invalid interest: " << interest);
return;
}
- _LOG_DEBUG(">> info_actions_folder: " << interest);
- m_executor.execute(bind(&StateServer::info_actions_fileOrFolder_Execute, this, interest, true));
+ m_ioService.post(bind(&StateServer::info_actions_fileOrFolder_Execute, this, interest, true));
}
void
-StateServer::info_actions_file(const Name& interest)
+StateServer::info_actions_file(const InterestFilter& interesFilter, const Interest& interestTrue)
{
+ Name interest = interestTrue.getName();
if (interest.size() - m_PREFIX_INFO.size() != 3 && interest.size() - m_PREFIX_INFO.size() != 4) {
_LOG_DEBUG("Invalid interest: " << interest);
return;
}
_LOG_DEBUG(">> info_actions_file: " << interest);
- m_executor.execute(bind(&StateServer::info_actions_fileOrFolder_Execute, this, interest, false));
+ m_ioService.post(bind(&StateServer::info_actions_fileOrFolder_Execute, this, interest, false));
}
-
void
-StateServer::info_actions_fileOrFolder_Execute(const Ccnx::Name& interest, bool isFolder /* = true*/)
+StateServer::info_actions_fileOrFolder_Execute(const Name& interest, bool isFolder /* = true*/)
{
// <PREFIX_INFO>/"actions"/"folder|file"/<folder|file>/<offset> get list of all actions
-
- try {
- int offset = interest.getCompFromBackAsInt(0);
-
- /// @todo !!! add security checking
-
- string fileOrFolderName;
- if (interest.size() - m_PREFIX_INFO.size() == 4)
- fileOrFolderName = interest.getCompFromBackAsString(1);
- else // == 3
- fileOrFolderName = "";
- /*
- * {
- * "actions": [
- * ...
- * ],
- *
- * // only if there are more actions available
- * "more": "<NDN-NAME-OF-NEXT-SEGMENT-OF-ACTION>"
- * }
- */
-
- using namespace json_spirit;
- Object json;
-
- Array actions;
- bool more;
- if (isFolder) {
- more =
- m_actionLog->LookupActionsInFolderRecursively(boost::bind(StateServer::formatActionJson,
- boost::ref(actions), _1, _2, _3),
- fileOrFolderName, offset * 10, 10);
- }
- else {
- more = m_actionLog->LookupActionsForFile(boost::bind(StateServer::formatActionJson,
- boost::ref(actions), _1, _2, _3),
- fileOrFolderName, offset * 10, 10);
- }
-
- json.push_back(Pair("actions", actions));
-
- if (more) {
- json.push_back(Pair("more", lexical_cast<string>(offset + 1)));
- // Ccnx::Name more = Name (interest.getPartialName (0, interest.size () - 1))(offset + 1);
- // json.push_back (Pair ("more", lexical_cast<string> (more)));
- }
-
- ostringstream os;
- write_stream(Value(json), os, pretty_print | raw_utf8);
- m_ccnx->publishData(interest, os.str(), 1);
- }
- catch (Ccnx::NameException& ne) {
+ if (interest.size() < 1) {
// ignore any unexpected interests and errors
- _LOG_ERROR(*boost::get_error_info<Ccnx::error_info_str>(ne));
+ _LOG_ERROR("empty interest name");
+ return;
}
+ uint64_t offset = interest.get(-1).toNumber();
+
+ /// @todo !!! add security checking
+
+ std::string fileOrFolderName;
+ if (interest.size() - m_PREFIX_INFO.size() == 4)
+ fileOrFolderName = interest.get(-2).toUri();
+ else // == 3
+ fileOrFolderName = "";
+ /*
+ * {
+ * "actions": [
+ * ...
+ * ],
+ *
+ * // only if there are more actions available
+ * "more": "<NDN-NAME-OF-NEXT-SEGMENT-OF-ACTION>"
+ * }
+ */
+
+ _LOG_DEBUG("info_actions_fileOrFolder_Execute! offset: " << offset);
+ using namespace json_spirit;
+ Object json;
+
+ Array actions;
+ bool more;
+ if (isFolder) {
+ more = m_actionLog->LookupActionsInFolderRecursively(bind(StateServer::formatActionJson,
+ boost::ref(actions), _1, _2, _3),
+ fileOrFolderName, offset * 10, 10);
+ }
+ else {
+ more = m_actionLog->LookupActionsForFile(bind(StateServer::formatActionJson,
+ boost::ref(actions), _1, _2, _3),
+ fileOrFolderName, offset * 10, 10);
+ }
+
+ json.push_back(Pair("actions", actions));
+
+ if (more) {
+ json.push_back(Pair("more", boost::lexical_cast<std::string>(offset + 1)));
+ // Name more = Name(interest.getPartialName(0, interest.size() - 1))(offset + 1);
+ // json.push_back(Pair("more", boost::lexical_cast<std::string>(more)));
+ }
+
+ std::ostringstream os;
+ write_stream(Value(json), os, pretty_print | raw_utf8);
+
+ shared_ptr<Data> data = make_shared<Data>();
+ data->setName(interest);
+ data->setFreshnessPeriod(m_freshness);
+ data->setContent(reinterpret_cast<const uint8_t*>(os.str().c_str()), os.str().size());
+ m_keyChain.sign(*data);
+ m_face.put(*data);
}
void
StateServer::formatFilestateJson(json_spirit::Array& files, const FileItem& file)
{
/**
- * {
- * "filestate": [
- * {
- * "filename": "<FILENAME>",
- * "owner": {
- * "userName": "<NDN-NAME-OF-THE-USER>",
- * "seqNo": "<SEQ_NO_OF_THE_ACTION>"
- * },
- *
- * "hash": "<FILE-HASH>",
- * "timestamp": "<FILE-TIMESTAMP>",
- * "chmod": "<FILE-MODE>",
- * "segNum": "<NUMBER-OF-SEGMENTS (~file size)>"
- * }, ...,
- * ]
- *
- * // only if there are more actions available
- * "more": "<NDN-NAME-OF-NEXT-SEGMENT-OF-FILESTATE>"
- * }
- */
+ * {
+ * "filestate": [
+ * {
+ * "filename": "<FILENAME>",
+ * "owner": {
+ * "userName": "<NDN-NAME-OF-THE-USER>",
+ * "seqNo": "<SEQ_NO_OF_THE_ACTION>"
+ * },
+ *
+ * "hash": "<FILE-HASH>",
+ * "timestamp": "<FILE-TIMESTAMP>",
+ * "chmod": "<FILE-MODE>",
+ * "segNum": "<NUMBER-OF-SEGMENTS(~file size)>"
+ * }, ...,
+ * ]
+ *
+ * // only if there are more actions available
+ * "more": "<NDN-NAME-OF-NEXT-SEGMENT-OF-FILESTATE>"
+ * }
+ */
using namespace json_spirit;
using namespace boost::posix_time;
@@ -291,19 +321,19 @@
json.push_back(Pair("version", file.version()));
{
Object owner;
- Ccnx::Name device_name(file.device_name().c_str(), file.device_name().size());
- owner.push_back(Pair("userName", boost::lexical_cast<string>(device_name)));
+ Name device_name(file.device_name());
+ owner.push_back(Pair("userName", boost::lexical_cast<std::string>(device_name)));
owner.push_back(Pair("seqNo", file.seq_no()));
json.push_back(Pair("owner", owner));
}
- json.push_back(Pair("hash", boost::lexical_cast<string>(
- Hash(file.file_hash().c_str(), file.file_hash().size()))));
+ json.push_back(Pair("hash", toHex(reinterpret_cast<const uint8_t*>(file.file_hash().data()),
+ file.file_hash().size())));
json.push_back(Pair("timestamp", to_iso_extended_string(from_time_t(file.mtime()))));
- ostringstream chmod;
- chmod << setbase(8) << setfill('0') << setw(4) << file.mode();
+ std::ostringstream chmod;
+ chmod << std::setbase(8) << std::setfill('0') << std::setw(4) << file.mode();
json.push_back(Pair("chmod", chmod.str()));
json.push_back(Pair("segNum", file.seg_num()));
@@ -318,163 +348,204 @@
}
void
-StateServer::info_files_folder(const Ccnx::Name& interest)
+StateServer::info_files_folder(const InterestFilter& interesFilter, const Interest& interestTrue)
{
+ Name interest = interestTrue.getName();
if (interest.size() - m_PREFIX_INFO.size() != 3 && interest.size() - m_PREFIX_INFO.size() != 4) {
_LOG_DEBUG("Invalid interest: " << interest << ", " << interest.size() - m_PREFIX_INFO.size());
return;
}
_LOG_DEBUG(">> info_files_folder: " << interest);
- m_executor.execute(bind(&StateServer::info_files_folder_Execute, this, interest));
+ m_ioService.post(bind(&StateServer::info_files_folder_Execute, this, interest));
}
-
void
-StateServer::info_files_folder_Execute(const Ccnx::Name& interest)
+StateServer::info_files_folder_Execute(const Name& interest)
{
// <PREFIX_INFO>/"filestate"/"folder"/<one-component-relative-folder-name>/<offset>
- try {
- int offset = interest.getCompFromBackAsInt(0);
-
- // /// @todo !!! add security checking
-
- string folder;
- if (interest.size() - m_PREFIX_INFO.size() == 4)
- folder = interest.getCompFromBackAsString(1);
- else // == 3
- folder = "";
-
- /*
- * {
- * "files": [
- * ...
- * ],
- *
- * // only if there are more actions available
- * "more": "<NDN-NAME-OF-NEXT-SEGMENT-OF-ACTION>"
- * }
- */
-
- using namespace json_spirit;
- Object json;
-
- Array files;
- bool more = m_actionLog->GetFileState()
- ->LookupFilesInFolderRecursively(boost::bind(StateServer::formatFilestateJson,
- boost::ref(files), _1),
- folder, offset * 10, 10);
-
- json.push_back(Pair("files", files));
-
- if (more) {
- json.push_back(Pair("more", lexical_cast<string>(offset + 1)));
- // Ccnx::Name more = Name (interest.getPartialName (0, interest.size () - 1))(offset + 1);
- // json.push_back (Pair ("more", lexical_cast<string> (more)));
- }
-
- ostringstream os;
- write_stream(Value(json), os, pretty_print | raw_utf8);
- m_ccnx->publishData(interest, os.str(), 1);
- }
- catch (Ccnx::NameException& ne) {
+ if (interest.size() < 1) {
// ignore any unexpected interests and errors
- _LOG_ERROR(*boost::get_error_info<Ccnx::error_info_str>(ne));
+ _LOG_ERROR("empty interest name");
+ return;
}
+ uint64_t offset = interest.get(-1).toNumber();
+
+ // /// @todo !!! add security checking
+
+ std::string folder;
+ if (interest.size() - m_PREFIX_INFO.size() == 4)
+ folder = interest.get(-2).toUri();
+ else // == 3
+ folder = "";
+
+ /*
+ *{
+ * "files": [
+ * ...
+ * ],
+ *
+ * // only if there are more actions available
+ * "more": "<NDN-NAME-OF-NEXT-SEGMENT-OF-ACTION>"
+ *}
+ */
+
+ using namespace json_spirit;
+ Object json;
+
+ Array files;
+ bool more =
+ m_actionLog->GetFileState()->LookupFilesInFolderRecursively(bind(StateServer::formatFilestateJson,
+ boost::ref(files), _1),
+ folder, offset * 10, 10);
+
+ json.push_back(Pair("files", files));
+
+ if (more) {
+ json.push_back(Pair("more", boost::lexical_cast<std::string>(offset + 1)));
+ // Name more = Name(interest.getPartialName(0, interest.size() - 1))(offset + 1);
+ // json.push_back(Pair("more", boost::lexical_cast<std::string>(more)));
+ }
+
+ std::ostringstream os;
+ write_stream(Value(json), os, pretty_print | raw_utf8);
+
+ shared_ptr<Data> data = make_shared<Data>();
+ data->setName(interest);
+ data->setFreshnessPeriod(m_freshness);
+ data->setContent(reinterpret_cast<const uint8_t*>(os.str().c_str()), os.str().size());
+ m_keyChain.sign(*data);
+ m_face.put(*data);
}
-
void
-StateServer::cmd_restore_file(const Ccnx::Name& interest)
+StateServer::cmd_restore_file(const InterestFilter& interesFilter, const Interest& interestTrue)
{
+ Name interest = interestTrue.getName();
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_executor.execute(bind(&StateServer::cmd_restore_file_Execute, this, interest));
+ m_ioService.post(bind(&StateServer::cmd_restore_file_Execute, this, interest));
}
void
-StateServer::cmd_restore_file_Execute(const Ccnx::Name& interest)
+StateServer::cmd_restore_file_Execute(const Name& interest)
{
// <PREFIX_CMD>/"restore"/"file"/<one-component-relative-file-name>/<version>/<file-hash>
/// @todo !!! add security checking
- try {
- FileItemPtr file;
+ FileItemPtr file;
- 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
+ if (interest.size() - m_PREFIX_CMD.size() == 5) {
+ const Buffer hash(interest.get(-1).value(), interest.get(-1).value_size());
+ uint64_t version = interest.get(-2).toNumber();
+ std::string filename = interest.get(-3).toUri(); // 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
+ _LOG_DEBUG("filename: " << filename << " version: " << version);
- file = m_actionLog->LookupAction(filename, version, Hash(0, 0));
- if (!file) {
- _LOG_ERROR("Requested file is not found: [" << filename << "] version [" << version << "]");
- }
- }
+ file = m_actionLog->LookupAction(filename, version, hash);
if (!file) {
- m_ccnx->publishData(interest, "FAIL: Requested file is not found", 1);
- return;
+ _LOG_ERROR("Requested file is not found: [" << filename << "] version [" << version << "] hash ["
+ << toHex(hash)
+ << "]");
}
+ }
+ else {
+ uint64_t version = interest.get(-1).toNumber();
+ std::string filename = interest.get(-2).toUri();
+ file = m_actionLog->LookupAction(filename, version, Buffer(0, 0));
+ if (!file) {
+ _LOG_ERROR("Requested file is not found: [" << filename << "] version [" << version << "]");
+ }
+ }
- Hash hash = Hash(file->file_hash().c_str(), file->file_hash().size());
+ if (!file) {
+ shared_ptr<Data> data = make_shared<Data>();
+ data->setName(interest);
+ data->setFreshnessPeriod(m_freshness);
+ std::string msg = "FAIL: Requested file is not found";
+ data->setContent(reinterpret_cast<const uint8_t*>(msg.c_str()), msg.size());
+ m_keyChain.sign(*data);
+ m_face.put(*data);
+ return;
+ }
- ///////////////////
- // now the magic //
- ///////////////////
+ const Buffer hash(file->file_hash().c_str(), file->file_hash().size());
- boost::filesystem::path filePath = m_rootDir / file->filename();
- Name deviceName(file->device_name().c_str(), file->device_name().size());
+ ///////////////////
+ // now the magic //
+ ///////////////////
- try {
- if (filesystem::exists(filePath) && filesystem::last_write_time(filePath) == file->mtime() &&
+ fs::path filePath = m_rootDir / file->filename();
+ Name deviceName(
+ Block((const unsigned char*)file->device_name().c_str(), file->device_name().size()));
+
+ _LOG_DEBUG("filePath" << filePath << " deviceName " << deviceName);
+
+ try {
+ if (fs::exists(filePath) && fs::last_write_time(filePath) == file->mtime()
#if BOOST_VERSION >= 104900
- filesystem::status(filePath).permissions() == static_cast<filesystem::perms>(file->mode()) &&
+ &&
+ fs::status(filePath).permissions() == static_cast<fs::perms>(file->mode())
#endif
- *Hash::FromFileContent(filePath) == hash) {
- m_ccnx->publishData(interest, "OK: File already exists", 1);
+ ) {
+ fs::ifstream input(filePath, std::ios::in | std::ios::binary);
+ if (*util::Sha256(input).computeDigest() == hash) {
+ shared_ptr<Data> data = make_shared<Data>();
+ data->setName(interest);
+ data->setFreshnessPeriod(m_freshness);
+ std::string msg = "OK: File already exists";
+ data->setContent(reinterpret_cast<const uint8_t*>(msg.c_str()), msg.size());
+ m_keyChain.sign(*data);
+ m_face.put(*data);
_LOG_DEBUG("Asking to assemble a file, but file already exists on a filesystem");
return;
}
}
- catch (filesystem::filesystem_error& error) {
- m_ccnx->publishData(interest, "FAIL: File operation failed", 1);
- _LOG_ERROR("File operations failed on [" << filePath << "] (ignoring)");
- }
-
- _LOG_TRACE("Restoring file [" << filePath << "]");
- if (m_objectManager.objectsToLocalFile(deviceName, hash, filePath)) {
- last_write_time(filePath, file->mtime());
-#if BOOST_VERSION >= 104900
- permissions(filePath, static_cast<filesystem::perms>(file->mode()));
-#endif
- m_ccnx->publishData(interest, "OK", 1);
- }
- else {
- m_ccnx->publishData(interest, "FAIL: Unknown error while restoring file", 1);
- }
}
- catch (Ccnx::NameException& ne) {
- // ignore any unexpected interests and errors
- _LOG_ERROR(*boost::get_error_info<Ccnx::error_info_str>(ne));
+ catch (fs::filesystem_error& error) {
+ shared_ptr<Data> data = make_shared<Data>();
+ data->setName(interest);
+ data->setFreshnessPeriod(m_freshness);
+ std::string msg = "FAIL: File operation failed";
+ data->setContent(reinterpret_cast<const uint8_t*>(msg.c_str()), msg.size());
+ m_keyChain.sign(*data);
+ m_face.put(*data);
+ _LOG_ERROR("File operations failed on [" << filePath << "](ignoring)");
+ }
+
+ _LOG_TRACE("Restoring file [" << filePath << "]"
+ << " deviceName "
+ << deviceName);
+ if (m_objectManager.objectsToLocalFile(deviceName, hash, filePath)) {
+ last_write_time(filePath, file->mtime());
+#if BOOST_VERSION >= 104900
+ permissions(filePath, static_cast<fs::perms>(file->mode()));
+#endif
+ shared_ptr<Data> data = make_shared<Data>();
+ data->setName(interest);
+ data->setFreshnessPeriod(m_freshness);
+ std::string msg = "OK";
+ data->setContent(reinterpret_cast<const uint8_t*>(msg.c_str()), msg.size());
+ m_keyChain.sign(*data);
+ m_face.put(*data);
+ _LOG_DEBUG("Restoring file successfully!");
+ }
+ else {
+ shared_ptr<Data> data = make_shared<Data>();
+ data->setName(interest);
+ data->setFreshnessPeriod(m_freshness);
+ std::string msg = "FAIL: Unknown error while restoring file";
+ data->setContent(reinterpret_cast<const uint8_t*>(msg.c_str()), msg.size());
+ m_keyChain.sign(*data);
+ m_face.put(*data);
}
}
+
+} // namespace chronoshare
+} // namespace ndn
diff --git a/src/state-server.hpp b/src/state-server.hpp
index 72dd275..876cebc 100644
--- a/src/state-server.hpp
+++ b/src/state-server.hpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
- * Copyright (c) 2013-2016, Regents of the University of California.
+ * Copyright (c) 2013-2017, Regents of the University of California.
*
* This file is part of ChronoShare, a decentralized file sharing application over NDN.
*
@@ -21,13 +21,12 @@
#ifndef STATE_SERVER_H
#define STATE_SERVER_H
+#include "core/chronoshare-common.hpp"
+
#include "action-log.hpp"
-#include "ccnx-wrapper.hpp"
-#include "executor.hpp"
#include "object-db.hpp"
#include "object-manager.hpp"
-#include <boost/thread/locks.hpp>
-#include <boost/thread/shared_mutex.hpp>
+
#include <map>
#include <set>
@@ -38,6 +37,9 @@
#error Please define JSON_SPIRIT_VALUE_ENABLED for the Value type to be enabled
#endif
+namespace ndn {
+namespace chronoshare {
+
/**
* @brief Class serving state information from ChronoShare
*
@@ -45,30 +47,33 @@
*
* Information available:
*
- * For now serving only locally (using <PREFIX> = /localhost/<user's-device-name>/"chronoshare"/<FOLDER>/"info")
+ * For now serving only locally(using <PREFIX> =
+ * ndn:/localhop/<user's-device-name>/"chronoshare"/<FOLDER>/"info")
*
- * - state: get list of SyncNodes, their sequence numbers, and forwarding hint (almost the same as RECOVERY interest)
+ * - state: get list of SyncNodes, their sequence numbers, and forwarding hint(almost the same as
+ * RECOVERY interest)
*
- * <PREFIX_INFO>/"state" (@todo: authentification code or authentication code should in addition somewhere)
+ * <PREFIX_INFO>/"state" (@todo: authentification code or authentication code should in addition
+ * somewhere)
*
* - action
*
- * Get list of actions for a folder (for all files under this folder)
+ * Get list of actions for a folder(for all files under this folder)
*
- * <PREFIX_INFO>/"actions"/"folder"/<offset> (all actions)
+ * <PREFIX_INFO>/"actions"/"folder"/<offset> (all actions)
* or
* <PREFIX_INFO>/"actions"/"folder"/<one-component-relative-file-name>/<offset>
*
- * Actions are ordered in decreasing order (latest will go first).
+ * Actions are ordered in decreasing order(latest will go first).
*
* Each data packet contains up to 100 actions.
*
- * TEMPORARILY LIMIT IS REDUCED TO 10 ! (for debug purposes)
- * (may be even not temporarily...)
+ * TEMPORARILY LIMIT IS REDUCED TO 10 !(for debug purposes)
+ * (may be even not temporarily...)
*
* If more items are available, application data will specify URL for the next packet
*
- * Format of returned data (JSON):
+ * Format of returned data(JSON):
* {
* "actions": [
* {
@@ -86,7 +91,7 @@
* "hash": "<FILE-HASH>",
* "timestamp": "<FILE-TIMESTAMP>",
* "chmod": "<FILE-MODE>",
- * "segNum": "<NUMBER-OF-SEGMENTS (~file size)>"
+ * "segNum": "<NUMBER-OF-SEGMENTS(~file size)>"
* },
*
* // if parent_device_name is set
@@ -103,17 +108,17 @@
*
* - file
*
- * <PREFIX_INFO>/"files"/"folder"/<offset> (full filestate)
+ * <PREFIX_INFO>/"files"/"folder"/<offset> (full filestate)
* or
* <PREFIX_INFO>/"files"/"folder"/<one-component-relative-folder-name>/<offset>
*
* 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
*
- * TEMPORARILY LIMIT IS REDUCED TO 10 ! (for debug purposes)
- * (may be even not temporarily...)
+ * TEMPORARILY LIMIT IS REDUCED TO 10 !(for debug purposes)
+ * (may be even not temporarily...)
*
- * Format of returned data (JSON):
+ * Format of returned data(JSON):
* {
* "files": [
* {
@@ -126,7 +131,7 @@
* "hash": "<FILE-HASH>",
* "timestamp": "<FILE-TIMESTAMP>",
* "chmod": "<FILE-MODE>",
- * "segNum": "<NUMBER-OF-SEGMENTS (~file size)>"
+ * "segNum": "<NUMBER-OF-SEGMENTS(~file size)>"
* }, ...,
* ]
*
@@ -136,7 +141,8 @@
*
* Commands available:
*
- * For now serving only locally (using <PREFIX_CMD> = /localhost/<user's-device-name>/"chronoshare"/<FOLDER>/"cmd")
+ * For now serving only locally(using <PREFIX_CMD> =
+ * ndn:/localhop/<user's-device-name>/"chronoshare"/<FOLDER>/"cmd")
*
* - restore version of the file
*
@@ -145,39 +151,39 @@
* <PREFIX_CMD>/"restore"/"file"/<one-component-relative-file-name>/<version>/<file-hash>
*
* - clean state log
- * (this may not need to be here, if we implement periodic cleaning)
- * - ? flatten action log (should be supported eventually, but not supported now)
+ * (this may not need to be here, if we implement periodic cleaning)
+ * - ? flatten action log(should be supported eventually, but not supported now)
*/
class StateServer
{
public:
- StateServer(Ccnx::CcnxWrapperPtr ccnx, ActionLogPtr actionLog,
- const boost::filesystem::path& rootDir, const Ccnx::Name& userName,
- const std::string& sharedFolderName, const std::string& appName,
- ObjectManager& objectManager, int freshness = -1);
+ StateServer(Face& face, ActionLogPtr actionLog, const boost::filesystem::path& rootDir,
+ const Name& userName, const std::string& sharedFolderName, const name::Component& appName,
+ ObjectManager& objectManager, KeyChain& keyChain,
+ time::milliseconds freshness = time::seconds(5));
~StateServer();
private:
void
- info_actions_folder(const Ccnx::Name& interest);
+ info_actions_folder(const InterestFilter&, const Interest&);
void
- info_actions_file(const Ccnx::Name& interest);
+ info_actions_file(const InterestFilter&, const Interest&);
void
- info_actions_fileOrFolder_Execute(const Ccnx::Name& interest, bool isFolder = true);
+ info_actions_fileOrFolder_Execute(const Name& interest, bool isFolder = true);
void
- info_files_folder(const Ccnx::Name& interest);
+ info_files_folder(const InterestFilter&, const Interest&);
void
- info_files_folder_Execute(const Ccnx::Name& interest);
+ info_files_folder_Execute(const Name& interest);
void
- cmd_restore_file(const Ccnx::Name& interest);
+ cmd_restore_file(const InterestFilter&, const Interest&);
void
- cmd_restore_file_Execute(const Ccnx::Name& interest);
+ cmd_restore_file_Execute(const Name& interest);
private:
void
@@ -187,27 +193,37 @@
deregisterPrefixes();
static void
- formatActionJson(json_spirit::Array& actions, const Ccnx::Name& name, sqlite3_int64 seq_no,
+ formatActionJson(json_spirit::Array& actions, const Name& name, sqlite3_int64 seq_no,
const ActionItem& action);
static void
formatFilestateJson(json_spirit::Array& files, const FileItem& file);
private:
- Ndnx::NdnxWrapperPtr m_ndnx;
+ Face& m_face;
ActionLogPtr m_actionLog;
ObjectManager& m_objectManager;
- Ndnx::Name m_PREFIX_INFO;
- Ndnx::Name m_PREFIX_CMD;
+ Name m_PREFIX_INFO;
+ Name m_PREFIX_CMD;
+
+ const RegisteredPrefixId* actionsFolderId;
+ const RegisteredPrefixId* actionsFileId;
+ const RegisteredPrefixId* filesFolderId;
+ const RegisteredPrefixId* restoreFileId;
boost::filesystem::path m_rootDir;
- int m_freshness;
+ time::milliseconds m_freshness;
- Executor m_executor;
-
- Ccnx::Name m_userName;
+ Name m_userName;
std::string m_sharedFolderName;
- std::string m_appName;
+ name::Component m_appName;
+ KeyChain& m_keyChain;
+
+ boost::asio::io_service& m_ioService;
};
+
+} // namespace chronoshare
+} // namespace ndn
+
#endif // CONTENT_SERVER_H
diff --git a/wscript b/wscript
index 878f27c..a3baf14 100644
--- a/wscript
+++ b/wscript
@@ -110,7 +110,8 @@
'src/object-*.cpp',
'src/fetch*.cpp',
'src/content-server.cpp',
- 'src/dispatcher.cpp'
+ 'src/dispatcher.cpp',
+ 'src/state-server.cpp'
]),
use='core-objects adhoc NDN_CXX BOOST TINYXML SQLITE3',
includes="src",