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