From 38a98af07053173203dfa0f1a4c5ebaf4df5b523 Mon Sep 17 00:00:00 2001 From: 0xFEEDC0DE64 Date: Thu, 6 Oct 2022 02:44:58 +0200 Subject: [PATCH] Lots of improvements --- espremoteagent/espremoteagent.cpp | 38 +++++++++++++++++++++++-- espremoteagent/espremoteagent.h | 7 ++++- espremoteagent/espremoteagent.ini | 10 +++++-- espremoteagent/espremoteport.cpp | 20 +++++++++++++ espremoteagent/espremoteport.h | 5 ++++ espremoteagent/main.cpp | 18 +++++++++++- espremotemanager/espremotemanager.cpp | 6 ++-- espremotemanager/main.cpp | 2 +- webserver/webserverclientconnection.cpp | 23 +++++++++++++-- webserver/webserverclientconnection.h | 2 ++ 10 files changed, 117 insertions(+), 14 deletions(-) diff --git a/espremoteagent/espremoteagent.cpp b/espremoteagent/espremoteagent.cpp index 0f0b931..a49359e 100644 --- a/espremoteagent/espremoteagent.cpp +++ b/espremoteagent/espremoteagent.cpp @@ -1,5 +1,7 @@ #include "espremoteagent.h" +#include +#include #include #include #include @@ -9,9 +11,12 @@ #include "espremoteagentcontainers.h" #include "espremoteport.h" -EspRemoteAgent::EspRemoteAgent(std::vector &&serialPortConfigs, QObject *parent) : - AbstractWebserver{parent} +EspRemoteAgent::EspRemoteAgent(QWebSocketServer &websocketServer, std::vector &&serialPortConfigs, QObject *parent) : + AbstractWebserver{parent}, + m_websocketServer{websocketServer} { + connect(&m_websocketServer, &QWebSocketServer::newConnection, this, &EspRemoteAgent::newWebsocketConnect); + m_ports.reserve(serialPortConfigs.size()); for (auto &config : serialPortConfigs) @@ -54,6 +59,35 @@ void EspRemoteAgent::requestReceived(WebserverClientConnection &client, const Re qWarning() << "sending response failed"; } +void EspRemoteAgent::newWebsocketConnect() +{ + while (const auto socket = m_websocketServer.nextPendingConnection()) + { + connect(socket, &QWebSocket::disconnected, socket, &QObject::deleteLater); + + auto path = socket->requestUrl().path(); + if (path.startsWith('/')) + path.remove(0, 1); + bool ok{}; + int id = path.toInt(&ok); + if (!ok) + { + qWarning() << "invalid id" << path; + socket->close(); + continue; + } + + if (id < 0 || id >= m_ports.size()) + { + qWarning() << "invalid id" << path; + socket->close(); + continue; + } + + (*std::next(std::begin(m_ports), id))->clientConnected(socket); + } +} + void EspRemoteAgent::sendRootResponse(WebserverClientConnection &client, const QUrl &url, const QUrlQuery &query) { QString content = diff --git a/espremoteagent/espremoteagent.h b/espremoteagent/espremoteagent.h index 49298c0..0cc3bc1 100644 --- a/espremoteagent/espremoteagent.h +++ b/espremoteagent/espremoteagent.h @@ -5,6 +5,7 @@ #include "abstractwebserver.h" +class QWebSocketServer; class SerialPortConfig; class WebserverClientConnection; class Request; @@ -17,12 +18,15 @@ class EspRemoteAgent : public AbstractWebserver Q_OBJECT public: - explicit EspRemoteAgent(std::vector &&serialPortConfigs, QObject *parent = nullptr); + explicit EspRemoteAgent(QWebSocketServer &websocketServer, std::vector &&serialPortConfigs, QObject *parent = nullptr); ~EspRemoteAgent() override; protected: void requestReceived(WebserverClientConnection &client, const Request &request) override; +private slots: + void newWebsocketConnect(); + private: void sendRootResponse(WebserverClientConnection &client, const QUrl &url, const QUrlQuery &query); void sendOpenResponse(WebserverClientConnection &client, const QUrl &url, const QUrlQuery &query); @@ -31,5 +35,6 @@ private: void sendSetDTRResponse(WebserverClientConnection &client, const QUrl &url, const QUrlQuery &query); void sendSetRTSResponse(WebserverClientConnection &client, const QUrl &url, const QUrlQuery &query); + QWebSocketServer &m_websocketServer; std::vector> m_ports; }; diff --git a/espremoteagent/espremoteagent.ini b/espremoteagent/espremoteagent.ini index 08ef0ea..f3fc7fd 100644 --- a/espremoteagent/espremoteagent.ini +++ b/espremoteagent/espremoteagent.ini @@ -1,13 +1,17 @@ [Webserver] listen=Any -port=80 +port=8080 + +[Websocket] +listen=Any +port=8081 [PortA] port=/dev/ttyUSB0 baudrate=115200 -url=ws://office-pi:1235/charger0 +#url=ws://office-pi:1235/charger0 [PortB] port=/dev/ttyUSB1 baudrate=115200 -url=ws://office-pi:1235/charger1 +#url=ws://office-pi:1235/charger1 diff --git a/espremoteagent/espremoteport.cpp b/espremoteagent/espremoteport.cpp index 7b48592..1e22910 100644 --- a/espremoteagent/espremoteport.cpp +++ b/espremoteagent/espremoteport.cpp @@ -110,6 +110,18 @@ void EspRemotePort::close() m_port->close(); } +void EspRemotePort::clientConnected(QWebSocket *client) +{ + if (!client) + { + qWarning() << "invalid client"; + return; + } + + connect(client, &QObject::destroyed, this, &EspRemotePort::clientDestroyed); + m_clients.emplace_back(client); +} + void EspRemotePort::timerEvent(QTimerEvent *event) { if (event->timerId() == m_reconnectTimerId) @@ -140,6 +152,9 @@ void EspRemotePort::serialReadyRead() line.chop(1); } + for (auto &client : m_clients) + client->sendTextMessage(line); + // qDebug() << line; if (m_websocket) @@ -223,3 +238,8 @@ void EspRemotePort::websocketTextMessageReceived(const QString &message) else qWarning() << "unknown command type" << type; } + +void EspRemotePort::clientDestroyed(QObject *object) +{ + m_clients.erase(std::remove(std::begin(m_clients), std::end(m_clients), object), std::end(m_clients)); +} diff --git a/espremoteagent/espremoteport.h b/espremoteagent/espremoteport.h index c8d4f45..ef06855 100644 --- a/espremoteagent/espremoteport.h +++ b/espremoteagent/espremoteport.h @@ -35,6 +35,8 @@ public: bool tryOpen(); void close(); + void clientConnected(QWebSocket *client); + protected: void timerEvent(QTimerEvent *event) override; @@ -44,6 +46,7 @@ private slots: void websocketDisconnected(); void websocketError(QAbstractSocket::SocketError error); void websocketTextMessageReceived(const QString &message); + void clientDestroyed(QObject *object = nullptr); private: SerialPortConfig m_config; @@ -53,4 +56,6 @@ private: iterable_queue m_logOutput; int m_reconnectTimerId{-1}; + + std::vector m_clients; }; diff --git a/espremoteagent/main.cpp b/espremoteagent/main.cpp index 649a0ca..f87cad1 100644 --- a/espremoteagent/main.cpp +++ b/espremoteagent/main.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include "espremoteagent.h" @@ -59,9 +60,24 @@ int main(int argc, char *argv[]) qFatal("could not parse webserver port"); } - EspRemoteAgent agent{std::move(serialPortConfigs)}; + QHostAddress websocketListen = parseHostAddress(settings.value("Websocket/listen").toString()); + int websocketPort; + { + bool ok{}; + websocketPort = settings.value("Websocket/port", 1234).toInt(&ok); + if (!ok) + qFatal("could not parse webserver port"); + } + + QWebSocketServer websocketServer{"dafuq", QWebSocketServer::NonSecureMode}; + + EspRemoteAgent agent{websocketServer, std::move(serialPortConfigs)}; + if (!agent.listen(webserverListen, webserverPort)) qFatal("could not start listening %s", qPrintable(agent.errorString())); + if (!websocketServer.listen(websocketListen, websocketPort)) + qFatal("could not start webserver listening %s", qPrintable(websocketServer.errorString())); + return app.exec(); } diff --git a/espremotemanager/espremotemanager.cpp b/espremotemanager/espremotemanager.cpp index 3fbb49e..3226a94 100644 --- a/espremotemanager/espremotemanager.cpp +++ b/espremotemanager/espremotemanager.cpp @@ -44,9 +44,9 @@ void EspRemoteManager::newConnection() { while (const auto socket = m_websocketServer.nextPendingConnection()) { - auto ö = new EspRemoteClient(socket, *this, this); - connect(ö, &QObject::destroyed, this, &EspRemoteManager::clientDestroyed); - m_clients.emplace_back(ö); + auto client = new EspRemoteClient(socket, *this, this); + connect(client, &QObject::destroyed, this, &EspRemoteManager::clientDestroyed); + m_clients.emplace_back(client); } } diff --git a/espremotemanager/main.cpp b/espremotemanager/main.cpp index aaf6a6e..4340545 100644 --- a/espremotemanager/main.cpp +++ b/espremotemanager/main.cpp @@ -48,7 +48,7 @@ int main(int argc, char *argv[]) qFatal("could not start webserver listening %s", qPrintable(manager.errorString())); if (!websocketServer.listen(websocketListen, websocketPort)) - qFatal("could not start webserver listening %s", qPrintable(manager.errorString())); + qFatal("could not start webserver listening %s", qPrintable(websocketServer.errorString())); return app.exec(); } diff --git a/webserver/webserverclientconnection.cpp b/webserver/webserverclientconnection.cpp index 593b6d6..0da4b42 100644 --- a/webserver/webserverclientconnection.cpp +++ b/webserver/webserverclientconnection.cpp @@ -58,7 +58,7 @@ bool WebserverClientConnection::sendFullResponse(int status, const QByteArray &m }; if (!containsKey("Connection")) - responseHeaders.insert("Connection", "keep"); + responseHeaders.insert("Connection", m_closeConnectionAfterResponse ? "close" : "keep"); if (!response.isEmpty() && !containsKey("Content-Length")) responseHeaders.insert("Content-Length", QString::number(response.size()).toUtf8()); @@ -69,6 +69,9 @@ bool WebserverClientConnection::sendFullResponse(int status, const QByteArray &m m_socket->write(response); m_socket->flush(); + if (m_closeConnectionAfterResponse) + m_socket->close(); + m_request.clear(); m_status = RequestLine; @@ -120,9 +123,23 @@ void WebserverClientConnection::readyRead() { const auto index = line.indexOf(": "); if (index == -1) + { qWarning() << "could not parse request header" << line; - else - m_request.headers.insert(line.left(index), line.mid(index + 2)); + continue; + } + + auto key = line.left(index); + auto value = line.mid(index + 2); + + if (key.compare("Connection", Qt::CaseInsensitive) == 0) + { + if (value.compare("close", Qt::CaseInsensitive) == 0) + m_closeConnectionAfterResponse = true; + else if (value.compare("keep-alive", Qt::CaseInsensitive) == 0) + m_closeConnectionAfterResponse = false; + } + + m_request.headers.insert(std::move(key), std::move(value)); } continue; diff --git a/webserver/webserverclientconnection.h b/webserver/webserverclientconnection.h index f8a8673..8e4645d 100644 --- a/webserver/webserverclientconnection.h +++ b/webserver/webserverclientconnection.h @@ -39,4 +39,6 @@ private: Status m_status{RequestLine}; Request m_request; + + bool m_closeConnectionAfterResponse{}; };