mirror of
https://github.com/outbackdingo/sysadm.git
synced 2026-01-27 10:20:26 +00:00
Split off the Events subsystem from the server class and set it up for easy expansion later.
This commit is contained in:
60
src/server/EventWatcher.cpp
Normal file
60
src/server/EventWatcher.cpp
Normal 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
41
src/server/EventWatcher.h
Normal 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
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
43
src/server/globals-qt.h
Normal 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
25
src/server/globals.h
Normal 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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user