Lots of improvements
This commit is contained in:
@ -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 =
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -39,4 +39,6 @@ private:
|
||||
Status m_status{RequestLine};
|
||||
|
||||
Request m_request;
|
||||
|
||||
bool m_closeConnectionAfterResponse{};
|
||||
};
|
||||
|
Reference in New Issue
Block a user