blob: ca18016413a76aff1bb570d60ac4edf700cafcb1 [file] [log] [blame]
Alexander Afanasyevfa2f6622016-12-25 12:28:00 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Alexander Afanasyeva9369b42017-01-11 11:58:00 -08003 * Copyright (c) 2013-2017, 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
Lijing Wangb95c6a52016-12-25 14:45:17 -080021#include "state-server.hpp"
22#include "core/logging.hpp"
23
24#include <ndn-cxx/util/digest.hpp>
25#include <ndn-cxx/util/string-helper.hpp>
26
27#include <boost/asio/io_service.hpp>
Alexander Afanasyeve1c95042013-02-27 01:02:36 -080028#include <boost/date_time/posix_time/posix_time.hpp>
Lijing Wangb95c6a52016-12-25 14:45:17 -080029#include <boost/filesystem/fstream.hpp>
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080030#include <boost/lexical_cast.hpp>
Lijing Wangb95c6a52016-12-25 14:45:17 -080031
32namespace ndn {
33namespace chronoshare {
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080034
Alexander Afanasyev1cf5c432017-01-13 23:22:15 -080035_LOG_INIT(StateServer);
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080036
Lijing Wangb95c6a52016-12-25 14:45:17 -080037namespace fs = boost::filesystem;
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080038
Lijing Wangb95c6a52016-12-25 14:45:17 -080039StateServer::StateServer(Face& face, ActionLogPtr actionLog, const fs::path& rootDir,
40 const Name& userName, const std::string& sharedFolderName,
41 const name::Component& appName, ObjectManager& objectManager,
42 KeyChain& keyChain, time::milliseconds freshness)
43 : m_face(face)
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080044 , m_actionLog(actionLog)
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080045 , m_objectManager(objectManager)
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080046 , m_rootDir(rootDir)
47 , m_freshness(freshness)
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080048 , m_userName(userName)
49 , m_sharedFolderName(sharedFolderName)
50 , m_appName(appName)
Lijing Wangb95c6a52016-12-25 14:45:17 -080051 , m_keyChain(keyChain)
52 , m_ioService(m_face.getIoService())
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080053{
Lijing Wangb95c6a52016-12-25 14:45:17 -080054 // may be later /localhop should be replaced with /%C1.M.S.localhost
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080055
Lijing Wangb95c6a52016-12-25 14:45:17 -080056 // <PREFIX_INFO> = /localhop/<user's-device-name>/"chronoshare"/"info"
57 m_PREFIX_INFO = Name("/localhop");
58 m_PREFIX_INFO.append(m_userName).append(m_appName).append(m_sharedFolderName).append("info");
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080059
Lijing Wangb95c6a52016-12-25 14:45:17 -080060 // <PREFIX_CMD> = /localhop/<user's-device-name>/"chronoshare"/"cmd"
61 m_PREFIX_CMD = Name("/localhop");
62 m_PREFIX_CMD.append(m_userName).append(m_appName).append(m_sharedFolderName).append("cmd");
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080063
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080064 registerPrefixes();
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080065}
66
67StateServer::~StateServer()
68{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080069 deregisterPrefixes();
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080070}
71
72void
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080073StateServer::registerPrefixes()
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080074{
75 // currently supporting limited number of command.
76 // will be extended to support all planned commands later
77
Alexander Afanasyev3c95c852013-03-01 18:58:50 -080078 // <PREFIX_INFO>/"actions"/"all"/<segment> get list of all actions
Lijing Wangb95c6a52016-12-25 14:45:17 -080079 Name actionsFolder = Name(m_PREFIX_INFO);
80 actionsFolder.append("actions").append("folder");
81 actionsFolderId =
82 m_face.setInterestFilter(InterestFilter(actionsFolder),
83 bind(&StateServer::info_actions_folder, this, _1, _2),
84 RegisterPrefixSuccessCallback(), RegisterPrefixFailureCallback());
85
86 _LOG_DEBUG("Register Prefix: " << actionsFolder);
87
88 Name actionsFile = Name(m_PREFIX_INFO);
89 actionsFile.append("actions").append("file");
90 actionsFileId =
91 m_face.setInterestFilter(InterestFilter(actionsFile),
92 bind(&StateServer::info_actions_file, this, _1, _2),
93 RegisterPrefixSuccessCallback(), RegisterPrefixFailureCallback());
94
95 _LOG_DEBUG("Register Prefix: " << actionsFile);
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080096
Alexander Afanasyev3c95c852013-03-01 18:58:50 -080097 // <PREFIX_INFO>/"filestate"/"all"/<segment>
Lijing Wangb95c6a52016-12-25 14:45:17 -080098 Name filesFolder = Name(m_PREFIX_INFO);
99 filesFolder.append("files").append("folder");
100 filesFolderId =
101 m_face.setInterestFilter(InterestFilter(filesFolder),
102 bind(&StateServer::info_files_folder, this, _1, _2),
103 RegisterPrefixSuccessCallback(), RegisterPrefixFailureCallback());
104
105 _LOG_DEBUG("Register Prefix: " << filesFolder);
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800106
107 // <PREFIX_CMD>/"restore"/"file"/<one-component-relative-file-name>/<version>/<file-hash>
Lijing Wangb95c6a52016-12-25 14:45:17 -0800108 Name restoreFile = Name(m_PREFIX_CMD);
109 restoreFile.append("restore").append("file");
110 restoreFileId =
111 m_face.setInterestFilter(InterestFilter(restoreFile),
112 bind(&StateServer::cmd_restore_file, this, _1, _2),
113 RegisterPrefixSuccessCallback(), RegisterPrefixFailureCallback());
114
115 _LOG_DEBUG("Register Prefix: " << restoreFile);
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800116}
117
118void
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800119StateServer::deregisterPrefixes()
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800120{
Lijing Wangb95c6a52016-12-25 14:45:17 -0800121 m_face.unsetInterestFilter(actionsFolderId);
122 m_face.unsetInterestFilter(actionsFileId);
123 m_face.unsetInterestFilter(filesFolderId);
124 m_face.unsetInterestFilter(restoreFileId);
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800125}
126
Alexander Afanasyeve1c95042013-02-27 01:02:36 -0800127void
Lijing Wangb95c6a52016-12-25 14:45:17 -0800128StateServer::formatActionJson(json_spirit::Array& actions, const Name& name, sqlite3_int64 seq_no,
129 const ActionItem& action)
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800130{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800131 /*
Lijing Wangb95c6a52016-12-25 14:45:17 -0800132 * {
133 * "id": {
134 * "userName": "<NDN-NAME-OF-THE-USER>",
135 * "seqNo": "<SEQ_NO_OF_THE_ACTION>"
136 * },
137 * "timestamp": "<ACTION-TIMESTAMP>",
138 * "filename": "<FILENAME>",
139 *
140 * "action": "UPDATE | DELETE",
141 *
142 * // only if update
143 * "update": {
144 * "hash": "<FILE-HASH>",
145 * "timestamp": "<FILE-TIMESTAMP>",
146 * "chmod": "<FILE-MODE>",
147 * "segNum": "<NUMBER-OF-SEGMENTS(~file size)>"
148 * },
149 *
150 * // if parent_device_name is set
151 * "parentId": {
152 * "userName": "<NDN-NAME-OF-THE-USER>",
153 * "seqNo": "<SEQ_NO_OF_THE_ACTION>"
154 * }
155 * }
156 */
Alexander Afanasyeve1c95042013-02-27 01:02:36 -0800157
158 using namespace json_spirit;
159 using namespace boost::posix_time;
160
161 Object json;
162 Object id;
163
Lijing Wangb95c6a52016-12-25 14:45:17 -0800164 id.push_back(Pair("userName", boost::lexical_cast<std::string>(name)));
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800165 id.push_back(Pair("seqNo", static_cast<int64_t>(seq_no)));
Alexander Afanasyeve1c95042013-02-27 01:02:36 -0800166
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800167 json.push_back(Pair("id", id));
Alexander Afanasyeve1c95042013-02-27 01:02:36 -0800168
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800169 json.push_back(Pair("timestamp", to_iso_extended_string(from_time_t(action.timestamp()))));
170 json.push_back(Pair("filename", action.filename()));
171 json.push_back(Pair("version", action.version()));
172 json.push_back(Pair("action", (action.action() == 0) ? "UPDATE" : "DELETE"));
Alexander Afanasyeve1c95042013-02-27 01:02:36 -0800173
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800174 if (action.action() == 0) {
175 Object update;
Lijing Wangb95c6a52016-12-25 14:45:17 -0800176 const Buffer hash(action.file_hash().c_str(), action.file_hash().size());
177 update.push_back(Pair("hash", toHex(hash)));
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800178 update.push_back(Pair("timestamp", to_iso_extended_string(from_time_t(action.mtime()))));
Alexander Afanasyeve1c95042013-02-27 01:02:36 -0800179
Lijing Wangb95c6a52016-12-25 14:45:17 -0800180 std::ostringstream chmod;
181 chmod << std::setbase(8) << std::setfill('0') << std::setw(4) << action.mode();
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800182 update.push_back(Pair("chmod", chmod.str()));
Alexander Afanasyeve1c95042013-02-27 01:02:36 -0800183
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800184 update.push_back(Pair("segNum", action.seg_num()));
185 json.push_back(Pair("update", update));
186 }
Alexander Afanasyeve1c95042013-02-27 01:02:36 -0800187
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800188 if (action.has_parent_device_name()) {
189 Object parentId;
Lijing Wangb95c6a52016-12-25 14:45:17 -0800190 Name parent_device_name(action.parent_device_name());
191 id.push_back(Pair("userName", boost::lexical_cast<std::string>(parent_device_name)));
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800192 id.push_back(Pair("seqNo", action.parent_seq_no()));
Alexander Afanasyeve1c95042013-02-27 01:02:36 -0800193
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800194 json.push_back(Pair("parentId", parentId));
195 }
Alexander Afanasyeve1c95042013-02-27 01:02:36 -0800196
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800197 actions.push_back(json);
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800198}
199
200void
Lijing Wangb95c6a52016-12-25 14:45:17 -0800201StateServer::info_actions_folder(const InterestFilter& interesFilter, const Interest& interestTrue)
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800202{
Lijing Wangb95c6a52016-12-25 14:45:17 -0800203 Name interest = interestTrue.getName();
204 _LOG_DEBUG(">> info_actions_folder: " << interest);
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800205 if (interest.size() - m_PREFIX_INFO.size() != 3 && interest.size() - m_PREFIX_INFO.size() != 4) {
206 _LOG_DEBUG("Invalid interest: " << interest);
207 return;
208 }
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800209
Lijing Wangb95c6a52016-12-25 14:45:17 -0800210 m_ioService.post(bind(&StateServer::info_actions_fileOrFolder_Execute, this, interest, true));
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800211}
212
213void
Lijing Wangb95c6a52016-12-25 14:45:17 -0800214StateServer::info_actions_file(const InterestFilter& interesFilter, const Interest& interestTrue)
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800215{
Lijing Wangb95c6a52016-12-25 14:45:17 -0800216 Name interest = interestTrue.getName();
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800217 if (interest.size() - m_PREFIX_INFO.size() != 3 && interest.size() - m_PREFIX_INFO.size() != 4) {
218 _LOG_DEBUG("Invalid interest: " << interest);
219 return;
220 }
Alexander Afanasyev39dbc4b2013-03-01 10:39:23 -0800221
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800222 _LOG_DEBUG(">> info_actions_file: " << interest);
Lijing Wangb95c6a52016-12-25 14:45:17 -0800223 m_ioService.post(bind(&StateServer::info_actions_fileOrFolder_Execute, this, interest, false));
Alexander Afanasyev39dbc4b2013-03-01 10:39:23 -0800224}
225
Alexander Afanasyev39dbc4b2013-03-01 10:39:23 -0800226void
Lijing Wangb95c6a52016-12-25 14:45:17 -0800227StateServer::info_actions_fileOrFolder_Execute(const Name& interest, bool isFolder /* = true*/)
Alexander Afanasyev39dbc4b2013-03-01 10:39:23 -0800228{
Alexander Afanasyev3c95c852013-03-01 18:58:50 -0800229 // <PREFIX_INFO>/"actions"/"folder|file"/<folder|file>/<offset> get list of all actions
Lijing Wangb95c6a52016-12-25 14:45:17 -0800230 if (interest.size() < 1) {
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800231 // ignore any unexpected interests and errors
Lijing Wangb95c6a52016-12-25 14:45:17 -0800232 _LOG_ERROR("empty interest name");
233 return;
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800234 }
Lijing Wangb95c6a52016-12-25 14:45:17 -0800235 uint64_t offset = interest.get(-1).toNumber();
236
237 /// @todo !!! add security checking
238
239 std::string fileOrFolderName;
240 if (interest.size() - m_PREFIX_INFO.size() == 4)
241 fileOrFolderName = interest.get(-2).toUri();
242 else // == 3
243 fileOrFolderName = "";
244 /*
245 * {
246 * "actions": [
247 * ...
248 * ],
249 *
250 * // only if there are more actions available
251 * "more": "<NDN-NAME-OF-NEXT-SEGMENT-OF-ACTION>"
252 * }
253 */
254
255 _LOG_DEBUG("info_actions_fileOrFolder_Execute! offset: " << offset);
256 using namespace json_spirit;
257 Object json;
258
259 Array actions;
260 bool more;
261 if (isFolder) {
262 more = m_actionLog->LookupActionsInFolderRecursively(bind(StateServer::formatActionJson,
263 boost::ref(actions), _1, _2, _3),
264 fileOrFolderName, offset * 10, 10);
265 }
266 else {
267 more = m_actionLog->LookupActionsForFile(bind(StateServer::formatActionJson,
268 boost::ref(actions), _1, _2, _3),
269 fileOrFolderName, offset * 10, 10);
270 }
271
272 json.push_back(Pair("actions", actions));
273
274 if (more) {
275 json.push_back(Pair("more", boost::lexical_cast<std::string>(offset + 1)));
276 // Name more = Name(interest.getPartialName(0, interest.size() - 1))(offset + 1);
277 // json.push_back(Pair("more", boost::lexical_cast<std::string>(more)));
278 }
279
280 std::ostringstream os;
281 write_stream(Value(json), os, pretty_print | raw_utf8);
282
283 shared_ptr<Data> data = make_shared<Data>();
284 data->setName(interest);
285 data->setFreshnessPeriod(m_freshness);
286 data->setContent(reinterpret_cast<const uint8_t*>(os.str().c_str()), os.str().size());
287 m_keyChain.sign(*data);
288 m_face.put(*data);
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800289}
290
Alexander Afanasyev94240b52013-02-27 11:57:29 -0800291void
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800292StateServer::formatFilestateJson(json_spirit::Array& files, const FileItem& file)
Alexander Afanasyev94240b52013-02-27 11:57:29 -0800293{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800294 /**
Lijing Wangb95c6a52016-12-25 14:45:17 -0800295 * {
296 * "filestate": [
297 * {
298 * "filename": "<FILENAME>",
299 * "owner": {
300 * "userName": "<NDN-NAME-OF-THE-USER>",
301 * "seqNo": "<SEQ_NO_OF_THE_ACTION>"
302 * },
303 *
304 * "hash": "<FILE-HASH>",
305 * "timestamp": "<FILE-TIMESTAMP>",
306 * "chmod": "<FILE-MODE>",
307 * "segNum": "<NUMBER-OF-SEGMENTS(~file size)>"
308 * }, ...,
309 * ]
310 *
311 * // only if there are more actions available
312 * "more": "<NDN-NAME-OF-NEXT-SEGMENT-OF-FILESTATE>"
313 * }
314 */
Alexander Afanasyev94240b52013-02-27 11:57:29 -0800315 using namespace json_spirit;
316 using namespace boost::posix_time;
317
318 Object json;
319
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800320 json.push_back(Pair("filename", file.filename()));
321 json.push_back(Pair("version", file.version()));
Alexander Afanasyev94240b52013-02-27 11:57:29 -0800322 {
323 Object owner;
Yukai Tu40f184f2017-01-26 09:00:43 -0800324 Name device_name(Block(file.device_name().data(), file.device_name().size()));
325 owner.push_back(Pair("userName", device_name.toUri()));
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800326 owner.push_back(Pair("seqNo", file.seq_no()));
Alexander Afanasyev94240b52013-02-27 11:57:29 -0800327
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800328 json.push_back(Pair("owner", owner));
Alexander Afanasyev94240b52013-02-27 11:57:29 -0800329 }
330
Lijing Wangb95c6a52016-12-25 14:45:17 -0800331 json.push_back(Pair("hash", toHex(reinterpret_cast<const uint8_t*>(file.file_hash().data()),
332 file.file_hash().size())));
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800333 json.push_back(Pair("timestamp", to_iso_extended_string(from_time_t(file.mtime()))));
Alexander Afanasyev94240b52013-02-27 11:57:29 -0800334
Lijing Wangb95c6a52016-12-25 14:45:17 -0800335 std::ostringstream chmod;
336 chmod << std::setbase(8) << std::setfill('0') << std::setw(4) << file.mode();
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800337 json.push_back(Pair("chmod", chmod.str()));
Alexander Afanasyev94240b52013-02-27 11:57:29 -0800338
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800339 json.push_back(Pair("segNum", file.seg_num()));
Alexander Afanasyev94240b52013-02-27 11:57:29 -0800340
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800341 files.push_back(json);
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800342}
343
344void
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800345debugFileState(const FileItem& file)
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800346{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800347 std::cout << file.filename() << std::endl;
348}
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800349
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800350void
Lijing Wangb95c6a52016-12-25 14:45:17 -0800351StateServer::info_files_folder(const InterestFilter& interesFilter, const Interest& interestTrue)
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800352{
Lijing Wangb95c6a52016-12-25 14:45:17 -0800353 Name interest = interestTrue.getName();
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800354 if (interest.size() - m_PREFIX_INFO.size() != 3 && interest.size() - m_PREFIX_INFO.size() != 4) {
355 _LOG_DEBUG("Invalid interest: " << interest << ", " << interest.size() - m_PREFIX_INFO.size());
356 return;
357 }
358
359 _LOG_DEBUG(">> info_files_folder: " << interest);
Lijing Wangb95c6a52016-12-25 14:45:17 -0800360 m_ioService.post(bind(&StateServer::info_files_folder_Execute, this, interest));
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800361}
362
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800363void
Lijing Wangb95c6a52016-12-25 14:45:17 -0800364StateServer::info_files_folder_Execute(const Name& interest)
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800365{
Alexander Afanasyev3c95c852013-03-01 18:58:50 -0800366 // <PREFIX_INFO>/"filestate"/"folder"/<one-component-relative-folder-name>/<offset>
Lijing Wangb95c6a52016-12-25 14:45:17 -0800367 if (interest.size() < 1) {
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800368 // ignore any unexpected interests and errors
Lijing Wangb95c6a52016-12-25 14:45:17 -0800369 _LOG_ERROR("empty interest name");
370 return;
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800371 }
Lijing Wangb95c6a52016-12-25 14:45:17 -0800372 uint64_t offset = interest.get(-1).toNumber();
373
374 // /// @todo !!! add security checking
375
376 std::string folder;
377 if (interest.size() - m_PREFIX_INFO.size() == 4)
378 folder = interest.get(-2).toUri();
379 else // == 3
380 folder = "";
381
382 /*
383 *{
384 * "files": [
385 * ...
386 * ],
387 *
388 * // only if there are more actions available
389 * "more": "<NDN-NAME-OF-NEXT-SEGMENT-OF-ACTION>"
390 *}
391 */
392
393 using namespace json_spirit;
394 Object json;
395
396 Array files;
397 bool more =
398 m_actionLog->GetFileState()->LookupFilesInFolderRecursively(bind(StateServer::formatFilestateJson,
399 boost::ref(files), _1),
400 folder, offset * 10, 10);
401
402 json.push_back(Pair("files", files));
403
404 if (more) {
405 json.push_back(Pair("more", boost::lexical_cast<std::string>(offset + 1)));
406 // Name more = Name(interest.getPartialName(0, interest.size() - 1))(offset + 1);
407 // json.push_back(Pair("more", boost::lexical_cast<std::string>(more)));
408 }
409
410 std::ostringstream os;
411 write_stream(Value(json), os, pretty_print | raw_utf8);
412
413 shared_ptr<Data> data = make_shared<Data>();
414 data->setName(interest);
415 data->setFreshnessPeriod(m_freshness);
416 data->setContent(reinterpret_cast<const uint8_t*>(os.str().c_str()), os.str().size());
417 m_keyChain.sign(*data);
418 m_face.put(*data);
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800419}
420
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800421void
Lijing Wangb95c6a52016-12-25 14:45:17 -0800422StateServer::cmd_restore_file(const InterestFilter& interesFilter, const Interest& interestTrue)
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800423{
Lijing Wangb95c6a52016-12-25 14:45:17 -0800424 Name interest = interestTrue.getName();
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800425 if (interest.size() - m_PREFIX_CMD.size() != 4 && interest.size() - m_PREFIX_CMD.size() != 5) {
426 _LOG_DEBUG("Invalid interest: " << interest);
427 return;
428 }
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800429
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800430 _LOG_DEBUG(">> cmd_restore_file: " << interest);
Lijing Wangb95c6a52016-12-25 14:45:17 -0800431 m_ioService.post(bind(&StateServer::cmd_restore_file_Execute, this, interest));
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800432}
433
434void
Lijing Wangb95c6a52016-12-25 14:45:17 -0800435StateServer::cmd_restore_file_Execute(const Name& interest)
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800436{
437 // <PREFIX_CMD>/"restore"/"file"/<one-component-relative-file-name>/<version>/<file-hash>
438
439 /// @todo !!! add security checking
440
Lijing Wangb95c6a52016-12-25 14:45:17 -0800441 FileItemPtr file;
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800442
Lijing Wangb95c6a52016-12-25 14:45:17 -0800443 if (interest.size() - m_PREFIX_CMD.size() == 5) {
444 const Buffer hash(interest.get(-1).value(), interest.get(-1).value_size());
445 uint64_t version = interest.get(-2).toNumber();
446 std::string filename = interest.get(-3).toUri(); // should be safe even with full relative path
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800447
Lijing Wangb95c6a52016-12-25 14:45:17 -0800448 _LOG_DEBUG("filename: " << filename << " version: " << version);
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800449
Lijing Wangb95c6a52016-12-25 14:45:17 -0800450 file = m_actionLog->LookupAction(filename, version, hash);
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800451
452 if (!file) {
Lijing Wangb95c6a52016-12-25 14:45:17 -0800453 _LOG_ERROR("Requested file is not found: [" << filename << "] version [" << version << "] hash ["
454 << toHex(hash)
455 << "]");
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800456 }
Lijing Wangb95c6a52016-12-25 14:45:17 -0800457 }
458 else {
459 uint64_t version = interest.get(-1).toNumber();
460 std::string filename = interest.get(-2).toUri();
461 file = m_actionLog->LookupAction(filename, version, Buffer(0, 0));
462 if (!file) {
463 _LOG_ERROR("Requested file is not found: [" << filename << "] version [" << version << "]");
464 }
465 }
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800466
Lijing Wangb95c6a52016-12-25 14:45:17 -0800467 if (!file) {
468 shared_ptr<Data> data = make_shared<Data>();
469 data->setName(interest);
470 data->setFreshnessPeriod(m_freshness);
471 std::string msg = "FAIL: Requested file is not found";
472 data->setContent(reinterpret_cast<const uint8_t*>(msg.c_str()), msg.size());
473 m_keyChain.sign(*data);
474 m_face.put(*data);
475 return;
476 }
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800477
Lijing Wangb95c6a52016-12-25 14:45:17 -0800478 const Buffer hash(file->file_hash().c_str(), file->file_hash().size());
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800479
Lijing Wangb95c6a52016-12-25 14:45:17 -0800480 ///////////////////
481 // now the magic //
482 ///////////////////
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800483
Lijing Wangb95c6a52016-12-25 14:45:17 -0800484 fs::path filePath = m_rootDir / file->filename();
485 Name deviceName(
486 Block((const unsigned char*)file->device_name().c_str(), file->device_name().size()));
487
488 _LOG_DEBUG("filePath" << filePath << " deviceName " << deviceName);
489
490 try {
491 if (fs::exists(filePath) && fs::last_write_time(filePath) == file->mtime()
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800492#if BOOST_VERSION >= 104900
Lijing Wangb95c6a52016-12-25 14:45:17 -0800493 &&
494 fs::status(filePath).permissions() == static_cast<fs::perms>(file->mode())
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800495#endif
Lijing Wangb95c6a52016-12-25 14:45:17 -0800496 ) {
497 fs::ifstream input(filePath, std::ios::in | std::ios::binary);
498 if (*util::Sha256(input).computeDigest() == hash) {
499 shared_ptr<Data> data = make_shared<Data>();
500 data->setName(interest);
501 data->setFreshnessPeriod(m_freshness);
502 std::string msg = "OK: File already exists";
503 data->setContent(reinterpret_cast<const uint8_t*>(msg.c_str()), msg.size());
504 m_keyChain.sign(*data);
505 m_face.put(*data);
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800506 _LOG_DEBUG("Asking to assemble a file, but file already exists on a filesystem");
507 return;
508 }
509 }
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800510 }
Lijing Wangb95c6a52016-12-25 14:45:17 -0800511 catch (fs::filesystem_error& error) {
512 shared_ptr<Data> data = make_shared<Data>();
513 data->setName(interest);
514 data->setFreshnessPeriod(m_freshness);
515 std::string msg = "FAIL: File operation failed";
516 data->setContent(reinterpret_cast<const uint8_t*>(msg.c_str()), msg.size());
517 m_keyChain.sign(*data);
518 m_face.put(*data);
519 _LOG_ERROR("File operations failed on [" << filePath << "](ignoring)");
520 }
521
522 _LOG_TRACE("Restoring file [" << filePath << "]"
523 << " deviceName "
524 << deviceName);
525 if (m_objectManager.objectsToLocalFile(deviceName, hash, filePath)) {
526 last_write_time(filePath, file->mtime());
527#if BOOST_VERSION >= 104900
528 permissions(filePath, static_cast<fs::perms>(file->mode()));
529#endif
530 shared_ptr<Data> data = make_shared<Data>();
531 data->setName(interest);
532 data->setFreshnessPeriod(m_freshness);
533 std::string msg = "OK";
534 data->setContent(reinterpret_cast<const uint8_t*>(msg.c_str()), msg.size());
535 m_keyChain.sign(*data);
536 m_face.put(*data);
537 _LOG_DEBUG("Restoring file successfully!");
538 }
539 else {
540 shared_ptr<Data> data = make_shared<Data>();
541 data->setName(interest);
542 data->setFreshnessPeriod(m_freshness);
543 std::string msg = "FAIL: Unknown error while restoring file";
544 data->setContent(reinterpret_cast<const uint8_t*>(msg.c_str()), msg.size());
545 m_keyChain.sign(*data);
546 m_face.put(*data);
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800547 }
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800548}
Lijing Wangb95c6a52016-12-25 14:45:17 -0800549
550} // namespace chronoshare
551} // namespace ndn