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>
51 , _container(container)
54 VFS::WARN( QString(
"Creating mongo cache entry: '%1'").arg(
_path) );
69 VFS::ERROR(
_reason = QString(
"Collection was not found, and createCollection was not set: %1").arg(e.
what()));
91 _reason = QString(
"VFS_mongo cache exception: %1").arg(e.
what());
96 _reason =
"VFS_mongo cache exception, and no message was available. (2a) "+
_path;
106 _reason = QString(
"VFS_Mongo cache entryException: %1").arg(e.
what());
111 _reason = QString(
"VFS_Mongo cache directoryException: %1").arg(e.
what());
114 catch (bsoncxx::exception &e)
121 catch (std::exception &e)
123 _reason = QString(
"VFS_mongo cache exception: %1").arg(e.
what());
128 _reason =
"VFS_mongo cache exception, and no message was available. (1) "+
_path;
204 catch (bsoncxx::exception &e)
210 catch (std::exception& e)
218 VFS::ERROR(
"Caught unspecified mongo exception while flushing "+
_path );
261 VFS_mongo::VFS_mongo(QString
url, QString db, QString collection, quint64 size,
bool debug,
int flushInterval,
int expireInterval,
bool createCollection)
263 , _flushInterval(flushInterval)
264 , _expireInterval(expireInterval)
267 , _collection(collection)
268 , _createCollection(createCollection)
272 _client = client( uri(qUtf8Printable(url)) );
274 VFS::LOG( QString(
"Created %1 node pointing to '%2/%3@%4'").arg(
className()).arg(url).arg(db).arg(collection) );
276 catch (mongocxx::exception& e)
282 VFS::ERROR(
"Caught unspecified mongo error." );
320 VFS::WARN(
"tried to create a container when a file already existed.");
326 QStringList pp = path.split(
"/",Qt::SkipEmptyParts);
382 o[
"_container"] =
true;
384 QByteArray j = QJsonDocument(o).toJson();
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;
393 bsoncxx::stdx::optional<mongocxx::result::replace_one> updated =
_database[
_collection.toStdString()].replace_one( f.view(), u.view(), op );
398 return (quint64) j.size();
419 bsoncxx::document::view_or_value f = bsoncxx::builder::stream::document{} <<
"_path" << path.toStdString() << bsoncxx::builder::stream::finalize;
424 bsoncxx::stdx::optional<mongocxx::result::delete_result> deleted =
_database[
_collection.toStdString()].delete_one( f.view() );
454 return QJsonObject();
457 bsoncxx::document::value f = bsoncxx::builder::stream::document{} <<
"_path" << path.toStdString() << bsoncxx::builder::stream::finalize;
459 bsoncxx::stdx::optional<bsoncxx::document::value> maybe_result =
_database[
_collection.toStdString()].find_one(std::move(f));
462 bsoncxx::document::value v = maybe_result.value();
464 QByteArray b = QByteArray::fromStdString(bsoncxx::to_json(v));
465 QJsonDocument d = QJsonDocument::fromJson(b);
466 QJsonObject o = d.object();
468 size = (quint64) b.size();
469 container = o.value(
"_container").toBool(
false);
473 o.remove(
"_container");
490 bool success =
false;
494 _database.create_collection(name.toStdString());
496 auto index_specification = bsoncxx::builder::stream::document{};
497 index_specification <<
"_path" << 1;
498 bsoncxx::document::value ii = index_specification << bsoncxx::builder::stream::finalize;
501 bsoncxx::stdx::optional<bsoncxx::document::value> maybe_result =
_database[name.toStdString()].create_index(std::move(ii));
504 {
VFS::ERROR(
"(1) Could not index collection "+name);
508 catch (mongocxx::logic_error &e)
510 VFS::ERROR(
"(2) Could not index collection "+name);
515 catch (mongocxx::operation_exception &e)
517 VFS::ERROR(
"(3) Could not index collection "+name);
524 VFS::ERROR(
"Unknown error when creating indexes on '"+name+
"'. Behavior will be undefined.");
532 catch (mongocxx::operation_exception &e)
534 VFS::ERROR(
"Could not create collection "+name);
539 VFS::ERROR(
"Could not create collection "+name);
606 QMutexLocker _l(&
_lock);
608 QString path = r->
_path;
611 bool container(
false);
628 { query = QString(
" \
629 { \"_path\": { \"$regex\": \"^[^/]*$\", \
630 \"$options\": \"\" } \
634 { query = QString(
" \
635 { \"_path\": { \"$regex\": \"^%1/[^/]*$\", \
636 \"$options\": \"\" } \
640 bsoncxx::document::view_or_value q = {};
641 q = bsoncxx::from_json( query.toStdString() );
646 QString projection(
"{ \"_path\": 1, \"_container\":1 }");
648 bsoncxx::document::view_or_value p = bsoncxx::from_json( projection.toStdString() );
661 bsoncxx::document::view v;
662 bsoncxx::document::element e;
663 cursor::iterator i = c.begin();
672 if (e && e.type() == bsoncxx::type::k_bool)
673 container = e.get_bool();
682 if (e.type() == bsoncxx::type::k_utf8)
683 m = QString::fromStdString(e.get_utf8().value.to_string());
688 m.remove(0,path.length());
689 if (m.startsWith(
"/"))
693 pp = m.split(
"/",Qt::SkipEmptyParts);
694 if (pp.length() == 1)
704 catch (mongocxx::logic_error &e)
717 if (r->
_metadata.value(
"sequence").toBool(
false))
720 r->
_data.setObject(out);
741 QMutexLocker l(&
_lock);
745 QString p = r->
_path;
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);
817 QMutexLocker l(&
_lock);
819 QString p = r->
_path;
822 bool container = r->
_metadata.value(
"container").toBool(
false);
841 VFS::WARN( QString(
"Creating: '%1'").arg(p) );
847 QStringList dirs = r->
_path.split(
"/",Qt::SkipEmptyParts);
848 QString newFile = dirs.takeLast();
849 QString dirPath = dirs.join(
"/");
858 if (!
_cache.remove(dirPath))
885 QMutexLocker l(&
_lock);
889 QString p = r->
_path;
915 QMutexLocker l(&
_lock);
917 QString p = r->
_path;
918 bool creating = r->
_metadata.value(
"createIfMissing").toBool(
false);
919 bool container = r->
_metadata.value(
"container").toBool(
false);
951 QJsonDocument fd = en->
getData();
1007 QStringList dirs = r->
_path.split(
"/",Qt::SkipEmptyParts);
1008 QString rmFile = dirs.takeLast();
1009 QString dirPath = dirs.join(
"/");
1013 QJsonDocument diffData;
1015 o[ rmFile ] = QJsonValue::Null;
1016 diffData.setObject(o);
1020 r->
_data = diffData;
1028 r->
_reason = QString(
"Can't delete non-existent file: '%1'").arg(r->
_path);
A pure virtual class which must be subclassed for data storage.
quint64 _size
The size of the data. Always initialized to zero. Must be set in a subclass.
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.
bool _debug
Debug flag, for verbose output.
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...
bool _dirty
Changes have occurred but they are not commited to storage yet.
QJsonDocument _data
The actual cache data.
bool insert(const QString &key, VFS_datastore_cache_entry *object)
Insert a new entry.
A base class for creating storage nodes in VFS.
VFS_datastore_cache _cache
The data cache.
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.
A subclass of VFS_datastore_cache_entry, used for mongo database access.
virtual ~VFS_mongo_cache_entry()
VFS_mongo_cache_entry destructor.
QString _path
The path associated with this cache entry.
virtual bool isContainer()
Return the container-ness of this entry.
VFS_mongo * _mongo
The VFS_mongo instance that owns this item's cache.
virtual void flush()
Actually write the document to the database.
virtual bool valid(QString &reason)
If the file or directory does not exist or is not readable, _valid is set to false.
bool _container
The entry is a container.
VFS_mongo_cache_entry(VFS_mongo *mongo, QString path, bool debug, int flushInterval, int expireInterval, bool create=false, bool container=false, QJsonObject createData=QJsonObject())
A subclass of VFS_mongo_exception signalling a problem with the collection path of an operation.
VFS_mongo_collectionException(QString m)
VFS_mongo_collectionException constructor.
virtual ~VFS_mongo_collectionException()
A subclass of VFS_mongo_exception signalling a problem with the path of a read or write operation.
virtual ~VFS_mongo_directoryException()
VFS_mongo_directoryException(QString m)
VFS_mongo_directoryException constructor.
A subclass of VFS_mongo_exception signalling a problem with the path of a read or write operation.
virtual ~VFS_mongo_entryException()
VFS_mongo_entryException(QString m)
VFS_mongo_entryException constructor.
Base class for VFS_mongo_exception subclasses.
virtual const char * what() const
Fetch the exception message, in the style of std::exception.
VFS_mongo_exception(QString m)
VFS_mongo_exception constructor.
QString _message
This exception's message.
virtual ~VFS_mongo_exception()
A VFS_datastore subclass for accessing data in Mongo.
virtual QByteArray icon()
The "disk" icon found in the VFS_icons library.
virtual void subscribe(VFS_request *r)
Subscribe to changes on a database document.
client _client
The Mongo (mongocxx) client object.
static instance _instance
The global mongocxx instance. There should only ever be one of these.
bool createDocument(QString path, QJsonObject o, quint64 &size, bool container=false)
Create a new document in the database if it doesn't exist.
QJsonObject readDocument(QString path, quint64 &size, bool &container)
Search for a document by "_path" in the database.
int _flushInterval
Interval for cache entries to flush, in milliseconds.
virtual void submit(VFS_request *r)
Submit data to a file, applying the data as a diff.
virtual void metadata(VFS_request *r)
Fetch the metadata for a database document.
database _database
The Mongo (mongocxx) database object.
virtual QString reportDetails()
Report the current cache usage.
bool removeDocument(QString path)
Remove a document from the database.
virtual void write(VFS_request *r)
Write data to a database document.
int _expireInterval
Interval for cache entries to expire, in milliseconds.
quint64 writeDocument(QString path, QJsonObject o, bool container=false)
Update a document in the database.
QString _collection
The collection to use.
friend class VFS_mongo_cache_entry
bool _createCollection
If a reference is made to a non-existent collection, create it, or throw an error.
virtual void rm(VFS_request *r)
Attempt to delete a file.
virtual void ls(VFS_request *r)
List the contents of a collection using a Mongo find() on the path.
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.
virtual void read(VFS_request *r)
Read the contents of a database document.
bool createCollection(QString name)
Create a collection.
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.
virtual void metadata(VFS_request *r)
Fetch the metadata of this node.
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.
virtual void unsubscribePath(QString path)
Unsubscribe all references to a subpath.
QMutex _lock
A recursive mutex that is local to this node.
virtual void rm(VFS_request *r)
Remove a child entry from a node, or the node itself.
virtual void subscribe(VFS_request *r)
Add an entry to this node's _subscription list.
The base class for all requests between nodes.
requestType
Requests perform one of these actions.
@ create
create a new file/path (2)
requestType _requestType
the action this request is performing or requesting
QString _user
who initiated this request, mostly for logging
QString _reason
if something (probably bad) happened, this is the reason
QString _path
the target path remnant... the remaining path element once the request has found its target
bool _success
if the request was successfully completed
QJsonDocument _data
the request payload
QJsonObject _metadata
the request payload
static void LOG(QString message, int level=0, QString user="server")
Send a message to the VFS::_messages VFS_stream.
static void ERROR(QString message, int level=0, QString user="server")
Send a message to the VFS::_errors VFS_stream.
static void CRITICAL(QString message)
Send a message to the VFS::_critical VFS_stream.
static void WARN(QString message, int level=0, QString user="server")
Send a message to the VFS::_warnings VFS_stream.
setter name
a setter DOCME
getter path
a getter DOCME
QString cleanPath(QString path)
Clean and normalize a VFS path.
QJsonObject sequenceListing(QJsonObject l, QStringList types=sequenceTypes)
Given a list of filenames and a regex list, collapse the listing to sequences when possible.