Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/keepalive-timeout-reconnect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'firmware': minor
---

feat: add a keepalive ping timeout that forces a reconnect on backend connection loss
3 changes: 3 additions & 0 deletions include/GatewayClient.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#pragma once

Check warning on line 1 in include/GatewayClient.h

View workflow job for this annotation

GitHub Actions / C/C++ Linter

include/GatewayClient.h:1:1 [portability-avoid-pragma-once]

avoid 'pragma once' directive; use include guards instead

#include "Common.h"
#include "GatewayClientState.h"
Expand All @@ -13,22 +13,24 @@

namespace OpenShock {
class GatewayClient {
DISABLE_COPY(GatewayClient);

Check warning on line 16 in include/GatewayClient.h

View workflow job for this annotation

GitHub Actions / C/C++ Linter

include/GatewayClient.h:16:5 [modernize-use-trailing-return-type]

use a trailing return type for this function
DISABLE_MOVE(GatewayClient);

Check warning on line 17 in include/GatewayClient.h

View workflow job for this annotation

GitHub Actions / C/C++ Linter

include/GatewayClient.h:17:5 [modernize-use-trailing-return-type]

use a trailing return type for this function

public:
GatewayClient(const std::string& authToken);
~GatewayClient();

inline GatewayClientState state() const { return m_state; }

Check warning on line 23 in include/GatewayClient.h

View workflow job for this annotation

GitHub Actions / C/C++ Linter

include/GatewayClient.h:23:31 [modernize-use-trailing-return-type]

use a trailing return type for this function

Check warning on line 23 in include/GatewayClient.h

View workflow job for this annotation

GitHub Actions / C/C++ Linter

include/GatewayClient.h:23:5 [readability-redundant-inline-specifier]

function 'state' has inline specifier but is implicitly inlined

Check warning on line 23 in include/GatewayClient.h

View workflow job for this annotation

GitHub Actions / C/C++ Linter

include/GatewayClient.h:23:5 [modernize-use-nodiscard]

function 'state' should be marked [[nodiscard]]

void connect(const std::string& host, uint16_t port, const std::string& path);
void disconnect();

bool sendMessageTXT(std::string_view data);

Check warning on line 28 in include/GatewayClient.h

View workflow job for this annotation

GitHub Actions / C/C++ Linter

include/GatewayClient.h:28:10 [modernize-use-trailing-return-type]

use a trailing return type for this function
bool sendMessageBIN(tcb::span<const uint8_t> data);

Check warning on line 29 in include/GatewayClient.h

View workflow job for this annotation

GitHub Actions / C/C++ Linter

include/GatewayClient.h:29:10 [modernize-use-trailing-return-type]

use a trailing return type for this function

void markPingReceived();

bool loop();

Check warning on line 33 in include/GatewayClient.h

View workflow job for this annotation

GitHub Actions / C/C++ Linter

include/GatewayClient.h:33:10 [modernize-use-trailing-return-type]

use a trailing return type for this function

private:
void _setState(GatewayClientState state);
Expand All @@ -37,5 +39,6 @@

WebSocketsClient m_webSocket;
GatewayClientState m_state;
int64_t m_lastPingTimestamp;
};
} // namespace OpenShock
2 changes: 2 additions & 0 deletions include/GatewayConnectionManager.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#pragma once

Check warning on line 1 in include/GatewayConnectionManager.h

View workflow job for this annotation

GitHub Actions / C/C++ Linter

include/GatewayConnectionManager.h:1:1 [portability-avoid-pragma-once]

avoid 'pragma once' directive; use include guards instead

#include "AccountLinkResultCode.h"
#include "span.h"
Expand All @@ -19,5 +19,7 @@
bool SendMessageTXT(std::string_view data);
bool SendMessageBIN(tcb::span<const uint8_t> data);

void MarkPingReceived();

void Update();
} // namespace OpenShock::GatewayConnectionManager
16 changes: 16 additions & 0 deletions src/GatewayClient.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#include "GatewayClient.h"

const char* const TAG = "GatewayClient";
Expand All @@ -14,11 +14,14 @@

using namespace OpenShock;

const int64_t GATEWAY_PING_TIMEOUT = 90'000;

static bool s_bootStatusSent = false;

GatewayClient::GatewayClient(const std::string& authToken)
: m_webSocket()
, m_state(GatewayClientState::Disconnected)
, m_lastPingTimestamp(0)
{
OS_LOGD(TAG, "Creating GatewayClient");

Expand Down Expand Up @@ -90,6 +93,11 @@
return m_webSocket.sendBIN(data.data(), data.size());
}

void GatewayClient::markPingReceived()
{
m_lastPingTimestamp = OpenShock::millis();
}

bool GatewayClient::loop()
{
if (m_state == GatewayClientState::Disconnected) {
Expand All @@ -104,6 +112,13 @@
return true;
}

if (m_lastPingTimestamp != 0 && (OpenShock::millis() - m_lastPingTimestamp) > GATEWAY_PING_TIMEOUT) {
Comment thread
hhvrc marked this conversation as resolved.
OS_LOGW(TAG, "No ping received from gateway for %lld ms, forcing reconnect", GATEWAY_PING_TIMEOUT);
m_webSocket.disconnect();
_setState(GatewayClientState::Disconnected);
return false;
}

return true;
}

Expand Down Expand Up @@ -160,6 +175,7 @@
_setState(GatewayClientState::Disconnected);
break;
case WStype_CONNECTED:
m_lastPingTimestamp = 0;
_setState(GatewayClientState::Connected);
_sendBootStatus();
break;
Expand Down
10 changes: 10 additions & 0 deletions src/GatewayConnectionManager.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#include "GatewayConnectionManager.h"

const char* const TAG = "GatewayConnectionManager";
Expand Down Expand Up @@ -194,6 +194,16 @@
return client->sendMessageBIN(data);
}

void GatewayConnectionManager::MarkPingReceived()
{
auto client = GetClient();
if (client == nullptr) {
return;
}

client->markPingReceived();
}

bool FetchHubInfo(std::string authToken)
{
// TODO: this function is very slow, should be optimized!
Expand Down
1 change: 1 addition & 0 deletions src/message_handlers/websocket/gateway/Ping.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@ void _Private::HandlePing(const OpenShock::Serialization::Gateway::GatewayToHubM
return;
}

GatewayConnectionManager::MarkPingReceived();
Serialization::Gateway::SerializePongMessage(GatewayConnectionManager::SendMessageBIN);
}