Remoto - VFS: VFS_mongo.cpp Source File
Remoto - VFS
VFS_mongo.cpp
Go to the documentation of this file.
1 
2 #include "VFS.h"
3 #include "utilities/rutils.h"
4 
6 #include "VFS_base/VFS_icons.h"
7 
8 #include "VFS_mongo.h"
9 
10 #include <QFileInfo>
11 
12 #include <iostream>
13 
14 #ifndef Q_MOC_RUN
15 #include <bsoncxx/json.hpp>
16 #include <bsoncxx/exception/exception.hpp>
17 #include <mongocxx/exception/exception.hpp>
18 #include <mongocxx/exception/query_exception.hpp>
19 #include <mongocxx/exception/logic_error.hpp>
20 #endif
21 
22 //this is bullshit... their driver should manage this
23 mongocxx::instance VFS_mongo::_instance = std::move(mongocxx::instance::current());
24 
47 VFS_mongo_cache_entry::VFS_mongo_cache_entry(VFS_mongo *mongo, QString path, bool debug, int flushInterval, int expireInterval, bool create, bool container, QJsonObject createData)
48 : VFS_datastore_cache_entry(debug,flushInterval,expireInterval)
49 , _mongo(mongo)
50 , _path(path)
51 , _container(container)
52 {
53  if (_debug)
54  VFS::WARN( QString("Creating mongo cache entry: '%1'").arg(_path) );
55 
56  try //try to read the document
57  {
58  QJsonObject o = _mongo->readDocument(_path,_size,_container);
59 
60  //printf("CACHE DATA: %s\n%s\n%s\n",qUtf8Printable(_path),qUtf8Printable(b),qUtf8Printable( QJsonDocument(o).toJson() ));
61 
62  setData(o);
63 
64  _dirty = false;
65  _valid = true;
66  }
67  catch (VFS_mongo_collectionException &e) //exception meaning that the collection doesn't exist
68  {
69  VFS::ERROR( _reason = QString("Collection was not found, and createCollection was not set: %1").arg(e.what()));
70  _valid = false;
71  }
72  catch (VFS_mongo_entryException &e)
73  {
74  if (create)
75  {
76  try
77  {
78  if (_mongo->createDocument(_path,createData,_size,container))
79  { setData(createData);
80  _valid = true;
81  _dirty = false;
82  return;
83  }
84  else
85  {
86  _valid = false;
87  }
88  }
89  catch(VFS_mongo_exception &e)
90  {
91  _reason = QString("VFS_mongo cache exception: %1").arg(e.what());
92  _valid = false;
93  }
94  catch(...)
95  {
96  _reason = "VFS_mongo cache exception, and no message was available. (2a) "+_path;
97  _valid = false;
98  }
99  }
100  else
101  {
102  //VFS::ERROR( _reason = "Entry was not found and create was not set: "+_path);
103  _valid = false;
104  }
105 
106  _reason = QString("VFS_Mongo cache entryException: %1").arg(e.what());//+_path;
107  _valid = false;
108  }
109  catch (VFS_mongo_directoryException &e) //exception meaning that the path was too short
110  {
111  _reason = QString("VFS_Mongo cache directoryException: %1").arg(e.what());//+_path;
112  _valid = false;
113  }
114  catch (bsoncxx::exception &e)
115  {
116  _reason = e.what();
117  _dirty = true;
118  _valid = false;
119  return;
120  }
121  catch (std::exception &e)
122  {
123  _reason = QString("VFS_mongo cache exception: %1").arg(e.what());
124  _valid = false;
125  }
126  catch (...)
127  {
128  _reason = "VFS_mongo cache exception, and no message was available. (1) "+_path;
129  _valid = false;
130  }
131 }
132 
133 
144 {
145  if (_debug)
146  VFS::WARN( QString("Cache deleted: '%1'").arg(_path) );
147 
148  if (_dirty && _valid)
149  flush();
150 }
151 
152 
159 bool VFS_mongo_cache_entry::valid(QString &reason)
160 {
161  if (_valid)
162  return _valid;
163 
164  return VFS_datastore_cache_entry::valid(reason);
165 }
166 
173 {
174  return _container;
175 }
176 
177 
192 {
193  if (_debug)
194  VFS::WARN( QString("Flushing '%1'").arg(_path) );
195 
196  if (!_dirty)
197  return;
198 
199  try
200  {
201  _size = _mongo->writeDocument(_path, _data.object() );
202  _dirty = false;
203  }
204  catch (bsoncxx::exception &e)
205  {
206  _reason = e.what();
207  _dirty = true;
208  _valid = false;
209  }
210  catch (std::exception& e)
211  {
212  _reason = e.what();
213  _dirty = true;
214  _valid = false;
215  }
216  catch (...)
217  {
218  VFS::ERROR( "Caught unspecified mongo exception while flushing "+_path );
219  //issue a VFS::CRITICAL message if disk is full or other deep failure happens
220  VFS::CRITICAL( _reason = QString("Unable to write to %1... Is the disk full or a permission problem?").arg(_path) );
221  _dirty = true;
222  _valid = false;
223  }
224 }
225 
226 
261 VFS_mongo::VFS_mongo(QString url, QString db, QString collection, quint64 size, bool debug, int flushInterval, int expireInterval, bool createCollection)
262 : VFS_datastore(size, debug)
263 , _flushInterval(flushInterval)
264 , _expireInterval(expireInterval)
265 , _url(url)
266 , _databaseName(db)
267 , _collection(collection)
268 , _createCollection(createCollection)
269 {
270  try
271  {
272  _client = client( uri(qUtf8Printable(url)) );
273  _database = _client[ qUtf8Printable(db) ];
274  VFS::LOG( QString("Created %1 node pointing to '%2/%3@%4'").arg(className()).arg(url).arg(db).arg(collection) );
275  }
276  catch (mongocxx::exception& e)
277  {
278  VFS::ERROR( e.what() );
279  }
280  catch (...)
281  {
282  VFS::ERROR( "Caught unspecified mongo error." );
283  }
284 }
285 
287 {
288 
289 }
290 
305 bool VFS_mongo::createDocument(QString path, QJsonObject o, quint64 &size, bool container)
306 {
307  if (!_database.has_collection(_collection.toStdString()))
309  throw VFS_mongo_collectionException("Collection '"+_collection+"' doesn't exist.");
310 
311  if (path == "")
312  throw VFS_mongo_directoryException("Path was empty.");
313 
314  try //query to see if path already exists
315  {
316  bool c;
317  readDocument(path,size,c); //if read is successful
318 
319  if (c!=container)
320  VFS::WARN("tried to create a container when a file already existed.");
321 
322  return false; //don't create the document, as it already exists
323  }
324  catch (VFS_mongo_entryException) //if the path does not exist, create it, and check/create all parent directories as well
325  {
326  QStringList pp = path.split("/",Qt::SkipEmptyParts);
327 
328  if (pp.length())
329  pp.takeLast(); //remove the actual entry we are creating
330 
331  QString p;
332  quint64 s;
333  bool c;
334  while (pp.length()) //ensure all parent directories are created
335  {
336  p = rutils::cleanPath( p + "/" + pp.takeFirst() );
337 
338  try
339  {
340  readDocument(p,s,c);
341  }
343  {
344  //printf("Creating parent entry: %s\n",qUtf8Printable(p));
345  writeDocument(p,QJsonObject(),true);
346  }
347  }
348 
349  size = writeDocument(path,o,container);
350  }
351 
352  return true;
353 }
354 
355 
369 quint64 VFS_mongo::writeDocument(QString path, QJsonObject o, bool container)
370 {
371  if (!_database.has_collection(_collection.toStdString()))
373  throw VFS_mongo_collectionException("Collection '"+_collection+"' doesn't exist.");
374 
375  if (path == "")
376  throw VFS_mongo_directoryException("Path was empty.");
377 
378  o.remove("_id"); //never ever ever update or create the _id field!
379  o["_path"] = path;
380 
381  if (container)
382  o["_container"] = true;
383 
384  QByteArray j = QJsonDocument(o).toJson();
385 
386  bsoncxx::document::value u = bsoncxx::from_json( j.toStdString() );
387  bsoncxx::document::value f = bsoncxx::builder::stream::document{} << "_path" << path.toStdString() << bsoncxx::builder::stream::finalize;
388 
389  options::update op;
390  op.upsert(true);
391 
392  //bsoncxx::stdx::optional<mongocxx::result::update> updated = _database[_collection.toStdString()].update_one( f.view(), u.view(), op );
393  bsoncxx::stdx::optional<mongocxx::result::replace_one> updated = _database[_collection.toStdString()].replace_one( f.view(), u.view(), op );
394 
395  if (!updated)
396  throw VFS_mongo_entryException("Unable to write to '"+path+"'.");
397 
398  return (quint64) j.size();
399 }
400 
401 
414 {
415  if (!_database.has_collection(_collection.toStdString()))
417  throw VFS_mongo_collectionException("Collection '"+_collection+"' doesn't exist.");
418 
419  bsoncxx::document::view_or_value f = bsoncxx::builder::stream::document{} << "_path" << path.toStdString() << bsoncxx::builder::stream::finalize;
420 
421  // FIXME: should not allow deleting a "_container" if it has children entries
422  // this will require a query first and then a decision to delete or not
423 
424  bsoncxx::stdx::optional<mongocxx::result::delete_result> deleted = _database[_collection.toStdString()].delete_one( f.view() );
425 
426  if (!deleted)
427  throw VFS_mongo_entryException("Unable to remove '"+path+"'.");
428 
429  return true;
430 }
431 
432 
445 QJsonObject VFS_mongo::readDocument(QString path, quint64 &size, bool &container)
446 {
447  if (!_database.has_collection(_collection.toStdString()))
449  throw VFS_mongo_collectionException("Collection '"+_collection+"' doesn't exist.");
450 
451  if (path == "") //if the path is empty, the collection is a container
452  { size = 0;
453  container = true;
454  return QJsonObject();
455  }
456 
457  bsoncxx::document::value f = bsoncxx::builder::stream::document{} << "_path" << path.toStdString() << bsoncxx::builder::stream::finalize;
458 
459  bsoncxx::stdx::optional<bsoncxx::document::value> maybe_result = _database[_collection.toStdString()].find_one(std::move(f));
460  if (maybe_result)
461  {
462  bsoncxx::document::value v = maybe_result.value();
463 
464  QByteArray b = QByteArray::fromStdString(bsoncxx::to_json(v)); //I wish there was a better way here!
465  QJsonDocument d = QJsonDocument::fromJson(b);
466  QJsonObject o = d.object();
467 
468  size = (quint64) b.size();
469  container = o.value("_container").toBool(false);
470 
471  o.remove("_id");
472  o.remove("_path");
473  o.remove("_container");
474 
475  return o;
476  }
477  else
478  throw VFS_mongo_entryException("Unable to read '"+path+"'.");
479 }
480 
481 
489 {
490  bool success = false;
491 
492  try
493  {
494  _database.create_collection(name.toStdString());
495 
496  auto index_specification = bsoncxx::builder::stream::document{};
497  index_specification << "_path" << 1;
498  bsoncxx::document::value ii = index_specification << bsoncxx::builder::stream::finalize;
499 
500  try {
501  bsoncxx::stdx::optional<bsoncxx::document::value> maybe_result = _database[name.toStdString()].create_index(std::move(ii));
502 
503  if (!maybe_result)
504  { VFS::ERROR("(1) Could not index collection "+name);
505  return false;
506  }
507  }
508  catch (mongocxx::logic_error &e) //if the options are invalid.
509  {
510  VFS::ERROR("(2) Could not index collection "+name);
511  VFS::ERROR(e.what());
512 
513  return false;
514  }
515  catch (mongocxx::operation_exception &e) //if index creation fails.
516  {
517  VFS::ERROR("(3) Could not index collection "+name);
518  VFS::ERROR(e.what());
519 
520  return false;
521  }
522  catch (...)
523  {
524  VFS::ERROR("Unknown error when creating indexes on '"+name+"'. Behavior will be undefined.");
525 
526  return false;
527  }
528 
529  VFS::WARN("Created and indexed collection '"+name+"'", 0, className());
530  success = true;
531  }
532  catch (mongocxx::operation_exception &e)
533  {
534  VFS::ERROR("Could not create collection "+name);
535  VFS::ERROR(e.what());
536  }
537  catch (...)
538  {
539  VFS::ERROR("Could not create collection "+name);
540  }
541 
542  return success;
543 }
544 
545 
553 QByteArray VFS_mongo::icon()
554 {
555  return VFS_icons::get("disk");
556 }
557 
564 {
565  QString s = VFS_datastore::reportDetails();
566 
567  return s;
568  //return s+"\nFIXME: calculate cache usage and file count here!";
569 }
570 
571 
605 {
606  QMutexLocker _l(&_lock);
607 
608  QString path = r->_path;
609 
610  QJsonObject out;
611  bool container(false);
612 
613  try
614  {
615  //check collection
616  if (!_database.has_collection(_collection.toStdString()))
618  { r->_success = false;
619  r->_reason = QString("Unable to create collection '%1'").arg(_collection);
620  return;
621  }
622 
623  //ignore the "closest" flag for now
624 
625  //query
626  QString query;
627  if (path=="")
628  { query = QString(" \
629  { \"_path\": { \"$regex\": \"^[^/]*$\", \
630  \"$options\": \"\" } \
631  }").arg(path);
632  }
633  else
634  { query = QString(" \
635  { \"_path\": { \"$regex\": \"^%1/[^/]*$\", \
636  \"$options\": \"\" } \
637  }").arg(path);
638  }
639 
640  bsoncxx::document::view_or_value q = {};
641  q = bsoncxx::from_json( query.toStdString() );
642 
643  //printf("path: %s\nquery: %s\n",qUtf8Printable(path),qUtf8Printable(query));
644 
645  //projection
646  QString projection("{ \"_path\": 1, \"_container\":1 }"); //we only care about the path and container-ness
647 
648  bsoncxx::document::view_or_value p = bsoncxx::from_json( projection.toStdString() );
649 
650  options::find o;
651  o.projection(p);
652 
653  //perform query
654  //this should use an aggregator
655 
656  cursor c = _database[_collection.toStdString()].find(q,o);
657  //throw VFS_mongo_entryException("Unable to read '"+path+"'.");
658 
659  QString m;
660  QStringList pp;
661  bsoncxx::document::view v;
662  bsoncxx::document::element e;
663  cursor::iterator i = c.begin();
664  while (i != c.end())
665  {
666  //std::cout << bsoncxx::to_json(*i) << std::endl;
667 
668  v = *i;
669 
670  e = v["_container"];
671 
672  if (e && e.type() == bsoncxx::type::k_bool)
673  container = e.get_bool();
674  else
675  container = false;
676 
677  e = v["_path"];
678  m = "";
679 
680  if (e) //if element is valid
681  {
682  if (e.type() == bsoncxx::type::k_utf8)
683  m = QString::fromStdString(e.get_utf8().value.to_string());
684 
685  if (m != "")
686  {
687  //remove the path p from the beginning of the string
688  m.remove(0,path.length());
689  if (m.startsWith("/"))
690  m.remove(0,1);
691 
692  //find the directory or file name, which is now the beginning of the string
693  pp = m.split("/",Qt::SkipEmptyParts);
694  if (pp.length() == 1)
695  out[m] = container;
696  }
697  }
698 
699  i++;
700  }
701 
702  //printf("OUT: %s\n",qUtf8Printable(QJsonDocument(out).toJson()));
703  }
704  catch (mongocxx::logic_error &e)
705  {
706  VFS::ERROR( r->_reason = r->_path+": "+e.what() );
707  r->_success = false;
708  return;
709  }
710  catch (...)
711  {
712  VFS::ERROR( r->_reason = r->_path+": Caught unspecified mongo error." );
713  r->_success = false;
714  return;
715  }
716 
717  if (r->_metadata.value("sequence").toBool(false))
718  out = rutils::sequenceListing(out);
719 
720  r->_data.setObject(out);
721  r->_success = true;
722 }
723 
724 
740 {
741  QMutexLocker l(&_lock);
742 
743  //printf("VFS_MONGO read %s\n",qUtf8Printable(r->toJson(0,true,true)));
744 
745  QString p = r->_path;
746 
747  bool creating = r->_metadata.value("createIfMissing").toBool(false);
748  bool container = r->_metadata.value("container").toBool(false);
749  bool cache = r->_metadata.value("cache").toBool(true);
750 
751  VFS_mongo_cache_entry *en = dynamic_cast<VFS_mongo_cache_entry *>( _cache[r->_path] );
752  if (!en)
753  {
754  en = new VFS_mongo_cache_entry(this,p,_debug,_flushInterval,_expireInterval,creating,container,r->_data.object());
755  //printf("MONGO DATASTORE READ: %d %p '%s'\n%s",creating,this,qUtf8Printable(r->_path),qUtf8Printable(QJsonDocument(en->getData()).toJson()));
756 
757  if (!en->valid(r->_reason))
758  {
759  //printf("MONGO DATASTORE INVALID\n");
760 
761  delete en;
762 
763  if (creating)
764  {
765  //printf("CREATE FROM READ: %s\n%s\n",qUtf8Printable(r->_path),qUtf8Printable(r->_data.toJson()));
766 
769  write(r);
770  r->_requestType = t;
771  return;
772  }
773  else
774  {
775  //ls(r);
776  //printf("MONGO READ LS:%s\n",qUtf8Printable(r->toJson(0,true,true)));
777  r->_success = false;
778  return;
779  }
780  }
781 
782  if (en->isContainer())
783  {
784  ls(r);
785  //en->setData(r->_data.object());
786  //printf("MONGO READ LS:%s\n",qUtf8Printable(r->toJson(0,true,true)));
787  return; //we have the data... don't cache it, just return.
788  }
789 
790  if (cache)
791  if (!_cache.insert(r->_path,en))
792  VFS::WARN( QString("%1::read(): '%2' was too large to cache!").arg(className()).arg(r->_path) );
793  }
794  else
795  {
796  //printf("MONGO CACHE was valid\n");
797  }
798 
799  r->_data = en->getData();
800  r->_success = true;
801 }
802 
803 
816 {
817  QMutexLocker l(&_lock);
818 
819  QString p = r->_path;
820  QJsonObject m = r->_metadata;
821  bool creating = r->_requestType == VFS_request::create;
822  bool container = r->_metadata.value("container").toBool(false);
823 
824  VFS_mongo_cache_entry *en = dynamic_cast<VFS_mongo_cache_entry *>( _cache[r->_path] );
825  if (!en)
826  {
827  en = new VFS_mongo_cache_entry(this,p,_debug,_flushInterval,_expireInterval,creating,container,r->_data.object());
828 
829  if (!en->valid(r->_reason))
830  { r->_success = false;
831  if (creating)
832  { //VFS::ERROR("report some bad create error here. "+r->_reason);
833  }
834  delete en;
835  return;
836  }
837 
838  if (creating)
839  {
840  if (_debug)
841  VFS::WARN( QString("Creating: '%1'").arg(p) );
842 
843  r->_data.setObject( en->getData().object() );
844 
845  //create a diff for anything that is subscribed to the containing directory
846 
847  QStringList dirs = r->_path.split("/",Qt::SkipEmptyParts);
848  QString newFile = dirs.takeLast();
849  QString dirPath = dirs.join("/");
850 
851  QJsonObject o;
852  o[newFile] = true;
853  //FIXME: may need to write metadata here
854  VFS_request *c = createRequest(r->_requestType,dirPath,r->_user,QJsonDocument(o));
855  emit diff(this,c);
856  delete c;
857 
858  if (!_cache.remove(dirPath)) //it will be re-created if needed
859  { //printf("Unable to remove cache entry: %s\n",qUtf8Printable(dirPath));
860  }
861  }
862 
863  if (!_cache.insert(en->_path,en))
864  VFS::WARN( QString("%1::write(): '%2' was too large to cache!").arg(className()).arg(r->_path) );
865  }
866 
867  en->setData(r->_data.object());
868  //en->setMetadata(r->_metadata);
869 
870  r->_success = true;
871 
872  emit diff(this,r);
873 }
874 
875 
884 {
885  QMutexLocker l(&_lock);
886 
887  //printf("VFS_MONGO metadata %s\n",qUtf8Printable(r->_path));
888 
889  QString p = r->_path;
890 
891  QJsonObject mt = r->_metadata;
892 
894 
895  r->_metadata["type"] = VFS_node_type::getType(p);
896  r->_success = true;
897 }
898 
899 
914 {
915  QMutexLocker l(&_lock);
916 
917  QString p = r->_path;
918  bool creating = r->_metadata.value("createIfMissing").toBool(false);
919  bool container = r->_metadata.value("container").toBool(false);
920 
922  if (!en)
923  {
924  en = new VFS_mongo_cache_entry(this, p,_debug,_flushInterval,_expireInterval,creating,container,r->_data.object());
925 
926  if (!en->valid(r->_reason))
927  {
928  delete en;
929 
930  if (creating)
931  {
932  //printf("CREATE FROM SUBMIT: %s\n%s\n",qUtf8Printable(r->_path),qUtf8Printable(r->_data.toJson()));
933 
936  write(r);
937  r->_requestType = t;
938  return;
939  }
940  else
941  {
942  r->_success = false;
943  return;
944  }
945  }
946 
947  if (!_cache.insert(r->_path,en))
948  VFS::WARN( QString("%1::submit(): '%2' was too large to cache!").arg(className()).arg(r->_path) );
949  }
950 
951  QJsonDocument fd = en->getData();
952  QJsonObject o;
953 
954  o = applyJsonDiff( fd.object(), r->_data.object(), "", r->_user );
955 
956  //printf("Diffed: %s\n",qUtf8Printable( QJsonDocument(o).toJson() ));
957 
958  en->setData(o);
959 
960  r->_success = true;
961 
962  emit diff(this,r);
963 }
964 
965 
981 {
982  //check if path is empty... that means that this node is to be removed
983  if (r->_path=="")
984  {
985  VFS_node::rm(r);
986  return;
987  }
988 
989  bool s = false;
990 
991  try
992  {
993  _cache.remove(r->_path); //hate to flush and then remove, but there doesn't seem a better way.
994  s = removeDocument(r->_path);
995  }
997  {
998  s = false;
999  }
1000  catch (...)
1001  {
1002  s = false;
1003  }
1004 
1005  if (s)
1006  {
1007  QStringList dirs = r->_path.split("/",Qt::SkipEmptyParts);
1008  QString rmFile = dirs.takeLast();
1009  QString dirPath = dirs.join("/");
1010 
1011  _cache.remove(dirPath); //it will be re-created if needed.
1012 
1013  QJsonDocument diffData;
1014  QJsonObject o;
1015  o[ rmFile ] = QJsonValue::Null; //null means remove
1016  diffData.setObject(o);
1017 
1018  unsubscribePath(r->_path); //unsubscribePath on this path... it no longer exists!
1019 
1020  r->_data = diffData;
1021  r->_path = dirPath;
1022  r->_success = true;
1023 
1024  emit diff(this,r);
1025  }
1026  else
1027  {
1028  r->_reason = QString("Can't delete non-existent file: '%1'").arg(r->_path);
1029  r->_success = false;
1030  }
1031 }
1032 
1033 
1045 {
1047 }
1048 
1049 
1066 {
1067  if (!_message.endsWith('\n'))
1068  _message += "\n";
1069 }
1070 
1072 
1078 const char *VFS_mongo_exception::what() const throw()
1079 {
1080  return qUtf8Printable(_message);
1081 }
1082 
1103 
1105 
1125 
1127 
1148 
1150 
A pure virtual class which must be subclassed for data storage.
Definition: VFS_datastore.h:13
quint64 _size
The size of the data. Always initialized to zero. Must be set in a subclass.
Definition: VFS_datastore.h:34
virtual bool valid(QString &reason)
virtual void setData(QJsonObject json)
Write data to the entry.
QString _reason
The reason this may be invalid. Set by a subclass.
Definition: VFS_datastore.h:38
bool _debug
Debug flag, for verbose output.
Definition: VFS_datastore.h:39
virtual QJsonDocument getData()
Return the data from an entry.
bool _valid
Defaults to false. A subclass will determine if _valid is true, like for instance if an underlying fi...
Definition: VFS_datastore.h:37
bool _dirty
Changes have occurred but they are not commited to storage yet.
Definition: VFS_datastore.h:36
QJsonDocument _data
The actual cache data.
Definition: VFS_datastore.h:32
bool insert(const QString &key, VFS_datastore_cache_entry *object)
Insert a new entry.
A base class for creating storage nodes in VFS.
Definition: VFS_datastore.h:84
VFS_datastore_cache _cache
The data cache.
bool _debug
Debug mode.
static QJsonObject applyJsonDiff(QJsonObject obj, QJsonObject diff, QString trace="", QString user="server")
Apply a json diff to a json object.
virtual QString reportDetails()
Report the current cache usage.
static char * get(QString which="")
Fetch an icon from the library.
Definition: VFS_icons.cpp:34
A subclass of VFS_datastore_cache_entry, used for mongo database access.
Definition: VFS_mongo.h:20
virtual ~VFS_mongo_cache_entry()
VFS_mongo_cache_entry destructor.
Definition: VFS_mongo.cpp:143
QString _path
The path associated with this cache entry.
Definition: VFS_mongo.h:34
virtual bool isContainer()
Return the container-ness of this entry.
Definition: VFS_mongo.cpp:172
VFS_mongo * _mongo
The VFS_mongo instance that owns this item's cache.
Definition: VFS_mongo.h:33
virtual void flush()
Actually write the document to the database.
Definition: VFS_mongo.cpp:191
virtual bool valid(QString &reason)
If the file or directory does not exist or is not readable, _valid is set to false.
Definition: VFS_mongo.cpp:159
bool _container
The entry is a container.
Definition: VFS_mongo.h:35
VFS_mongo_cache_entry(VFS_mongo *mongo, QString path, bool debug, int flushInterval, int expireInterval, bool create=false, bool container=false, QJsonObject createData=QJsonObject())
Definition: VFS_mongo.cpp:47
A subclass of VFS_mongo_exception signalling a problem with the collection path of an operation.
Definition: VFS_mongo.h:120
VFS_mongo_collectionException(QString m)
VFS_mongo_collectionException constructor.
Definition: VFS_mongo.cpp:1147
A subclass of VFS_mongo_exception signalling a problem with the path of a read or write operation.
Definition: VFS_mongo.h:113
VFS_mongo_directoryException(QString m)
VFS_mongo_directoryException constructor.
Definition: VFS_mongo.cpp:1124
A subclass of VFS_mongo_exception signalling a problem with the path of a read or write operation.
Definition: VFS_mongo.h:106
virtual ~VFS_mongo_entryException()
Definition: VFS_mongo.cpp:1104
VFS_mongo_entryException(QString m)
VFS_mongo_entryException constructor.
Definition: VFS_mongo.cpp:1102
Base class for VFS_mongo_exception subclasses.
Definition: VFS_mongo.h:94
virtual const char * what() const
Fetch the exception message, in the style of std::exception.
Definition: VFS_mongo.cpp:1078
VFS_mongo_exception(QString m)
VFS_mongo_exception constructor.
Definition: VFS_mongo.cpp:1065
QString _message
This exception's message.
Definition: VFS_mongo.h:102
virtual ~VFS_mongo_exception()
Definition: VFS_mongo.cpp:1071
A VFS_datastore subclass for accessing data in Mongo.
Definition: VFS_mongo.h:43
virtual ~VFS_mongo()
Definition: VFS_mongo.cpp:286
virtual QByteArray icon()
The "disk" icon found in the VFS_icons library.
Definition: VFS_mongo.cpp:553
virtual void subscribe(VFS_request *r)
Subscribe to changes on a database document.
Definition: VFS_mongo.cpp:1044
client _client
The Mongo (mongocxx) client object.
Definition: VFS_mongo.h:85
static instance _instance
The global mongocxx instance. There should only ever be one of these.
Definition: VFS_mongo.h:83
bool createDocument(QString path, QJsonObject o, quint64 &size, bool container=false)
Create a new document in the database if it doesn't exist.
Definition: VFS_mongo.cpp:305
QJsonObject readDocument(QString path, quint64 &size, bool &container)
Search for a document by "_path" in the database.
Definition: VFS_mongo.cpp:445
int _flushInterval
Interval for cache entries to flush, in milliseconds.
Definition: VFS_mongo.h:55
virtual void submit(VFS_request *r)
Submit data to a file, applying the data as a diff.
Definition: VFS_mongo.cpp:913
virtual void metadata(VFS_request *r)
Fetch the metadata for a database document.
Definition: VFS_mongo.cpp:883
database _database
The Mongo (mongocxx) database object.
Definition: VFS_mongo.h:86
virtual QString reportDetails()
Report the current cache usage.
Definition: VFS_mongo.cpp:563
bool removeDocument(QString path)
Remove a document from the database.
Definition: VFS_mongo.cpp:413
virtual void write(VFS_request *r)
Write data to a database document.
Definition: VFS_mongo.cpp:815
int _expireInterval
Interval for cache entries to expire, in milliseconds.
Definition: VFS_mongo.h:56
quint64 writeDocument(QString path, QJsonObject o, bool container=false)
Update a document in the database.
Definition: VFS_mongo.cpp:369
QString _collection
The collection to use.
Definition: VFS_mongo.h:81
friend class VFS_mongo_cache_entry
Definition: VFS_mongo.h:46
bool _createCollection
If a reference is made to a non-existent collection, create it, or throw an error.
Definition: VFS_mongo.h:88
virtual void rm(VFS_request *r)
Attempt to delete a file.
Definition: VFS_mongo.cpp:980
virtual void ls(VFS_request *r)
List the contents of a collection using a Mongo find() on the path.
Definition: VFS_mongo.cpp:604
Q_INVOKABLE VFS_mongo(QString uri, QString db, QString collection, quint64 size=VFS_datastore_cache::DEFAULT_DATACACHE_SIZE, bool debug=false, int flushInterval=5000, int expireInterval=60000, bool createCollection=false)
Create a VFS_Mongo node.
Definition: VFS_mongo.cpp:261
virtual void read(VFS_request *r)
Read the contents of a database document.
Definition: VFS_mongo.cpp:739
bool createCollection(QString name)
Create a collection.
Definition: VFS_mongo.cpp:488
static QString getType(QString _path, QString _default="unknownType")
Fetch the type of a file, based on path/filename.ext.
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
virtual void metadata(VFS_request *r)
Fetch the metadata of this node.
Definition: VFS_node.cpp:797
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
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 rm(VFS_request *r)
Remove a child entry from a node, or the node itself.
Definition: VFS_node.cpp:1005
virtual void subscribe(VFS_request *r)
Add an entry to this node's _subscription list.
Definition: VFS_node.cpp:1204
The base class for all requests between nodes.
Definition: VFS_node.h:54
requestType
Requests perform one of these actions.
Definition: VFS_node.h:63
@ create
create a new file/path (2)
Definition: VFS_node.h:66
requestType _requestType
the action this request is performing or requesting
Definition: VFS_node.h:87
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 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 CRITICAL(QString message)
Send a message to the VFS::_critical VFS_stream.
Definition: VFS.cpp:357
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 name
a setter DOCME
getter path
a getter DOCME
url(value, options)
QString cleanPath(QString path)
Clean and normalize a VFS path.
Definition: rutils.cpp:32
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