Remoto - VFS: VFS_node.cpp Source File
Remoto - VFS
VFS_node.cpp
Go to the documentation of this file.
1 
2 #include <stdexcept>
3 
4 #include <QMutableMapIterator>
5 #include <QDateTime>
6 #include <QTimer>
7 #include <QCoreApplication>
8 
9 #include "VFS.h"
10 
11 #include "VFS_node.h"
12 #include "VFS_auth/VFS_session.h"
13 //#include "VFS_acl.h"
14 #include "VFS_icons.h"
15 #include "utilities/rutils.h"
16 
17 const char* VFS_request::requestTypeStrings[] =
18 {
19  "none",
20  "ls",
21  "create",
22  "rm",
23  "read",
24  "write",
25  "metadata",
26  "diff",
27  "submit",
28  "subscribe",
29  "unsubscribe",
30  "acl",
31  "report",
32  "requestlock",
33  "releaselock",
34  "code",
35  "codeDirectory",
36  nullptr
37 };
38 
39 long VFS_request::_refcount = 0;
40 quint32 VFS_request::_sampleCount = 0;
41 QMutex VFS_request::_sampleLock(QMutex::Recursive);
42 int EXIT_DEPTH = 0; //for pretty printing on exit
43 
74 VFS_request::VFS_request(requestType type, VFS_node *origin, QString path, QString user, QJsonDocument data, QJsonObject metadata, bool dontDelete)
75 #ifdef DEBUG_DANGLING_REQUESTS
76 : QObject()
77 , _requestType(type)
78 #else
79 : _requestType(type)
80 #endif
81 , _origin(origin)
82 , _originPath("")
83 , _responder(nullptr)
84 , _initialPath(path)
85 , _prefixPath()
86 , _path(path)
87 , _callback(nullptr)
88 , _isCallback(false)
89 , _metadata(metadata)
90 , _data(data)
91 , _session(nullptr)
92 , _user(user)
93 , _success(false) //default to no success
94 , _reason()
95 , _dontDelete(dontDelete)
96 {
97  QMutexLocker l(&_sampleLock);
98 
99  _refcount++;
100  _sampleCount++;
101 
102  //don't let an invalid path in no matter what
103  _path = rutils::cleanPath(_path);
104  _initialPath = rutils::cleanPath(_initialPath);
105 
106  #ifdef DEBUG_DANGLING_REQUESTS
107  {
108  QTimer::singleShot(10000, this, SLOT(timerEvent() ));
109 
110  //VFS_request *c = this;
111  //QString p = this->_initialPath;
112  //QTimer::singleShot(2000, [=] {
113  // printf("VFS_request timeout: %s %p\n",qUtf8Printable(p),this);
114  //});
115 
116  /*
117  _timer.setSingleShot(true);
118  _timer.connect(&_timer,
119  &QTimer::timeout,
120  [=]() {
121  printf("VFS_request timeout: %s\n",qUtf8Printable(p));
122  });
123  _timer.start(2000);
124  */
125  }
126  #endif
127 
128  _metadata["stamp"] = QDateTime::currentMSecsSinceEpoch();
129 
130  #ifdef DEBUG_DANGLING_REQUESTS
131  printf("CREATE REFCOUNT: %ld (%p) %s %s\n",_refcount,this,qUtf8Printable(_user),qUtf8Printable(_path));
132  #endif
133 }
134 
135 
146 #ifdef DEBUG_DANGLING_REQUESTS
147 : QObject()
148 , _requestType(c._requestType)
149 #else
150 : _requestType(c._requestType)
151 #endif
152 , _origin(c._origin)
153 , _originPath(c._originPath)
154 , _responder(c._responder)
155 , _initialPath(c._initialPath)
156 , _prefixPath(c._prefixPath)
157 , _path(c._path)
158 , _callback(c._callback)
159 , _isCallback(c._isCallback)
160 , _metadata(c._metadata)
161 , _data(c._data)
162 , _rawData(c._rawData)
163 , _session(c._session)
164 , _user(c._user)
165 , _success(c._success)
166 , _reason(c._reason)
167 , _notifyExceptions(c._notifyExceptions)
168 , _dontDelete(c._dontDelete)
169 {
170  QMutexLocker l(&_sampleLock);
171 
172  _refcount++;
173  _sampleCount++;
174 
175  //printf("VFS_request COPY CTOR!\n");
176 }
177 
178 
188 {
189  QMutexLocker l(&_sampleLock);
190 
191  _refcount--;
192  #ifdef DEBUG_DANGLING_REQUESTS
193  printf("DELETE REFCOUNT: %ld (%p) %s %s\n",_refcount,this,qUtf8Printable(_user),qUtf8Printable(_path));
194  #endif
195 
196 // if (_callback)
197 // delete _callback;
198 }
199 
200 
220 void VFS_request::timerEvent(QTimerEvent *)
221 {
222  printf("TIMEOUT: %s (%ld outstanding)!\n",requestTypeStrings[_requestType],_refcount);
223  printf("%s %s\n",qUtf8Printable(_initialPath),qUtf8Printable(this->toJson(0,true,true)));
224 
225  //delete this;
226  //printf("REFCOUNT: %ld (%lld)\n",_refcount,(quintptr)this);
227 }
228 
229 
236 {
237  QMutexLocker l(&_sampleLock);
238 
239  quint32 s = _sampleCount;
240  _sampleCount = 0;
241 
242  return s;
243 }
244 
245 
256 {
257  //printf("VFS_request::execute %p %p\n",this,_origin);
258 
259  if (!_success)
260  if (!(_metadata.contains("suppressError") && _metadata["suppressError"].toBool() == true))
261  {
262  if (_reason == "")
263  VFS::WARN( QString("VFS_request::execute %1 was not successful on '%2'").arg(requestTypeStrings[_requestType]).arg(_initialPath), 0, _user );
264  else
265  VFS::WARN( _reason, 0, _user );
266  }
267 }
268 
269 
287 {
288  if (_callback)
289  VFS::WARN("WARN: setting callback when one is already present!\n");
290 
291  _callback = c;
292  c->_isCallback = _callback ? true : false;
293 }
294 
295 
317 {
319  r->_data = _data;
320  r->_metadata = _metadata;
321  //r->_initialPath = _initialPath;
323  r->_session = _session;
324 
325  r->setCallback(this);
326 
327  return r;
328 }
329 
330 
337 {
338  if (_callback)
339  return true;
340 
341  return false;
342 }
343 
344 
356 {
357  _metadata = d->_metadata;
358  _data = d->_data;
359  _rawData = d->_rawData;
360  _session = d->_session;
361 
362  //_receiver = d->_receiver //NOT RECEIVER! callback will already have a receiver
363  //_origin = d->_origin //NOT ORIGIN!
364  //_callback = _callback //DEFINITELY NOT!
365  //_prefixPath = d->_prefixPath; //possibly, if we want to bypass a proxy requestor
366  //_requestType = d->_requestType //NOT TYPE! want to keep type of original caller
367 
368  //_path = d->_path;
369  //_initialPath = "XXXXX";
370 
371  _success = d->_success;
372 
373  //printf("COPY CALLBACK:\n%s\n%s\n",qUtf8Printable(_reason),qUtf8Printable(d->_reason));
374 
375  _reason = d->_reason;
376 }
377 
378 
391 VFS_request *VFS_request::createDiff(VFS_node *origin, QString originPath)
392 {
395  //r->_prefixPath = _prefixPath;
396  //r->_notifyExceptions = _notifyExceptions; //we don't want this! It needs to be a new request.
397  r->_originPath = originPath;
398 
399  return r;
400 }
401 
402 
415 QByteArray VFS_request::toJson(postID id, bool ignoreSuccess, bool includeInitialPath)
416 {
417  QJsonDocument d;
418  QJsonObject o;
419 
420  //o["class"] = "VFS_request";
421 
422  o["id"] = id;
423  o["type"] = _requestType;
424  //o["originPath"] = _originPath;
425  o["path"] = rutils::cleanPath(_path);
426  o["user"] = _user;
427 
428  if (includeInitialPath)
429  o["initialPath"] = _initialPath;
430 
431  //so we're not sending back the same data we received, or useless data if there's a failure
432  if (_success || ignoreSuccess)
433  {
434  if (!_metadata.empty())
435  o["metadata"] = _metadata;
436 
437  if (!_data.isEmpty())
438  o["data"] = _data.object();
439 
440  if (!_rawData.isEmpty())
441  o["rawdata"] = QJsonValue::fromVariant( _rawData.toBase64() );
442  }
443  else
444  o["reason"] = _reason;
445 
446  if (_session)
447  o["session"] = QString("0x%1").arg((quintptr)_session, QT_POINTER_SIZE * 2, 16, QChar('0'));
448 
449  o["success"] = _success;
450 
451  d.setObject(o);
452  return d.toJson();
453 }
454 
455 
466 void VFS_request::fromJsonObject(QJsonObject json, bool includeInitialPath)
467 {
468  _requestType = static_cast<VFS_request::requestType>(json["type"].toInt());
469  //_originPath = json["originPath"].toString();
470  _path = json["path"].toString();
471  _user = json["user"].toString();
472 
473  _success = json["success"].toBool();
474  _reason = json["reason"].toString("");
475 
476  if (includeInitialPath)
477  _initialPath = json["initialPath"].toString(_path); //FIXME: there may be cases where this is needed, but for tcp_mount, you wouldn't want this.
478 
479  if (json.contains("data"))
480  {
481  if (json["data"].isArray())
482  _data = QJsonDocument(json["data"].toArray()); //FIXME: I don't think this case ever happens
483  else
484  _data = QJsonDocument(json["data"].toObject());
485  }
486  else
487  _data = QJsonDocument();
488 
489  if (json.contains("rawdata"))
490  {
491  _rawData = QByteArray::fromBase64( json["rawdata"].toString().toUtf8() );
492  }
493 
494  _metadata = json["metadata"].toObject();
495 
496  //_session = ??
497 }
498 
499 
516 : QObject()
517 , _lock(QMutex::Recursive)
518 {
519  __addNode(this);
520 }
521 
522 
532 {
533  QMutexLocker l(&_lock);
534 
535  __removeNode(this);
536 
537  unmount();
538 
539  //printf("node dtor: %s...\n",qUtf8Printable(className()));
540  //VFS::LOG( QString("Deleting %1 (%2)").arg(className()).arg((quintptr)this) );
541  //printf("VFS_node::~VFS_node: %p\n",this);
542 
543  QString p;
544  VFS_node *o;
545 
546  int kc = 0;
547 
549 
550  kc = 0;
551  EXIT_DEPTH++;
552  while(!_children.isEmpty())
553  {
554  it = _children.begin();
555  p = it.key();
556  o = it.value();
557  remove(o);
558  //remove(p);
559  delete o;
560  //o->deleteLater();
561 
562  if (kc++ > 10000)
563  { printf("Error: deleting too many children!\n");
564  return;
565  //throw("Deleting too many children!");
566  }
567  }
568  EXIT_DEPTH--;
569 
570  //printf("node dtor 2...\n");
571 
572  emit finished(true);
573 }
574 
575 
576 QSet<VFS_node *> VFS_node::__allNodes;
577 QMutex VFS_node::__allNodesMutex(QMutex::Recursive);
578 
579 
589 {
590  QMutexLocker l(&__allNodesMutex);
591 
592  return __allNodes.contains(n);
593 }
594 
595 
604 {
605  QMutexLocker l(&__allNodesMutex);
606 
607  __allNodes.insert(n);
608 }
609 
610 
618 {
619  if (__isNode(n))
620  {
621  QMutexLocker l(&__allNodesMutex);
622  __allNodes.remove(n);
623  return true;
624  }
625 
626  return false;
627 }
628 
629 
655 QByteArray VFS_node::icon()
656 {
657  //to be overridden by meaningful data in subclasses
658 
659  if (isContainer())
660  return VFS_icons::get("folder"); //a default folder icon
661 
662  return VFS_icons::get("document"); //a default document icon
663 }
664 
665 
693 {
694  QMutexLocker _l(&_lock);
695 
697  QJsonObject a;
698 
699  for (it=_children.begin();it!=_children.end();it++)
700  {
701  a[it.key()] = it.value()->isContainer(); //bool means whether it's a container.
702  }
703 
704  r->_data = QJsonDocument(a);
705  r->_success = true;
706 }
707 
708 
725 {
726  if (isContainer() && r->_path == "")
727  {
728  if (!r->_metadata.contains("type"))
729  r->_metadata["type"] = "listing";
730  ls(r);
731  return;
732  }
733 
734  //VFS::WARN( r->_reason = QString("%1::read() has no default meaning on non-containers. Need to subclass?").arg(className()), 0, r->_user );
735  r->_success = false;
736 }
737 
738 
768 {
769  VFS::WARN( r->_reason = QString("%1::write() has no default meaning. Need to subclass?").arg(className()), 0, r->_user );
770  r->_success = false;
771 }
772 
773 
798 {
799  r->_metadata["icon"] = QString(icon());
800  //r->_metadata["class"] = className();
801 
802  r->_success = true;
803 }
804 
805 
818 {
819  QMutexLocker l(&_lock);
820 
821  QJsonDocument d = r->_data;
822  QJsonObject o;
823 
824  o["address"] = QString("0x%1").arg((quintptr)this, QT_POINTER_SIZE * 2, 16, QChar('0'));
825  o["class"] = className();
826  o["container"] = isContainer();
827  o["thread"] = QString("0x%1").arg((quintptr)thread(), QT_POINTER_SIZE * 2, 16, QChar('0'));
828  o["details"] = reportDetails();
829  o["icon"] = QString(icon());
830 
831  metadata(r); //get the metadata
832  //o["metadata"] = QJsonValue::fromVariant(r->_metadata);
833 
834  QJsonArray s; //subscriptions
835  VFS_subscriptionType::iterator si = _subscribers.begin();
836  while (si != _subscribers.end())
837  {
838  QString v = si.key();
839  VFS_subscriptionOrigin so = si.value();
840  VFS_subscriptionOrigin::iterator soi = so.begin();
841 
842  while(soi != so.end())
843  {
844  QString vo = soi.key();
845  VFS_subscriptionCounter cv = soi.value();
846  VFS_subscriptionCounter::iterator ci = cv.begin();
847 
848  while (ci != cv.end())
849  {
850  if (v!="")
851  {
852  //s.append( QString("%1 %4 ← (%2) ← %3").arg((quintptr)ci.key()).arg(ci.value()).arg(v).arg(vo) );
853  s.append( QString("%1 %4 ← (%2) ← %3").arg(QString("0x%1").arg((quintptr)ci.key(), QT_POINTER_SIZE * 2, 16, QChar('0'))).arg(ci.value()).arg(v).arg(vo) );
854  }
855  else
856  {
857  //s.append( QString("%1 %4 ← (%2)").arg((quintptr)ci.key()).arg(ci.value()).arg(vo) );
858  s.append( QString("%1 %4 ← (%2)").arg(QString("0x%1").arg((quintptr)ci.key(), QT_POINTER_SIZE * 2, 16, QChar('0'))).arg(ci.value()).arg(vo) );
859  }
860 
861  ci++;
862  }
863 
864  soi++;
865  }
866 
867  si++;
868  }
869  o["subscriptions"] = s;
870 
871  VFS_node *child;
872  bool childIsDir;
873  QJsonObject c; //children
874  VFS_childrenIterator ci = _children.begin();
875  while (ci != _children.end())
876  { child = ci.value();
877  //childIsDir = child->_children.size();
878  childIsDir = child->isContainer() || child->_children.size();
879  c[ci.key()+(childIsDir?"/":"")] = (qint64)((quintptr)child);
880  ci++;
881  }
882  o["children"] = c;
883 
884  d.setObject(o);
885 
886  r->_data = d;
887  r->_success = true;
888 }
889 
890 
901 {
902  return "";
903 }
904 
905 
919 {
920  r->_data.setObject( QJsonObject { { "default", true } } );
921  r->_success = true;
922 }
923 
924 
979 {
980  VFS::WARN( r->_reason = QString("%1::submit() has no default meaning. Need to subclass?").arg(className()), 0, r->_user );
981 
982  r->_success = true;
983 
984  emit diff(this,r);
985 }
986 
987 
1006 {
1007  if (r->_path == "" && _children.count()==0)
1008  {
1009  emit finished(true); //the parent listens for this
1010  r->_success = true;
1011 
1012  //unsubscribePath(r->_path); //unsubscribePath on this path... it no longer exists!
1013 
1014  return;
1015  }
1016 
1017  VFS::WARN( r->_reason = QString("%1::rm() cannot delete non-empty directory or bad path.").arg(className()), 0, r->_user );
1018  r->_success = false;
1019 }
1020 
1021 
1038 QString VFS_node::code(QString nodename, QString libname, QString &error)
1039 {
1040  /*
1041  A well-behaved node/library would probably load these from a qrc file or
1042  directly off the disk.
1043 
1044  Loading directly off disk is a nice idea, because the author could change
1045  source js files without recompiling.
1046 
1047  But, placing them directly in source code or qrc would obfuscate the code
1048  from those poking around, and also encapsulate them in a lib
1049  */
1050 
1051  error = QString("Cannot load library: %1:%2").arg(nodename).arg(libname);
1052 
1053  return "";
1054 }
1055 
1056 
1066 {
1067  VFS::WARN( r->_reason = QString("%1::requestLock() has no default meaning. Need to subclass?").arg(className()), 0, r->_user );
1068 
1069  r->_success = false;
1070 }
1071 
1072 
1082 {
1083  VFS::WARN( r->_reason = QString("%1::releaseLock() has no default meaning. Need to subclass?").arg(className()), 0, r->_user );
1084 
1085  r->_success = false;
1086 }
1087 
1088 
1101 {
1102  VFS_request r(VFS_request::none,nullptr,path);
1103  r._metadata["suppressError"] = true;
1104  return find( &r );
1105 }
1106 
1107 
1136 {
1137  QStringList pl = r->_path.split("/",Qt::SkipEmptyParts);
1138 
1139  if (pl.isEmpty())
1140  return this;
1141 
1142  QMutexLocker l(&_lock);
1143 
1144  QString p = pl.takeFirst();
1145  if (_children.contains(p))
1146  {
1147  r->_path = pl.join("/");
1148  r->_prefixPath += p;
1149  return _children[p]->find(r);
1150  }
1151 
1153  if (!r->_metadata.value("suppressError").toBool(false))
1154  { //r->_reason = QString("%1 non-existent path: '%2' (%3 on '%4' => '%5') %6 %7 %8").arg(className()).arg(p).arg(VFS_request::requestTypeStrings[r->_requestType]).arg(r->_prefixPath.join("/")).arg(r->_initialPath).arg((quintptr)r,0,16).arg((quintptr)r->_origin,0,16).arg(qUtf8Printable(r->_data.toJson()));
1155  r->_reason = QString("%1 non-existent path: '%2' (%3 on '%4' => '%5')").arg(className()).arg(p).arg(VFS_request::requestTypeStrings[r->_requestType]).arg(r->_prefixPath.join("/")).arg(r->_initialPath);
1156  //printf("JSON: %s\n",qUtf8Printable(r->toJson(0,true,true)));
1157  }
1158 
1159  r->_success = false;
1160 
1161  return nullptr;
1162 }
1163 
1164 
1205 {
1206  VFS_node *subscriber = r->_origin;
1207  QString subscriberSubpath = rutils::cleanPath( r->_originPath );
1208 
1209  //FIXME: check that this does not create a circular subscription reference!
1210 
1211  if (__isNode(subscriber))
1212  {
1213  //only lock until _subscribers is updated
1214  {
1215  QMutexLocker l(&_lock);
1216 
1217  int count = r->_metadata.value("subscriptions").toInt(1);
1218  _subscribers[r->_path][subscriberSubpath][subscriber]+=count; //will create default/empty values as needed.
1219  }
1220 
1221  connect( subscriber, SIGNAL(unmounted(VFS_node *)), this, SLOT(unsubscribeAll(VFS_node *)), Qt::UniqueConnection );
1222 
1223  if (!r->_isCallback)
1224  {
1225  metadata(r);
1226  if (!r->_success) return;
1227  }
1228 
1229  if (!r->_metadata.contains("__SUBSCRIBE_ONLY__") || r->_metadata["__SUBSCRIBE_ONLY__"].toBool()!=true)
1230  if (!r->_isCallback)
1231  {
1232  read(r);
1233  if (!r->_success) return;
1234  }
1235  //else
1236  // printf("WAS CALLBACK!\n");
1237 
1238  //r->_success = true;
1239 
1240  //VFS::LOG( QString("%1 subscribe on %2 (%3->%4)").arg(className()).arg(r->_path).arg((quintptr)subscriber).arg(subscriber->className()) );
1241  }
1242  else
1243  VFS::ERROR( r->_reason = "Cannot subscribe null subscriber.", 0, r->_user );
1244 }
1245 
1246 
1264 {
1265  QMutexLocker l(&_lock);
1266 
1267  VFS_node *subscriber = r->_origin;
1268 
1269  if (subscriber)
1270  {
1271  //printf("Unsubscribing: %s\n",qUtf8Printable(r->_path));
1272  if (_subscribers.contains(r->_path) && _subscribers.value(r->_path).value(r->_originPath).contains(subscriber))
1273  {
1274  int count = r->_metadata.value("unsubscriptions").toInt(1);
1275 
1276  if ((_subscribers[r->_path][r->_originPath][subscriber]-=count) <= 0) //decrement the count
1277  { _subscribers[r->_path][r->_originPath].remove(subscriber); //remove if zero
1278  //printf("REMOVED 1: %d\n",count);
1279  }
1280 
1281  if (!_subscribers.value(r->_path).value(r->_originPath).size())
1282  { _subscribers[r->_path].remove(r->_originPath);
1283  //printf("REMOVED 2\n");
1284  }
1285 
1286  if (!_subscribers.value(r->_path).size()) //clean up the path part
1287  { _subscribers.remove(r->_path); //remove if empty
1288  //printf("REMOVED 3\n");
1289  }
1290 
1291  int i=0;
1292  //Check if no subscriptions are left for subscriber
1293  //recurse through all subscription paths to count subscriber references
1294  VFS_subscriptionType::iterator it = _subscribers.begin();
1295  while (it != _subscribers.end())
1296  {
1297  VFS_subscriptionOrigin o = it.value();
1298  VFS_subscriptionOrigin::iterator ito = o.begin();
1299  while (ito != o.end())
1300  {
1301  i+= ito.value().count(subscriber);
1302  ito++;
1303  }
1304 
1305  it++;
1306  }
1307 
1308  if (i==0)
1309  { disconnect( subscriber, SIGNAL(unmounted(VFS_node *)), this, SLOT(unsubscribeAll(VFS_node *)) );
1310  //disconnect( this, SIGNAL(diff(VFS_request*)), subscriber, SLOT(applyDiff(VFS_request*)) );
1311  }
1312 
1313  r->_success = true;
1314  }
1315  else
1316  { //r->_reason = QString("%1 Unable to unsubscribe from '%2'... was it subscribed?").arg(className()).arg(r->_path);
1317  r->_success = true; //consider all properly-formed unsubscribe operations to be a success, regardless of if a subscription existed.
1318  }
1319  }
1320  else
1321  { //VFS::ERROR( r->_reason = "Unable to unsubscribe without a subscriber...", 0, r->_user );
1322  r->_reason = "Unable to unsubscribe without a subscriber...";
1323  }
1324 }
1325 
1326 
1337 {
1338  QMutexLocker l(&_lock);
1339 
1340  int c;
1341 
1342  QMutableMapIterator<QString, VFS_subscriptionOrigin > ito(_subscribers);
1343  while (ito.hasNext())
1344  {
1345  ito.next();
1346 
1347  QMutableMapIterator<QString, VFS_subscriptionCounter > it(ito.value());
1348  while (it.hasNext())
1349  {
1350  it.next();
1351 
1352  c=it.value().remove(subscriber);
1353  //if ((c=it.value().remove(subscriber)))
1354  //{ VFS::LOG( QString("unsubscribeAll removed '%1' (%2)").arg(it.key()).arg(c), 9 );
1355  //}
1356 
1357  if (!it.value().size())
1358  it.remove();
1359  //_subscribers.remove(it.key())
1360 
1361  if (c)
1362  VFS::LOG( QString("unsubscribeAll removed '%1' %2 (%3)").arg(ito.key()).arg(className()).arg(c), 9 );
1363  }
1364 
1365  if (!ito.value().size())
1366  ito.remove();
1367  }
1368 
1369  //rely on the VFS_node's destructor to do the cleanup...
1370  //disconnect( subscriber, SIGNAL(unmounted(VFS_node *)), this, SLOT(unsubscribeAll(VFS_node *)) );
1371 }
1372 
1373 
1385 {
1386  QMutexLocker l(&_lock);
1387 
1388  if (_subscribers.contains(path))
1389  {
1391  VFS_subscriptionOrigin::iterator i = so.begin();
1392  while (i != so.end())
1393  {
1394  QString k = i.key();
1395  VFS_subscriptionCounter v = i.value();
1396  int c = 0;
1397  VFS_subscriptionCounter::iterator ci = v.begin();
1398  while (ci != v.end())
1399  { c += ci.value();
1400  ci++;
1401  }
1402 
1403  //l.unlock(); //don't emit when locked
1404 
1405  //printf("emit null unsubscribe diff: %s / %s / %d\n",qUtf8Printable(path),qUtf8Printable(k),c);
1406  VFS_request *r = createRequest(VFS_request::none,path,"server"); //emit a null diff to notify subscribers of the removal
1407  emit diff(this,r);
1408  delete r;
1409 
1410  //l.relock(); //but re-lock for the next loop
1411 
1412  i++;
1413  }
1414  }
1415 
1416  if (!_subscribers.remove(path))
1417  {
1418  //FIXME: seems like we would want this message, except in the case of rm() it will probably be for a non-existent path
1419  //VFS::ERROR( QString("%1 unable to unsubscribePath from '%2'... was it subscribed?").arg(className()).arg(path) );
1420 
1421  /*
1422  VFS::WARN( QString("%1 unable to unsubscribePath from '%2'... was it subscribed?").arg(className()).arg(path) );
1423  VFS_subscriptionIterator si = _subscribers.begin();
1424  while (si != _subscribers.end())
1425  {
1426  QString v = si.key();
1427  VFS_subscriptionCounter cv = si.value();
1428  VFS_subscriptionCounterIterator ci = cv.begin();
1429 
1430  while (ci != cv.end())
1431  {
1432  if (v!="")
1433  VFS::WARN( QString("%2 ← (%3) ← %1").arg(v).arg((quintptr)ci.key()).arg(ci.value()) );
1434  else
1435  VFS::WARN( QString("%1 ← (%2)").arg((quintptr)ci.key()).arg(ci.value()) );
1436 
1437  ci++;
1438  }
1439 
1440  si++;
1441  }
1442  */
1443  }
1444 }
1445 
1446 
1464 {
1465  //VFS::WARN( QString("%1::applyDiff() has no default meaning. Need to subclass?").arg(className()), 0, r->_user );
1466 
1467  //notifySubscribers(this,r); //This is already linked via connect() to the diff() signal.
1468  emit diff(this,r);
1469 
1470  r->_success = true;
1471 }
1472 
1473 
1498 {
1499  QMutexLocker lk(&_lock);
1500 
1501  //no need to send empty data around
1502  if (t->_data.isEmpty() && t->_metadata.isEmpty())
1503  { printf("SKIPPING notify on empty request: %s\n",qUtf8Printable(t->_path));
1504  return;
1505  }
1506 
1507  VFS_request *r;
1508  VFS_subscriptionOrigin origins = _subscribers.value(t->_path); //will return empty QMap if non-existant
1509 
1510  foreach(QString o, origins.keys())
1511  {
1512  VFS_subscriptionCounter subscribers = origins.value(o);
1513 
1514  foreach(VFS_node *s,subscribers.keys())
1515  {
1516  //printf(" CHECK: %p \"%s\"\n",s,qUtf8Printable(t->_initialPath));
1517  //if (true)
1518  if ( ! t->_notifyExceptions.contains( notifyException(s,t->_initialPath) ) )
1519  {
1520  //printf( " EMIT: %p \"%s\" \"%s\"\n", s, qUtf8Printable(t->_path), qUtf8Printable( t->_initialPath ) );
1521 
1522  QMutexLocker l(&VFS_node::__allNodesMutex);
1523  if (__isNode(s))
1524  {
1525  //printf(" Origin: %s %s %s\n",qUtf8Printable(o),qUtf8Printable(t->_path),qUtf8Printable(t->_initialPath));
1526 
1527  // r = new VFS_request(VFS_request::diff,origin,t->_path,t->_user,t->_data,t->_metadata);
1528  // r->_initialPath = t->_initialPath;
1529  // //r->_prefixPath = t->_prefixPath;
1530  // //r->_notifyExceptions = t->_notifyExceptions; //we don't want this! It needs to be a new request.
1531  // r->_originPath = o;
1532 
1533  r = t->createDiff(origin,o);
1534 
1535  //may want to unlock lk now
1536  //lk.unlock();
1537 
1538  QMetaObject::invokeMethod( s, "executeRequest", Qt::AutoConnection, Q_ARG(VFS_request*, r) );
1539  //QMetaObject::invokeMethod( s, "executeRequest", Qt::QueuedConnection, Q_ARG(VFS_request*, r) );
1540 
1541  //...and relock lk here
1542  //lk.relock();
1543  }
1544  //else
1545  // printf(" Not a node!\n");
1546  }
1547  else
1548  { //printf( " SKIP: %p %s \"%s\"\n", s, qUtf8Printable(t->_path), qUtf8Printable( t->_initialPath ) );
1549  }
1550  }
1551  }
1552 }
1553 
1554 
1566 VFS_node *VFS_node::append(QString name, VFS_node *node, bool containerCheck, QString user)
1567 {
1568  if (containerCheck)
1569  if (!isContainer())
1570  { VFS::ERROR( QString("Cannot append '%1' to a %2 node where isContainer() is false. Not appending.").arg(name).arg(className()) );
1571  return nullptr;
1572  }
1573 
1574  if (!validChildName(name))
1575  { VFS::ERROR( QString("Node name is invalid: '%1'. Not appending.").arg(name) );
1576  return nullptr;
1577  }
1578 
1579  if (_children.contains(name))
1580  { VFS::ERROR( QString("Child with name '%1' already exists. Not appending.").arg(name) );
1581  return nullptr;
1582  }
1583 
1584  if (!node)
1585  { VFS::ERROR( QString("Cannot append null node '%1'").arg(name) );
1586  return nullptr;
1587  }
1588 
1589  //new context for the lock to expire...
1590  //we want this to be unlocked when diff() is emitted because we don't know what thread we're in
1591  {
1592  connect(node, SIGNAL(finished(bool)), this, SLOT(remove(bool)));
1593 
1594  QMutexLocker l(&_lock);
1595 
1596  _children[name] = node->mount();
1597  }
1598 
1599  VFS::LOG( QString("Appended node '%1'").arg(name), 8, user );
1600 
1601  //do ACL check for defaults here
1602  /*
1603  if (VFS_acl::hasRegisteredDefaults( node->className() ))
1604  {
1605  printf("Would add features to %s node\n", qUtf8Printable(node->className()));
1606  //VFS_acl::includeACLDefaults(env["vfscwd"].toString(), node->className());
1607  }
1608  */
1609 
1610  QJsonObject d;
1611  d[name] = node->isContainer();
1612  VFS_request r(VFS_request::diff,this,"",user);
1613  r._data = QJsonDocument(d);
1614  emit diff(this,&r);
1615 
1616  return node;
1617 }
1618 
1619 
1629 void VFS_node::remove(bool andDelete)
1630 {
1631  VFS_node *node = dynamic_cast< VFS_node * >(sender());
1632  //VFS_node *node = qobject_cast< VFS_node * >(sender());
1633 
1634  if (node)
1635  {
1636  remove();
1637 
1638  if (andDelete)
1639  //delete node;
1640  node->deleteLater();
1641  }
1642  else
1643  VFS::WARN( QString("%1 No sender found... unable to remove()").arg(className()) );
1644 }
1645 
1646 
1660 void VFS_node::remove(VFS_node *node, QString *rname, QString user)
1661 {
1662  //printf("REMOVE: %p\n",this);
1663 
1664  if (!node)
1665  node = dynamic_cast< VFS_node * >(sender());
1666 
1667  //printf("REMOVE: %p %p\n",node,this);
1668 
1669  if (node)
1670  {
1671  QMutexLocker l(&_lock);
1672 
1673  QString name = _children.key(node,"");
1674 
1675  if (_children.contains(name))
1676  {
1677  if (rname) (*rname) = name;
1678 
1679  VFS_node *node = _children.take(name);
1680 
1681  disconnect(node, SIGNAL(finished(bool)), this, SLOT(remove(bool)));
1682 
1683  node->unmount();
1684 
1685  VFS::LOG( QString("Removing node%2'%1'").arg(name).arg(' ',(EXIT_DEPTH-1)*3), 8, user );
1686 
1687  l.unlock(); //want to release this before the diff is emitted
1688 
1689  //VFS_request r(VFS_request::diff,this,"","server");
1690  QJsonObject d;
1691  d[name] = QJsonValue::Null;
1692  VFS_request r(VFS_request::diff,this,"",user);
1693  r._data = QJsonDocument(d);
1694  emit diff(this,&r);
1695  }
1696  else
1697  VFS::WARN( QString("Unable to unmount node '%1'").arg(name) );
1698  }
1699  else
1700  { VFS::WARN( QString("Unable to unmount null node") );
1701  //emit finished(true);
1702  }
1703 }
1704 
1705 
1719 {
1720  connect( this, SIGNAL(diff(VFS_node *,VFS_request *)),
1721  this, SLOT(notifySubscribers(VFS_node *,VFS_request *)) );
1722 
1723  //setParent(_mount);
1724 
1725  emit mounted();
1726 
1727  return this;
1728 }
1729 
1730 
1743 {
1744  disconnect( this, SIGNAL(diff(VFS_node *,VFS_request *)),
1745  this, SLOT(notifySubscribers(VFS_node *,VFS_request *)) );
1746 
1747  emit unmounted(this);
1748 
1749  //disconnect( this, SIGNAL(unmounted(VFS_node *)));
1750 
1751  return this;
1752 }
1753 
1754 
1768 {
1769  //QMutexLocker l(&_lock);
1770 
1771  VFS_node *n = find(t);
1772 
1773  if (n)
1774  {
1775  n->executeRequest(t);
1776  }
1777  else
1778  {
1780  {
1781  //if (!t->_session || __isNode(t->_session))
1782  if (!(t->_metadata.contains("suppressError") && t->_metadata["suppressError"].toBool(false) == true))
1783  {
1784  if (t->_reason == "")
1785  t->_reason = QString("%1 request on path '%2' could not be found.").arg(VFS_request::requestTypeStrings[t->_requestType]).arg(t->_initialPath);
1786  //this causes duplicate warning messages
1787  //VFS::WARN( t->_reason, 0, t->_user );
1788  }
1789  }
1790 
1791  t->_success = false;
1792 
1793  issueResponse(t);
1794  }
1795 }
1796 
1797 
1810 {
1811  //QMutexLocker l(&_lock);
1812 
1813  try
1814  {
1815  switch(t->_requestType)
1816  {
1817  case VFS_request::none: VFS::WARN( "Cannot execute request on VFS_request::none." ); break;
1818 
1819  case VFS_request::ls: ls(t); break;
1820  case VFS_request::create: write(t); break;
1821  case VFS_request::rm: rm(t); break;
1822  case VFS_request::read: read(t); break;
1823  case VFS_request::write: write(t); break;
1824  case VFS_request::metadata: metadata(t); break;
1825  case VFS_request::diff: applyDiff(t); break;
1826  case VFS_request::submit: submit(t); break;
1827  case VFS_request::subscribe: subscribe(t); break;
1828  case VFS_request::unsubscribe: unsubscribe(t); break;
1829  case VFS_request::acl: aclDefaults(t); break;
1830  case VFS_request::report: report(t); break;
1831  case VFS_request::requestlock: requestLock(t); break;
1832  case VFS_request::releaselock: releaseLock(t); break;
1833 
1834  default: VFS::WARN( QString("Unknown requestType: %1").arg(t->_requestType) ); break;
1835  }
1836  }
1837  catch (std::exception &e)
1838  {
1839  VFS::ERROR( QString("executeRequest() caught exception for %1 operation: %2").arg(VFS_request::requestTypeStrings[t->_requestType]).arg(e.what()), 0, className());
1840  t->_success = false;
1841  exit(3);
1842  }
1843  catch (...)
1844  {
1845  VFS::ERROR( QString("executeRequest() caught exception for %1 operation").arg(VFS_request::requestTypeStrings[t->_requestType]), 0, className());
1846  t->_success = false;
1847  exit(3);
1848  }
1849 
1850  if (!t->_isCallback)
1851  issueResponse(t);
1852 }
1853 
1854 
1871 {
1872  //printf("VFS_node::receiveResponse %p %s %s\n",t,qUtf8Printable(t->_initialPath),qUtf8Printable(t->_data.object()["data"].toString()));
1873 
1874  if (t)
1875  {
1876  t->execute();
1877 
1878  if (t->_callback)
1879  { //printf("Issuing response to callback on '%s'.\n",qUtf8Printable(t->_initialPath));
1880  t->_callback->copyCallback(t);
1882  }
1883 
1884  if (!t->_dontDelete)
1885  delete t;
1886  }
1887  else
1888  VFS::ERROR( "receiveResponse() called with null request." );
1889 }
1890 
1891 
1913 VFS_request *VFS_node::createRequest(VFS_request::requestType type, QString path, QString user, QJsonDocument data, QJsonObject metadata, bool dontDelete)
1914 {
1915  VFS_request *r = new VFS_request(type,this,path,user,data,metadata,dontDelete);
1916  return r;
1917 }
1918 
1919 
1934 {
1935  issueRequest(VFS::root(),t);
1936 }
1937 
1938 
1956 {
1957  QMutexLocker l(&VFS_node::__allNodesMutex);
1958  if (__isNode(target))
1959  {
1960  QMetaObject::invokeMethod(target,"subtreeRequest",Qt::AutoConnection,Q_ARG(VFS_request*, t));
1961  //QMetaObject::invokeMethod(target,"subtreeRequest",Qt::QueuedConnection,Q_ARG(VFS_request*, t));
1962  }
1963  else
1964  { printf("issueRequest() called without a node. Deleting request.\n");
1965  delete t;
1966  }
1967 }
1968 
1969 
1982 {
1983  //QMutexLocker l(&_lock);
1984 
1985  if (t && t->_origin)
1986  {
1987  VFS_node *target = t->_origin;
1988 
1989  t->_responder = this;
1990 
1991  QMutexLocker l(&VFS_node::__allNodesMutex);
1992  if (__isNode(target))
1993  {
1994  QMetaObject::invokeMethod(target,"receiveResponse",Qt::AutoConnection,Q_ARG(VFS_request*, t));
1995  //QMetaObject::invokeMethod(target,"receiveResponse",Qt::QueuedConnection,Q_ARG(VFS_request*, t));
1996  }
1997  else
1998  { //printf("RESPONSE TARGET IS NOT A NODE for %s... deleting request.\n",qUtf8Printable(t->_initialPath));
1999  delete t;
2000  }
2001  }
2002  else
2003  { VFS::ERROR( "issueResponse() called with null request or no receiver. Deleting request." );
2004  delete t;
2005  }
2006 }
2007 
2008 
2026 {
2027  return true;
2028 }
2029 
2030 
2040 {
2041  return metaObject()->className();
2042 }
2043 
2044 
2055 {
2056  QMutexLocker l(&_lock);
2057 
2058  int i=1;
2059  QString temp = name;
2060 
2061  //FIXME: this should not return a name that does not pass validChildName(name)
2062  while (_children.contains(temp))
2063  temp = QString("%1-%2").arg(name).arg(i++);
2064 
2065  return temp;
2066 }
2067 
2068 
2079 {
2080  QMutexLocker l(&_lock);
2081 
2082  return _children.value(name,nullptr);
2083 }
2084 
2085 
2102 {
2103  if (name.trimmed().isEmpty()) return false; //can't be empty
2104  if (name.contains(QRegExp("[/]"))) return false; //bad chars. Really the only bad one is a slash.
2105  if (name.trimmed() != name) return false; //can't start or end with whitespace; that's just dumb
2106 
2107  return true;
2108 }
2109 
2110 
2131 void VFS_node::addACLDefault( QJsonObject &acl, bool value, QString description )
2132 {
2133  acl["default"] = value;
2134  if (!description.isEmpty())
2135  acl["description"] = description;
2136 }
2137 
2138 
2148 void VFS_node::addACLGroup( QJsonObject &acl, QString group, bool value )
2149 {
2150  QJsonObject g = acl["groups"].toObject();
2151  g[group] = value;
2152  acl["groups"] = g;
2153 }
2154 
2155 
2165 void VFS_node::addACLUser( QJsonObject &acl, QString user, bool value )
2166 {
2167  QJsonObject u = acl["users"].toObject();
2168  u[user] = value;
2169  acl["users"] = u;
2170 }
2171 
2172 
2183 void VFS_node::addACLFeature( QJsonObject &acl, QString feature, bool value, QString description )
2184 {
2185  QJsonObject fs = acl["features"].toObject();
2186  QJsonObject f = fs[feature].toObject();
2187  f["default"] = value;
2188  if (!description.isEmpty())
2189  f["description"] = description;
2190  fs[feature] = f;
2191  acl["features"] = fs;
2192 }
2193 
2194 
2205 void VFS_node::addACLFeatureGroup( QJsonObject &acl, QString feature, QString group, bool value )
2206 {
2207  QJsonObject fs = acl["features"].toObject();
2208  QJsonObject f = fs[feature].toObject();
2209  QJsonObject g = f["groups"].toObject();
2210  g[group] = value;
2211  f["groups"] = g;
2212  fs[feature] = f;
2213  acl["features"] = fs;
2214 }
2215 
2216 
2227 void VFS_node::addACLFeatureUser( QJsonObject &acl, QString feature, QString user, bool value )
2228 {
2229  QJsonObject fs = acl["features"].toObject();
2230  QJsonObject f = fs[feature].toObject();
2231  QJsonObject u = f["users"].toObject();
2232  u[user] = value;
2233  f["users"] = u;
2234  fs[feature] = f;
2235  acl["features"] = fs;
2236 }
int EXIT_DEPTH
Definition: VFS_node.cpp:42
QPair< VFS_node *, QString > notifyException
Definition: VFS_node.h:42
quint16 postID
Definition: VFS_node.h:24
QMap< QString, VFS_node * >::const_iterator VFS_childrenConstIterator
Definition: VFS_node.h:40
QMap< VFS_node *, qint32 > VFS_subscriptionCounter
Definition: VFS_node.h:29
QMap< QString, VFS_node * >::iterator VFS_childrenIterator
Definition: VFS_node.h:39
QMap< QString, VFS_subscriptionCounter > VFS_subscriptionOrigin
Definition: VFS_node.h:35
static char * get(QString which="")
Fetch an icon from the library.
Definition: VFS_icons.cpp:34
VFS_node is the base class from which all other VFS_node classes derive.
Definition: VFS_node.h:143
virtual VFS_node * unmount()
Unmount this node.
Definition: VFS_node.cpp:1742
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 executeRequest(VFS_request *t)
Based on the VFS_request::requestType, execute the function associated with an operation.
Definition: VFS_node.cpp:1809
virtual bool validChildName(QString name)
Check if a node name is valid.
Definition: VFS_node.cpp:2101
virtual VFS_request * createRequest(VFS_request::requestType type, QString path, QString user="unknown", QJsonDocument data=QJsonDocument(), QJsonObject metadata=QJsonObject(), bool dontDelete=false)
Create a new VFS_request with this object as _origin.
Definition: VFS_node.cpp:1913
VFS_children _children
This node's children.
Definition: VFS_node.h:179
virtual void read(VFS_request *r)
Return the data contents of this node, or if it's a container call ls()
Definition: VFS_node.cpp:724
virtual void issueResponse(VFS_request *t)
Once a request has been completed, issue a response.
Definition: VFS_node.cpp:1981
Q_INVOKABLE VFS_node()
The VFS_node constructor will add its instance to the VFS_node::__allNodes global node registry,...
Definition: VFS_node.cpp:515
void addACLGroup(QJsonObject &acl, QString group, bool value)
Add a group to the acl object.
Definition: VFS_node.cpp:2148
virtual void metadata(VFS_request *r)
Fetch the metadata of this node.
Definition: VFS_node.cpp:797
static bool __removeNode(VFS_node *)
Remove a node from the global registry.
Definition: VFS_node.cpp:617
virtual void requestLock(VFS_request *r)
Request a lock on this node.
Definition: VFS_node.cpp:1065
QString uniqueChildName(QString name)
Generate a unique child name.
Definition: VFS_node.cpp:2054
virtual void report(VFS_request *r)
Report debugging information about the current state of this node.
Definition: VFS_node.cpp:817
virtual void unsubscribeAll(VFS_node *n)
Remove all references to a subscriber from this node.
Definition: VFS_node.cpp:1336
virtual void submit(VFS_request *r)
Submit a diff to a node.
Definition: VFS_node.cpp:978
virtual void issueRequest(VFS_request *t)
A convenience function.
Definition: VFS_node.cpp:1933
static bool __isNode(VFS_node *)
Check to see if a node is in the global registry.
Definition: VFS_node.cpp:588
void addACLFeatureUser(QJsonObject &acl, QString feature, QString user, bool value)
Add a feature user to the acl object.
Definition: VFS_node.cpp:2227
void addACLFeature(QJsonObject &acl, QString feature, bool value, QString description="")
Add a feature to the acl object.
Definition: VFS_node.cpp:2183
VFS_node * findChildWithName(QString name)
Check if a child with a given name exists.
Definition: VFS_node.cpp:2078
VFS_node * find(QString path)
Find a node by string path.
Definition: VFS_node.cpp:1100
virtual void write(VFS_request *r)
Write data to this node.
Definition: VFS_node.cpp:767
virtual void releaseLock(VFS_request *r)
Release a lock on this node.
Definition: VFS_node.cpp:1081
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 mounted()
Emitted when a node is mount()ed.
static QString code(QString nodename, QString libname, QString &error)
Fetch code or any other resource from a node.
Definition: VFS_node.cpp:1038
void unmounted(VFS_node *self)
Emitted when a node is unmount()ed.
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
VFS_subscriptionType _subscribers
This node's subscribers. These subscribers will receive diff notifications.
Definition: VFS_node.h:180
void remove(bool andDelete)
Remove a child node.
Definition: VFS_node.cpp:1629
virtual bool isContainer()
A VFS_node may have children.
Definition: VFS_node.cpp:2025
void addACLFeatureGroup(QJsonObject &acl, QString feature, QString group, bool value)
Add a feature group to the acl object.
Definition: VFS_node.cpp:2205
void addACLUser(QJsonObject &acl, QString user, bool value)
Add a user to the acl object.
Definition: VFS_node.cpp:2165
virtual ~VFS_node()
VFS_node destructor.
Definition: VFS_node.cpp:531
void addACLDefault(QJsonObject &acl, bool value, QString description="")
Add a default value to the acl object.
Definition: VFS_node.cpp:2131
virtual void unsubscribePath(QString path)
Unsubscribe all references to a subpath.
Definition: VFS_node.cpp:1384
QMutex _lock
A recursive mutex that is local to this node.
Definition: VFS_node.h:178
virtual void subtreeRequest(VFS_request *t)
find() the target of a VFS_request, and execute the request
Definition: VFS_node.cpp:1767
void notifySubscribers(VFS_node *origin, VFS_request *t)
Propagate a diff to subscribers.
Definition: VFS_node.cpp:1497
static void __addNode(VFS_node *)
Add a node to the global registry.
Definition: VFS_node.cpp:603
static QSet< VFS_node * > __allNodes
The static global registry for all exiting nodes, used for thread safety checks.
Definition: VFS_node.h:215
virtual void applyDiff(VFS_request *r)
Apply a diff received via subscription.
Definition: VFS_node.cpp:1463
virtual void rm(VFS_request *r)
Remove a child entry from a node, or the node itself.
Definition: VFS_node.cpp:1005
virtual void aclDefaults(VFS_request *r)
Return default values and features associated wth this node.
Definition: VFS_node.cpp:918
virtual QString reportDetails()
Additional details for a generated report.
Definition: VFS_node.cpp:900
static QMutex __allNodesMutex
The global registry mutex, which will lock when node creation or deletion is being performed.
Definition: VFS_node.h:216
void finished(bool andDelete=false)
Emitted if a thread fails to create its node, or a node is rm()'d, or any other reason a node has com...
virtual void unsubscribe(VFS_request *r)
Remove an entry from this node's _subscription list.
Definition: VFS_node.cpp:1263
virtual VFS_node * mount()
Mount this node.
Definition: VFS_node.cpp:1718
virtual void subscribe(VFS_request *r)
Add an entry to this node's _subscription list.
Definition: VFS_node.cpp:1204
virtual void receiveResponse(VFS_request *t)
Once a VFS_request has been completed, a response will be issued back to its _origin.
Definition: VFS_node.cpp:1870
The base class for all requests between nodes.
Definition: VFS_node.h:54
static const char * requestTypeStrings[]
A printable string for each request type.
Definition: VFS_node.h:127
requestType
Requests perform one of these actions.
Definition: VFS_node.h:63
@ diff
send a diff (7)
Definition: VFS_node.h:71
@ read
read full contents (4)
Definition: VFS_node.h:68
@ report
provide node report, for debugging (12)
Definition: VFS_node.h:76
@ requestlock
request a lock (13)
Definition: VFS_node.h:77
@ unsubscribe
unsubscribe from a path (10)
Definition: VFS_node.h:74
@ ls
list children of a node (1)
Definition: VFS_node.h:65
@ acl
return the ACL defaults for this node (11)
Definition: VFS_node.h:75
@ metadata
read metadata (6)
Definition: VFS_node.h:70
@ create
create a new file/path (2)
Definition: VFS_node.h:66
@ write
write full contents (5)
Definition: VFS_node.h:69
@ releaselock
release a lock (14)
Definition: VFS_node.h:78
@ subscribe
subscribe to a path (9)
Definition: VFS_node.h:73
@ submit
apply a diff (8)
Definition: VFS_node.h:72
@ rm
delete an existing file/path (3)
Definition: VFS_node.h:67
virtual ~VFS_request()
VFS_request destructor.
Definition: VFS_node.cpp:187
VFS_node * _responder
the receiver of the request
Definition: VFS_node.h:92
static QMutex _sampleLock
A mutex to protect thread safety of samples.
Definition: VFS_node.h:124
VFS_node * _origin
the origin of the request
Definition: VFS_node.h:89
virtual void setCallback(VFS_request *c)
Chain a callback onto this request.
Definition: VFS_node.cpp:286
QByteArray _rawData
the request payload, but raw data
Definition: VFS_node.h:103
bool hasCallback()
Check if this request has a callback set.
Definition: VFS_node.cpp:336
VFS_request(requestType type=VFS_request::none, VFS_node *origin=nullptr, QString path="", QString user="unknown", QJsonDocument data=QJsonDocument(), QJsonObject metadata=QJsonObject(), bool dontDelete=false)
VFS_request constructor.
Definition: VFS_node.cpp:74
requestType _requestType
the action this request is performing or requesting
Definition: VFS_node.h:87
static quint32 getSample()
Get the current sample count and clear the counter.
Definition: VFS_node.cpp:235
static quint32 _sampleCount
A count of the number of VFS_requests since the last sample was taken.
Definition: VFS_node.h:123
QString _initialPath
the target path when the request was made (relative to the responder)
Definition: VFS_node.h:93
QStringList _prefixPath
the prefix elements found while searching for the target
Definition: VFS_node.h:94
bool _dontDelete
A rarely used flag that will cause VFS_node::receiveResponse to not delete the node,...
Definition: VFS_node.h:112
QString _user
who initiated this request, mostly for logging
Definition: VFS_node.h:106
virtual void copyCallback(VFS_request *d)
Copy the data from a callback to this VFS_request.
Definition: VFS_node.cpp:355
virtual void fromJsonObject(QJsonObject json, bool includeInitialPath=false)
Deserialize a JSON string into a VFS_request.
Definition: VFS_node.cpp:466
virtual void execute()
after a request has completed, a request may have a special execute function.
Definition: VFS_node.cpp:255
VFS_session * _session
The session associated with this request. This is an optional value, and care should be taken to chec...
Definition: VFS_node.h:105
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 _isCallback
whether or not to issue a response (IE, another request is chained to this request,...
Definition: VFS_node.h:98
virtual VFS_request * createDiff(VFS_node *origin, QString originPath)
VFS_request::createDiff.
Definition: VFS_node.cpp:391
QString _originPath
the subpath of the origin node
Definition: VFS_node.h:90
QList< notifyException > _notifyExceptions
a list of nodes not to send responses to for this transaction. For instance if a node submits to a no...
Definition: VFS_node.h:110
bool _success
if the request was successfully completed
Definition: VFS_node.h:107
QJsonDocument _data
the request payload
Definition: VFS_node.h:102
virtual VFS_request * getCallback(VFS_node *receiver)
Create and chain a VFS_request for a receiver.
Definition: VFS_node.cpp:316
VFS_request * _callback
request to execute once this request completes
Definition: VFS_node.h:97
virtual QByteArray toJson(postID id=0, bool ignoreSuccess=false, bool includeInitialPath=false)
Serialize this request.
Definition: VFS_node.cpp:415
virtual void timerEvent(QTimerEvent *e=nullptr)
The callback for when a request times out.
Definition: VFS_node.cpp:220
static long _refcount
A reference counter for VFS_request instances, used for debugging to ensure all instances are properl...
Definition: VFS_node.h:122
QJsonObject _metadata
the request payload
Definition: VFS_node.h:101
static VFS * root()
Return the root node of the VFS filesystem.
Definition: VFS.cpp:399
static void LOG(QString message, int level=0, QString user="server")
Send a message to the VFS::_messages VFS_stream.
Definition: VFS.cpp:209
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 value
a setter DOCME
setter user
a setter DOCME
setter name
a setter DOCME
setter type
a setter DOCME
getter path
a getter DOCME
metadata(paths)
setter error
Set the error value of this widget.
QString cleanPath(QString path)
Clean and normalize a VFS path.
Definition: rutils.cpp:32