Split off the Events subsystem from the server class and set it up for easy expansion later.

This commit is contained in:
Ken Moore
2016-01-15 15:36:04 -05:00
parent ec7f25d804
commit 82b549ead3
10 changed files with 214 additions and 127 deletions

View File

@@ -0,0 +1,60 @@
// ===============================
// PC-BSD REST API Server
// Available under the 3-clause BSD License
// Written by: Ken Moore <ken@pcbsd.org> 2015-2016
// =================================
#include "EventWatcher.h"
// === PUBLIC ===
EventWatcher::EventWatcher(){
watcher = new QFileSystemWatcher(this);
connect(watcher, SIGNAL(fileChanged(const QString&)), this, SLOT(WatcherUpdate(QString)) );
connect(watcher, SIGNAL(directoryChanged(const QString&)), this, SLOT(WatcherUpdate(QString)) );
}
EventWatcher::~EventWatcher(){
}
void EventWatcher::start(){
// - DISPATCH Events
if(!QFile::exists(DISPATCHWORKING)){ QProcess::execute("touch "+DISPATCHWORKING); }
qDebug() << " Dispatcher Events:" << DISPATCHWORKING;
watcher->addPath(DISPATCHWORKING);
WatcherUpdate(DISPATCHWORKING); //load it initially
}
QString EventWatcher::lastEvent(EVENT_TYPE type){
if(HASH.contains(type)){ return HASH.value(type); }
else{ return ""; }
}
// === PRIVATE ===
QString EventWatcher::readFile(QString path){
QFile file(path);
if(!file.open(QIODevice::ReadOnly | QIODevice::Text)){ return ""; }
QTextStream in(&file);
QString contents = in.readAll();
file.close();
if(contents.endsWith("\n")){ contents.chop(1); }
return contents;
}
// === PRIVATE SLOTS ===
void EventWatcher::WatcherUpdate(QString path){
if(path==DISPATCHWORKING){
//Read the file contents
QString stat = readFile(DISPATCHWORKING);
if(stat.simplified().isEmpty()){ stat = "idle"; }
qDebug() << "Dispatcher Update:" << stat;
HASH.insert(DISPATCHER,stat); //save for later
//Forward those contents on to the currently-open sockets
emit NewEvent(DISPATCHER, stat);
}
//Make sure this file/dir is not removed from the watcher
if(!watcher->files().contains(path) && !watcher->directories().contains(path)){
watcher->addPath(path); //re-add it to the watcher. This happens when the file is removed/re-created instead of just overwritten
}
}

41
src/server/EventWatcher.h Normal file
View File

@@ -0,0 +1,41 @@
// ===============================
// PC-BSD REST API Server
// Available under the 3-clause BSD License
// Written by: Ken Moore <ken@pcbsd.org> 2015-2016
// =================================
#ifndef _PCBSD_SYSADM_EVENT_WATCHER_SYSTEM_H
#define _PCBSD_SYSADM_EVENT_WATCHER_SYSTEM_H
#include "globals-qt.h"
#define DISPATCHWORKING QString("/var/tmp/appcafe/dispatch-queue.working")
class EventWatcher : public QObject{
Q_OBJECT
public:
//Add more event types here as needed
enum EVENT_TYPE{ DISPATCHER };
EventWatcher();
~EventWatcher();
void start();
QString lastEvent(EVENT_TYPE type);
private:
QFileSystemWatcher *watcher;
QHash<EVENT_TYPE, QString> HASH;
QString readFile(QString path);
public slots:
private slots:
//File watcher signals
void WatcherUpdate(QString);
signals:
void NewEvent(EVENT_TYPE ev, QString msg); //type/message
};
#endif

View File

@@ -5,34 +5,20 @@
// =================================
#include "WebServer.h"
#include <QCoreApplication>
#include <QUrl>
#include <QFile>
#include <QTextStream>
#include <QProcess>
#include <QSslKey>
#include <QSslCertificate>
#define DEBUG 0
#define APPCAFEWORKING QString("/var/tmp/appcafe/dispatch-queue.working")
//=======================
// PUBLIC
//=======================
WebServer::WebServer(){
//Setup all the various settings
//Any SSL changes
/*QSslConfiguration ssl = this->sslConfiguration();
ssl.setProtocol(QSsl::SecureProtocols);
this->setSslConfiguration(ssl);*/
WSServer = 0;
TCPServer = 0;
AUTH = new AuthorizationManager();
watcher = new QFileSystemWatcher(this);
//watcher = new QFileSystemWatcher(this);
connect(watcher, SIGNAL(fileChanged(const QString&)), this, SLOT(WatcherUpdate(QString)) );
connect(watcher, SIGNAL(directoryChanged(const QString&)), this, SLOT(WatcherUpdate(QString)) );
//connect(watcher, SIGNAL(fileChanged(const QString&)), this, SLOT(WatcherUpdate(QString)) );
//connect(watcher, SIGNAL(directoryChanged(const QString&)), this, SLOT(WatcherUpdate(QString)) );
}
WebServer::~WebServer(){
@@ -54,11 +40,7 @@ bool WebServer::startServer(quint16 port, bool websocket){
qDebug() << "Server Started:" << QDateTime::currentDateTime().toString(Qt::ISODate);
qDebug() << " Port:" << port;
if(WSServer!=0){ qDebug() << " URL:" << WSServer->serverUrl().toString(); }
if(!QFile::exists(APPCAFEWORKING)){ QProcess::execute("touch "+APPCAFEWORKING); }
qDebug() << " Dispatcher Events:" << APPCAFEWORKING;
watcher->addPath(APPCAFEWORKING);
WatcherUpdate(APPCAFEWORKING); //load it initially
EVENTS->start();
}else{
qCritical() << "Could not start server - exiting...";
}
@@ -127,16 +109,6 @@ QString WebServer::generateID(){
return QString::number(id);
}
QString WebServer::readFile(QString path){
QFile file(path);
if(!file.open(QIODevice::ReadOnly | QIODevice::Text)){ return ""; }
QTextStream in(&file);
QString contents = in.readAll();
file.close();
if(contents.endsWith("\n")){ contents.chop(1); }
return contents;
}
//=======================
// PRIVATE SLOTS
//=======================
@@ -152,8 +124,7 @@ void WebServer::NewSocketConnection(){
if(sock==0){ return; } //no new connection
qDebug() << "New Socket Connection";
connect(sock, SIGNAL(SocketClosed(QString)), this, SLOT(SocketClosed(QString)) );
connect(this, SIGNAL(DispatchStatusUpdate(QString)), sock, SLOT(AppCafeStatusUpdate(QString)) );
sock->setLastDispatch(lastDispatch); //make sure this socket is aware of the latest notification
connect(EVENTS, SIGNAL(NewEvent(EventWatcher::EVENT_TYPE, QString)), sock, SLOT(EventUpdate(EventWatcher::EVENT_TYPE, QString)) );
OpenSockets << sock;
}
@@ -205,19 +176,3 @@ void WebServer::SocketClosed(QString ID){
}
QTimer::singleShot(0,this, SLOT(NewSocketConnection()) ); //check for a new connection
}
void WebServer::WatcherUpdate(QString path){
if(path==APPCAFEWORKING){
//Read the file contents
QString stat = readFile(APPCAFEWORKING);
if(stat.simplified().isEmpty()){ stat = "idle"; }
qDebug() << "Dispatcher Update:" << stat;
lastDispatch = stat; //save for later
//Forward those contents on to the currently-open sockets
emit DispatchStatusUpdate(stat);
}
//Make sure this file/dir is not removed from the watcher
if(!watcher->files().contains(path) && !watcher->directories().contains(path)){
watcher->addPath(path); //re-add it to the watcher. This happens when the file is removed/re-created instead of just overwritten
}
}

View File

@@ -6,18 +6,7 @@
#ifndef _PCBSD_REST_WEB_SERVER_H
#define _PCBSD_REST_WEB_SERVER_H
#include <QWebSocketServer>
#include <QTcpServer>
#include <QWebSocket>
#include <QSslSocket>
#include <QWebSocketCorsAuthenticator>
#include <QFileSystemWatcher>
#include <QSslError>
#include <QList>
#include <QObject>
#include <QTimer>
#include <QDebug>
#include <QtDebug> //for better syntax of qDebug() / qWarning() / qCritical() / qFatal()
#include "globals.h"
#include "WebSocket.h"
#include "AuthorizationManager.h"
@@ -38,8 +27,6 @@ private:
SslServer *TCPServer;
QList<WebSocket*> OpenSockets;
AuthorizationManager *AUTH;
QFileSystemWatcher *watcher;
QString lastDispatch;
//Server Setup functions
bool setupWebSocket(quint16 port);
@@ -47,7 +34,6 @@ private:
//Generic functions for either type of server
QString generateID(); //generate a new ID for a socket
QString readFile(QString path);
private slots:
// Generic Server Slots
@@ -63,11 +49,8 @@ private slots:
void SslErrors(const QList<QSslError>&); //sslErrors() signal
void SocketClosed(QString ID);
//File watcher signals
void WatcherUpdate(QString);
signals:
void DispatchStatusUpdate(QString);
//void DispatchStatusUpdate(QString);
};

View File

@@ -65,11 +65,6 @@ QString WebSocket::ID(){
return SockID;
}
void WebSocket::setLastDispatch(QString msg){
//used on initialization only
lastDispatchEvent = msg;
}
//=======================
// PRIVATE
//=======================
@@ -340,25 +335,18 @@ void WebSocket::SslError(const QList<QSslError> &err){ //sslErrors() signal
// ======================
// PUBLIC SLOTS
// ======================
void WebSocket::AppCafeStatusUpdate(QString msg){
if(!msg.isEmpty()){ lastDispatchEvent = msg; }
else{ msg = lastDispatchEvent; }
void WebSocket::EventUpdate(EventWatcher::EVENT_TYPE evtype, QString msg){
if(msg.isEmpty()){ msg = EVENTS->lastEvent(evtype); }
//qDebug() << "Socket Status Update:" << msg;
if(!SendAppCafeEvents){ return; } //don't report events on this socket
RestOutputStruct out;
out.CODE = RestOutputStruct::OK;
out.in_struct.name = "dispatcher";
out.in_struct.namesp = "events";
//Pre-set any output fields
//QJsonObject outargs;
//outargs.insert("name", "dispatcher");
// outargs.insert("args",QJsonValue(msg));
out.out_args = QJsonValue(msg);//outargs;
//Assemble the output JSON document/text
if(evtype==EventWatcher::DISPATCHER){
if(!SendAppCafeEvents){ return; } //don't report events on this socket
RestOutputStruct out;
out.CODE = RestOutputStruct::OK;
out.in_struct.name = "dispatcher";
out.in_struct.namesp = "events";
out.out_args = QJsonValue(msg);//outargs;
out.Header << "Content-Type: text/json; charset=utf-8"; //REST header info
//Now send the message back through the socket
this->sendReply(out.assembleMessage());
/* if(SOCKET!=0){ SOCKET->sendTextMessage(out.assembleMessage()); }
else if(TSOCKET!=0){ TSOCKET->write(out.assembleMessage().toUtf8().data()); }*/
//Now send the message back through the socket
this->sendReply(out.assembleMessage());
} //end of DISPATCH event
}

View File

@@ -6,17 +6,7 @@
#ifndef _PCBSD_REST_WEB_SOCKET_H
#define _PCBSD_REST_WEB_SOCKET_H
#include <QWebSocket>
#include <QSslSocket>
#include <QSslError>
#include <QList>
#include <QObject>
#include <QJsonDocument>
#include <QJsonArray>
#include <QJsonObject>
#include <QJsonValue>
#include <QTimer>
#include "globals.h"
#include "RestStructs.h"
#include "AuthorizationManager.h"
@@ -29,13 +19,12 @@ public:
~WebSocket();
QString ID();
void setLastDispatch(QString); //used on initialization only
private:
QTimer *idletimer;
QWebSocket *SOCKET;
QSslSocket *TSOCKET;
QString SockID, SockAuthToken, lastDispatchEvent;
QString SockID, SockAuthToken;
AuthorizationManager *AUTHSYSTEM;
bool SendAppCafeEvents;
@@ -77,7 +66,7 @@ private slots:
void SslError(const QList<QSslError>&); //sslErrors() signal
public slots:
void AppCafeStatusUpdate(QString msg = "");
void EventUpdate(EventWatcher::EVENT_TYPE, QString msg = "");
signals:
void SocketClosed(QString); //ID

43
src/server/globals-qt.h Normal file
View File

@@ -0,0 +1,43 @@
// ===============================
// PC-BSD REST API Server
// Available under the 3-clause BSD License
// Written by: Ken Moore <ken@pcbsd.org> 2015-2016
// =================================
#ifndef _PCBSD_SYSADM_SERVER_QT_GLOBALS_H
#define _PCBSD_SYSADM_SERVER_QT_GLOBALS_H
//General-purpose includes
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonValue>
#include <QJsonArray>
#include <QString>
#include <QStringList>
#include <QSettings>
#include <QCoreApplication>
#include <QUrl>
#include <QFile>
#include <QDir>
#include <QTextStream>
#include <QProcess>
#include <QSslKey>
#include <QSslCertificate>
#include <QSslError>
#include <QWebSocketServer>
#include <QWebSocketCorsAuthenticator>
#include <QWebSocket>
#include <QTcpServer>
#include <QSslSocket>
#include <QFileSystemWatcher>
#include <QList>
#include <QHash>
#include <QObject>
#include <QTimer>
#include <QDebug>
#include <QtDebug>
#endif

25
src/server/globals.h Normal file
View File

@@ -0,0 +1,25 @@
// ===============================
// PC-BSD REST API Server
// Available under the 3-clause BSD License
// Written by: Ken Moore <ken@pcbsd.org> 2015-2016
// =================================
#ifndef _PCBSD_SYSADM_SERVER_GLOBALS_H
#define _PCBSD_SYSADM_SERVER_GLOBALS_H
#include "globals-qt.h"
//Global variables/classes (intially created in main.cpp)
extern QSettings *CONFIG;
#include "EventWatcher.h"
extern EventWatcher *EVENTS;
//#include "ProcessQueue.h"
//extern ProcessQueue *PQUEUE;
//#include "LogManager.h"
//extern LogManager *LOGS;
//Special defines
#define WSPORTNUMBER 12150 // WebSocket server default port
#define PORTNUMBER 12151 // TCP server default port
#endif

View File

@@ -3,24 +3,20 @@
// Available under the 3-clause BSD License
// Written by: Ken Moore <ken@pcbsd.org> July 2015
// =================================
#include <QCoreApplication>
#include <QFile>
#include <QTextStream>
#include <QTimer>
#include <QDir>
#include "globals.h"
#include <unistd.h>
#include <sys/types.h>
#include "WebServer.h"
#ifndef PREFIX
#define PREFIX QString("/usr/local/")
#endif
#define DEBUG 1
#define WSPORTNUMBER 12150 // WebSocket server default port
#define PORTNUMBER 12151 // TCP server default port
//Create any global classes
QSettings *CONFIG = new QSettings("PCBSD","sysadm");
EventWatcher *EVENTS = new EventWatcher();
//Create the default logfile
QFile logfile;
void MessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg){
QString txt;
@@ -80,19 +76,23 @@ int main( int argc, char ** argv )
logfile.open(QIODevice::WriteOnly | QIODevice::Append);
qInstallMessageHandler(MessageOutput);
//Create and start the daemon
//Create the daemon
qDebug() << "Starting the PC-BSD sysadm server...." << (websocket ? "(WebSocket)" : "(TCP)");
WebServer *w = new WebServer();
//Start the daemon
int ret = 1; //error return value
if( w->startServer(port, websocket) ){
//Now start the event loop
int ret = a.exec();
ret = a.exec();
qDebug() << "Server Stopped:" << QDateTime::currentDateTime().toString(Qt::ISODate);
logfile.close();
return ret;
}else{
qDebug() << "[FATAL] Server could not be started:" << QDateTime::currentDateTime().toString(Qt::ISODate);
qDebug() << " - Tried port:" << port;
logfile.close();
return 1;
}
//Cleanup any globals
delete CONFIG;
logfile.close();
//Return
return ret;
}

View File

@@ -4,13 +4,15 @@ LANGUAGE = C++
CONFIG += qt warn_on release
QT = core network websockets
HEADERS += WebServer.h \
HEADERS += globals.h globals-qt.h \
WebServer.h \
WebSocket.h \
syscache-client.h \
dispatcher-client.h \
RestStructs.h \
AuthorizationManager.h \
SslServer.h
SslServer.h \
EventWatcher.h
SOURCES += main.cpp \
WebServer.cpp \
@@ -18,7 +20,8 @@ SOURCES += main.cpp \
WebBackend.cpp \
syscache-client.cpp \
dispatcher-client.cpp \
AuthorizationManager.cpp
AuthorizationManager.cpp \
EventWatcher.cpp
TARGET=sysadm-server