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 <QWebSocketServer>
#include <QWebSocket>
#include <QDebug>
#include <QUrl>
#include <QUrlQuery>
@ -9,9 +11,12 @@
#include "espremoteagentcontainers.h"
#include "espremoteport.h"
EspRemoteAgent::EspRemoteAgent(std::vector<SerialPortConfig> &&serialPortConfigs, QObject *parent) :
AbstractWebserver{parent}
EspRemoteAgent::EspRemoteAgent(QWebSocketServer &websocketServer, std::vector<SerialPortConfig> &&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 =

View File

@ -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<SerialPortConfig> &&serialPortConfigs, QObject *parent = nullptr);
explicit EspRemoteAgent(QWebSocketServer &websocketServer, std::vector<SerialPortConfig> &&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<std::unique_ptr<EspRemotePort>> m_ports;
};

View File

@ -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

View File

@ -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));
}

View File

@ -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<QString> m_logOutput;
int m_reconnectTimerId{-1};
std::vector<QWebSocket*> m_clients;
};

View File

@ -1,5 +1,6 @@
#include <QCoreApplication>
#include <QSettings>
#include <QWebSocketServer>
#include <QUrl>
#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();
}

View File

@ -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);
}
}

View File

@ -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();
}

View File

@ -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;

View File

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