3 #include <QCoreApplication>
4 #include <QPluginLoader>
9 #include "utilities/jsmin/jsmin.h"
67 VFS::LOG( QString(
" -Loaded stdlib") );
77 printf(
"\nNodes in stdlib:\n\n%s", qUtf8Printable(stdlib->
describe()) );
80 pluginsDirs.prepend(qApp->applicationDirPath()+
"/plugins");
82 foreach( QString dir, pluginsDirs )
84 VFS::LOG( QString(
"Scanning plugins directory: '%1'").arg(dir) );
90 if (!pluginsDir.cd(dir))
91 {
VFS::WARN( QString(
" -Plugins directory not found: '%1'... skipping.\n").arg(dir) );
97 foreach (QString fileName, pluginsDir.entryList(QDir::Files))
101 QPluginLoader *
loader =
new QPluginLoader(pluginsDir.absoluteFilePath(fileName));
106 fileName.remove(0,3);
107 fileName.remove( fileName.lastIndexOf(
'.'), 100 );
108 VFS::LOG( QString(
" -Loaded plugin: %1\n").arg(fileName) );
112 QStringList provided = plugin->
provides();
115 printf(
"\nNodes in %s:\n\n%s", qUtf8Printable(fileName), qUtf8Printable(plugin->
describe()) );
117 foreach (QString
node, provided)
123 VFS::WARN( QString(
" -Duplicate node '%1' from plugin '%2'. Not added.").arg(
node).arg(fileName) );
127 VFS::WARN( QString(
"Failed to initialize plugin: %1\n").arg(fileName) );
130 {
VFS::WARN( QString(
"Unable to load plugin: '%1'.").arg(fileName) );
150 QString d = QCoreApplication::applicationDirPath().toUtf8();
156 env[
"cwd"] = QDir::currentPath();
157 env[
"configfile"] =
"";
165 qApp->processEvents();
191 VFS::WARN(
"No config file provided... this VFS ain't gonna do much! Try: VFS -?" );
195 QString _currentDirectory = env[
"cwd"].toString();
196 QString _currentConfigFile = env[
"configfile"].toString();
197 QString _oldPWD = _currentDirectory;
199 if (configFile[0]!=
'/')
202 if (_currentDirectory==
"")
203 { QString d = QCoreApplication::applicationDirPath().toUtf8();
212 QFileInfo f(d+sep+configFile);
213 configFile = f.absoluteFilePath();
219 configFile = _currentDirectory+
"/"+configFile;
223 QFileInfo f(configFile);
224 _currentConfigFile = configFile;
227 {
VFS::ERROR( QString(
"Config file doesn't exist: '%1'").arg(f.absoluteFilePath()) );
231 VFS::LOG( QString(
"Reading config file: '%1'").arg(f.absoluteFilePath()), 0 );
233 _currentDirectory = f.absoluteDir().path();
236 env[
"cwd"] = _currentDirectory;
237 env[
"configfile"] = _currentConfigFile;
240 for (
int i=0;i<attrs.length();i++)
242 QDomNode n = attrs.item(i);
247 QFile configFileFile(configFile);
249 int configErrorLine, configErrorColumn;
252 if (!config.setContent(&configFileFile,&configError,&configErrorLine,&configErrorColumn))
254 VFS::ERROR( QString(
"Failed to load config file: %1, error on line %2 at %3").arg(configFile).arg(configErrorLine).arg(configErrorColumn) );
261 printf(
"%s\n",qUtf8Printable(config.toString(8)));
265 QDomElement r = config.documentElement();
269 int logLevel = r.attribute(
"logLevel",
"9").toInt();
273 int logTime = r.attribute(
"logTime",
"0").toInt();
279 QString monitorFile = r.attribute(
"monitor",
"");
280 if (monitorFile !=
"")
282 if (monitorFile ==
"true")
283 { monitorFile = configFile;
287 {
if (monitorFile !=
"false" && monitorFile !=
"0")
289 f = QFileInfo( monitorFile );
293 VFS::WARN( QString(
"Can't monitor file: '%1', it doesn't exist.").arg(monitorFile) );
324 QDomNodeList children = nodeConfig.childNodes();
335 for (
int i=0;i<children.length();i++)
337 child = children.at(i).toElement();
341 tag = child.tagName();
346 name =
configAttribute(env,child,
"name",(tag!=
"env" && tag!=
"include" && tag!=
"parameters")?
true:
false);
351 if (tag ==
"env") {
if (envset)
352 {
VFS::ERROR( QString(
"Only one env is allowed per context. Aborting.") );
361 if (env.contains(
"adminemail"))
379 else if (tag ==
"parameters") {
382 else if (tag ==
"include") {
385 QDomNamedNodeMap attrs = child.attributes();
386 attrs.removeNamedItem(
"path");
392 QVariant vfscwd = env[
"vfscwd"];
393 if (vfscwd.toString() ==
"")
394 env[
"vfscwd"] = name;
396 env[
"vfscwd"] = env[
"vfscwd"].toString() +
"/" + name;
400 env[
"vfscwd"] = vfscwd;
408 VFS::WARN( QString(
"Skipping inactive node '%1:%2'.").arg(tag).arg(name) );
413 QString currentConfigFile = env[
"configfile"].toString();
414 VFS::ERROR( QString(
"Failed to create node '%1' on line %2.").arg(tag).arg(child.lineNumber()) );
415 VFS::ERROR( QString(
"Config file '%1' did not completely load.").arg(currentConfigFile) );
442 QString tag = child.tagName();
448 QString m =
configAttribute(env,child,
"threadmode",
false,
"roundrobin");
464 VFS::WARN( QString(
"No license found to create '%1' nodes.").arg(tag) );
467 VFS::WARN( QString(
"Unknown node type: '%1'. It will not be created.").arg(tag) );
483 if (
node &&
node->isContainer() && !thread)
504 QDomNodeList children = c.childNodes();
506 for (
int i=0;i<children.length();i++)
508 child = children.at(i).toElement();
512 tag = child.tagName();
517 if (!env.contains(tag) && !child.hasAttribute(
"value") && !child.hasAttribute(
"default"))
519 VFS::ERROR( QString(
"Missing required environment variable: '%1'. Was it set when included?").arg(tag) );
520 throw "missing required variable";
523 if (env.contains(tag) && !child.hasAttribute(
"value"))
528 env[tag] =
configAttribute(env,child,
"value",(child.hasAttribute(
"default")?
false:
true),child.attribute(
"default"));
554 QDomNodeList children = c.childNodes();
556 for (
int i=0;i<children.length();i++)
558 child = children.at(i).toElement();
563 tag = child.tagName();
568 if (!env.contains(tag) && !child.hasAttribute(
"value") && !child.hasAttribute(
"default"))
570 VFS::ERROR( QString(
"Missing required environment variable: '%1'. Was it set when included?").arg(tag) );
571 throw "missing required variable";
578 QString p =
configAttribute(env,child,
"value",(child.hasAttribute(
"default")?
false:
true),child.attribute(
"default"));
579 QString t = child.attribute(
"type",
"string");
581 if (t ==
"string") value = QJsonValue(p);
582 else if (t ==
"int") value = QJsonValue(p.toInt());
583 else if (t ==
"bool") value = QJsonValue(p ==
"true" || p ==
"1");
584 else throw "bad parameter type: "+t;
611 if (req && !e.hasAttribute(attr))
613 VFS::ERROR( QString(
"Missing required attribute: '%1:%2'").arg(e.tagName()).arg(attr) );
615 throw "missing attribute";
642 if (req && !e.hasAttribute(attr))
643 {
VFS::ERROR( QString(
"Missing required path attribute: '%1'").arg(attr) );
644 throw "missing attribute";
648 p = p.split(
"/",Qt::SkipEmptyParts).join(
"/");
673 if (req && !e.hasAttribute(attr))
674 {
VFS::ERROR( QString(
"Missing required path attribute: '%1'").arg(attr) );
675 throw "missing attribute";
678 QString p =
resolveEnvValue( e.attribute(attr,
"default"), env ).toLower();
684 else if (p ==
"1" || p ==
"true" || p ==
"yes")
714 if (req && !e.hasAttribute(attr))
715 {
VFS::ERROR( QString(
"Missing required path attribute: '%1'").arg(attr) );
716 throw "missing attribute";
719 QString p =
resolveEnvValue( e.attribute(attr,
"default"), env ).toLower();
728 int j = p.toInt(&ok);
733 VFS::ERROR( QString(
"Could not parse as int: '%1'=>'%2'").arg(attr).arg(p) );
734 throw "unparseable attribute";
763 if (req && !e.hasAttribute(attr))
764 {
VFS::ERROR( QString(
"Missing required path attribute: '%1'").arg(attr) );
765 throw "missing attribute";
768 QString p =
resolveEnvValue( e.attribute(attr,
"default"), env ).toLower();
777 double j = p.toDouble(&ok);
782 VFS::ERROR( QString(
"Could not parse as double: '%1'=>'%2'").arg(attr).arg(p) );
783 throw "unparseable attribute";
832 QRegExp rx(
"(@\\w+@)");
839 while ((pos = rx.indexIn(value)) != -1)
842 n = m.mid(1,m.length()-2);
847 value.replace(pos,m.length(),v);
849 else if (env.contains(n))
851 v = env[n].toString();
852 value.replace(pos,m.length(),v);
856 {
VFS::ERROR( QString(
"Unknown environment variable: '%1'.").arg(n) );
857 throw QString(
"unknown variable");
862 VFS::ERROR( QString(
"Too many resolve steps... does a variable refer to itself?") );
863 throw QString(
"too many resolve iterations");
867 if (value.contains(
'+') || value.contains(
'-') || value.contains(
'*'))
872 QJSValue _jsvalue = _engine.evaluate(value);
873 if (_jsvalue.isNumber())
874 value = _jsvalue.toString();
909 QString library = r->
_path;
910 QStringList parts = library.split(
':',Qt::SkipEmptyParts);
914 if (parts.size() != 2)
916 r->
_reason =
"Cannot satisfy code request without proper syntax: \"nodename:libname\".";
920 QString nodename = parts[0];
921 QString libname = parts[1];
932 VFS::LOG( QString(
"Requested code '%1'").arg(library), 9, r->
_user );
934 QString c = plugin->
code(nodename,libname,error);
936 if (!error.isEmpty())
943 if (libname.endsWith(
".css"))
949 if (libname.endsWith(
".js"))
952 c = JsMin().minify(c);
959 r->
_data.setObject(o);
968 VFS::LOG( QString(
"Requesting code from remote resource '%1'").arg(library), 9, r->
_user );
976 r->
_reason = QString(
"No remote resource node found in plugin %1").arg(library);
980 r->
_reason = QString(
"No valid license found for a '%1' node.\n\nCan't return code for it.").arg(nodename);
983 r->
_reason = QString(
"Unknown type: '%1::%2'. Can't return code for it.").arg(nodename).arg(libname);
1010 QMap<QString, VFS_node_interface *>::iterator end =
_plugins.end();
1011 for (QMap<QString, VFS_node_interface *>::iterator it =
_plugins.begin(); it != end; ++it)
#define VFS_CREATOR_MAX_OUTSTANDING
static VFS_node * constructNode(QDomElement child, QVariantMap &env, bool printConfig=false)
VFS_creator::constructNode.
static QJsonObject codeDirectory(QString &error)
Gather and return a directory of code namespaces served by this VFS instance.
static void build(QString configFile, VFS_node *root, bool printConfig=false)
Build an environment for creating nodes.
static bool registerPlugin(QString name, VFS_node_interface *node)
Register a plugin.
static int configIntAttribute(QVariantMap env, QDomElement e, QString attr, bool req=true, int def=0)
Fetch an XML node attribute value and resolve it against an environment, returning it as an int.
static void constructNodes(QDomElement nodeConfig, QVariantMap env, VFS_node *mount, bool printConfig=false)
Now that the file is open and an environment exists, do the work.
static bool configBoolAttribute(QVariantMap env, QDomElement e, QString attr, bool req=true, bool def=false)
Fetch an XML node attribute value and resolve it against an environment, returning it as a bool.
static VFS_request * code(VFS_request *r)
Resolve a request for code.
static QString configAttribute(QVariantMap env, QDomElement e, QString attr, bool req=true, QString def="")
Fetch an XML node attribute value and resolve it against an environment.
static QMap< QString, VFS_node_interface * > _plugins
The plugin registry.
static void init(QStringList plugins=QStringList(), bool describe=false)
Initialize plugins recursively.
static bool unregisterPlugin(QString name)
Unregister a plugin.
static void constructConfig(QString configFile, QVariantMap env, VFS_node *mount, bool printConfig, QDomNamedNodeMap attrs=QDomNamedNodeMap())
Build nodes from a config file using the provided environment values.
static double configDoubleAttribute(QVariantMap env, QDomElement e, QString attr, bool req=true, double def=0.0)
Fetch an XML node attribute value and resolve it against an environment, returning it as a double val...
static QString configPathAttribute(QVariantMap env, QDomElement e, QString attr, bool req=true, QString def="")
Fetch an XML node attribute value and resolve it against an environment, ensuring it is a cleaned pat...
static QMutex _pluginsLock
A mutex for protecting the _plugins object.
static QVariantMap constructEnvironment(QVariantMap env, QDomElement c)
Construct an environment from an <env> node.
static QString resolveEnvValue(QString value, QVariantMap env)
Resolve an incoming value against the system environment and the provided environment.
static QProcessEnvironment _systemEnvironment
The system environment inherited during startup.
static void setParameters(QVariantMap env, QDomElement c)
Set parameters on the VFS::root() instance, for future query.
static QSemaphore _outstanding
A semaphore used to sync creation during startup.
The interface class for dynamically loaded plugins.
bool isRemote()
If a plugin represents a remote resource, this value will be true.
virtual bool initialize()
The plugin initializer.
virtual bool licensed(QString type)
A licensing mechanism for node creation.
QString describe()
Describe all the nodes in a plugin.
virtual QString code(QString nodename, QString libname, QString &error)
Request code or other resource from a plugin bundle.
virtual QStringList provides()
A string list of node names that this plugin is prepared to create.
VFS_node * remoteNode()
Return the node needed to satisfy a remote request.
virtual VFS_node * create(QString type, QVariantMap env, QDomElement child)
Create a new node instance.
VFS_node is the base class from which all other VFS_node classes derive.
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.
The base class for all requests between nodes.
@ code
request code from a node (15)
virtual void setCallback(VFS_request *c)
Chain a callback onto this request.
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
The standard library of nodes needed to build a VFS.
A wrapper for replicating nodes in different threads to produce more responsive workers in multithrea...
static const QStringList modeStrings
string names of each mode for the config file
mode
A pool will distribute requests based on a mode.
static QJsonObject _parameters
VFS parameters, defined in a config file.
static QMap< QString, QDateTime > _monitoredFiles
A list of path:datetime entries that the VFS will monitor for changes.
static VFS * root()
Return the root node of the VFS filesystem.
void setLogSettings(int loglevel, int logtime)
Set the loglevel and logtime values for the logger.
static void LOG(QString message, int level=0, QString user="server")
Send a message to the VFS::_messages VFS_stream.
void setAdminEmail(QString emails)
Set the admin email addresses for CRITICAL messages.
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