blob: 7e002ddea4204c5cbfc46692ead9acf8579945b2 [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"
23#include <boost/make_shared.hpp>
24#include <utility>
25#include "task.h"
26#include "periodic-task.h"
27#include "simple-interval-generator.h"
28#include <boost/lexical_cast.hpp>
Alexander Afanasyeve1c95042013-02-27 01:02:36 -080029#include <boost/date_time/posix_time/posix_time.hpp>
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080030
31INIT_LOGGER ("StateServer");
32
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 Afanasyev1dd37ed2013-08-14 18:08:09 -070037StateServer::StateServer(NdnxWrapperPtr ndnx, ActionLogPtr actionLog,
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080038 const boost::filesystem::path &rootDir,
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -070039 const Ndnx::Name &userName, const std::string &sharedFolderName,
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080040 const std::string &appName,
41 ObjectManager &objectManager,
42 int freshness/* = -1*/)
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -070043 : m_ndnx(ndnx)
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080044 , m_actionLog(actionLog)
45 , m_objectManager (objectManager)
46 , m_rootDir(rootDir)
47 , m_freshness(freshness)
Alexander Afanasyev95f9f552013-02-26 23:05:20 -080048 , m_executor (1)
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080049 , m_userName (userName)
50 , m_sharedFolderName (sharedFolderName)
51 , m_appName (appName)
52{
53 // may be later /localhost should be replaced with /%C1.M.S.localhost
54
55 // <PREFIX_INFO> = /localhost/<user's-device-name>/"chronoshare"/"info"
Alexander Afanasyev95f9f552013-02-26 23:05:20 -080056 m_PREFIX_INFO = Name ("/localhost")(m_userName)("chronoshare")(m_sharedFolderName)("info");
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080057
58 // <PREFIX_CMD> = /localhost/<user's-device-name>/"chronoshare"/"cmd"
Alexander Afanasyev95f9f552013-02-26 23:05:20 -080059 m_PREFIX_CMD = Name ("/localhost")(m_userName)("chronoshare")(m_sharedFolderName)("cmd");
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080060
Alexander Afanasyev95f9f552013-02-26 23:05:20 -080061 m_executor.start ();
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080062
63 registerPrefixes ();
64}
65
66StateServer::~StateServer()
67{
Alexander Afanasyev95f9f552013-02-26 23:05:20 -080068 m_executor.shutdown ();
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080069
70 deregisterPrefixes ();
71}
72
73void
74StateServer::registerPrefixes ()
75{
76 // currently supporting limited number of command.
77 // will be extended to support all planned commands later
78
Alexander Afanasyev3c95c852013-03-01 18:58:50 -080079 // <PREFIX_INFO>/"actions"/"all"/<segment> get list of all actions
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -070080 m_ndnx->setInterestFilter (Name (m_PREFIX_INFO)("actions")("folder"), bind(&StateServer::info_actions_folder, this, _1));
81 m_ndnx->setInterestFilter (Name (m_PREFIX_INFO)("actions")("file"), 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 Afanasyev1dd37ed2013-08-14 18:08:09 -070084 m_ndnx->setInterestFilter (Name (m_PREFIX_INFO)("files")("folder"), bind(&StateServer::info_files_folder, this, _1));
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080085
86 // <PREFIX_CMD>/"restore"/"file"/<one-component-relative-file-name>/<version>/<file-hash>
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -070087 m_ndnx->setInterestFilter (Name (m_PREFIX_CMD)("restore")("file"), bind(&StateServer::cmd_restore_file, this, _1));
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080088}
89
90void
91StateServer::deregisterPrefixes ()
92{
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -070093 m_ndnx->clearInterestFilter (Name (m_PREFIX_INFO)("actions")("folder"));
94 m_ndnx->clearInterestFilter (Name (m_PREFIX_INFO)("actions")("file"));
95 m_ndnx->clearInterestFilter (Name (m_PREFIX_INFO)("files")("folder"));
96 m_ndnx->clearInterestFilter (Name (m_PREFIX_CMD) ("restore")("file"));
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080097}
98
Alexander Afanasyeve1c95042013-02-27 01:02:36 -080099void
100StateServer::formatActionJson (json_spirit::Array &actions,
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700101 const Ndnx::Name &name, sqlite3_int64 seq_no, const ActionItem &action)
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800102{
Alexander Afanasyeve1c95042013-02-27 01:02:36 -0800103/*
104 * {
105 * "id": {
106 * "userName": "<NDN-NAME-OF-THE-USER>",
107 * "seqNo": "<SEQ_NO_OF_THE_ACTION>"
108 * },
109 * "timestamp": "<ACTION-TIMESTAMP>",
110 * "filename": "<FILENAME>",
111 *
112 * "action": "UPDATE | DELETE",
113 *
114 * // only if update
115 * "update": {
116 * "hash": "<FILE-HASH>",
117 * "timestamp": "<FILE-TIMESTAMP>",
118 * "chmod": "<FILE-MODE>",
119 * "segNum": "<NUMBER-OF-SEGMENTS (~file size)>"
120 * },
121 *
122 * // if parent_device_name is set
123 * "parentId": {
124 * "userName": "<NDN-NAME-OF-THE-USER>",
125 * "seqNo": "<SEQ_NO_OF_THE_ACTION>"
126 * }
127 * }
128 */
129
130 using namespace json_spirit;
131 using namespace boost::posix_time;
132
133 Object json;
134 Object id;
135
136 id.push_back (Pair ("userName", boost::lexical_cast<string> (name)));
Alexander Afanasyev95f4e922013-03-17 18:09:36 -0700137 id.push_back (Pair ("seqNo", static_cast<int64_t> (seq_no)));
Alexander Afanasyeve1c95042013-02-27 01:02:36 -0800138
139 json.push_back (Pair ("id", id));
140
Alexander Afanasyev46bd8062013-02-27 23:59:15 -0800141 json.push_back (Pair ("timestamp", to_iso_extended_string (from_time_t (action.timestamp ()))));
Alexander Afanasyeve1c95042013-02-27 01:02:36 -0800142 json.push_back (Pair ("filename", action.filename ()));
Alexander Afanasyevf63a5142013-02-28 02:21:42 -0800143 json.push_back (Pair ("version", action.version ()));
Alexander Afanasyeve1c95042013-02-27 01:02:36 -0800144 json.push_back (Pair ("action", (action.action () == 0) ? "UPDATE" : "DELETE"));
145
146 if (action.action () == 0)
147 {
148 Object update;
149 update.push_back (Pair ("hash", boost::lexical_cast<string> (Hash (action.file_hash ().c_str (), action.file_hash ().size ()))));
Alexander Afanasyev46bd8062013-02-27 23:59:15 -0800150 update.push_back (Pair ("timestamp", to_iso_extended_string (from_time_t (action.mtime ()))));
Alexander Afanasyeve1c95042013-02-27 01:02:36 -0800151
152 ostringstream chmod;
153 chmod << setbase (8) << setfill ('0') << setw (4) << action.mode ();
154 update.push_back (Pair ("chmod", chmod.str ()));
155
156 update.push_back (Pair ("segNum", action.seg_num ()));
157 json.push_back (Pair ("update", update));
158 }
159
160 if (action.has_parent_device_name ())
161 {
162 Object parentId;
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700163 Ndnx::Name parent_device_name (action.parent_device_name ().c_str (), action.parent_device_name ().size ());
Alexander Afanasyeve1c95042013-02-27 01:02:36 -0800164 id.push_back (Pair ("userName", boost::lexical_cast<string> (parent_device_name)));
165 id.push_back (Pair ("seqNo", action.parent_seq_no ()));
166
167 json.push_back (Pair ("parentId", parentId));
168 }
169
170 actions.push_back (json);
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800171}
172
173void
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800174StateServer::info_actions_folder (const Name &interest)
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800175{
Alexander Afanasyev3c95c852013-03-01 18:58:50 -0800176 if (interest.size () - m_PREFIX_INFO.size () != 3 &&
177 interest.size () - m_PREFIX_INFO.size () != 4)
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800178 {
179 _LOG_DEBUG ("Invalid interest: " << interest);
180 return;
181 }
182
Alexander Afanasyev39dbc4b2013-03-01 10:39:23 -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 Afanasyev39dbc4b2013-03-01 10:39:23 -0800188StateServer::info_actions_file (const Name &interest)
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800189{
Alexander Afanasyev3c95c852013-03-01 18:58:50 -0800190 if (interest.size () - m_PREFIX_INFO.size () != 3 &&
191 interest.size () - m_PREFIX_INFO.size () != 4)
Alexander Afanasyev39dbc4b2013-03-01 10:39:23 -0800192 {
193 _LOG_DEBUG ("Invalid interest: " << interest);
194 return;
195 }
196
197 _LOG_DEBUG (">> info_actions_file: " << interest);
198 m_executor.execute (bind (&StateServer::info_actions_fileOrFolder_Execute, this, interest, false));
199}
200
201
202void
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700203StateServer::info_actions_fileOrFolder_Execute (const Ndnx::Name &interest, bool isFolder/* = true*/)
Alexander Afanasyev39dbc4b2013-03-01 10:39:23 -0800204{
Alexander Afanasyev3c95c852013-03-01 18:58:50 -0800205 // <PREFIX_INFO>/"actions"/"folder|file"/<folder|file>/<offset> get list of all actions
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800206
207 try
208 {
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800209 int offset = interest.getCompFromBackAsInt (0);
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800210
211 /// @todo !!! add security checking
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800212
Alexander Afanasyev39dbc4b2013-03-01 10:39:23 -0800213 string fileOrFolderName;
Alexander Afanasyev3c95c852013-03-01 18:58:50 -0800214 if (interest.size () - m_PREFIX_INFO.size () == 4)
215 fileOrFolderName = interest.getCompFromBackAsString (1);
216 else // == 3
Alexander Afanasyev39dbc4b2013-03-01 10:39:23 -0800217 fileOrFolderName = "";
Alexander Afanasyeve1c95042013-02-27 01:02:36 -0800218/*
219 * {
220 * "actions": [
221 * ...
222 * ],
223 *
224 * // only if there are more actions available
225 * "more": "<NDN-NAME-OF-NEXT-SEGMENT-OF-ACTION>"
226 * }
227 */
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800228
Alexander Afanasyeve1c95042013-02-27 01:02:36 -0800229 using namespace json_spirit;
230 Object json;
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800231
Alexander Afanasyeve1c95042013-02-27 01:02:36 -0800232 Array actions;
Alexander Afanasyev39dbc4b2013-03-01 10:39:23 -0800233 bool more;
234 if (isFolder)
235 {
Alexander Afanasyev3c95c852013-03-01 18:58:50 -0800236 more = m_actionLog->LookupActionsInFolderRecursively
Alexander Afanasyev39dbc4b2013-03-01 10:39:23 -0800237 (boost::bind (StateServer::formatActionJson, boost::ref(actions), _1, _2, _3),
238 fileOrFolderName, offset*10, 10);
239 }
240 else
241 {
Alexander Afanasyev3c95c852013-03-01 18:58:50 -0800242 more = m_actionLog->LookupActionsForFile
Alexander Afanasyev39dbc4b2013-03-01 10:39:23 -0800243 (boost::bind (StateServer::formatActionJson, boost::ref(actions), _1, _2, _3),
244 fileOrFolderName, offset*10, 10);
245 }
Alexander Afanasyeve1c95042013-02-27 01:02:36 -0800246
247 json.push_back (Pair ("actions", actions));
248
249 if (more)
250 {
Alexander Afanasyev3c95c852013-03-01 18:58:50 -0800251 json.push_back (Pair ("more", lexical_cast<string> (offset + 1)));
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700252 // Ndnx::Name more = Name (interest.getPartialName (0, interest.size () - 1))(offset + 1);
Alexander Afanasyev3c95c852013-03-01 18:58:50 -0800253 // json.push_back (Pair ("more", lexical_cast<string> (more)));
Alexander Afanasyeve1c95042013-02-27 01:02:36 -0800254 }
255
256 ostringstream os;
257 write_stream (Value (json), os, pretty_print | raw_utf8);
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700258 m_ndnx->publishData (interest, os.str (), 1);
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800259 }
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700260 catch (Ndnx::NameException &ne)
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800261 {
262 // ignore any unexpected interests and errors
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700263 _LOG_ERROR (*boost::get_error_info<Ndnx::error_info_str>(ne));
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800264 }
265}
266
Alexander Afanasyev94240b52013-02-27 11:57:29 -0800267void
268StateServer::formatFilestateJson (json_spirit::Array &files, const FileItem &file)
269{
270/**
271 * {
272 * "filestate": [
273 * {
274 * "filename": "<FILENAME>",
275 * "owner": {
276 * "userName": "<NDN-NAME-OF-THE-USER>",
277 * "seqNo": "<SEQ_NO_OF_THE_ACTION>"
278 * },
279 *
280 * "hash": "<FILE-HASH>",
281 * "timestamp": "<FILE-TIMESTAMP>",
282 * "chmod": "<FILE-MODE>",
283 * "segNum": "<NUMBER-OF-SEGMENTS (~file size)>"
284 * }, ...,
285 * ]
286 *
287 * // only if there are more actions available
288 * "more": "<NDN-NAME-OF-NEXT-SEGMENT-OF-FILESTATE>"
289 * }
290 */
291 using namespace json_spirit;
292 using namespace boost::posix_time;
293
294 Object json;
295
296 json.push_back (Pair ("filename", file.filename ()));
297 json.push_back (Pair ("version", file.version ()));
298 {
299 Object owner;
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700300 Ndnx::Name device_name (file.device_name ().c_str (), file.device_name ().size ());
Alexander Afanasyev94240b52013-02-27 11:57:29 -0800301 owner.push_back (Pair ("userName", boost::lexical_cast<string> (device_name)));
302 owner.push_back (Pair ("seqNo", file.seq_no ()));
303
304 json.push_back (Pair ("owner", owner));
305 }
306
307 json.push_back (Pair ("hash", boost::lexical_cast<string> (Hash (file.file_hash ().c_str (), file.file_hash ().size ()))));
Alexander Afanasyev46bd8062013-02-27 23:59:15 -0800308 json.push_back (Pair ("timestamp", to_iso_extended_string (from_time_t (file.mtime ()))));
Alexander Afanasyev94240b52013-02-27 11:57:29 -0800309
310 ostringstream chmod;
311 chmod << setbase (8) << setfill ('0') << setw (4) << file.mode ();
312 json.push_back (Pair ("chmod", chmod.str ()));
313
314 json.push_back (Pair ("segNum", file.seg_num ()));
315
316 files.push_back (json);
317}
318
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800319void debugFileState (const FileItem &file)
320{
321 std::cout << file.filename () << std::endl;
322}
323
324void
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700325StateServer::info_files_folder (const Ndnx::Name &interest)
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800326{
Alexander Afanasyev3c95c852013-03-01 18:58:50 -0800327 if (interest.size () - m_PREFIX_INFO.size () != 3 &&
328 interest.size () - m_PREFIX_INFO.size () != 4)
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800329 {
330 _LOG_DEBUG ("Invalid interest: " << interest << ", " << interest.size () - m_PREFIX_INFO.size ());
331 return;
332 }
333
Alexander Afanasyev39dbc4b2013-03-01 10:39:23 -0800334 _LOG_DEBUG (">> info_files_folder: " << interest);
Alexander Afanasyev94240b52013-02-27 11:57:29 -0800335 m_executor.execute (bind (&StateServer::info_files_folder_Execute, this, interest));
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800336}
337
338
339void
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700340StateServer::info_files_folder_Execute (const Ndnx::Name &interest)
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800341{
Alexander Afanasyev3c95c852013-03-01 18:58:50 -0800342 // <PREFIX_INFO>/"filestate"/"folder"/<one-component-relative-folder-name>/<offset>
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800343 try
344 {
345 int offset = interest.getCompFromBackAsInt (0);
346
347 // /// @todo !!! add security checking
348
349 string folder;
Alexander Afanasyev3c95c852013-03-01 18:58:50 -0800350 if (interest.size () - m_PREFIX_INFO.size () == 4)
351 folder = interest.getCompFromBackAsString (1);
352 else // == 3
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800353 folder = "";
354
Alexander Afanasyev94240b52013-02-27 11:57:29 -0800355/*
356 * {
357 * "files": [
358 * ...
359 * ],
360 *
361 * // only if there are more actions available
362 * "more": "<NDN-NAME-OF-NEXT-SEGMENT-OF-ACTION>"
363 * }
364 */
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800365
Alexander Afanasyev94240b52013-02-27 11:57:29 -0800366 using namespace json_spirit;
367 Object json;
368
369 Array files;
370 bool more = m_actionLog
371 ->GetFileState ()
372 ->LookupFilesInFolderRecursively
373 (boost::bind (StateServer::formatFilestateJson, boost::ref (files), _1),
374 folder, offset*10, 10);
375
376 json.push_back (Pair ("files", files));
377
378 if (more)
379 {
Alexander Afanasyev3c95c852013-03-01 18:58:50 -0800380 json.push_back (Pair ("more", lexical_cast<string> (offset + 1)));
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700381 // Ndnx::Name more = Name (interest.getPartialName (0, interest.size () - 1))(offset + 1);
Alexander Afanasyev3c95c852013-03-01 18:58:50 -0800382 // json.push_back (Pair ("more", lexical_cast<string> (more)));
Alexander Afanasyev94240b52013-02-27 11:57:29 -0800383 }
384
385 ostringstream os;
386 write_stream (Value (json), os, pretty_print | raw_utf8);
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700387 m_ndnx->publishData (interest, os.str (), 1);
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800388 }
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700389 catch (Ndnx::NameException &ne)
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800390 {
391 // ignore any unexpected interests and errors
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700392 _LOG_ERROR (*boost::get_error_info<Ndnx::error_info_str>(ne));
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800393 }
394}
395
396
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800397void
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700398StateServer::cmd_restore_file (const Ndnx::Name &interest)
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800399{
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800400 if (interest.size () - m_PREFIX_CMD.size () != 4 &&
401 interest.size () - m_PREFIX_CMD.size () != 5)
402 {
403 _LOG_DEBUG ("Invalid interest: " << interest);
404 return;
405 }
406
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800407 _LOG_DEBUG (">> cmd_restore_file: " << interest);
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800408 m_executor.execute (bind (&StateServer::cmd_restore_file_Execute, this, interest));
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800409}
410
411void
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700412StateServer::cmd_restore_file_Execute (const Ndnx::Name &interest)
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800413{
414 // <PREFIX_CMD>/"restore"/"file"/<one-component-relative-file-name>/<version>/<file-hash>
415
416 /// @todo !!! add security checking
417
418 try
419 {
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800420 FileItemPtr file;
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800421
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800422 if (interest.size () - m_PREFIX_CMD.size () == 5)
423 {
424 Hash hash (head(interest.getCompFromBack (0)), interest.getCompFromBack (0).size());
425 int64_t version = interest.getCompFromBackAsInt (1);
426 string filename = interest.getCompFromBackAsString (2); // should be safe even with full relative path
427
428 file = m_actionLog->LookupAction (filename, version, hash);
429 if (!file)
430 {
431 _LOG_ERROR ("Requested file is not found: [" << filename << "] version [" << version << "] hash [" << hash.shortHash () << "]");
432 }
433 }
434 else
435 {
436 int64_t version = interest.getCompFromBackAsInt (0);
437 string filename = interest.getCompFromBackAsString (1); // should be safe even with full relative path
438
439 file = m_actionLog->LookupAction (filename, version, Hash (0,0));
440 if (!file)
441 {
442 _LOG_ERROR ("Requested file is not found: [" << filename << "] version [" << version << "]");
443 }
444 }
445
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800446 if (!file)
447 {
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700448 m_ndnx->publishData (interest, "FAIL: Requested file is not found", 1);
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800449 return;
450 }
451
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800452 Hash hash = Hash (file->file_hash ().c_str (), file->file_hash ().size ());
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800453
454 ///////////////////
455 // now the magic //
456 ///////////////////
457
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800458 boost::filesystem::path filePath = m_rootDir / file->filename ();
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800459 Name deviceName (file->device_name ().c_str (), file->device_name ().size ());
460
461 try
462 {
463 if (filesystem::exists (filePath) &&
464 filesystem::last_write_time (filePath) == file->mtime () &&
Alexander Afanasyevf8ff5e12013-07-11 13:57:32 -0700465#if BOOST_VERSION >= 104900
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800466 filesystem::status (filePath).permissions () == static_cast<filesystem::perms> (file->mode ()) &&
Alexander Afanasyevf8ff5e12013-07-11 13:57:32 -0700467#endif
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800468 *Hash::FromFileContent (filePath) == hash)
469 {
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700470 m_ndnx->publishData (interest, "OK: File already exists", 1);
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800471 _LOG_DEBUG ("Asking to assemble a file, but file already exists on a filesystem");
472 return;
473 }
474 }
475 catch (filesystem::filesystem_error &error)
476 {
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700477 m_ndnx->publishData (interest, "FAIL: File operation failed", 1);
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800478 _LOG_ERROR ("File operations failed on [" << filePath << "] (ignoring)");
479 }
480
481 _LOG_TRACE ("Restoring file [" << filePath << "]");
482 if (m_objectManager.objectsToLocalFile (deviceName, hash, filePath))
483 {
484 last_write_time (filePath, file->mtime ());
Alexander Afanasyevf8ff5e12013-07-11 13:57:32 -0700485#if BOOST_VERSION >= 104900
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800486 permissions (filePath, static_cast<filesystem::perms> (file->mode ()));
Alexander Afanasyevf8ff5e12013-07-11 13:57:32 -0700487#endif
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700488 m_ndnx->publishData (interest, "OK", 1);
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800489 }
490 else
491 {
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700492 m_ndnx->publishData (interest, "FAIL: Unknown error while restoring file", 1);
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800493 }
494 }
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700495 catch (Ndnx::NameException &ne)
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800496 {
497 // ignore any unexpected interests and errors
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700498 _LOG_ERROR(*boost::get_error_info<Ndnx::error_info_str>(ne));
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800499 }
500}