diff options
| author | Thomas Vanbesien <tvanbesi@proton.me> | 2026-03-13 11:58:45 +0100 |
|---|---|---|
| committer | Thomas Vanbesien <tvanbesi@proton.me> | 2026-03-13 11:58:45 +0100 |
| commit | 02fe86ab2a04a02b114d7ca8ce4374a29a1d5f45 (patch) | |
| tree | ebec2643d7238d0447a236a278757c718b0ef0ac | |
| parent | a2b1ccf17845e55caef7f69a5e68f49a55b6a166 (diff) | |
| download | QtXpl2-02fe86ab2a04a02b114d7ca8ce4374a29a1d5f45.tar.gz QtXpl2-02fe86ab2a04a02b114d7ca8ce4374a29a1d5f45.zip | |
Coalesce mock server into single MockServer class
Replace three independent EchoServer instances with one MockServer
that owns three QTcpServers, shares a single KA_PING timer, and
uses a flat client list with localPort() for port resolution.
| -rw-r--r-- | mock-server/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | mock-server/EchoServer.cpp | 97 | ||||
| -rw-r--r-- | mock-server/EchoServer.h | 33 | ||||
| -rw-r--r-- | mock-server/MockServer.cpp | 122 | ||||
| -rw-r--r-- | mock-server/MockServer.h | 44 | ||||
| -rw-r--r-- | mock-server/main.cpp | 8 |
6 files changed, 170 insertions, 136 deletions
diff --git a/mock-server/CMakeLists.txt b/mock-server/CMakeLists.txt index f5d54f8..abcb65c 100644 --- a/mock-server/CMakeLists.txt +++ b/mock-server/CMakeLists.txt @@ -1,4 +1,4 @@ -qt_add_executable(Xpl2MockServer main.cpp EchoServer.h EchoServer.cpp) +qt_add_executable(Xpl2MockServer main.cpp MockServer.h MockServer.cpp) set_target_properties(Xpl2MockServer PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin") diff --git a/mock-server/EchoServer.cpp b/mock-server/EchoServer.cpp deleted file mode 100644 index 8d86df1..0000000 --- a/mock-server/EchoServer.cpp +++ /dev/null @@ -1,97 +0,0 @@ -/** - * @file EchoServer.cpp - * @brief Mock XPL2 server for a single port. - */ -#include "EchoServer.h" - -#include <QTcpSocket> - -EchoServer::EchoServer (quint16 port, const char *name, QObject *parent) - : QTcpServer (parent), m_name (name), m_port (port) -{ - connect (this, &QTcpServer::newConnection, this, - &EchoServer::onNewConnection); - - connect (&m_pingTimer, &QTimer::timeout, this, &EchoServer::sendKaPing); - - if (!listen (QHostAddress::Any, port)) - qCritical ("Failed to listen on %s port %d: %s", m_name, m_port, - qPrintable (errorString ())); - else - { - qInfo ("Listening on %s port %d", m_name, m_port); - m_pingTimer.start (1000); - } -} - -void -EchoServer::onNewConnection () -{ - while (auto *sock = nextPendingConnection ()) - { - qInfo ("[%s:%d] client connected", m_name, m_port); - m_clients.append (sock); - connect (sock, &QTcpSocket::readyRead, this, - &EchoServer::onClientMessageReady); - connect (sock, &QTcpSocket::disconnected, this, - &EchoServer::onClientDisconnected); - } -} - -void -EchoServer::onClientMessageReady () -{ - auto *sock = qobject_cast<QTcpSocket *> (sender ()); - while (sock->canReadLine ()) - { - QByteArray line = sock->readLine (); - handleCommand (sock, line); - } -} - -void -EchoServer::onClientDisconnected () -{ - auto *sock = qobject_cast<QTcpSocket *> (sender ()); - qInfo ("[%s:%d] client disconnected", m_name, m_port); - m_clients.removeOne (sock); - sock->deleteLater (); -} - -void -EchoServer::sendKaPing () -{ - for (auto *client : m_clients) - { - if (client->state () == QAbstractSocket::ConnectedState) - client->write ("KA_PING\n"); - } -} - -void -EchoServer::handleCommand (QTcpSocket *client, const QByteArray &line) -{ - QByteArray trimmed = line.trimmed (); - if (trimmed.isEmpty ()) - return; - - /* Split on first comma to get command token. */ - int comma = trimmed.indexOf (','); - QByteArray cmd = (comma >= 0) ? trimmed.left (comma) : trimmed; - - if (cmd == "KA_PING") - { - qDebug ("[%s:%d] KA_PING ACK received", m_name, m_port); - return; - } - - if (cmd == "GS_JC_VERSION") - { - qInfo ("[%s:%d] -> GS_JC_VERSION reply", m_name, m_port); - client->write ("GS_JC_VERSION,1,\"1.05\",\"2.00\",15\n"); - return; - } - - qWarning ("[%s:%d] Unknown command: %s", m_name, m_port, - trimmed.constData ()); -} diff --git a/mock-server/EchoServer.h b/mock-server/EchoServer.h deleted file mode 100644 index c0a41c9..0000000 --- a/mock-server/EchoServer.h +++ /dev/null @@ -1,33 +0,0 @@ -/** - * @file EchoServer.h - * @brief Mock XPL2 server for a single port. - */ -#pragma once - -#include <QList> -#include <QTcpServer> -#include <QTimer> - -class QTcpSocket; - -class EchoServer : public QTcpServer -{ - Q_OBJECT - -public: - EchoServer (quint16 port, const char *name, QObject *parent = nullptr); - -private slots: - void onNewConnection (); - void onClientMessageReady (); - void onClientDisconnected (); - void sendKaPing (); - -private: - void handleCommand (QTcpSocket *client, const QByteArray &line); - - const char *m_name; - quint16 m_port; - QList<QTcpSocket *> m_clients; - QTimer m_pingTimer; -}; diff --git a/mock-server/MockServer.cpp b/mock-server/MockServer.cpp new file mode 100644 index 0000000..52db5a1 --- /dev/null +++ b/mock-server/MockServer.cpp @@ -0,0 +1,122 @@ +/** + * @file MockServer.cpp + * @brief Mock XPL2 server — listens on all three protocol ports. + */ +#include "MockServer.h" + +#include <QTcpSocket> + +MockServer::MockServer (QObject *parent) : QObject (parent) +{ + setupPort (m_command, "Command", 9110); + setupPort (m_imaging, "Imaging", 9111); + setupPort (m_status, "Status", 9112); + + connect (&m_pingTimer, &QTimer::timeout, this, &MockServer::sendKaPing); + m_pingTimer.start (1000); +} + +void +MockServer::setupPort (Port &port, const char *name, quint16 number) +{ + port.name = name; + port.number = number; + + connect (&port.server, &QTcpServer::newConnection, this, + &MockServer::onNewConnection); + + if (!port.server.listen (QHostAddress::Any, number)) + qCritical ("Failed to listen on %s port %d: %s", name, number, + qPrintable (port.server.errorString ())); + else + qInfo ("Listening on %s port %d", name, number); +} + +const char * +MockServer::portName (quint16 localPort) const +{ + if (localPort == m_command.number) + return m_command.name; + if (localPort == m_imaging.number) + return m_imaging.name; + if (localPort == m_status.number) + return m_status.name; + return "Unknown"; +} + +void +MockServer::onNewConnection () +{ + auto *server = qobject_cast<QTcpServer *> (sender ()); + while (auto *sock = server->nextPendingConnection ()) + { + quint16 lp = sock->localPort (); + qInfo ("[%s:%d] client connected", portName (lp), lp); + m_clients.append (sock); + connect (sock, &QTcpSocket::readyRead, this, + &MockServer::onClientMessageReady); + connect (sock, &QTcpSocket::disconnected, this, + &MockServer::onClientDisconnected); + } +} + +void +MockServer::onClientMessageReady () +{ + auto *sock = qobject_cast<QTcpSocket *> (sender ()); + while (sock->canReadLine ()) + { + QByteArray line = sock->readLine (); + handleCommand (sock, line); + } +} + +void +MockServer::onClientDisconnected () +{ + auto *sock = qobject_cast<QTcpSocket *> (sender ()); + quint16 lp = sock->localPort (); + qInfo ("[%s:%d] client disconnected", portName (lp), lp); + m_clients.removeOne (sock); + sock->deleteLater (); +} + +void +MockServer::sendKaPing () +{ + for (auto *client : m_clients) + { + if (client->state () == QAbstractSocket::ConnectedState) + client->write ("KA_PING\n"); + } +} + +void +MockServer::handleCommand (QTcpSocket *client, const QByteArray &line) +{ + QByteArray trimmed = line.trimmed (); + if (trimmed.isEmpty ()) + return; + + quint16 lp = client->localPort (); + + /* Split on first comma to get command token. */ + int comma = trimmed.indexOf (','); + QByteArray cmd = (comma >= 0) ? trimmed.left (comma) : trimmed; + + if (cmd == "KA_PING") + { + qDebug ("[%s:%d] KA_PING ACK received", portName (lp), lp); + return; + } + + if (cmd == "GS_JC_VERSION") + { + qInfo ("[%s:%d] -> GS_JC_VERSION reply", portName (lp), lp); + client->write ("GS_JC_VERSION,1,\"1.05\",\"2.00\",15\n"); + return; + } + + qWarning ("[%s:%d] Unknown command: %s", portName (lp), lp, + trimmed.constData ()); +} diff --git a/mock-server/MockServer.h b/mock-server/MockServer.h new file mode 100644 index 0000000..21d4d32 --- /dev/null +++ b/mock-server/MockServer.h @@ -0,0 +1,44 @@ +/** + * @file MockServer.h + * @brief Mock XPL2 server — listens on all three protocol ports. + */ +#pragma once + +#include <QList> +#include <QObject> +#include <QTcpServer> +#include <QTimer> + +class QTcpSocket; + +class MockServer : public QObject +{ + Q_OBJECT + +public: + explicit MockServer (QObject *parent = nullptr); + +private slots: + void onNewConnection (); + void onClientMessageReady (); + void onClientDisconnected (); + void sendKaPing (); + +private: + struct Port + { + QTcpServer server; + const char *name = nullptr; + quint16 number = 0; + }; + + void setupPort (Port &port, const char *name, quint16 number); + const char *portName (quint16 localPort) const; + void handleCommand (QTcpSocket *client, const QByteArray &line); + + Port m_command; + Port m_imaging; + Port m_status; + QList<QTcpSocket *> m_clients; + QTimer m_pingTimer; +}; diff --git a/mock-server/main.cpp b/mock-server/main.cpp index 0694e4d..b104685 100644 --- a/mock-server/main.cpp +++ b/mock-server/main.cpp @@ -1,8 +1,8 @@ /** * @file main.cpp - * @brief Mock XPL2 server — echoes back on three ports. + * @brief Mock XPL2 server on three protocol ports. */ -#include "EchoServer.h" +#include "MockServer.h" #include <QCoreApplication> @@ -11,9 +11,7 @@ main (int argc, char *argv[]) { QCoreApplication app (argc, argv); - new EchoServer (9110, "Command", &app); - new EchoServer (9111, "Imaging", &app); - new EchoServer (9112, "Status", &app); + new MockServer (&app); return app.exec (); } |
