4 #include <QMutableMapIterator>
7 #include <QCoreApplication>
75 #ifdef DEBUG_DANGLING_REQUESTS
95 , _dontDelete(dontDelete)
97 QMutexLocker l(&_sampleLock);
106 #ifdef DEBUG_DANGLING_REQUESTS
108 QTimer::singleShot(10000,
this, SLOT(timerEvent() ));
128 _metadata[
"stamp"] = QDateTime::currentMSecsSinceEpoch();
130 #ifdef DEBUG_DANGLING_REQUESTS
131 printf(
"CREATE REFCOUNT: %ld (%p) %s %s\n",_refcount,
this,qUtf8Printable(_user),qUtf8Printable(_path));
146 #ifdef DEBUG_DANGLING_REQUESTS
170 QMutexLocker l(&_sampleLock);
192 #ifdef DEBUG_DANGLING_REQUESTS
193 printf(
"DELETE REFCOUNT: %ld (%p) %s %s\n",
_refcount,
this,qUtf8Printable(
_user),qUtf8Printable(
_path));
223 printf(
"%s %s\n",qUtf8Printable(
_initialPath),qUtf8Printable(this->
toJson(0,
true,
true)));
260 if (!(
_metadata.contains(
"suppressError") &&
_metadata[
"suppressError"].toBool() ==
true))
289 VFS::WARN(
"WARN: setting callback when one is already present!\n");
428 if (includeInitialPath)
437 if (!
_data.isEmpty())
438 o[
"data"] =
_data.object();
441 o[
"rawdata"] = QJsonValue::fromVariant(
_rawData.toBase64() );
447 o[
"session"] = QString(
"0x%1").arg((quintptr)
_session, QT_POINTER_SIZE * 2, 16, QChar(
'0'));
470 _path = json[
"path"].toString();
471 _user = json[
"user"].toString();
473 _success = json[
"success"].toBool();
474 _reason = json[
"reason"].toString(
"");
476 if (includeInitialPath)
479 if (json.contains(
"data"))
481 if (json[
"data"].isArray())
482 _data = QJsonDocument(json[
"data"].toArray());
484 _data = QJsonDocument(json[
"data"].toObject());
487 _data = QJsonDocument();
489 if (json.contains(
"rawdata"))
491 _rawData = QByteArray::fromBase64( json[
"rawdata"].toString().toUtf8() );
517 , _lock(QMutex::Recursive)
533 QMutexLocker l(&
_lock);
563 { printf(
"Error: deleting too many children!\n");
694 QMutexLocker _l(&
_lock);
701 a[it.key()] = it.value()->isContainer();
704 r->
_data = QJsonDocument(a);
819 QMutexLocker l(&
_lock);
821 QJsonDocument d = r->
_data;
824 o[
"address"] = QString(
"0x%1").arg((quintptr)
this, QT_POINTER_SIZE * 2, 16, QChar(
'0'));
827 o[
"thread"] = QString(
"0x%1").arg((quintptr)thread(), QT_POINTER_SIZE * 2, 16, QChar(
'0'));
829 o[
"icon"] = QString(
icon());
835 VFS_subscriptionType::iterator si =
_subscribers.begin();
838 QString v = si.key();
840 VFS_subscriptionOrigin::iterator soi = so.begin();
842 while(soi != so.end())
844 QString vo = soi.key();
846 VFS_subscriptionCounter::iterator ci = cv.begin();
848 while (ci != cv.end())
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) );
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) );
869 o[
"subscriptions"] = s;
876 { child = ci.value();
879 c[ci.key()+(childIsDir?
"/":
"")] = (qint64)((quintptr)child);
920 r->
_data.setObject( QJsonObject { {
"default",
true } } );
1051 error = QString(
"Cannot load library: %1:%2").arg(nodename).arg(libname);
1137 QStringList pl = r->
_path.split(
"/",Qt::SkipEmptyParts);
1142 QMutexLocker l(&
_lock);
1144 QString p = pl.takeFirst();
1147 r->
_path = pl.join(
"/");
1153 if (!r->
_metadata.value(
"suppressError").toBool(
false))
1215 QMutexLocker l(&
_lock);
1217 int count = r->
_metadata.value(
"subscriptions").toInt(1);
1229 if (!r->
_metadata.contains(
"__SUBSCRIBE_ONLY__") || r->
_metadata[
"__SUBSCRIBE_ONLY__"].toBool()!=
true)
1265 QMutexLocker l(&
_lock);
1274 int count = r->
_metadata.value(
"unsubscriptions").toInt(1);
1294 VFS_subscriptionType::iterator it =
_subscribers.begin();
1298 VFS_subscriptionOrigin::iterator ito = o.begin();
1299 while (ito != o.end())
1301 i+= ito.value().count(subscriber);
1322 r->
_reason =
"Unable to unsubscribe without a subscriber...";
1338 QMutexLocker l(&
_lock);
1342 QMutableMapIterator<QString, VFS_subscriptionOrigin > ito(
_subscribers);
1343 while (ito.hasNext())
1347 QMutableMapIterator<QString, VFS_subscriptionCounter > it(ito.value());
1348 while (it.hasNext())
1352 c=it.value().remove(subscriber);
1357 if (!it.value().size())
1362 VFS::LOG( QString(
"unsubscribeAll removed '%1' %2 (%3)").arg(ito.key()).arg(
className()).arg(c), 9 );
1365 if (!ito.value().size())
1386 QMutexLocker l(&
_lock);
1391 VFS_subscriptionOrigin::iterator i = so.begin();
1392 while (i != so.end())
1394 QString k = i.key();
1397 VFS_subscriptionCounter::iterator ci = v.begin();
1398 while (ci != v.end())
1499 QMutexLocker lk(&
_lock);
1503 { printf(
"SKIPPING notify on empty request: %s\n",qUtf8Printable(t->
_path));
1510 foreach(QString o, origins.keys())
1514 foreach(
VFS_node *s,subscribers.keys())
1538 QMetaObject::invokeMethod( s,
"executeRequest", Qt::AutoConnection, Q_ARG(
VFS_request*, r) );
1570 {
VFS::ERROR( QString(
"Cannot append '%1' to a %2 node where isContainer() is false. Not appending.").arg(name).arg(
className()) );
1575 {
VFS::ERROR( QString(
"Node name is invalid: '%1'. Not appending.").arg(name) );
1580 {
VFS::ERROR( QString(
"Child with name '%1' already exists. Not appending.").arg(name) );
1585 {
VFS::ERROR( QString(
"Cannot append null node '%1'").arg(name) );
1594 QMutexLocker l(&
_lock);
1599 VFS::LOG( QString(
"Appended node '%1'").arg(name), 8, user );
1611 d[name] =
node->isContainer();
1613 r.
_data = QJsonDocument(d);
1640 node->deleteLater();
1671 QMutexLocker l(&
_lock);
1677 if (rname) (*rname) = name;
1685 VFS::LOG( QString(
"Removing node%2'%1'").arg(name).arg(
' ',(
EXIT_DEPTH-1)*3), 8, user );
1691 d[name] = QJsonValue::Null;
1693 r.
_data = QJsonDocument(d);
1697 VFS::WARN( QString(
"Unable to unmount node '%1'").arg(name) );
1700 {
VFS::WARN( QString(
"Unable to unmount null node") );
1782 if (!(t->
_metadata.contains(
"suppressError") && t->
_metadata[
"suppressError"].toBool(
false) ==
true))
1837 catch (std::exception &e)
1888 VFS::ERROR(
"receiveResponse() called with null request." );
1960 QMetaObject::invokeMethod(target,
"subtreeRequest",Qt::AutoConnection,Q_ARG(
VFS_request*, t));
1964 { printf(
"issueRequest() called without a node. Deleting request.\n");
1994 QMetaObject::invokeMethod(target,
"receiveResponse",Qt::AutoConnection,Q_ARG(
VFS_request*, t));
2003 {
VFS::ERROR(
"issueResponse() called with null request or no receiver. Deleting request." );
2041 return metaObject()->className();
2056 QMutexLocker l(&
_lock);
2059 QString temp = name;
2063 temp = QString(
"%1-%2").arg(name).arg(i++);
2080 QMutexLocker l(&
_lock);
2103 if (name.trimmed().isEmpty())
return false;
2104 if (name.contains(QRegExp(
"[/]")))
return false;
2105 if (name.trimmed() != name)
return false;
2133 acl[
"default"] = value;
2134 if (!description.isEmpty())
2135 acl[
"description"] = description;
2150 QJsonObject g = acl[
"groups"].toObject();
2167 QJsonObject u = acl[
"users"].toObject();
2185 QJsonObject fs = acl[
"features"].toObject();
2186 QJsonObject f = fs[feature].toObject();
2187 f[
"default"] = value;
2188 if (!description.isEmpty())
2189 f[
"description"] = description;
2191 acl[
"features"] = fs;
2207 QJsonObject fs = acl[
"features"].toObject();
2208 QJsonObject f = fs[feature].toObject();
2209 QJsonObject g = f[
"groups"].toObject();
2213 acl[
"features"] = fs;
2229 QJsonObject fs = acl[
"features"].toObject();
2230 QJsonObject f = fs[feature].toObject();
2231 QJsonObject u = f[
"users"].toObject();
2235 acl[
"features"] = fs;
QPair< VFS_node *, QString > notifyException
QMap< QString, VFS_node * >::const_iterator VFS_childrenConstIterator
QMap< VFS_node *, qint32 > VFS_subscriptionCounter
QMap< QString, VFS_node * >::iterator VFS_childrenIterator
QMap< QString, VFS_subscriptionCounter > VFS_subscriptionOrigin
static char * get(QString which="")
Fetch an icon from the library.
VFS_node is the base class from which all other VFS_node classes derive.
virtual VFS_node * unmount()
Unmount this node.
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.
virtual void executeRequest(VFS_request *t)
Based on the VFS_request::requestType, execute the function associated with an operation.
virtual bool validChildName(QString name)
Check if a node name is valid.
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.
VFS_children _children
This node's children.
virtual void read(VFS_request *r)
Return the data contents of this node, or if it's a container call ls()
virtual void issueResponse(VFS_request *t)
Once a request has been completed, issue a response.
Q_INVOKABLE VFS_node()
The VFS_node constructor will add its instance to the VFS_node::__allNodes global node registry,...
void addACLGroup(QJsonObject &acl, QString group, bool value)
Add a group to the acl object.
virtual void metadata(VFS_request *r)
Fetch the metadata of this node.
static bool __removeNode(VFS_node *)
Remove a node from the global registry.
virtual void requestLock(VFS_request *r)
Request a lock on this node.
QString uniqueChildName(QString name)
Generate a unique child name.
virtual void report(VFS_request *r)
Report debugging information about the current state of this node.
virtual void unsubscribeAll(VFS_node *n)
Remove all references to a subscriber from this node.
virtual void submit(VFS_request *r)
Submit a diff to a node.
virtual void issueRequest(VFS_request *t)
A convenience function.
static bool __isNode(VFS_node *)
Check to see if a node is in the global registry.
void addACLFeatureUser(QJsonObject &acl, QString feature, QString user, bool value)
Add a feature user to the acl object.
void addACLFeature(QJsonObject &acl, QString feature, bool value, QString description="")
Add a feature to the acl object.
VFS_node * findChildWithName(QString name)
Check if a child with a given name exists.
VFS_node * find(QString path)
Find a node by string path.
virtual void write(VFS_request *r)
Write data to this node.
virtual void releaseLock(VFS_request *r)
Release a lock on this node.
virtual QByteArray icon()
Fetch the icon for a node.
virtual void ls(VFS_request *r)
List the contents of this node.
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.
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.
VFS_subscriptionType _subscribers
This node's subscribers. These subscribers will receive diff notifications.
void remove(bool andDelete)
Remove a child node.
virtual bool isContainer()
A VFS_node may have children.
void addACLFeatureGroup(QJsonObject &acl, QString feature, QString group, bool value)
Add a feature group to the acl object.
void addACLUser(QJsonObject &acl, QString user, bool value)
Add a user to the acl object.
virtual ~VFS_node()
VFS_node destructor.
void addACLDefault(QJsonObject &acl, bool value, QString description="")
Add a default value to the acl object.
virtual void unsubscribePath(QString path)
Unsubscribe all references to a subpath.
QMutex _lock
A recursive mutex that is local to this node.
virtual void subtreeRequest(VFS_request *t)
find() the target of a VFS_request, and execute the request
void notifySubscribers(VFS_node *origin, VFS_request *t)
Propagate a diff to subscribers.
static void __addNode(VFS_node *)
Add a node to the global registry.
static QSet< VFS_node * > __allNodes
The static global registry for all exiting nodes, used for thread safety checks.
virtual void applyDiff(VFS_request *r)
Apply a diff received via subscription.
virtual void rm(VFS_request *r)
Remove a child entry from a node, or the node itself.
virtual void aclDefaults(VFS_request *r)
Return default values and features associated wth this node.
virtual QString reportDetails()
Additional details for a generated report.
static QMutex __allNodesMutex
The global registry mutex, which will lock when node creation or deletion is being performed.
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.
virtual VFS_node * mount()
Mount this node.
virtual void subscribe(VFS_request *r)
Add an entry to this node's _subscription list.
virtual void receiveResponse(VFS_request *t)
Once a VFS_request has been completed, a response will be issued back to its _origin.
The base class for all requests between nodes.
static const char * requestTypeStrings[]
A printable string for each request type.
requestType
Requests perform one of these actions.
@ read
read full contents (4)
@ report
provide node report, for debugging (12)
@ requestlock
request a lock (13)
@ unsubscribe
unsubscribe from a path (10)
@ ls
list children of a node (1)
@ acl
return the ACL defaults for this node (11)
@ metadata
read metadata (6)
@ create
create a new file/path (2)
@ write
write full contents (5)
@ releaselock
release a lock (14)
@ subscribe
subscribe to a path (9)
@ rm
delete an existing file/path (3)
virtual ~VFS_request()
VFS_request destructor.
VFS_node * _responder
the receiver of the request
static QMutex _sampleLock
A mutex to protect thread safety of samples.
VFS_node * _origin
the origin of the request
virtual void setCallback(VFS_request *c)
Chain a callback onto this request.
QByteArray _rawData
the request payload, but raw data
bool hasCallback()
Check if this request has a callback set.
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.
requestType _requestType
the action this request is performing or requesting
static quint32 getSample()
Get the current sample count and clear the counter.
static quint32 _sampleCount
A count of the number of VFS_requests since the last sample was taken.
QString _initialPath
the target path when the request was made (relative to the responder)
QStringList _prefixPath
the prefix elements found while searching for the target
bool _dontDelete
A rarely used flag that will cause VFS_node::receiveResponse to not delete the node,...
QString _user
who initiated this request, mostly for logging
virtual void copyCallback(VFS_request *d)
Copy the data from a callback to this VFS_request.
virtual void fromJsonObject(QJsonObject json, bool includeInitialPath=false)
Deserialize a JSON string into a VFS_request.
virtual void execute()
after a request has completed, a request may have a special execute function.
VFS_session * _session
The session associated with this request. This is an optional value, and care should be taken to chec...
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 _isCallback
whether or not to issue a response (IE, another request is chained to this request,...
virtual VFS_request * createDiff(VFS_node *origin, QString originPath)
VFS_request::createDiff.
QString _originPath
the subpath of the origin node
QList< notifyException > _notifyExceptions
a list of nodes not to send responses to for this transaction. For instance if a node submits to a no...
bool _success
if the request was successfully completed
QJsonDocument _data
the request payload
virtual VFS_request * getCallback(VFS_node *receiver)
Create and chain a VFS_request for a receiver.
VFS_request * _callback
request to execute once this request completes
virtual QByteArray toJson(postID id=0, bool ignoreSuccess=false, bool includeInitialPath=false)
Serialize this request.
virtual void timerEvent(QTimerEvent *e=nullptr)
The callback for when a request times out.
static long _refcount
A reference counter for VFS_request instances, used for debugging to ensure all instances are properl...
QJsonObject _metadata
the request payload
static VFS * root()
Return the root node of the VFS filesystem.
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 WARN(QString message, int level=0, QString user="server")
Send a message to the VFS::_warnings VFS_stream.
setter value
a setter DOCME
setter name
a setter DOCME
setter type
a setter DOCME
getter path
a getter DOCME
QString cleanPath(QString path)
Clean and normalize a VFS path.