Remoto - VFS: VFS_creator.cpp Source File
Remoto - VFS
VFS_creator.cpp
Go to the documentation of this file.
1 #include "VFS_creator.h"
2 
3 #include <QCoreApplication>
4 #include <QPluginLoader>
5 #include <QJSEngine>
6 //#include <QHostInfo>
7 #include <QDir>
8 
9 #include "utilities/jsmin/jsmin.h"
10 
11 #include "VFS_base/VFS_thread.h"
13 #include "VFS_base/VFS_acl.h"
14 #include "VFS_stdlib/VFS_stdlib.h"
15 
37 QMutex VFS_creator::_pluginsLock(QMutex::Recursive);
38 QMap<QString, VFS_node_interface *> VFS_creator::_plugins;
40 QProcessEnvironment VFS_creator::_systemEnvironment;
41 
42 /*
43 VFS_creator::VFS_creator()
44 {
45 }
46 
47 VFS_creator::~VFS_creator()
48 {
49 }
50 */
51 
60 void VFS_creator::init(QStringList pluginsDirs,bool describe)
61 {
62  //VFS::LOG( "Loading plugins..." );
63 
64  QMutexLocker l(&_pluginsLock);
65 
66  if (describe)
67  VFS::LOG( QString(" -Loaded stdlib") );
68 
69  //create the factory for standard types and for core js/css code
70  VFS_node_interface *stdlib = new VFS_stdlib();
71  stdlib->initialize();
72  _plugins["stdlib"] = stdlib;
73  foreach (QString node, stdlib->provides())
74  _plugins[node] = stdlib;
75 
76  if (describe)
77  printf( "\nNodes in stdlib:\n\n%s", qUtf8Printable(stdlib->describe()) );
78 
79  //prepend the default plugins directory
80  pluginsDirs.prepend(qApp->applicationDirPath()+"/plugins");
81 
82  foreach( QString dir, pluginsDirs )
83  {
84  VFS::LOG( QString("Scanning plugins directory: '%1'").arg(dir) );
85 
86  //descend into plugins dirs, and load those
87  QDir pluginsDir;// = QDir(qApp->applicationDirPath());
88 
89  //if (!pluginsDir.cd("plugins"))
90  if (!pluginsDir.cd(dir))
91  { VFS::WARN( QString(" -Plugins directory not found: '%1'... skipping.\n").arg(dir) );
92  continue;
93  }
94 
95  //printf("plugin dir: %s\n",qUtf8Printable(pluginsDir.path()));
96 
97  foreach (QString fileName, pluginsDir.entryList(QDir::Files))
98  {
99  //VFS::LOG( QString("Loading '%1'...").arg(fileName) );
100 
101  QPluginLoader *loader = new QPluginLoader(pluginsDir.absoluteFilePath(fileName));
102  VFS_node_interface *plugin = qobject_cast<VFS_node_interface *>(loader->instance());
103 
104  if (plugin)
105  {
106  fileName.remove(0,3); //remove 'lib' from the fileName
107  fileName.remove( fileName.lastIndexOf('.'), 100 );
108  VFS::LOG( QString(" -Loaded plugin: %1\n").arg(fileName) );
109 
110  if (plugin->initialize())
111  {
112  QStringList provided = plugin->provides();
113 
114  if (describe)
115  printf( "\nNodes in %s:\n\n%s", qUtf8Printable(fileName), qUtf8Printable(plugin->describe()) );
116 
117  foreach (QString node, provided)
118  {
119  //node = node.toLower();
120  if (!_plugins.contains(node))
121  _plugins[node] = plugin;
122  else
123  VFS::WARN( QString(" -Duplicate node '%1' from plugin '%2'. Not added.").arg(node).arg(fileName) );
124  }
125  }
126  else
127  VFS::WARN( QString("Failed to initialize plugin: %1\n").arg(fileName) );
128  }
129  else
130  { VFS::WARN( QString("Unable to load plugin: '%1'.").arg(fileName) );
131  VFS::WARN( loader->errorString() );
132  }
133  }
134  }
135 }
136 
148 void VFS_creator::build(QString configFile, VFS_node *root, bool printConfig)
149 {
150  QString d = QCoreApplication::applicationDirPath().toUtf8();
151 
152  _systemEnvironment = QProcessEnvironment::systemEnvironment();
153 
154  QVariantMap env;
155  env["approot"] = d;
156  env["cwd"] = QDir::currentPath();
157  env["configfile"] = "";
158  env["vfscwd"] = "";
159 
160  _outstanding.acquire();
161 
162  constructConfig(configFile,env,root,printConfig);
163 
164  _outstanding.acquire(VFS_CREATOR_MAX_OUTSTANDING-1); //wait until all others have been released.
165  qApp->processEvents(); //clear out event queue before returning for exec in main(), so messages can be printed before returning.
166  _outstanding.release(VFS_CREATOR_MAX_OUTSTANDING); //and then release them now that it's synced
167 }
168 
187 void VFS_creator::constructConfig(QString configFile, QVariantMap env, VFS_node *mount, bool printConfig, QDomNamedNodeMap attrs)
188 {
189  if (configFile=="/")
190  {
191  VFS::WARN( "No config file provided... this VFS ain't gonna do much! Try: VFS -?" );
192  return;
193  }
194 
195  QString _currentDirectory = env["cwd"].toString();
196  QString _currentConfigFile = env["configfile"].toString();
197  QString _oldPWD = _currentDirectory;
198 
199  if (configFile[0]!='/')
200  {
201  //if it's the first time...
202  if (_currentDirectory=="")
203  { QString d = QCoreApplication::applicationDirPath().toUtf8();
204 
205  #ifdef Q_OS_MAC
206  //QString sep = "/../../../";
207  QString sep = "/";
208  #else
209  QString sep = "/";
210  #endif
211 
212  QFileInfo f(d+sep+configFile);
213  configFile = f.absoluteFilePath();
214  }
215  //if it's an include...
216  else
217  {
218  //printf("include: %s (%s)\n",qUtf8Printable(configFile),qUtf8Printable(_currentDirectory));
219  configFile = _currentDirectory+"/"+configFile;
220  }
221  }
222 
223  QFileInfo f(configFile);
224  _currentConfigFile = configFile;
225 
226  if (!f.isFile())
227  { VFS::ERROR( QString("Config file doesn't exist: '%1'").arg(f.absoluteFilePath()) );
228  exit(1);
229  }
230  else
231  VFS::LOG( QString("Reading config file: '%1'").arg(f.absoluteFilePath()), 0 );
232 
233  _currentDirectory = f.absoluteDir().path();
234  //printf("current: %s\n",qUtf8Printable(_currentDirectory));
235 
236  env["cwd"] = _currentDirectory;
237  env["configfile"] = _currentConfigFile;
238 
239  //add any additional inherited env values, probably from an include call.
240  for (int i=0;i<attrs.length();i++)
241  {
242  QDomNode n = attrs.item(i);
243  env[n.nodeName()] = resolveEnvValue( n.nodeValue(), env );
244  }
245 
246  //parse config file
247  QFile configFileFile(configFile);
248  QString configError;
249  int configErrorLine, configErrorColumn;
250 
251  QDomDocument config;
252  if (!config.setContent(&configFileFile,&configError,&configErrorLine,&configErrorColumn))
253  {
254  VFS::ERROR( QString("Failed to load config file: %1, error on line %2 at %3").arg(configFile).arg(configErrorLine).arg(configErrorColumn) );
255  VFS::ERROR( configError );
256  exit(1);
257  }
258 
259  //print config values
260  if (printConfig)
261  printf("%s\n",qUtf8Printable(config.toString(8)));
262 
263  if (mount == VFS::root())
264  {
265  QDomElement r = config.documentElement();
266 
267  //QString version = r.attribute("version","1.0"); //make use of this someday
268 
269  int logLevel = r.attribute("logLevel","9").toInt();
270  if(_systemEnvironment.contains("VFS_LOG_LEVEL"))
271  logLevel = _systemEnvironment.value("VFS_LOG_LEVEL").toInt();
272 
273  int logTime = r.attribute("logTime","0").toInt();
274  if(_systemEnvironment.contains("VFS_LOG_TIME"))
275  logTime = _systemEnvironment.value("VFS_LOG_TIME").toInt();
276 
277  VFS::root()->setLogSettings(logLevel, logTime );
278 
279  QString monitorFile = r.attribute("monitor","");
280  if (monitorFile != "")
281  {
282  if (monitorFile == "true") //string "true" resolves to the current config file
283  { monitorFile = configFile;
284  VFS::_monitoredFiles.insert(monitorFile,f.lastModified());
285  }
286  else
287  { if (monitorFile != "false" && monitorFile != "0")
288  {
289  f = QFileInfo( monitorFile );
290  if (f.exists())
291  VFS::_monitoredFiles.insert(monitorFile,f.lastModified());
292  else
293  VFS::WARN( QString("Can't monitor file: '%1', it doesn't exist.").arg(monitorFile) );
294  }
295  }
296 
297  }
298  }
299 
300  constructNodes(config.documentElement(),env,mount,printConfig);
301 
302  //_currentDirectory = _oldPWD;
303 }
304 
322 void VFS_creator::constructNodes(QDomElement nodeConfig, QVariantMap env, VFS_node *mount, bool printConfig)
323 {
324  QDomNodeList children = nodeConfig.childNodes();
325  QDomElement child;
326 
327  VFS_node *node=nullptr;
328  QString name,tag;
329  bool envset = false;
330  //uint thread = 0;
331 
332  //QVariantMap e(_env.top());
333  //_env.push(e); //create a new context from the previous one.
334 
335  for (int i=0;i<children.length();i++)
336  {
337  child = children.at(i).toElement();
338  if (child.isNull())
339  continue;
340 
341  tag = child.tagName();
342  //printf("TAG: %s\n",qUtf8Printable(tag));
343 
344  try
345  {
346  name = configAttribute(env,child,"name",(tag!="env" && tag!="include" && tag!="parameters")?true:false);
347  //thread = configAttribute(env,child,"thread",false,"0").toInt();
348 
349  if (configAttribute(env,child,"active",false,"true") == "true")
350  {
351  if (tag == "env") { if (envset)
352  { VFS::ERROR( QString("Only one env is allowed per context. Aborting.") );
353  exit(2);
354  }
355 
356  envset = true;
357 
358  env = constructEnvironment(env,child);
359 
360  if (mount == VFS::root())
361  if (env.contains("adminemail"))
362  VFS::root()->setAdminEmail( env["adminemail"].toString() );
363 
364  /*
365  printf("ENV STACK:\n");
366  for (int i=0;i<_env.length();i++)
367  {
368  printf("%d ========================\n",i);
369  QVariantMap::const_iterator it = _env.at(i).begin();
370  while(it!=_env.at(i).end())
371  {
372  printf("v: %s \t%s\n",qUtf8Printable(it.key()),qUtf8Printable(it.value().toString()));
373  it++;
374  }
375  }
376  //exit(1);
377  */
378  }
379  else if (tag == "parameters") {
380  setParameters(env,child);
381  }
382  else if (tag == "include") {
383  QString path = configAttribute(env,child,"path",true);
384 
385  QDomNamedNodeMap attrs = child.attributes();
386  attrs.removeNamedItem("path");
387 
388  constructConfig(path,env,mount,printConfig,attrs);
389  }
390  else
391  {
392  QVariant vfscwd = env["vfscwd"]; //set to current child
393  if (vfscwd.toString() == "")
394  env["vfscwd"] = name;
395  else
396  env["vfscwd"] = env["vfscwd"].toString() + "/" + name;
397 
398  node = constructNode(child,env,printConfig);
399 
400  env["vfscwd"] = vfscwd; //return to previous value
401 
402  if (node)
403  mount->append(name,node);
404  }
405  }
406  else
407  {
408  VFS::WARN( QString("Skipping inactive node '%1:%2'.").arg(tag).arg(name) );
409  }
410  }
411  catch (...)
412  {
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) );
416  }
417  }
418 }
419 
437 VFS_node *VFS_creator::constructNode(QDomElement child, QVariantMap &env, bool printConfig)
438 {
439  QMutexLocker l(&_pluginsLock);
440 
441  VFS_node *node=nullptr;
442  QString tag = child.tagName();
443  uint thread = configAttribute(env,child,"thread",false,"0").toUInt();
444 
445  if (thread) {
446  if (thread > 1)
447  {
448  QString m = configAttribute(env,child,"threadmode",false,"roundrobin");
449  int mi = qMax( VFS_threadpool::modeStrings.indexOf( m ), 0);
450  VFS_threadpool::mode mode = static_cast<VFS_threadpool::mode>(mi);
451  node = new VFS_threadpool(thread, mode, child, env, printConfig);
452  }
453  else
454  node = new VFS_thread(child, env, printConfig);
455  }
456  else {
457  if (_plugins.contains(tag))
458  {
459  VFS_node_interface *plugin = _plugins[tag];
460 
461  if (plugin->licensed(tag))
462  node = plugin->create(tag,env,child);
463  else
464  VFS::WARN( QString("No license found to create '%1' nodes.").arg(tag) );
465  }
466  else
467  VFS::WARN( QString("Unknown node type: '%1'. It will not be created.").arg(tag) );
468  }
469 
470  /*
471  if (node && !thread)
472  {
473  //printf("Checking %s %s\n", qUtf8Printable(env["vfscwd"].toString()),qUtf8Printable(node->className()));
474 
475  if (VFS_acl::hasRegisteredDefaults( node->className() ))
476  {
477  //printf("Would add features to %s\n", qUtf8Printable(env["vfscwd"].toString()));
478  VFS_acl::includeACLDefaults(env["vfscwd"].toString(), node->className());
479  }
480  }
481  */
482 
483  if (node && node->isContainer() && !thread)
484  constructNodes(child,env,node,printConfig);
485 
486  return node;
487 }
488 
489 
499 QVariantMap VFS_creator::constructEnvironment(QVariantMap env, QDomElement c)
500 {
501  QDomElement child;
502  QString tag;
503 
504  QDomNodeList children = c.childNodes();
505 
506  for (int i=0;i<children.length();i++)
507  {
508  child = children.at(i).toElement();
509  if (child.isNull())
510  continue;
511 
512  tag = child.tagName();
513 
514  //printf("parsing: %s %d\n",qUtf8Printable(tag),(child.hasAttribute("default")));
515 
516  //if not exist, and will not be set by this (no default or value), then we know it's required and needs to be provided by an ancestor
517  if (!env.contains(tag) && !child.hasAttribute("value") && !child.hasAttribute("default"))
518  {
519  VFS::ERROR( QString("Missing required environment variable: '%1'. Was it set when included?").arg(tag) );
520  throw "missing required variable";
521  }
522 
523  if (env.contains(tag) && !child.hasAttribute("value")) //if it does exist, but is not going to be explicitly set (we don't care about defaults), then move on.
524  continue;
525  else
526  {
527  //FIXME: do a type conversion here based on specified "type" field?
528  env[tag] = configAttribute(env,child,"value",(child.hasAttribute("default")?false:true),child.attribute("default"));
529  }
530  }
531 
532  return env;
533 }
534 
548 void VFS_creator::setParameters(QVariantMap env, QDomElement c)
549 {
550  QDomElement child;
551  QString tag;
552  QJsonValue value;
553 
554  QDomNodeList children = c.childNodes();
555 
556  for (int i=0;i<children.length();i++)
557  {
558  child = children.at(i).toElement();
559 
560  if (child.isNull())
561  continue;
562 
563  tag = child.tagName();
564 
565  //printf("parsing: %s %d\n",qUtf8Printable(tag),(child.hasAttribute("default")));
566 
567  //if not exist, and will not be set by this (no default or value), then we know it's required and needs to be provided by an ancestor
568  if (!env.contains(tag) && !child.hasAttribute("value") && !child.hasAttribute("default"))
569  {
570  VFS::ERROR( QString("Missing required environment variable: '%1'. Was it set when included?").arg(tag) );
571  throw "missing required variable";
572  }
573 
574  // if (env.contains(tag) && !child.hasAttribute("value")) //if does exist, but is not going to be explicitly set (we don't care about defaults), then move on.
575  // continue;
576  // else
577  {
578  QString p = configAttribute(env,child,"value",(child.hasAttribute("default")?false:true),child.attribute("default"));
579  QString t = child.attribute("type","string");
580 
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;
585 
586  VFS::_parameters[tag] = value;
587  env[tag] = p;
588  }
589  }
590 }
591 
609 QString VFS_creator::configAttribute(QVariantMap env, QDomElement e, QString attr, bool req, QString def)
610 {
611  if (req && !e.hasAttribute(attr))
612  {
613  VFS::ERROR( QString("Missing required attribute: '%1:%2'").arg(e.tagName()).arg(attr) );
614 
615  throw "missing attribute";
616  }
617 
618  return resolveEnvValue( e.attribute(attr,def), env );
619 }
620 
640 QString VFS_creator::configPathAttribute(QVariantMap env, QDomElement e, QString attr, bool req, QString def)
641 {
642  if (req && !e.hasAttribute(attr))
643  { VFS::ERROR( QString("Missing required path attribute: '%1'").arg(attr) );
644  throw "missing attribute";
645  }
646 
647  QString p = resolveEnvValue( e.attribute(attr,def), env );
648  p = p.split("/",Qt::SkipEmptyParts).join("/"); //sanitize any incoming path
649  return p;
650 }
651 
652 
671 bool VFS_creator::configBoolAttribute(QVariantMap env, QDomElement e, QString attr, bool req, bool def)
672 {
673  if (req && !e.hasAttribute(attr))
674  { VFS::ERROR( QString("Missing required path attribute: '%1'").arg(attr) );
675  throw "missing attribute";
676  }
677 
678  QString p = resolveEnvValue( e.attribute(attr,"default"), env ).toLower();
679 
680  bool b;
681 
682  if (p == "default")
683  b = def;
684  else if (p == "1" || p == "true" || p == "yes")
685  b = true;
686  else
687  b = false;
688 
689  return b;
690 }
691 
692 
712 int VFS_creator::configIntAttribute(QVariantMap env, QDomElement e, QString attr, bool req, int def)
713 {
714  if (req && !e.hasAttribute(attr))
715  { VFS::ERROR( QString("Missing required path attribute: '%1'").arg(attr) );
716  throw "missing attribute";
717  }
718 
719  QString p = resolveEnvValue( e.attribute(attr,"default"), env ).toLower();
720 
721  int i;
722 
723  if (p == "default")
724  i = def;
725  else
726  {
727  bool ok=0;
728  int j = p.toInt(&ok);
729  if (ok)
730  i = j;
731  else
732  {
733  VFS::ERROR( QString("Could not parse as int: '%1'=>'%2'").arg(attr).arg(p) );
734  throw "unparseable attribute";
735  }
736  }
737 
738  return i;
739 }
740 
741 
761 double VFS_creator::configDoubleAttribute(QVariantMap env, QDomElement e, QString attr, bool req, double def)
762 {
763  if (req && !e.hasAttribute(attr))
764  { VFS::ERROR( QString("Missing required path attribute: '%1'").arg(attr) );
765  throw "missing attribute";
766  }
767 
768  QString p = resolveEnvValue( e.attribute(attr,"default"), env ).toLower();
769 
770  double r;
771 
772  if (p == "default")
773  r = def;
774  else
775  {
776  bool ok=0;
777  double j = p.toDouble(&ok);
778  if (ok)
779  r = j;
780  else
781  {
782  VFS::ERROR( QString("Could not parse as double: '%1'=>'%2'").arg(attr).arg(p) );
783  throw "unparseable attribute";
784  }
785  }
786 
787  //printf("PARSED: %s %f\n",qUtf8Printable(p),r);
788 
789  return r;
790 }
791 
792 
830 QString VFS_creator::resolveEnvValue(QString value, QVariantMap env)
831 {
832  QRegExp rx("(@\\w+@)");
833  QString m,n,v;
834  int pos = 0;
835 
836  //VFS::WARN( QString(" resolving: %1").arg(value) );
837 
838  int count = 0;
839  while ((pos = rx.indexIn(value)) != -1)
840  {
841  m = rx.cap(1);
842  n = m.mid(1,m.length()-2); //trim off '@'
843 
844  if(_systemEnvironment.contains(n)) //check the system environment for existence
845  {
846  v = _systemEnvironment.value(n);
847  value.replace(pos,m.length(),v);
848  }
849  else if (env.contains(n)) //then the local environment
850  {
851  v = env[n].toString();
852  value.replace(pos,m.length(),v);
853  //pos += rx.matchedLength();
854  }
855  else
856  { VFS::ERROR( QString("Unknown environment variable: '%1'.").arg(n) );
857  throw QString("unknown variable");
858  }
859 
860  if(count++ > 20)
861  {
862  VFS::ERROR( QString("Too many resolve steps... does a variable refer to itself?") );
863  throw QString("too many resolve iterations");
864  }
865  }
866 
867  if (value.contains('+') || value.contains('-') || value.contains('*')) //evaluate basic math operations
868  {
869  //printf("EVAL1: %s\n",qUtf8Printable(value));
870 
871  QJSEngine _engine;
872  QJSValue _jsvalue = _engine.evaluate(value);
873  if (_jsvalue.isNumber())
874  value = _jsvalue.toString();
875  //value = _engine.evaluate(value).toString();
876 
877  //printf("EVAL2: %s\n",qUtf8Printable(value));
878  }
879 
880  //VFS::WARN( QString(" resolved: %1").arg(value) );
881 
882  return value;
883 }
884 
906 {
907  QMutexLocker l(&_pluginsLock);
908 
909  QString library = r->_path;
910  QStringList parts = library.split(':',Qt::SkipEmptyParts);
911 
912  r->_success = false;
913 
914  if (parts.size() != 2)
915  {
916  r->_reason = "Cannot satisfy code request without proper syntax: \"nodename:libname\".";
917  return r;
918  }
919 
920  QString nodename = parts[0];
921  QString libname = parts[1];
922  QString error;
923 
924  if (_plugins.contains(nodename))
925  {
926  VFS_node_interface *plugin = _plugins[nodename];
927 
928  if (plugin->licensed(nodename))
929  {
930  if (!plugin->isRemote()) //local resource
931  {
932  VFS::LOG( QString("Requested code '%1'").arg(library), 9, r->_user );
933 
934  QString c = plugin->code(nodename,libname,error);
935 
936  if (!error.isEmpty())
937  {
938  r->_reason = error;
939  r->_success = false;
940  return r;
941  }
942 
943  if (libname.endsWith(".css"))
944  {
945  //insert css parser here, which can detokenize stuff if we want
946  //c = parseCSS(c);
947  }
948 
949  if (libname.endsWith(".js"))
950  {
951  //printf("USE JSMIN!:\n%s\n",qUtf8Printable( JsMin().minify(c.toUtf8())) );
952  c = JsMin().minify(c);
953  }
954 
955  QJsonObject o;
956  o["name"] = library;
957  o["code"] = c;
958 
959  r->_data.setObject(o);
960  r->_success = true;
961  }
962  else //remote resource
963  {
964  VFS_node *p = plugin->remoteNode();
965 
966  if (p)
967  {
968  VFS::LOG( QString("Requesting code from remote resource '%1'").arg(library), 9, r->_user );
969 
970  VFS_request *rr = new VFS_request(VFS_request::code,p,library,r->_user);
971  rr->setCallback(r);
972 
973  return rr;
974  }
975  else
976  r->_reason = QString("No remote resource node found in plugin %1").arg(library);
977  }
978  }
979  else
980  r->_reason = QString("No valid license found for a '%1' node.\n\nCan't return code for it.").arg(nodename);
981  }
982  else
983  r->_reason = QString("Unknown type: '%1::%2'. Can't return code for it.").arg(nodename).arg(libname);
984 
985  return r;
986 }
987 
988 
999 QJsonObject VFS_creator::codeDirectory(QString &error)
1000 {
1001  QMutexLocker l(&_pluginsLock);
1002 
1003  error = "";
1004 
1005  VFS_node_interface *stdlib = _plugins["stdlib"];
1006 
1007  QJsonObject o;
1008 
1009  VFS_node_interface *n;
1010  QMap<QString, VFS_node_interface *>::iterator end = _plugins.end();
1011  for (QMap<QString, VFS_node_interface *>::iterator it = _plugins.begin(); it != end; ++it)
1012  {
1013  //std::cout << qUtf8Printable(it.key()) << "," << qUtf8Printable(it.value());
1014 
1015  n = it.value();
1016  if (n!=stdlib)
1017  {
1018  o[it.key()] = true;
1019  }
1020  }
1021 
1022  return o;
1023 }
1024 
1036 {
1037  QMutexLocker l(&_pluginsLock);
1038 
1039  if (!_plugins.contains(name))
1040  {
1041  _plugins[name] = node;
1042  return true;
1043  }
1044 
1045  return false;
1046 }
1047 
1058 {
1059  QMutexLocker l(&_pluginsLock);
1060 
1061  if (!_plugins.contains(name))
1062  return false;
1063 
1064  _plugins.remove(name);
1065 
1066  return true;
1067 }
#define VFS_CREATOR_MAX_OUTSTANDING
Definition: VFS_creator.h:15
static VFS_node * constructNode(QDomElement child, QVariantMap &env, bool printConfig=false)
VFS_creator::constructNode.
friend class VFS_thread
Definition: VFS_creator.h:20
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.
Definition: VFS_creator.h:54
static void init(QStringList plugins=QStringList(), bool describe=false)
Initialize plugins recursively.
Definition: VFS_creator.cpp:60
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.
Definition: VFS_creator.h:41
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.
Definition: VFS_creator.h:57
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.
Definition: VFS_creator.h:56
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.
Definition: VFS_node.h:143
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
The base class for all requests between nodes.
Definition: VFS_node.h:54
@ code
request code from a node (15)
Definition: VFS_node.h:79
virtual void setCallback(VFS_request *c)
Chain a callback onto this request.
Definition: VFS_node.cpp:286
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
The standard library of nodes needed to build a VFS.
Definition: VFS_stdlib.h:7
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.
Definition: VFS.h:39
static QMap< QString, QDateTime > _monitoredFiles
A list of path:datetime entries that the VFS will monitor for changes.
Definition: VFS.h:57
static VFS * root()
Return the root node of the VFS filesystem.
Definition: VFS.cpp:399
void setLogSettings(int loglevel, int logtime)
Set the loglevel and logtime values for the logger.
Definition: VFS.cpp:163
static void LOG(QString message, int level=0, QString user="server")
Send a message to the VFS::_messages VFS_stream.
Definition: VFS.cpp:209
void setAdminEmail(QString emails)
Set the admin email addresses for CRITICAL messages.
Definition: VFS.cpp:148
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 name
a setter DOCME
setter error
Set the error value of this widget.