Remoto - VFS: VFS_ephemeral.cpp Source File
Remoto - VFS
VFS_ephemeral.cpp
Go to the documentation of this file.
1 
2 #include <QDirIterator>
3 #include <QFile>
4 #include <QDir>
5 #include <QMimeDatabase>
6 #include <QMimeType>
7 
8 #include "VFS.h"
9 #include "VFS_ephemeral.h"
10 #include "VFS_base/VFS_icons.h"
11 #include "utilities/rutils.h"
13 #include "VFS_base/VFS_node_type.h"
14 
25 #define VFS_EPHEMERAL_MAX_READABLE 104857600 //100mb
26 
27 QMimeDatabase VFS_ephemeral::_mimeDatabase;
28 
35 VFS_ephemeral::VFS_ephemeral(bool container, bool raw)
36 : VFS_node()
37 , _container(container)
38 , _raw(raw)
39 {
40  _modified = QDateTime::currentDateTimeUtc();
41 }
42 
44 {
45 }
46 
47 
55 QByteArray VFS_ephemeral::icon()
56 {
57  return VFS_node::icon();
58 }
59 
60 
67 {
68  QString s = QString("Size: %1\nModified: %2").arg(size()).arg(_modified.toString());
69 
70  return s;
71 }
72 
73 
81 {
82  VFS_node *n = VFS_node::find(r);
83 
84  if (!n && _container)
85  {
86  bool creating = r->_metadata.value("createIfMissing").toBool(false) || r->_requestType == VFS_request::create;
87  bool container = r->_metadata.value("container").toBool(false);
88  bool raw = r->_metadata.value("raw").toBool(false) || _raw;
89 
90  if (creating)
91  {
92  QStringList pl = r->_path.split("/",Qt::SkipEmptyParts);
93  QString p = pl.takeFirst();
94  if (pl.length() == 0)
95  n = new VFS_ephemeral(container,raw);
96  else
97  n = new VFS_ephemeral(true,raw);
98 
99  if (append(p,n,true,r->_user))
100  { r->_reason = "";
101  r->_path = pl.join("/");
102  r->_prefixPath += p;
103  return n->find(r);
104  }
105  else
106  {
107  delete n;
108  n = nullptr;
109  }
110  }
111  }
112 
113  return n;
114 }
115 
116 
123 {
124  return _container;
125 }
126 
127 
139 VFS_node *VFS_ephemeral::append(QString nodename, VFS_node *node, bool containerCheck, QString user)
140 {
141  VFS_ephemeral *t = dynamic_cast<VFS_ephemeral *>(node);
142 
143  if (!t)
144  { VFS::ERROR( QString("Can only append nodes of type 'VFS_ephemeral'. Unable to append '%1'.").arg(nodename), 0, className() );
145  return nullptr;
146  }
147  else
148  t->populateMetadata(nodename);
149 
150  return VFS_node::append(nodename,node,containerCheck,user);
151 }
152 
153 
162 {
163  if (_container)
164  return;
165 
166  QString t = VFS_node_type::getType(name,"");
167 
168  if (t == "")
169  {
170  QMimeType mime = _mimeDatabase.mimeTypeForFile(name);
171  t = mime.name();
172 
173  _metadata["mime"] = t;
174  _metadata["type"] = mime.comment();
175  }
176  else
177  _metadata["type"] = t;
178 }
179 
180 
189 {
190  if (_raw) return (quint64) _rawData.size();
191  else return (quint64) QJsonDocument(_data).toJson().size();
192 }
193 
194 
203 {
204  //FIXME: add stuff for "closest" and listing
205 
206  if (_container)
207  {
208  VFS_node::ls(r);
209 
210  if (r->_metadata.value("sequence").toBool(false) && _container)
211  r->_data.setObject( rutils::sequenceListing(r->_data.object()) );
212 
213  return;
214  }
215 
216  r->_success = false;
217  r->_reason = "Cannot list a file";
218 }
219 
220 
233 {
234  if (isContainer() && r->_path == "")
235  {
236  r->_metadata["type"] = "listing";
237  ls(r);
238  return;
239  }
240 
241  QMutexLocker l(&_lock);
242 
243  bool creating = r->_metadata.value("createIfMissing").toBool(false);
244  //bool container = r->_metadata.value("container").toBool(false);
245 
246  bool raw = r->_metadata.value("raw").toBool(false) || _raw;
247  bool range = r->_metadata.contains("range") ? true : false;
248 
249  if (range)
250  {
251  if (raw)
252  return fetchRange(r);
253  else
254  VFS::WARN("Range request was present on non-raw VFS_ephemeral node. Range will be ignored.",0,className());
255  }
256 
257  if (creating && !size())
258  {
259  //printf("CREATE FROM READ: %s\n%s\n",qUtf8Printable(r->_path),qUtf8Printable(r->_data.toJson()));
260 
261  _data = r->_data.object();
262  _rawData = r->_rawData;
263  _modified = QDateTime::currentDateTimeUtc();
264  }
265 
266  if (raw && !_rawData.isEmpty())
267  r->_rawData = _rawData;
268  else
269  r->_data.setObject(_data);
270 
271  r->_success = true;
272 }
273 
274 
287 {
288  QMutexLocker l(&_lock);
289 
290  _data = r->_data.object();
291  _rawData = r->_rawData;
292  _modified = QDateTime::currentDateTimeUtc();
293 
294  r->_success = true;
295 
296  emit diff(this,r);
297 }
298 
307 {
308  QMutexLocker l(&_lock);
309 
310  r->_metadata = _metadata;
311 
313 
314  if (_raw)
315  r->_metadata["raw"] = true;
316 
317  r->_success = true;
318 }
319 
320 
338 {
339  QMutexLocker l(&_lock);
340 
341  //bool creating = r->_metadata.value("createIfMissing").toBool(false);
342  bool raw = r->_metadata.value("raw").toBool(false) || _raw;
343  QString method = r->_metadata.value("method").toString("json");
344 
345  if (!raw)
346  {
347  if (method == "delta")
348  _data["data"] = VFS_datastore::applyDeltaDiff( _data["data"].toString(), r->_data.object(), "", r->_user );
349  else
350  _data = VFS_datastore::applyJsonDiff( _data, r->_data.object(), "", r->_user );
351 
352  r->_success = true;
353 
354  _modified = QDateTime::currentDateTimeUtc();
355 
356  emit diff(this,r);
357  }
358  else
359  {
360  if (method == "delta")
361  {
362  _rawData = VFS_datastore::applyDeltaDiff( QString::fromUtf8(_rawData), r->_data.object(), "", r->_user ).toUtf8();
363 
364  r->_success = true;
365 
366  _modified = QDateTime::currentDateTimeUtc();
367 
368  emit diff(this,r);
369  }
370  else
371  {
372  r->_success = false;
373  r->_reason = "Can't apply a json diff to _raw data.";
374  }
375  }
376 }
377 
378 
388 {
389  submit(r);
390 }
391 
392 
420 {
421  if (!_raw)
422  {
423  r->_reason = "Cannot fetch range on non-raw data.";
424  r->_success = false;
425  return;
426  }
427 
428  QJsonObject range = r->_metadata["range"].toObject();
429 
430  qint64 start(0);
431  qint64 end(0);
432 
433  if (range.contains("s"))
434  start = (qint64) range["s"].toDouble();
435 
436  if (range.contains("e"))
437  end = (qint64) range["e"].toDouble();
438 
439  qint64 size = _rawData.size();
440 
441  if (start < 0 && -start <= size) start = size + start; //which should now be positive or zero
442  if (end < 0 && -end <= size) end = size + end; //which should now be positive or zero
443  if (end == 0) end = size - 1; //the end of the file, which must be offset by one
444 
445  if (start > end)
446  {
447  r->_reason = QString("Can't fetch range where start >= end (%1,%2)").arg(start).arg(end);
448  r->_success = false;
449  return;
450  }
451 
452  if (end - start > VFS_EPHEMERAL_MAX_READABLE)
453  {
454  r->_reason = QString("Won't fetch range greater than %1 bytes. Requested %2 bytes.").arg(VFS_EPHEMERAL_MAX_READABLE).arg(end-start+1);
455  r->_success = false;
456  return;
457  }
458 
459  if (start >= size || end >= size)
460  {
461  r->_reason = QString("Can't fetch beyond the end of data. Requested bytes %1-%2").arg(start).arg(end);
462  r->_success = false;
463  return;
464  }
465 
466  qint64 bytes = end - start + 1;
467 
468  if (start < _rawData.size())
469  {
470  QByteArray data(_rawData.data(),(int)bytes);
471 
472  if (data.length() != bytes)
473  {
474  r->_reason = QString("Could not read %1 bytes. Requested bytes %2-%3, but only %4 were returned.").arg(bytes).arg(start).arg(end).arg(data.length());
475  r->_success = false;
476  return;
477  }
478 
479  range["s"] = start;
480  range["e"] = end;
481  r->_metadata["range"] = range;
482 
483  r->_rawData = data;
484  r->_success = true;
485  }
486  else
487  {
488  r->_reason = QString("Start value is out of range. Requested bytes %1-%2").arg(start).arg(end);
489  r->_success = false;
490  return;
491  }
492 }
#define VFS_EPHEMERAL_MAX_READABLE
static QString applyDeltaDiff(QString data, QJsonObject delta, QString trace="", QString user="server")
Apply a delta diff to a json object.
static QJsonObject applyJsonDiff(QJsonObject obj, QJsonObject diff, QString trace="", QString user="server")
Apply a json diff to a json object.
A VFS_datastore subclass for storing data directly in memory as if it was a filesystem.
Definition: VFS_ephemeral.h:11
QJsonObject _data
Definition: VFS_ephemeral.h:48
void populateMetadata(QString name)
Use an incoming file type to try to populate mime type.
Q_INVOKABLE VFS_ephemeral(bool container, bool raw=false)
Create a VFS_ephemeral node.
QByteArray _rawData
Definition: VFS_ephemeral.h:49
virtual QByteArray icon()
The "disk" icon found in the VFS_icons library.
virtual void fetchRange(VFS_request *r)
Fetch a byte range within a file.
virtual VFS_node * find(VFS_request *r)
Find a node using a VFS_request.
quint64 size()
Return the size of the data in this node.
virtual void write(VFS_request *r)
Write data to this node.
virtual void metadata(VFS_request *r)
Fetch the metadata for this node.
virtual bool isContainer()
The VFS_ephemeral node is a container or a document.
virtual void ls(VFS_request *r)
List the contents of a directory.
virtual void read(VFS_request *r)
Read the contents of this node.
QDateTime _modified
Definition: VFS_ephemeral.h:51
static QMimeDatabase _mimeDatabase
The mime database, used for metadata.
Definition: VFS_ephemeral.h:28
virtual VFS_node * append(QString name, VFS_node *node, bool containerCheck=true, QString user="server")
Append a VFS_ephemeral node as a child of this node.
virtual ~VFS_ephemeral()
virtual void submit(VFS_request *r)
Submit data to this node, applying the data as a diff.
QJsonObject _metadata
Definition: VFS_ephemeral.h:47
virtual QString reportDetails()
Report the current cache usage.
virtual void applyDiff(VFS_request *r)
Apply a diff to this node's data.
static QString getType(QString _path, QString _default="unknownType")
Fetch the type of a file, based on path/filename.ext.
VFS_node is the base class from which all other VFS_node classes derive.
Definition: VFS_node.h:143
virtual VFS_node * append(QString name, VFS_node *node, bool containerCheck=true, QString user="server")
Append a VFS_node as a child of this node.
Definition: VFS_node.cpp:1566
virtual void metadata(VFS_request *r)
Fetch the metadata of this node.
Definition: VFS_node.cpp:797
VFS_node * find(QString path)
Find a node by string path.
Definition: VFS_node.cpp:1100
virtual QByteArray icon()
Fetch the icon for a node.
Definition: VFS_node.cpp:655
virtual void ls(VFS_request *r)
List the contents of this node.
Definition: VFS_node.cpp:692
void diff(VFS_node *origin, VFS_request *t)
Emit a diff, which will trigger notifySubscribers() for a mounted node.
QString className()
Return the class name of a node.
Definition: VFS_node.cpp:2039
QMutex _lock
A recursive mutex that is local to this node.
Definition: VFS_node.h:178
The base class for all requests between nodes.
Definition: VFS_node.h:54
@ create
create a new file/path (2)
Definition: VFS_node.h:66
QByteArray _rawData
the request payload, but raw data
Definition: VFS_node.h:103
requestType _requestType
the action this request is performing or requesting
Definition: VFS_node.h:87
QStringList _prefixPath
the prefix elements found while searching for the target
Definition: VFS_node.h:94
QString _user
who initiated this request, mostly for logging
Definition: VFS_node.h:106
QString _reason
if something (probably bad) happened, this is the reason
Definition: VFS_node.h:108
QString _path
the target path remnant... the remaining path element once the request has found its target
Definition: VFS_node.h:95
bool _success
if the request was successfully completed
Definition: VFS_node.h:107
QJsonDocument _data
the request payload
Definition: VFS_node.h:102
QJsonObject _metadata
the request payload
Definition: VFS_node.h:101
static void ERROR(QString message, int level=0, QString user="server")
Send a message to the VFS::_errors VFS_stream.
Definition: VFS.cpp:307
static void WARN(QString message, int level=0, QString user="server")
Send a message to the VFS::_warnings VFS_stream.
Definition: VFS.cpp:258
setter user
a setter DOCME
setter name
a setter DOCME
QJsonObject sequenceListing(QJsonObject l, QStringList types=sequenceTypes)
Given a list of filenames and a regex list, collapse the listing to sequences when possible.
Definition: rutils.cpp:183