Lots of improvements

This commit is contained in:
2022-10-06 02:44:58 +02:00
parent 55be773896
commit 38a98af070
10 changed files with 117 additions and 14 deletions

View File

@ -1,5 +1,7 @@
#include "espremoteagent.h" #include "espremoteagent.h"
#include <QWebSocketServer>
#include <QWebSocket>
#include <QDebug> #include <QDebug>
#include <QUrl> #include <QUrl>
#include <QUrlQuery> #include <QUrlQuery>
@ -9,9 +11,12 @@
#include "espremoteagentcontainers.h" #include "espremoteagentcontainers.h"
#include "espremoteport.h" #include "espremoteport.h"
EspRemoteAgent::EspRemoteAgent(std::vector<SerialPortConfig> &&serialPortConfigs, QObject *parent) : EspRemoteAgent::EspRemoteAgent(QWebSocketServer &websocketServer, std::vector<SerialPortConfig> &&serialPortConfigs, QObject *parent) :
AbstractWebserver{parent} AbstractWebserver{parent},
m_websocketServer{websocketServer}
{ {
connect(&m_websocketServer, &QWebSocketServer::newConnection, this, &EspRemoteAgent::newWebsocketConnect);
m_ports.reserve(serialPortConfigs.size()); m_ports.reserve(serialPortConfigs.size());
for (auto &config : serialPortConfigs) for (auto &config : serialPortConfigs)
@ -54,6 +59,35 @@ void EspRemoteAgent::requestReceived(WebserverClientConnection &client, const Re
qWarning() << "sending response failed"; 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) void EspRemoteAgent::sendRootResponse(WebserverClientConnection &client, const QUrl &url, const QUrlQuery &query)
{ {
QString content = QString content =

View File

@ -5,6 +5,7 @@
#include "abstractwebserver.h" #include "abstractwebserver.h"
class QWebSocketServer;
class SerialPortConfig; class SerialPortConfig;
class WebserverClientConnection; class WebserverClientConnection;
class Request; class Request;
@ -17,12 +18,15 @@ class EspRemoteAgent : public AbstractWebserver
Q_OBJECT Q_OBJECT
public: public:
explicit EspRemoteAgent(std::vector<SerialPortConfig> &&serialPortConfigs, QObject *parent = nullptr); explicit EspRemoteAgent(QWebSocketServer &websocketServer, std::vector<SerialPortConfig> &&serialPortConfigs, QObject *parent = nullptr);
~EspRemoteAgent() override; ~EspRemoteAgent() override;
protected: protected:
void requestReceived(WebserverClientConnection &client, const Request &request) override; void requestReceived(WebserverClientConnection &client, const Request &request) override;
private slots:
void newWebsocketConnect();
private: private:
void sendRootResponse(WebserverClientConnection &client, const QUrl &url, const QUrlQuery &query); void sendRootResponse(WebserverClientConnection &client, const QUrl &url, const QUrlQuery &query);
void sendOpenResponse(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 sendSetDTRResponse(WebserverClientConnection &client, const QUrl &url, const QUrlQuery &query);
void sendSetRTSResponse(WebserverClientConnection &client, const QUrl &url, const QUrlQuery &query); void sendSetRTSResponse(WebserverClientConnection &client, const QUrl &url, const QUrlQuery &query);
QWebSocketServer &m_websocketServer;
std::vector<std::unique_ptr<EspRemotePort>> m_ports; std::vector<std::unique_ptr<EspRemotePort>> m_ports;
}; };

View File

@ -1,13 +1,17 @@
[Webserver] [Webserver]
listen=Any listen=Any
port=80 port=8080
[Websocket]
listen=Any
port=8081
[PortA] [PortA]
port=/dev/ttyUSB0 port=/dev/ttyUSB0
baudrate=115200 baudrate=115200
url=ws://office-pi:1235/charger0 #url=ws://office-pi:1235/charger0
[PortB] [PortB]
port=/dev/ttyUSB1 port=/dev/ttyUSB1
baudrate=115200 baudrate=115200
url=ws://office-pi:1235/charger1 #url=ws://office-pi:1235/charger1

View File

@ -110,6 +110,18 @@ void EspRemotePort::close()
m_port->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) void EspRemotePort::timerEvent(QTimerEvent *event)
{ {
if (event->timerId() == m_reconnectTimerId) if (event->timerId() == m_reconnectTimerId)
@ -140,6 +152,9 @@ void EspRemotePort::serialReadyRead()
line.chop(1); line.chop(1);
} }
for (auto &client : m_clients)
client->sendTextMessage(line);
// qDebug() << line; // qDebug() << line;
if (m_websocket) if (m_websocket)
@ -223,3 +238,8 @@ void EspRemotePort::websocketTextMessageReceived(const QString &message)
else else
qWarning() << "unknown command type" << type; 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));
}

View File

@ -35,6 +35,8 @@ public:
bool tryOpen(); bool tryOpen();
void close(); void close();
void clientConnected(QWebSocket *client);
protected: protected:
void timerEvent(QTimerEvent *event) override; void timerEvent(QTimerEvent *event) override;
@ -44,6 +46,7 @@ private slots:
void websocketDisconnected(); void websocketDisconnected();
void websocketError(QAbstractSocket::SocketError error); void websocketError(QAbstractSocket::SocketError error);
void websocketTextMessageReceived(const QString &message); void websocketTextMessageReceived(const QString &message);
void clientDestroyed(QObject *object = nullptr);
private: private:
SerialPortConfig m_config; SerialPortConfig m_config;
@ -53,4 +56,6 @@ private:
iterable_queue<QString> m_logOutput; iterable_queue<QString> m_logOutput;
int m_reconnectTimerId{-1}; int m_reconnectTimerId{-1};
std::vector<QWebSocket*> m_clients;
}; };

View File

@ -1,5 +1,6 @@
#include <QCoreApplication> #include <QCoreApplication>
#include <QSettings> #include <QSettings>
#include <QWebSocketServer>
#include <QUrl> #include <QUrl>
#include "espremoteagent.h" #include "espremoteagent.h"
@ -59,9 +60,24 @@ int main(int argc, char *argv[])
qFatal("could not parse webserver port"); 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)) if (!agent.listen(webserverListen, webserverPort))
qFatal("could not start listening %s", qPrintable(agent.errorString())); 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(); return app.exec();
} }

View File

@ -44,9 +44,9 @@ void EspRemoteManager::newConnection()
{ {
while (const auto socket = m_websocketServer.nextPendingConnection()) while (const auto socket = m_websocketServer.nextPendingConnection())
{ {
auto ö = new EspRemoteClient(socket, *this, this); auto client = new EspRemoteClient(socket, *this, this);
connect(ö, &QObject::destroyed, this, &EspRemoteManager::clientDestroyed); connect(client, &QObject::destroyed, this, &EspRemoteManager::clientDestroyed);
m_clients.emplace_back(ö); m_clients.emplace_back(client);
} }
} }

View File

@ -48,7 +48,7 @@ int main(int argc, char *argv[])
qFatal("could not start webserver listening %s", qPrintable(manager.errorString())); qFatal("could not start webserver listening %s", qPrintable(manager.errorString()));
if (!websocketServer.listen(websocketListen, websocketPort)) 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(); return app.exec();
} }

View File

@ -58,7 +58,7 @@ bool WebserverClientConnection::sendFullResponse(int status, const QByteArray &m
}; };
if (!containsKey("Connection")) if (!containsKey("Connection"))
responseHeaders.insert("Connection", "keep"); responseHeaders.insert("Connection", m_closeConnectionAfterResponse ? "close" : "keep");
if (!response.isEmpty() && !containsKey("Content-Length")) if (!response.isEmpty() && !containsKey("Content-Length"))
responseHeaders.insert("Content-Length", QString::number(response.size()).toUtf8()); 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->write(response);
m_socket->flush(); m_socket->flush();
if (m_closeConnectionAfterResponse)
m_socket->close();
m_request.clear(); m_request.clear();
m_status = RequestLine; m_status = RequestLine;
@ -120,9 +123,23 @@ void WebserverClientConnection::readyRead()
{ {
const auto index = line.indexOf(": "); const auto index = line.indexOf(": ");
if (index == -1) if (index == -1)
{
qWarning() << "could not parse request header" << line; qWarning() << "could not parse request header" << line;
else continue;
m_request.headers.insert(line.left(index), line.mid(index + 2)); }
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; continue;

View File

@ -39,4 +39,6 @@ private:
Status m_status{RequestLine}; Status m_status{RequestLine};
Request m_request; Request m_request;
bool m_closeConnectionAfterResponse{};
}; };