Introduce ping for keeping the connection alive

This commit is contained in:
Simon Stürz 2022-02-03 10:28:13 +01:00
parent 1ca3119995
commit accb6ec166
8 changed files with 68 additions and 10 deletions

View File

@ -79,7 +79,6 @@ public:
TcpSocketServer *tcpSocketServerTunnelProxy() const;
WebSocketServer *webSocketServerTunnelProxy() const;
MonitorServer *monitorServer() const;
LogEngine *logEngine() const;

View File

@ -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 &params, Trans
return createReply("DisconnectClient", response);
}
JsonReply *TunnelProxyHandler::Ping(const QVariantMap &params, 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 &params, TransportClient *transportClient)
{
qCDebug(dcJsonRpc()) << name() << "register client" << params << transportClient;

View File

@ -48,6 +48,7 @@ public:
// Server
Q_INVOKABLE JsonReply *RegisterServer(const QVariantMap &params, TransportClient *transportClient);
Q_INVOKABLE JsonReply *DisconnectClient(const QVariantMap &params, TransportClient *transportClient);
Q_INVOKABLE JsonReply *Ping(const QVariantMap &params, TransportClient *transportClient);
// Client
Q_INVOKABLE JsonReply *RegisterClient(const QVariantMap &params, TransportClient *transportClient);

View File

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

View File

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

View File

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

View File

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

View File

@ -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}\\\" \