From 37224472cc3be361e944fffa6d44c40c2d9c3f40 Mon Sep 17 00:00:00 2001 From: Ken Moore Date: Wed, 3 Feb 2016 10:12:01 -0500 Subject: [PATCH] Make the websocket/rest server distinctions a bit more clear. Now the logs are in websocket/restserver subdirectories, the LP file watchers will resume from the last log point (server-type aware), and a couple other changes for saving server-dependent variables. --- src/server/EventWatcher.cpp | 40 ++++++++++++++++++++++++------------- src/server/EventWatcher.h | 6 +++--- src/server/LogManager.cpp | 27 ++++++++++++++++++++----- src/server/LogManager.h | 10 +++++----- src/server/WebSocket.cpp | 6 +----- src/server/globals.h | 1 + src/server/main.cpp | 8 +++++--- 7 files changed, 63 insertions(+), 35 deletions(-) diff --git a/src/server/EventWatcher.cpp b/src/server/EventWatcher.cpp index 8775d80..34756e7 100644 --- a/src/server/EventWatcher.cpp +++ b/src/server/EventWatcher.cpp @@ -12,7 +12,6 @@ EventWatcher::EventWatcher(){ qRegisterMetaType("EventWatcher::EVENT_TYPE"); starting = true; - LPlog_pos = LPrep_pos = LPerr_pos = 0; //no pos yet watcher = new QFileSystemWatcher(this); filechecktimer = new QTimer(this); filechecktimer->setSingleShot(false); @@ -28,9 +27,6 @@ EventWatcher::~EventWatcher(){ void EventWatcher::start(){ // - DISPATCH Events starting = true; - //if(!QFile::exists(DISPATCHWORKING)){ QProcess::execute("touch "+DISPATCHWORKING); } - //qDebug() << " Dispatcher Events:" << DISPATCHWORKING; - //WatcherUpdate(DISPATCHWORKING); //load it initially (will also add it to the watcher) // - Life Preserver Events WatcherUpdate(LPLOG); //load it initially (will also add it to the watcher); WatcherUpdate(LPERRLOG); //load it initially (will also add it to the watcher); @@ -45,6 +41,12 @@ EventWatcher::EVENT_TYPE EventWatcher::typeFromString(QString typ){ else{ return BADEVENT; } } +QString EventWatcher::typeToString(EventWatcher::EVENT_TYPE typ){ + if(typ==DISPATCHER){ return "dispatcher"; } + else if(typ==LIFEPRESERVER){ return "life-preserver"; } + else{ return ""; } +} + QJsonValue EventWatcher::lastEvent(EVENT_TYPE type){ CheckLogFiles(); if(HASH.contains(type)){ return HASH.value(type); } @@ -143,9 +145,14 @@ void EventWatcher::ReadLPLogFile(){ QFile LPlogfile(LPLOG); if( !LPlogfile.open(QIODevice::ReadOnly) ){ return; } //could not open file QTextStream STREAM(&LPlogfile); - if(LPlog_pos>0){ STREAM.seek(LPlog_pos); } + qint64 LPlog_pos = CONFIG->value("internal/"+QString(WS_MODE ? "ws" : "tcp")+"/lp-log-pos",0).toLongLong(); + if(LPlog_pos>0 && QFileInfo(LPlogfile).created() < CONFIG->value("internal/"+QString(WS_MODE ? "ws" : "tcp")+"/lp-log-lastread").toDateTime() ){ + STREAM.seek(LPlog_pos); + } QStringList info = STREAM.readAll().split("\n"); - LPlog_pos = STREAM.pos(); + //Now save the file pointer for later + CONFIG->setValue("internal/"+QString(WS_MODE ? "ws" : "tcp")+"/lp-log-pos",STREAM.pos()); + CONFIG->setValue("internal/"+QString(WS_MODE ? "ws" : "tcp")+"/lp-log-lastread",QDateTime::currentDateTime()); LPlogfile.close(); //Now parse the new info line-by-line for(int i=0; isetValue("internal/"+QString(WS_MODE ? "ws" : "tcp")+"/lp-rep-pos",0); dev = message.section(" on ",1,1,QString::SectionSkipEmpty); //qDebug() << " - New Dev:" << dev << "Valid Pools:" << reppools; //Make sure the device is currently setup for replication @@ -192,7 +199,7 @@ void EventWatcher::ReadLPLogFile(){ }else if(message.contains("finished replication task", Qt::CaseInsensitive)){ //Done with this replication - close down the rep file watcher tmpLPRepFile.clear(); - LPrep_pos = 0; //reset file position + CONFIG->setValue("internal/"+QString(WS_MODE ? "ws" : "tcp")+"/lp-rep-pos",0); dev = message.section(" -> ",0,0).section(" ",-1).simplified(); //Make sure the device is currently setup for replication //if( reppools.contains(dev) ){ @@ -208,7 +215,7 @@ void EventWatcher::ReadLPLogFile(){ sendLPEvent("replication", 1, timestamp+": "+msg); }else if( message.contains("FAILED replication", Qt::CaseInsensitive) ){ tmpLPRepFile.clear(); - LPrep_pos = 0; //reset file position + CONFIG->setValue("internal/"+QString(WS_MODE ? "ws" : "tcp")+"/lp-rep-pos",0); //Now set the status of the process dev = message.section(" -> ",0,0).section(" ",-1).simplified(); //Make sure the device is currently setup for replication @@ -233,13 +240,14 @@ void EventWatcher::ReadLPErrFile(){ } void EventWatcher::ReadLPRepFile(){ - static QString stat = ""; - static QString repTotK = ""; - static QString lastSize = ""; + QString stat = CONFIG->value("internal/"+QString(WS_MODE ? "ws" : "tcp")+"/lp-rep-s","").toString(); + QString repTotK = CONFIG->value("internal/"+QString(WS_MODE ? "ws" : "tcp")+"/lp-rep-totk","").toString(); + QString lastSize = CONFIG->value("internal/"+QString(WS_MODE ? "ws" : "tcp")+"/lp-rep-lastsize","").toString(); //Open/Read any new info in the file QFile LPlogfile(LPLOG); if( !LPlogfile.open(QIODevice::ReadOnly) ){ return; } //could not open file QTextStream STREAM(&LPlogfile); + qint64 LPrep_pos = CONFIG->value("internal/"+QString(WS_MODE ? "ws" : "tcp")+"/lp-rep-pos",0).toLongLong(); if(LPrep_pos<=0 || !STREAM.seek(LPrep_pos) ){ //New file location stat.clear(); @@ -247,7 +255,7 @@ void EventWatcher::ReadLPRepFile(){ lastSize.clear(); } QStringList info = STREAM.readAll().split("\n"); - LPrep_pos = STREAM.pos(); + CONFIG->setValue("internal/"+QString(WS_MODE ? "ws" : "tcp")+"/lp-rep-pos",STREAM.pos()); LPlogfile.close(); //Now parse the new info line-by-line for(int i=0; isetValue("internal/"+QString(WS_MODE ? "ws" : "tcp")+"/lp-rep-stat",stat); + if(repTotK!="??"){CONFIG->setValue("internal/"+QString(WS_MODE ? "ws" : "tcp")+"/lp-rep-totk",repTotK); } + CONFIG->setValue("internal/"+QString(WS_MODE ? "ws" : "tcp")+"/lp-rep-lastsize",lastSize); } diff --git a/src/server/EventWatcher.h b/src/server/EventWatcher.h index 7cbb80c..9149e4f 100644 --- a/src/server/EventWatcher.h +++ b/src/server/EventWatcher.h @@ -22,9 +22,10 @@ public: EventWatcher(); ~EventWatcher(); - //Convert a string into the type flag + //Convert between strings and type flags static EVENT_TYPE typeFromString(QString); - + static QString typeToString(EventWatcher::EVENT_TYPE); + //Retrieve the most recent event message for a particular type of event QJsonValue lastEvent(EVENT_TYPE type); @@ -38,7 +39,6 @@ private: //Life Preserver Event variables/functions QString tmpLPRepFile; - qint64 LPlog_pos, LPrep_pos, LPerr_pos; //file position markers void sendLPEvent(QString system, int priority, QString msg); diff --git a/src/server/LogManager.cpp b/src/server/LogManager.cpp index c62b544..abc8865 100644 --- a/src/server/LogManager.cpp +++ b/src/server/LogManager.cpp @@ -1,17 +1,34 @@ +// =============================== +// PC-BSD REST/JSON API Server +// Available under the 3-clause BSD License +// Written by: Ken Moore 2016 +// ================================= #include "LogManager.h" - +#include "globals.h" + #define TMPBREAK "" //Overall check/creation of the log directory void LogManager::checkLogDir(){ - if(!QFile::exists(LOGDIR)){ - QDir dir(LOGDIR); - dir.mkpath(LOGDIR); + //Determing the log dir based on type of server + QString logd = LOGDIR; //base log dir + if(WS_MODE){ logd.append("/websocket"); } + else{ logd.append("/restserver"); } + //Check/create the dir + if(!QFile::exists(logd)){ + QDir dir(logd); + dir.mkpath(logd); } } //Main Log write function (all the overloaded versions end up calling this one) void LogManager::log(QString file, QStringList msgs, QDateTime time){ - qDebug() << "Log to File:" << file << msgs; + if(file.isEmpty()){ return; } + else if(!file.startsWith("/")){ + //relative path - put it in the main log dir + if(WS_MODE){ file.prepend(LOGDIR+"/websocket/"); } + else{ file.prepend(LOGDIR+"/restserver/"); } + } + //qDebug() << "Log to File:" << file << msgs; if(file.isEmpty()){ return; } QFile LOG(file); //if(!LOG.exists()){ system( QString("touch "+file).toLocal8Bit() ); } diff --git a/src/server/LogManager.h b/src/server/LogManager.h index 94e4636..b7855cc 100644 --- a/src/server/LogManager.h +++ b/src/server/LogManager.h @@ -49,7 +49,7 @@ public: //Log a list of strings (same timestamp for all lines) static void log(QString file, QStringList msgs, QDateTime time = QDateTime::currentDateTime()); static void log(LogManager::LOG_FILE file, QStringList msgs, QDateTime time = QDateTime::currentDateTime()){ - log(LOGDIR+"/"+flagToPath(file).arg(time.date().toString(Qt::ISODate)), msgs, time); + log(flagToPath(file).arg(time.date().toString(Qt::ISODate)), msgs, time); } //Log a simple text string @@ -57,7 +57,7 @@ public: log(file, QStringList() << msg, time); } static void log(LogManager::LOG_FILE file, QString msg, QDateTime time = QDateTime::currentDateTime()){ - log(LOGDIR+"/"+flagToPath(file).arg(time.date().toString(Qt::ISODate)), QStringList() << msg, time); + log(flagToPath(file).arg(time.date().toString(Qt::ISODate)), QStringList() << msg, time); } //Log a JSON Object @@ -65,15 +65,15 @@ public: log(file, QStringList() << QJsonDocument(obj).toJson(QJsonDocument::Compact), time); } static void log(LogManager::LOG_FILE file, QJsonObject obj, QDateTime time = QDateTime::currentDateTime()){ - log(LOGDIR+"/"+flagToPath(file).arg(time.date().toString(Qt::ISODate)), QStringList() << QJsonDocument(obj).toJson(QJsonDocument::Compact), time); + log(flagToPath(file).arg(time.date().toString(Qt::ISODate)), QStringList() << QJsonDocument(obj).toJson(QJsonDocument::Compact), time); } //Log a JSON Array static void log(QString file, QJsonArray array, QDateTime time = QDateTime::currentDateTime()){ - log(LOGDIR+"/"+file, QStringList() << QJsonDocument(array).toJson(QJsonDocument::Compact), time); + log(file, QStringList() << QJsonDocument(array).toJson(QJsonDocument::Compact), time); } static void log(LogManager::LOG_FILE file, QJsonArray array, QDateTime time = QDateTime::currentDateTime()){ - log(LOGDIR+"/"+flagToPath(file).arg(time.date().toString(Qt::ISODate)), QStringList() << QJsonDocument(array).toJson(QJsonDocument::Compact), time); + log(flagToPath(file).arg(time.date().toString(Qt::ISODate)), QStringList() << QJsonDocument(array).toJson(QJsonDocument::Compact), time); } // === READ FROM LOG FUNCTIONS === diff --git a/src/server/WebSocket.cpp b/src/server/WebSocket.cpp index 81e781a..31b9580 100644 --- a/src/server/WebSocket.cpp +++ b/src/server/WebSocket.cpp @@ -371,11 +371,7 @@ void WebSocket::EventUpdate(EventWatcher::EVENT_TYPE evtype, QJsonValue msg){ out.in_struct.namesp = "events"; out.out_args = msg; out.Header << "Content-Type: text/json; charset=utf-8"; //REST header info - if(evtype==EventWatcher::DISPATCHER){ - out.in_struct.name = "dispatcher"; - }else if(evtype==EventWatcher::LIFEPRESERVER){ - out.in_struct.name = "life-preserver"; - } + out.in_struct.name = EventWatcher::typeToString(evtype); //Now send the message back through the socket this->sendReply(out.assembleMessage()); diff --git a/src/server/globals.h b/src/server/globals.h index 05dd4d7..43fccb3 100644 --- a/src/server/globals.h +++ b/src/server/globals.h @@ -12,6 +12,7 @@ //Global variables/classes (intially created in main.cpp) extern QSettings *CONFIG; +extern bool WS_MODE; #include "EventWatcher.h" extern EventWatcher *EVENTS; diff --git a/src/server/main.cpp b/src/server/main.cpp index 04cf3f8..e4ee487 100644 --- a/src/server/main.cpp +++ b/src/server/main.cpp @@ -10,12 +10,13 @@ #include "WebServer.h" -#define DEBUG 1 +#define DEBUG 0 //Create any global classes QSettings *CONFIG = new QSettings("PCBSD","sysadm"); EventWatcher *EVENTS = new EventWatcher(); Dispatcher *DISPATCHER = new Dispatcher(); +bool WS_MODE = false; //Create the default logfile QFile logfile; @@ -52,13 +53,13 @@ int main( int argc, char ** argv ) qDebug() << "sysadm-server must be started as root!"; return 1; } - LogManager::checkLogDir(); //ensure the logging directry exists + //Evaluate input arguments bool websocket = false; quint16 port = 0; for(int i=1; i