From accb6ec166bdb41b494a5cc38c6c4b010c45bcf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Thu, 3 Feb 2022 10:28:13 +0100 Subject: [PATCH] Introduce ping for keeping the connection alive --- libnymea-remoteproxy/engine.h | 1 - .../jsonrpc/tunnelproxyhandler.cpp | 15 +++++++ .../jsonrpc/tunnelproxyhandler.h | 1 + .../proxyjsonrpcclient.cpp | 12 ++++++ .../proxyjsonrpcclient.h | 1 + .../tunnelproxy/tunnelproxysocketserver.cpp | 41 ++++++++++++++++--- .../tunnelproxy/tunnelproxysocketserver.h | 3 +- nymea-remoteproxy.pri | 4 +- 8 files changed, 68 insertions(+), 10 deletions(-) diff --git a/libnymea-remoteproxy/engine.h b/libnymea-remoteproxy/engine.h index ecf1eea..18fc3a2 100644 --- a/libnymea-remoteproxy/engine.h +++ b/libnymea-remoteproxy/engine.h @@ -79,7 +79,6 @@ public: TcpSocketServer *tcpSocketServerTunnelProxy() const; WebSocketServer *webSocketServerTunnelProxy() const; - MonitorServer *monitorServer() const; LogEngine *logEngine() const; diff --git a/libnymea-remoteproxy/jsonrpc/tunnelproxyhandler.cpp b/libnymea-remoteproxy/jsonrpc/tunnelproxyhandler.cpp index 73a82e6..24e8ca1 100644 --- a/libnymea-remoteproxy/jsonrpc/tunnelproxyhandler.cpp +++ b/libnymea-remoteproxy/jsonrpc/tunnelproxyhandler.cpp @@ -57,6 +57,13 @@ TunnelProxyHandler::TunnelProxyHandler(QObject *parent) : JsonHandler(parent) returns.insert("tunnelProxyError", JsonTypes::tunnelProxyErrorRef()); setReturns("DisconnectClient", returns); + params.clear(); returns.clear(); + setDescription("Ping", "In order to keep a connection alive when no client is connected, this Ping method can be used. The sent timestamp will be returned as sent in the response for speed measuements on the client side."); + params.insert("timestamp", JsonTypes::basicTypeToString(JsonTypes::UInt)); + setParams("Ping", params); + returns.insert("timestamp", JsonTypes::basicTypeToString(JsonTypes::UInt)); + setReturns("Ping", returns); + // Client params.clear(); returns.clear(); @@ -123,6 +130,14 @@ JsonReply *TunnelProxyHandler::DisconnectClient(const QVariantMap ¶ms, Trans return createReply("DisconnectClient", response); } +JsonReply *TunnelProxyHandler::Ping(const QVariantMap ¶ms, TransportClient *transportClient) +{ + qCDebug(dcJsonRpc()) << name() << "ping received" << params << transportClient; + QVariantMap response; + response.insert("timestamp", params.value("timestamp")); + return createReply("Ping", response); +} + JsonReply *TunnelProxyHandler::RegisterClient(const QVariantMap ¶ms, TransportClient *transportClient) { qCDebug(dcJsonRpc()) << name() << "register client" << params << transportClient; diff --git a/libnymea-remoteproxy/jsonrpc/tunnelproxyhandler.h b/libnymea-remoteproxy/jsonrpc/tunnelproxyhandler.h index c6524ef..518340f 100644 --- a/libnymea-remoteproxy/jsonrpc/tunnelproxyhandler.h +++ b/libnymea-remoteproxy/jsonrpc/tunnelproxyhandler.h @@ -48,6 +48,7 @@ public: // Server Q_INVOKABLE JsonReply *RegisterServer(const QVariantMap ¶ms, TransportClient *transportClient); Q_INVOKABLE JsonReply *DisconnectClient(const QVariantMap ¶ms, TransportClient *transportClient); + Q_INVOKABLE JsonReply *Ping(const QVariantMap ¶ms, TransportClient *transportClient); // Client Q_INVOKABLE JsonReply *RegisterClient(const QVariantMap ¶ms, TransportClient *transportClient); diff --git a/libnymea-remoteproxyclient/proxyjsonrpcclient.cpp b/libnymea-remoteproxyclient/proxyjsonrpcclient.cpp index f40bb5d..e5ed682 100644 --- a/libnymea-remoteproxyclient/proxyjsonrpcclient.cpp +++ b/libnymea-remoteproxyclient/proxyjsonrpcclient.cpp @@ -106,6 +106,18 @@ JsonReply *JsonRpcClient::callDisconnectClient(quint16 socketAddress) return reply; } +JsonReply *JsonRpcClient::callPing(uint timestamp) +{ + QVariantMap params; + params.insert("timestamp", timestamp); + + JsonReply *reply = new JsonReply(m_commandId, "TunnelProxy", "Ping", params, this); + qCDebug(dcRemoteProxyClientJsonRpc()) << "Calling" << QString("%1.%2").arg(reply->nameSpace()).arg(reply->method()); + sendRequest(reply->requestMap(), true); + m_replies.insert(m_commandId, reply); + return reply; +} + void JsonRpcClient::sendRequest(const QVariantMap &request, bool slipEnabled) { QByteArray data = QJsonDocument::fromVariant(request).toJson(QJsonDocument::Compact) + '\n'; diff --git a/libnymea-remoteproxyclient/proxyjsonrpcclient.h b/libnymea-remoteproxyclient/proxyjsonrpcclient.h index a751748..22d0321 100644 --- a/libnymea-remoteproxyclient/proxyjsonrpcclient.h +++ b/libnymea-remoteproxyclient/proxyjsonrpcclient.h @@ -57,6 +57,7 @@ public: JsonReply *callRegisterServer(const QUuid &serverUuid, const QString &serverName); JsonReply *callRegisterClient(const QUuid &clientUuid, const QString &clientName, const QUuid &serverUuid); JsonReply *callDisconnectClient(quint16 socketAddress); + JsonReply *callPing(uint timestamp); private: ProxyConnection *m_connection = nullptr; diff --git a/libnymea-remoteproxyclient/tunnelproxy/tunnelproxysocketserver.cpp b/libnymea-remoteproxyclient/tunnelproxy/tunnelproxysocketserver.cpp index f856ce0..903f702 100644 --- a/libnymea-remoteproxyclient/tunnelproxy/tunnelproxysocketserver.cpp +++ b/libnymea-remoteproxyclient/tunnelproxy/tunnelproxysocketserver.cpp @@ -42,7 +42,7 @@ TunnelProxySocketServer::TunnelProxySocketServer(const QUuid &serverUuid, const m_serverUuid(serverUuid), m_serverName(serverName) { - setupReconnectTimer(); + setupTimers(); } TunnelProxySocketServer::TunnelProxySocketServer(const QUuid &serverUuid, const QString &serverName, ConnectionType connectionType, QObject *parent) : @@ -51,7 +51,7 @@ TunnelProxySocketServer::TunnelProxySocketServer(const QUuid &serverUuid, const m_serverName(serverName), m_connectionType(connectionType) { - setupReconnectTimer(); + setupTimers(); } TunnelProxySocketServer::~TunnelProxySocketServer() @@ -189,6 +189,9 @@ void TunnelProxySocketServer::onConnectionDataAvailable(const QByteArray &data) { qCDebug(dcTunnelProxySocketServerTraffic()) << "Data received" << qUtf8Printable(data); + // We recived data, let's reset the keep alive timer + m_keepAliveTimer.start(); + if (m_state != StateRunning) { m_jsonClient->processData(data); m_dataBuffer.clear(); @@ -345,13 +348,13 @@ void TunnelProxySocketServer::requestSocketDisconnect(quint16 socketAddress) JsonReply *reply = m_jsonClient->callDisconnectClient(socketAddress); connect(reply, &JsonReply::finished, this, [=](){ - reply->deleteLater(); - // TODO: handle errors - qCDebug(dcTunnelProxySocketServer()) << "Request to disconnect client finished" << reply->response(); + reply->deleteLater(); + // TODO: handle errors + qCDebug(dcTunnelProxySocketServer()) << "Request to disconnect client finished" << reply->response(); }); } -void TunnelProxySocketServer::setupReconnectTimer() +void TunnelProxySocketServer::setupTimers() { m_reconnectTimer.setInterval(5000); m_reconnectTimer.setSingleShot(false); @@ -367,6 +370,24 @@ void TunnelProxySocketServer::setupReconnectTimer() startServer(m_serverUrl); } }); + + m_keepAliveTimer.setInterval(30000); + m_keepAliveTimer.setSingleShot(false); + connect(&m_keepAliveTimer, &QTimer::timeout, this, [this](){ + if (m_state == StateRunning) { + qCDebug(dcTunnelProxySocketServer()) << "Ping the proxy server to keep the connection alive"; + quint64 requestTimestamp = QDateTime::currentMSecsSinceEpoch(); + JsonReply *reply = m_jsonClient->callPing(QDateTime::currentMSecsSinceEpoch() / 1000); + connect(reply, &JsonReply::finished, this, [=](){ + quint64 pingDuration = QDateTime::currentMSecsSinceEpoch() - requestTimestamp; + reply->deleteLater(); + qCDebug(dcTunnelProxySocketServer()) << "Ping response received" << reply->response() << "Duration:" << pingDuration << "ms"; + }); + } else { + // The server is not running any more + m_keepAliveTimer.stop(); + } + }); } void TunnelProxySocketServer::setState(State state) @@ -383,6 +404,7 @@ void TunnelProxySocketServer::setState(State state) if (m_state == StateDisconnected && m_enabled) { qCDebug(dcTunnelProxySocketServer()) << "Starting reconnect timer..."; m_reconnectTimer.start(); + m_keepAliveTimer.stop(); } } @@ -394,6 +416,13 @@ void TunnelProxySocketServer::setRunning(bool running) qCDebug(dcTunnelProxySocketServer()) << "The TunnelProxy server" << (running ? "is now up and running. Listening for remote clients" : "not running any more."); m_running = running; emit runningChanged(m_running); + + if (m_running) { + qCDebug(dcTunnelProxySocketServer()) << "Starting the keep alive timer"; + m_keepAliveTimer.start(); + } else { + m_keepAliveTimer.stop(); + } } void TunnelProxySocketServer::setError(QAbstractSocket::SocketError error) diff --git a/libnymea-remoteproxyclient/tunnelproxy/tunnelproxysocketserver.h b/libnymea-remoteproxyclient/tunnelproxy/tunnelproxysocketserver.h index b6925d0..bcb397d 100644 --- a/libnymea-remoteproxyclient/tunnelproxy/tunnelproxysocketserver.h +++ b/libnymea-remoteproxyclient/tunnelproxy/tunnelproxysocketserver.h @@ -149,6 +149,7 @@ private: State m_state = StateDisconnected; QTimer m_reconnectTimer; + QTimer m_keepAliveTimer; bool m_enabled = false; ProxyConnection *m_connection = nullptr; @@ -159,7 +160,7 @@ private: QByteArray m_dataBuffer; void requestSocketDisconnect(quint16 socketAddress); - void setupReconnectTimer(); + void setupTimers(); void setState(State state); void setRunning(bool running); diff --git a/nymea-remoteproxy.pri b/nymea-remoteproxy.pri index 54e509c..7d85b99 100644 --- a/nymea-remoteproxy.pri +++ b/nymea-remoteproxy.pri @@ -4,8 +4,8 @@ QT -= gui # Define versions SERVER_NAME=nymea-remoteproxy API_VERSION_MAJOR=0 -API_VERSION_MINOR=4 -SERVER_VERSION=0.2.0 +API_VERSION_MINOR=5 +SERVER_VERSION=0.2.1 DEFINES += SERVER_NAME_STRING=\\\"$${SERVER_NAME}\\\" \ SERVER_VERSION_STRING=\\\"$${SERVER_VERSION}\\\" \