Remoto - VFS: VFS.cpp Source File
Remoto - VFS
VFS.cpp
Go to the documentation of this file.
1 
2 #include <iostream>
3 #include <math.h>
4 
5 #include <QMutexLocker>
6 #include <QFileInfo>
7 #include <QCoreApplication>
8 
9 #include "defines.h"
10 #include "VFS.h"
11 #include "VFS_creator.h"
12 #include "VFS_base/VFS_thread.h"
13 #include "VFS_base/VFS_icons.h"
14 
17 
18 VFS *VFS::_vfs(nullptr);
19 QJsonObject VFS::_parameters;
20 QMap<QString,QDateTime> VFS::_monitoredFiles;
21 
50 VFS::VFS(QString configFile, QStringList plugins, bool describe, bool printConfig)
51 : VFS_node()
52 , _start(QDateTime::currentMSecsSinceEpoch())
53 , cp_init(CYAN, BOLD)
54 , cp_bold(UNDEF, BOLD)
55 , cp_warn(YELLOW, BOLD)
56 , cp_error(RED, BOLD)
57 , _logLevel(9)
58 , _logTime(0)
59 , _logger(nullptr)
60 {
61  if (_vfs)
62  throw "Only one instance of the VFS is allowed.";
63 
64  //set the static global instance object
65  _vfs = this;
66 
67  if (configFile.isEmpty())
68  { VFS::ERROR("No config file specified.");
69  return;
70  }
71 
72  VFS::LOG("Initializing VFS on thread #0 'VFS'", 0);
73 
74  //name the main thread
75  thread()->setObjectName("VFS");
76 
77  //load all plugins
78  VFS_creator::init(plugins,describe);
79 
80  if (describe)
81  return;
82 
83  VFS::LOG( QString("Plugins loaded."), 0);
84  //VFS::LOG( "----------------------------------" );
85 
86 
87  //create the logger and wait for the thread to fully start
88  VFS_creator::_outstanding.acquire();
89  _logger = VFS_thread::fromConfig( QString("<logger name='logs' logLevel='%1' logTime='%2' adminAddress='%3' />").arg(_logLevel).arg(_logTime).arg("") );
90  append("logs", _logger);
92  qApp->processEvents();
94 
95  //now we're synchronized
96  VFS::LOG( "----------------------------------" );
97  VFS::LOG( QString("VFS %1").arg(VFS_GIT_VERSION),0);
98  VFS::LOG( QString("Logger started: %1 %2").arg(QDateTime::currentDateTime().toString()).arg(QDateTime::currentDateTime().toString("t")), 0);
99  VFS::LOG( "----------------------------------" );
100 
101  VFS_creator::build(configFile,this,printConfig);
102 
103 
104  if (_monitoredFiles.size())
105  {
106  LOG( "----------------------------------" );
107  LOG( QString("VFS monitoring %1 config file%2 for changes:").arg(_monitoredFiles.size()).arg(_monitoredFiles.size() > 1 ? "s" : ""), 0);
108  QMap<QString, QDateTime>::iterator i;
109  for (i = _monitoredFiles.begin(); i != _monitoredFiles.end(); ++i)
110  LOG(" - "+i.key());
111  LOG( "----------------------------------" );
112 
113  _monitorTimerID = startTimer(1*1000*30); //start the monitor timer, every 30 seconds.
114  }
115 
116  LOG( QString("VFS initialized with %1 thread%2.").arg(VFS_thread::threadcount()).arg(VFS_thread::threadcount() > 1 ? "s" : ""), 0);
117  LOG( "----------------------------------" );
118 
119 
120  emit initialized();
121 }
122 
133 {
134  //remove this referene so messages fall back to [ INIT ] state while the VFS is being destroyed
135  this->_logger = nullptr;
136 
137  WARN("Exiting VFS...");
138 
139  //remove static instance
140  //_vfs = nullptr; //leave for now so we get messages. The global _vfs will now be invalid.
141 }
142 
148 void VFS::setAdminEmail(QString emails)
149 {
150  QJsonObject o;
151  o["adminemail"] = emails;
152 
153  VFS_request *r = createRequest(VFS_request::submit,"logs/settings","server",QJsonDocument(o));
154  issueRequest(r);
155 }
156 
163 void VFS::setLogSettings(int loglevel, int logtime)
164 {
165  _logLevel = loglevel;
166  _logTime = logtime;
167 
168  QJsonObject o;
169  o["loglevel"] = loglevel;
170  o["logtime"] = logtime;
171 
172  VFS_request *r = createRequest(VFS_request::submit,"logs/settings","server",QJsonDocument(o));
173  issueRequest(r);
174 }
175 
182 void VFS::getLogSettings(int &loglevel, int &logtime)
183 {
184  loglevel = _logLevel;
185  logtime = _logTime;
186 }
187 
193 QByteArray VFS::icon()
194 {
195  return VFS_icons::get("application");
196 }
197 
209 void VFS::LOG(QString message, int level, QString user)
210 {
211  level = qBound(0,level,9);
212 
213  //if (level > _vfs->_logLevel)
214  // return;
215 
216  QDateTime now = QDateTime::currentDateTime();
217 
218  //QString s = QString("%1,LOG,%2,%3,%4%5").arg(now.toMSecsSinceEpoch()).arg(user).arg(level).arg(message).arg(message.right(1)=="\n" ? "" : "\n");
219 
220  //use https://stackoverflow.com/questions/57452407/qstring-arg-issue-when-arg-contains-a-character-how-to-prevent-recursive/57452837#57452837
221  QString s = QString("%1,LOG,%2,%3,%4%5").arg(QString::number(now.toMSecsSinceEpoch()),user,QString::number(level),message,message.right(1)=="\n" ? "" : "\n");
222 
223  if (!_vfs)
224  { printf("%s",qUtf8Printable(s));
225  return;
226  }
227 
228  if (_vfs->_logger && _vfs->_logger->hasNode())
229  {
230  QJsonObject o;
231  o["data"] = s;
232  QJsonDocument d(o);
233 
234  _vfs->issueRequest( _vfs->createRequest(VFS_request::submit,"logs/messages",user,d) );
235  }
236  else
237  {
238  if (level > _vfs->_logLevel)
239  return;
240 
241  QMutexLocker l(&_vfs->_printLock); //prevent interleaved messages
242  _vfs->cp_init.cprintf("[ INIT %d ] %s ",level,qUtf8Printable(user));
243  printf("%s%s",qUtf8Printable(message), (message.right(1)=="\n" ? "" : "\n"));
244  }
245 }
246 
258 void VFS::WARN(QString message, int level, QString user)
259 {
260  level = qBound(0,level,9);
261 
262  //if (level > _vfs->_logLevel)
263  // return;
264 
265  QDateTime now = QDateTime::currentDateTime();
266 
267  //QString s = QString("%1,WARN,%2,%3,%4%5").arg(now.toMSecsSinceEpoch()).arg(user).arg(level).arg(message).arg(message.right(1)=="\n" ? "" : "\n");
268 
269  //use https://stackoverflow.com/questions/57452407/qstring-arg-issue-when-arg-contains-a-character-how-to-prevent-recursive/57452837#57452837
270  QString s = QString("%1,WARN,%2,%3,%4%5").arg(QString::number(now.toMSecsSinceEpoch()),user,QString::number(level),message,message.right(1)=="\n" ? "" : "\n");
271 
272  if (!_vfs)
273  { printf("%s",qUtf8Printable(s));
274  return;
275  }
276 
277  if (_vfs->_logger && _vfs->_logger->hasNode())
278  {
279  QJsonObject o;
280  o["data"] = s;
281  QJsonDocument d(o);
282 
283  _vfs->issueRequest( _vfs->createRequest(VFS_request::submit,"logs/warnings",user,d) );
284  }
285  else
286  {
287  if (level > _vfs->_logLevel)
288  return;
289 
290  QMutexLocker l(&_vfs->_printLock); //prevent interleaved messages
291  _vfs->cp_warn.cprintf("[ WARN %d ] %s %s",level,qUtf8Printable(user),qUtf8Printable(message));
292  printf("%s",(message.right(1)=="\n" ? "" : "\n"));
293  }
294 }
295 
307 void VFS::ERROR(QString message, int level, QString user)
308 {
309  level = qBound(0,level,9);
310 
311  //if (level > _vfs->_logLevel)
312  // return;
313 
314  QDateTime now = QDateTime::currentDateTime();
315 
316  //QString s = QString("%1,ERROR,%2,%3,%4%5").arg(now.toMSecsSinceEpoch()).arg(user).arg(level).arg(message).arg(message.right(1)=="\n" ? "" : "\n");
317 
318  //use https://stackoverflow.com/questions/57452407/qstring-arg-issue-when-arg-contains-a-character-how-to-prevent-recursive/57452837#57452837
319  QString s = QString("%1,ERROR,%2,%3,%4%5").arg(QString::number(now.toMSecsSinceEpoch()),user,QString::number(level),message,message.right(1)=="\n" ? "" : "\n");
320 
321  if (!_vfs)
322  { printf("%s",qUtf8Printable(s));
323  return;
324  }
325 
326  if (_vfs->_logger && _vfs->_logger->hasNode())
327  {
328  QJsonObject o;
329  o["data"] = s;
330  QJsonDocument d(o);
331 
332  _vfs->issueRequest( _vfs->createRequest(VFS_request::submit,"logs/errors",user,d) );
333  }
334  else
335  {
336  if (level > _vfs->_logLevel)
337  return;
338 
339  QMutexLocker l(&_vfs->_printLock); //prevent interleaved messages
340  _vfs->cp_error.cprintferr("[ ERROR %d ] %s %s",level,qUtf8Printable(user),qUtf8Printable(message));
341  printf("%s",(message.right(1)=="\n" ? "" : "\n"));
342  }
343 }
344 
357 void VFS::CRITICAL(QString message)
358 {
359  int level = 0;
360 
361  QDateTime now = QDateTime::currentDateTime();
362 
363  //QString s = QString("%1,CRITICAL,%2,%3,%4%5").arg(now.toMSecsSinceEpoch()).arg("CRITICAL").arg(level).arg(message).arg(message.right(1)=="\n" ? "" : "\n");
364 
365  //use https://stackoverflow.com/questions/57452407/qstring-arg-issue-when-arg-contains-a-character-how-to-prevent-recursive/57452837#57452837
366  QString s = QString("%1,CRITICAL,%2,%3,%4%5").arg(QString::number(now.toMSecsSinceEpoch()),"CRITICAL",QString::number(level),message,message.right(1)=="\n" ? "" : "\n");
367 
368  if (!_vfs)
369  { printf("%s\n",qUtf8Printable(s));
370  return;
371  }
372 
373  if (_vfs->_logger && _vfs->_logger->hasNode())
374  {
375  QJsonObject o;
376  o["data"] = s;
377  QJsonDocument d(o);
378 
379  _vfs->issueRequest( _vfs->createRequest(VFS_request::submit,"logs/critical","CRITICAL",d) );
380  }
381  else
382  {
383  QMutexLocker l(&_vfs->_printLock); //prevent interleaved messages
384  _vfs->cp_error.cprintferr("[ CRITICAL ] %s",qUtf8Printable(message));
385  printf("%s",(message.right(1)=="\n" ? "" : "\n"));
386 
387  //email(_adminAddress,APPLICATION_NAME" CRITICAL",message);
388  //std::cerr << cp_error.cp_s_init() << " notification email sent to: " << qUtf8Printable(_adminAddress) << std::endl << cp_error.cp_s_rst();
389  }
390 }
391 
400 {
401  return _vfs;
402 }
403 
404 
412 QJsonDocument VFS::parameters()
413 {
414  return QJsonDocument( _parameters );
415 }
416 
423 {
424  return _vfs->_start;
425 }
426 
432 qint64 VFS::uptime()
433 {
434  return (QDateTime::currentMSecsSinceEpoch() - _vfs->_start);
435 }
436 
443 QString VFS::uptimeString(bool ms)
444 {
445  qint64 u = VFS::uptime();
446  if (ms)
447  return QString("%1:%2:%3:%4.%5")
448  .arg(u / (1000*60*60*24))
449  .arg((int)floor((u % (1000*60*60*24))/(1000*60*60)),2,(int)10,QChar('0'))
450  .arg((int)floor((u % (1000*60*60))/(1000*60)),2,(int)10,QChar('0'))
451  .arg((int)floor((u % (1000*60))/(1000)),2,(int)10,QChar('0'))
452  .arg((int)(u % 1000),3,(int)10,QChar('0'));
453  else
454  return QString("%1:%2:%3:%4")
455  .arg(u / (1000*60*60*24))
456  .arg((int)floor((u % (1000*60*60*24))/(1000*60*60)),2,(int)10,QChar('0'))
457  .arg((int)floor((u % (1000*60*60))/(1000*60)),2,(int)10,QChar('0'))
458  .arg((int)floor((u % (1000*60))/(1000)),2,(int)10,QChar('0'));
459 }
460 
468 void VFS::timerEvent(QTimerEvent *event)
469 {
470  if (event->timerId() == _monitorTimerID)
472 }
473 
474 
486 {
487  QDateTime t;
488  QFileInfo f;
489  QMap<QString, QDateTime>::iterator i;
490  for (i = _monitoredFiles.begin(); i != _monitoredFiles.end(); ++i)
491  {
492  LOG( QString("Checking modification time on '%1'...").arg(i.key()), 9 );
493 
494  t = i.value();
495  f.setFile( i.key() );
496 
497  if ( !f.exists() )
498  WARN( QString("Monitored file '%1' doesn't exist.").arg(i.key()), 8 );
499  else
500  { if ( f.lastModified() > t )
501  {
502  QMutexLocker l(&_printLock); //prevent interleaved messages
503 
504  QString message = QString("Monitored file '%1' has changed!").arg(i.key());
505  //WARN( message );
506  cp_warn.cprintf("[ WARN %d ] %s %s\n",0,"server",qUtf8Printable(message)); //do it manually so that it is the first message
507 
508  QCoreApplication::exit(0);
509  }
510  }
511  }
512 }
#define VFS_CREATOR_MAX_OUTSTANDING
Definition: VFS_creator.h:15
static void build(QString configFile, VFS_node *root, bool printConfig=false)
Build an environment for creating nodes.
static void init(QStringList plugins=QStringList(), bool describe=false)
Initialize plugins recursively.
Definition: VFS_creator.cpp:60
static QSemaphore _outstanding
A semaphore used to sync creation during startup.
Definition: VFS_creator.h:56
static char * get(QString which="")
Fetch an icon from the library.
Definition: VFS_icons.cpp:34
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
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 issueRequest(VFS_request *t)
A convenience function.
Definition: VFS_node.cpp:1933
The base class for all requests between nodes.
Definition: VFS_node.h:54
@ submit
apply a diff (8)
Definition: VFS_node.h:72
static VFS_thread * fromConfig(QString configString, QVariantMap env=QVariantMap(), bool printConfig=false)
A convenience method for creating threads.
Definition: VFS_thread.cpp:68
static int threadcount()
Return the current thread count, mostly only useful for logging output.
Definition: VFS_thread.cpp:132
bool hasNode()
When a thread is created, it must construct its root node to become operational.
Definition: VFS_thread.cpp:248
VFS is the root node for a Virtual Filesystem.
Definition: VFS.h:15
static QJsonObject _parameters
VFS parameters, defined in a config file.
Definition: VFS.h:39
void timerEvent(QTimerEvent *event)
Timer handler for VFS timer events.
Definition: VFS.cpp:468
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
int _logLevel
Filter log entries by this value... lower entries are very important, higher ones are more fine-grain...
Definition: VFS.h:51
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 CRITICAL(QString message)
Send a message to the VFS::_critical VFS_stream.
Definition: VFS.cpp:357
int _logTime
Include log entry time in output, where 0 = none, 1 = locale time, 2 = locale time and date,...
Definition: VFS.h:52
void initialized()
Emitted when the VFS_creator has completed its VFS_creator::build() call.
static QString uptimeString(bool ms=true)
Get the uptime of this VFS instance as a string.
Definition: VFS.cpp:443
int _monitorTimerID
The timerID for monitoring config file changes.
Definition: VFS.h:58
ColorPrint cp_init
Color settings to print messages when other streams do not exist.
Definition: VFS.h:46
static void WARN(QString message, int level=0, QString user="server")
Send a message to the VFS::_warnings VFS_stream.
Definition: VFS.cpp:258
VFS(QString configFile, QStringList plugins=QStringList(), bool describe=false, bool printConfig=false)
The VFS constructor will create a VFS based on an incoming config file and list of plugins.
Definition: VFS.cpp:50
void getLogSettings(int &loglevel, int &logtime)
Get the loglevel and logtime values for the logger.
Definition: VFS.cpp:182
void monitoredFilesCheck()
Iterate through all monitored files, and check their modification time.
Definition: VFS.cpp:485
qint64 _start
Set when the VFS instance begins. This is used to track uptime.
Definition: VFS.h:44
static qint64 starttime()
Get the epoch start time of this VFS instance, in milliseconds.
Definition: VFS.cpp:422
static qint64 uptime()
Get the uptime of this VFS instance, in milliseconds.
Definition: VFS.cpp:432
virtual QByteArray icon()
Fetch the icon for this node.
Definition: VFS.cpp:193
ColorPrint cp_error
Color settings for error messages.
Definition: VFS.h:49
static QJsonDocument parameters()
Fetch the parameters assigned to this VFS, as per the config file.
Definition: VFS.cpp:412
ColorPrint cp_warn
Color settings for warning messages.
Definition: VFS.h:48
VFS_thread * _logger
The VFS_logger instance, which will always be on another thread.
Definition: VFS.h:53
~VFS()
Destroy the VFS node, which will remove references to logging nodes and return output to cp_init colo...
Definition: VFS.cpp:132
QMutex _printLock
A lock for ensuring that print messags don't get interleaved.
Definition: VFS.h:55
static VFS * _vfs
The global and single instance of VFS, returned by VFS::root()
Definition: VFS.h:38
message(m)
Change the message of an existing arrowMessage.
setter user
a setter DOCME