blob: b791e16f7eab228557124cc30791a33bdeda5fb4 [file] [log] [blame]
Alexander Afanasyevfa2f6622016-12-25 12:28:00 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2013-2016, Regents of the University of California.
Alexander Afanasyev026eaf32013-02-23 16:37:14 -08004 *
Alexander Afanasyevfa2f6622016-12-25 12:28:00 -08005 * This file is part of ChronoShare, a decentralized file sharing application over NDN.
Alexander Afanasyev026eaf32013-02-23 16:37:14 -08006 *
Alexander Afanasyevfa2f6622016-12-25 12:28:00 -08007 * ChronoShare is free software: you can redistribute it and/or modify it under the terms
8 * of the GNU General Public License as published by the Free Software Foundation, either
9 * version 3 of the License, or (at your option) any later version.
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080010 *
Alexander Afanasyevfa2f6622016-12-25 12:28:00 -080011 * ChronoShare is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU General Public License for more details.
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080014 *
Alexander Afanasyevfa2f6622016-12-25 12:28:00 -080015 * You should have received copies of the GNU General Public License along with
16 * ChronoShare, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * See AUTHORS.md for complete list of ChronoShare authors and contributors.
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080019 */
20
21#include "state-server.h"
22#include "logging.h"
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080023#include "periodic-task.h"
24#include "simple-interval-generator.h"
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080025#include "task.h"
Alexander Afanasyeve1c95042013-02-27 01:02:36 -080026#include <boost/date_time/posix_time/posix_time.hpp>
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080027#include <boost/lexical_cast.hpp>
28#include <boost/make_shared.hpp>
29#include <utility>
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080030
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080031INIT_LOGGER("StateServer");
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080032
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -070033using namespace Ndnx;
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080034using namespace std;
35using namespace boost;
36
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080037StateServer::StateServer(CcnxWrapperPtr ccnx, ActionLogPtr actionLog,
38 const boost::filesystem::path& rootDir, const Ccnx::Name& userName,
39 const std::string& sharedFolderName, const std::string& appName,
40 ObjectManager& objectManager, int freshness /* = -1*/)
41 : m_ccnx(ccnx)
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080042 , m_actionLog(actionLog)
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080043 , m_objectManager(objectManager)
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080044 , m_rootDir(rootDir)
45 , m_freshness(freshness)
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080046 , m_executor(1)
47 , m_userName(userName)
48 , m_sharedFolderName(sharedFolderName)
49 , m_appName(appName)
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080050{
51 // may be later /localhost should be replaced with /%C1.M.S.localhost
52
53 // <PREFIX_INFO> = /localhost/<user's-device-name>/"chronoshare"/"info"
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080054 m_PREFIX_INFO = Name("/localhost")(m_userName)("chronoshare")(m_sharedFolderName)("info");
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080055
56 // <PREFIX_CMD> = /localhost/<user's-device-name>/"chronoshare"/"cmd"
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080057 m_PREFIX_CMD = Name("/localhost")(m_userName)("chronoshare")(m_sharedFolderName)("cmd");
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080058
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080059 m_executor.start();
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080060
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080061 registerPrefixes();
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080062}
63
64StateServer::~StateServer()
65{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080066 m_executor.shutdown();
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080067
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080068 deregisterPrefixes();
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080069}
70
71void
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080072StateServer::registerPrefixes()
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080073{
74 // currently supporting limited number of command.
75 // will be extended to support all planned commands later
76
Alexander Afanasyev3c95c852013-03-01 18:58:50 -080077 // <PREFIX_INFO>/"actions"/"all"/<segment> get list of all actions
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080078 m_ccnx->setInterestFilter(Name(m_PREFIX_INFO)("actions")("folder"),
79 bind(&StateServer::info_actions_folder, this, _1));
80 m_ccnx->setInterestFilter(Name(m_PREFIX_INFO)("actions")("file"),
81 bind(&StateServer::info_actions_file, this, _1));
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080082
Alexander Afanasyev3c95c852013-03-01 18:58:50 -080083 // <PREFIX_INFO>/"filestate"/"all"/<segment>
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080084 m_ccnx->setInterestFilter(Name(m_PREFIX_INFO)("files")("folder"),
85 bind(&StateServer::info_files_folder, this, _1));
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080086
87 // <PREFIX_CMD>/"restore"/"file"/<one-component-relative-file-name>/<version>/<file-hash>
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080088 m_ccnx->setInterestFilter(Name(m_PREFIX_CMD)("restore")("file"),
89 bind(&StateServer::cmd_restore_file, this, _1));
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080090}
91
92void
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080093StateServer::deregisterPrefixes()
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080094{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080095 m_ccnx->clearInterestFilter(Name(m_PREFIX_INFO)("actions")("folder"));
96 m_ccnx->clearInterestFilter(Name(m_PREFIX_INFO)("actions")("file"));
97 m_ccnx->clearInterestFilter(Name(m_PREFIX_INFO)("files")("folder"));
98 m_ccnx->clearInterestFilter(Name(m_PREFIX_CMD)("restore")("file"));
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080099}
100
Alexander Afanasyeve1c95042013-02-27 01:02:36 -0800101void
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800102StateServer::formatActionJson(json_spirit::Array& actions, const Ccnx::Name& name,
103 sqlite3_int64 seq_no, const ActionItem& action)
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800104{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800105 /*
Alexander Afanasyeve1c95042013-02-27 01:02:36 -0800106 * {
107 * "id": {
108 * "userName": "<NDN-NAME-OF-THE-USER>",
109 * "seqNo": "<SEQ_NO_OF_THE_ACTION>"
110 * },
111 * "timestamp": "<ACTION-TIMESTAMP>",
112 * "filename": "<FILENAME>",
113 *
114 * "action": "UPDATE | DELETE",
115 *
116 * // only if update
117 * "update": {
118 * "hash": "<FILE-HASH>",
119 * "timestamp": "<FILE-TIMESTAMP>",
120 * "chmod": "<FILE-MODE>",
121 * "segNum": "<NUMBER-OF-SEGMENTS (~file size)>"
122 * },
123 *
124 * // if parent_device_name is set
125 * "parentId": {
126 * "userName": "<NDN-NAME-OF-THE-USER>",
127 * "seqNo": "<SEQ_NO_OF_THE_ACTION>"
128 * }
129 * }
130 */
131
132 using namespace json_spirit;
133 using namespace boost::posix_time;
134
135 Object json;
136 Object id;
137
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800138 id.push_back(Pair("userName", boost::lexical_cast<string>(name)));
139 id.push_back(Pair("seqNo", static_cast<int64_t>(seq_no)));
Alexander Afanasyeve1c95042013-02-27 01:02:36 -0800140
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800141 json.push_back(Pair("id", id));
Alexander Afanasyeve1c95042013-02-27 01:02:36 -0800142
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800143 json.push_back(Pair("timestamp", to_iso_extended_string(from_time_t(action.timestamp()))));
144 json.push_back(Pair("filename", action.filename()));
145 json.push_back(Pair("version", action.version()));
146 json.push_back(Pair("action", (action.action() == 0) ? "UPDATE" : "DELETE"));
Alexander Afanasyeve1c95042013-02-27 01:02:36 -0800147
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800148 if (action.action() == 0) {
149 Object update;
150 update.push_back(Pair("hash", boost::lexical_cast<string>(
151 Hash(action.file_hash().c_str(), action.file_hash().size()))));
152 update.push_back(Pair("timestamp", to_iso_extended_string(from_time_t(action.mtime()))));
Alexander Afanasyeve1c95042013-02-27 01:02:36 -0800153
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800154 ostringstream chmod;
155 chmod << setbase(8) << setfill('0') << setw(4) << action.mode();
156 update.push_back(Pair("chmod", chmod.str()));
Alexander Afanasyeve1c95042013-02-27 01:02:36 -0800157
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800158 update.push_back(Pair("segNum", action.seg_num()));
159 json.push_back(Pair("update", update));
160 }
Alexander Afanasyeve1c95042013-02-27 01:02:36 -0800161
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800162 if (action.has_parent_device_name()) {
163 Object parentId;
164 Ccnx::Name parent_device_name(action.parent_device_name().c_str(),
165 action.parent_device_name().size());
166 id.push_back(Pair("userName", boost::lexical_cast<string>(parent_device_name)));
167 id.push_back(Pair("seqNo", action.parent_seq_no()));
Alexander Afanasyeve1c95042013-02-27 01:02:36 -0800168
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800169 json.push_back(Pair("parentId", parentId));
170 }
Alexander Afanasyeve1c95042013-02-27 01:02:36 -0800171
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800172 actions.push_back(json);
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800173}
174
175void
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800176StateServer::info_actions_folder(const Name& interest)
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800177{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800178 if (interest.size() - m_PREFIX_INFO.size() != 3 && interest.size() - m_PREFIX_INFO.size() != 4) {
179 _LOG_DEBUG("Invalid interest: " << interest);
180 return;
181 }
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800182
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800183 _LOG_DEBUG(">> info_actions_folder: " << interest);
184 m_executor.execute(bind(&StateServer::info_actions_fileOrFolder_Execute, this, interest, true));
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800185}
186
187void
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800188StateServer::info_actions_file(const Name& interest)
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800189{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800190 if (interest.size() - m_PREFIX_INFO.size() != 3 && interest.size() - m_PREFIX_INFO.size() != 4) {
191 _LOG_DEBUG("Invalid interest: " << interest);
192 return;
193 }
Alexander Afanasyev39dbc4b2013-03-01 10:39:23 -0800194
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800195 _LOG_DEBUG(">> info_actions_file: " << interest);
196 m_executor.execute(bind(&StateServer::info_actions_fileOrFolder_Execute, this, interest, false));
Alexander Afanasyev39dbc4b2013-03-01 10:39:23 -0800197}
198
199
200void
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800201StateServer::info_actions_fileOrFolder_Execute(const Ccnx::Name& interest, bool isFolder /* = true*/)
Alexander Afanasyev39dbc4b2013-03-01 10:39:23 -0800202{
Alexander Afanasyev3c95c852013-03-01 18:58:50 -0800203 // <PREFIX_INFO>/"actions"/"folder|file"/<folder|file>/<offset> get list of all actions
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800204
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800205 try {
206 int offset = interest.getCompFromBackAsInt(0);
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800207
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800208 /// @todo !!! add security checking
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800209
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800210 string fileOrFolderName;
211 if (interest.size() - m_PREFIX_INFO.size() == 4)
212 fileOrFolderName = interest.getCompFromBackAsString(1);
213 else // == 3
214 fileOrFolderName = "";
215 /*
Alexander Afanasyeve1c95042013-02-27 01:02:36 -0800216 * {
217 * "actions": [
218 * ...
219 * ],
220 *
221 * // only if there are more actions available
222 * "more": "<NDN-NAME-OF-NEXT-SEGMENT-OF-ACTION>"
223 * }
224 */
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800225
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800226 using namespace json_spirit;
227 Object json;
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800228
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800229 Array actions;
230 bool more;
231 if (isFolder) {
232 more =
233 m_actionLog->LookupActionsInFolderRecursively(boost::bind(StateServer::formatActionJson,
234 boost::ref(actions), _1, _2, _3),
235 fileOrFolderName, offset * 10, 10);
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800236 }
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800237 else {
238 more = m_actionLog->LookupActionsForFile(boost::bind(StateServer::formatActionJson,
239 boost::ref(actions), _1, _2, _3),
240 fileOrFolderName, offset * 10, 10);
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800241 }
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800242
243 json.push_back(Pair("actions", actions));
244
245 if (more) {
246 json.push_back(Pair("more", lexical_cast<string>(offset + 1)));
247 // Ccnx::Name more = Name (interest.getPartialName (0, interest.size () - 1))(offset + 1);
248 // json.push_back (Pair ("more", lexical_cast<string> (more)));
249 }
250
251 ostringstream os;
252 write_stream(Value(json), os, pretty_print | raw_utf8);
253 m_ccnx->publishData(interest, os.str(), 1);
254 }
255 catch (Ccnx::NameException& ne) {
256 // ignore any unexpected interests and errors
257 _LOG_ERROR(*boost::get_error_info<Ccnx::error_info_str>(ne));
258 }
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800259}
260
Alexander Afanasyev94240b52013-02-27 11:57:29 -0800261void
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800262StateServer::formatFilestateJson(json_spirit::Array& files, const FileItem& file)
Alexander Afanasyev94240b52013-02-27 11:57:29 -0800263{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800264 /**
Alexander Afanasyev94240b52013-02-27 11:57:29 -0800265 * {
266 * "filestate": [
267 * {
268 * "filename": "<FILENAME>",
269 * "owner": {
270 * "userName": "<NDN-NAME-OF-THE-USER>",
271 * "seqNo": "<SEQ_NO_OF_THE_ACTION>"
272 * },
273 *
274 * "hash": "<FILE-HASH>",
275 * "timestamp": "<FILE-TIMESTAMP>",
276 * "chmod": "<FILE-MODE>",
277 * "segNum": "<NUMBER-OF-SEGMENTS (~file size)>"
278 * }, ...,
279 * ]
280 *
281 * // only if there are more actions available
282 * "more": "<NDN-NAME-OF-NEXT-SEGMENT-OF-FILESTATE>"
283 * }
284 */
285 using namespace json_spirit;
286 using namespace boost::posix_time;
287
288 Object json;
289
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800290 json.push_back(Pair("filename", file.filename()));
291 json.push_back(Pair("version", file.version()));
Alexander Afanasyev94240b52013-02-27 11:57:29 -0800292 {
293 Object owner;
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800294 Ccnx::Name device_name(file.device_name().c_str(), file.device_name().size());
295 owner.push_back(Pair("userName", boost::lexical_cast<string>(device_name)));
296 owner.push_back(Pair("seqNo", file.seq_no()));
Alexander Afanasyev94240b52013-02-27 11:57:29 -0800297
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800298 json.push_back(Pair("owner", owner));
Alexander Afanasyev94240b52013-02-27 11:57:29 -0800299 }
300
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800301 json.push_back(Pair("hash", boost::lexical_cast<string>(
302 Hash(file.file_hash().c_str(), file.file_hash().size()))));
303 json.push_back(Pair("timestamp", to_iso_extended_string(from_time_t(file.mtime()))));
Alexander Afanasyev94240b52013-02-27 11:57:29 -0800304
305 ostringstream chmod;
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800306 chmod << setbase(8) << setfill('0') << setw(4) << file.mode();
307 json.push_back(Pair("chmod", chmod.str()));
Alexander Afanasyev94240b52013-02-27 11:57:29 -0800308
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800309 json.push_back(Pair("segNum", file.seg_num()));
Alexander Afanasyev94240b52013-02-27 11:57:29 -0800310
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800311 files.push_back(json);
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800312}
313
314void
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800315debugFileState(const FileItem& file)
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800316{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800317 std::cout << file.filename() << std::endl;
318}
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800319
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800320void
321StateServer::info_files_folder(const Ccnx::Name& interest)
322{
323 if (interest.size() - m_PREFIX_INFO.size() != 3 && interest.size() - m_PREFIX_INFO.size() != 4) {
324 _LOG_DEBUG("Invalid interest: " << interest << ", " << interest.size() - m_PREFIX_INFO.size());
325 return;
326 }
327
328 _LOG_DEBUG(">> info_files_folder: " << interest);
329 m_executor.execute(bind(&StateServer::info_files_folder_Execute, this, interest));
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800330}
331
332
333void
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800334StateServer::info_files_folder_Execute(const Ccnx::Name& interest)
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800335{
Alexander Afanasyev3c95c852013-03-01 18:58:50 -0800336 // <PREFIX_INFO>/"filestate"/"folder"/<one-component-relative-folder-name>/<offset>
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800337 try {
338 int offset = interest.getCompFromBackAsInt(0);
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800339
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800340 // /// @todo !!! add security checking
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800341
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800342 string folder;
343 if (interest.size() - m_PREFIX_INFO.size() == 4)
344 folder = interest.getCompFromBackAsString(1);
345 else // == 3
346 folder = "";
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800347
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800348 /*
Alexander Afanasyev94240b52013-02-27 11:57:29 -0800349 * {
350 * "files": [
351 * ...
352 * ],
353 *
354 * // only if there are more actions available
355 * "more": "<NDN-NAME-OF-NEXT-SEGMENT-OF-ACTION>"
356 * }
357 */
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800358
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800359 using namespace json_spirit;
360 Object json;
Alexander Afanasyev94240b52013-02-27 11:57:29 -0800361
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800362 Array files;
363 bool more = m_actionLog->GetFileState()
364 ->LookupFilesInFolderRecursively(boost::bind(StateServer::formatFilestateJson,
365 boost::ref(files), _1),
366 folder, offset * 10, 10);
Alexander Afanasyev94240b52013-02-27 11:57:29 -0800367
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800368 json.push_back(Pair("files", files));
Alexander Afanasyev94240b52013-02-27 11:57:29 -0800369
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800370 if (more) {
371 json.push_back(Pair("more", lexical_cast<string>(offset + 1)));
372 // Ccnx::Name more = Name (interest.getPartialName (0, interest.size () - 1))(offset + 1);
373 // json.push_back (Pair ("more", lexical_cast<string> (more)));
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800374 }
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800375
376 ostringstream os;
377 write_stream(Value(json), os, pretty_print | raw_utf8);
378 m_ccnx->publishData(interest, os.str(), 1);
379 }
380 catch (Ccnx::NameException& ne) {
381 // ignore any unexpected interests and errors
382 _LOG_ERROR(*boost::get_error_info<Ccnx::error_info_str>(ne));
383 }
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800384}
385
386
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800387void
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800388StateServer::cmd_restore_file(const Ccnx::Name& interest)
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800389{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800390 if (interest.size() - m_PREFIX_CMD.size() != 4 && interest.size() - m_PREFIX_CMD.size() != 5) {
391 _LOG_DEBUG("Invalid interest: " << interest);
392 return;
393 }
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800394
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800395 _LOG_DEBUG(">> cmd_restore_file: " << interest);
396 m_executor.execute(bind(&StateServer::cmd_restore_file_Execute, this, interest));
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800397}
398
399void
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800400StateServer::cmd_restore_file_Execute(const Ccnx::Name& interest)
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800401{
402 // <PREFIX_CMD>/"restore"/"file"/<one-component-relative-file-name>/<version>/<file-hash>
403
404 /// @todo !!! add security checking
405
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800406 try {
407 FileItemPtr file;
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800408
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800409 if (interest.size() - m_PREFIX_CMD.size() == 5) {
410 Hash hash(head(interest.getCompFromBack(0)), interest.getCompFromBack(0).size());
411 int64_t version = interest.getCompFromBackAsInt(1);
412 string filename =
413 interest.getCompFromBackAsString(2); // should be safe even with full relative path
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800414
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800415 file = m_actionLog->LookupAction(filename, version, hash);
416 if (!file) {
417 _LOG_ERROR("Requested file is not found: [" << filename << "] version [" << version
418 << "] hash ["
419 << hash.shortHash()
420 << "]");
421 }
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800422 }
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800423 else {
424 int64_t version = interest.getCompFromBackAsInt(0);
425 string filename =
426 interest.getCompFromBackAsString(1); // should be safe even with full relative path
427
428 file = m_actionLog->LookupAction(filename, version, Hash(0, 0));
429 if (!file) {
430 _LOG_ERROR("Requested file is not found: [" << filename << "] version [" << version << "]");
431 }
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800432 }
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800433
434 if (!file) {
435 m_ccnx->publishData(interest, "FAIL: Requested file is not found", 1);
436 return;
437 }
438
439 Hash hash = Hash(file->file_hash().c_str(), file->file_hash().size());
440
441 ///////////////////
442 // now the magic //
443 ///////////////////
444
445 boost::filesystem::path filePath = m_rootDir / file->filename();
446 Name deviceName(file->device_name().c_str(), file->device_name().size());
447
448 try {
449 if (filesystem::exists(filePath) && filesystem::last_write_time(filePath) == file->mtime() &&
450#if BOOST_VERSION >= 104900
451 filesystem::status(filePath).permissions() == static_cast<filesystem::perms>(file->mode()) &&
452#endif
453 *Hash::FromFileContent(filePath) == hash) {
454 m_ccnx->publishData(interest, "OK: File already exists", 1);
455 _LOG_DEBUG("Asking to assemble a file, but file already exists on a filesystem");
456 return;
457 }
458 }
459 catch (filesystem::filesystem_error& error) {
460 m_ccnx->publishData(interest, "FAIL: File operation failed", 1);
461 _LOG_ERROR("File operations failed on [" << filePath << "] (ignoring)");
462 }
463
464 _LOG_TRACE("Restoring file [" << filePath << "]");
465 if (m_objectManager.objectsToLocalFile(deviceName, hash, filePath)) {
466 last_write_time(filePath, file->mtime());
467#if BOOST_VERSION >= 104900
468 permissions(filePath, static_cast<filesystem::perms>(file->mode()));
469#endif
470 m_ccnx->publishData(interest, "OK", 1);
471 }
472 else {
473 m_ccnx->publishData(interest, "FAIL: Unknown error while restoring file", 1);
474 }
475 }
476 catch (Ccnx::NameException& ne) {
477 // ignore any unexpected interests and errors
478 _LOG_ERROR(*boost::get_error_info<Ccnx::error_info_str>(ne));
479 }
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800480}