mirror of
https://github.com/agessaman/MeshCore.git
synced 2026-08-28 22:59:46 +00:00
Enhance CommonCLI and JWTHelper for MQTT owner public key support
- Added functionality to load, save, and handle the MQTT owner public key in CommonCLI. - Implemented validation for the owner public key format and updated command handling to set the key. - Modified JWTHelper to include optional owner and client fields in JWT token creation. - Increased buffer sizes for JWT tokens in MQTTBridge to accommodate new fields.
This commit is contained in:
@@ -757,6 +757,18 @@ void MyMesh::begin(FILESYSTEM *fs) {
|
||||
_fs = fs;
|
||||
// load persisted prefs
|
||||
_cli.loadPrefs(_fs);
|
||||
|
||||
// Ensure analyzer servers are enabled by default (in case no prefs were loaded)
|
||||
if (_prefs.mqtt_analyzer_us_enabled == 0 && _prefs.mqtt_analyzer_eu_enabled == 0) {
|
||||
_prefs.mqtt_analyzer_us_enabled = 1; // enabled
|
||||
_prefs.mqtt_analyzer_eu_enabled = 1; // enabled
|
||||
MESH_DEBUG_PRINTLN("Setting analyzer servers to enabled by default");
|
||||
}
|
||||
|
||||
// Set MQTT origin to actual device name (not build-time ADVERT_NAME)
|
||||
StrHelper::strncpy(_prefs.mqtt_origin, _prefs.node_name, sizeof(_prefs.mqtt_origin));
|
||||
MESH_DEBUG_PRINTLN("MQTT origin set to device name: %s", _prefs.mqtt_origin);
|
||||
|
||||
acl.load(_fs);
|
||||
// TODO: key_store.begin();
|
||||
region_map.load(_fs);
|
||||
|
||||
@@ -129,6 +129,7 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) {
|
||||
// Let's Mesh Analyzer settings
|
||||
file.read((uint8_t *)&_prefs->mqtt_analyzer_us_enabled, sizeof(_prefs->mqtt_analyzer_us_enabled)); // 344
|
||||
file.read((uint8_t *)&_prefs->mqtt_analyzer_eu_enabled, sizeof(_prefs->mqtt_analyzer_eu_enabled)); // 345
|
||||
file.read((uint8_t *)&_prefs->mqtt_owner_public_key, sizeof(_prefs->mqtt_owner_public_key)); // 346
|
||||
// 209
|
||||
>>>>>>> 6f42dc3 (Implement Let's Mesh Analyzer integration in MQTT Bridge)
|
||||
|
||||
@@ -264,6 +265,7 @@ void CommonCLI::savePrefs(FILESYSTEM* fs) {
|
||||
// Let's Mesh Analyzer settings
|
||||
file.write((uint8_t *)&_prefs->mqtt_analyzer_us_enabled, sizeof(_prefs->mqtt_analyzer_us_enabled)); // 344
|
||||
file.write((uint8_t *)&_prefs->mqtt_analyzer_eu_enabled, sizeof(_prefs->mqtt_analyzer_eu_enabled)); // 345
|
||||
file.write((uint8_t *)&_prefs->mqtt_owner_public_key, sizeof(_prefs->mqtt_owner_public_key)); // 346
|
||||
// 209
|
||||
>>>>>>> 6f42dc3 (Implement Let's Mesh Analyzer integration in MQTT Bridge)
|
||||
|
||||
@@ -494,6 +496,12 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
|
||||
sprintf(reply, "> %s", _prefs->mqtt_analyzer_us_enabled ? "on" : "off");
|
||||
} else if (memcmp(config, "mqtt.analyzer.eu", 17) == 0) {
|
||||
sprintf(reply, "> %s", _prefs->mqtt_analyzer_eu_enabled ? "on" : "off");
|
||||
} else if (memcmp(config, "mqtt.owner", 10) == 0) {
|
||||
if (_prefs->mqtt_owner_public_key[0] != '\0') {
|
||||
sprintf(reply, "> %s", _prefs->mqtt_owner_public_key);
|
||||
} else {
|
||||
strcpy(reply, "> (not set)");
|
||||
}
|
||||
} else if (memcmp(config, "mqtt.config.valid", 17) == 0) {
|
||||
// Check if MQTT configuration is valid using static method
|
||||
bool valid = MQTTBridge::isConfigValid(_prefs);
|
||||
@@ -777,6 +785,31 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
|
||||
_prefs->mqtt_analyzer_eu_enabled = memcmp(&config[17], "on", 2) == 0;
|
||||
savePrefs();
|
||||
strcpy(reply, "OK");
|
||||
} else if (memcmp(config, "mqtt.owner ", 11) == 0) {
|
||||
// Validate that it's a valid hex string of the correct length (64 hex chars = 32 bytes)
|
||||
const char* owner_key = &config[11];
|
||||
int key_len = strlen(owner_key);
|
||||
if (key_len == 64) {
|
||||
// Validate hex characters
|
||||
bool valid = true;
|
||||
for (int i = 0; i < key_len; i++) {
|
||||
if (!((owner_key[i] >= '0' && owner_key[i] <= '9') ||
|
||||
(owner_key[i] >= 'A' && owner_key[i] <= 'F') ||
|
||||
(owner_key[i] >= 'a' && owner_key[i] <= 'f'))) {
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (valid) {
|
||||
StrHelper::strncpy(_prefs->mqtt_owner_public_key, owner_key, sizeof(_prefs->mqtt_owner_public_key));
|
||||
savePrefs();
|
||||
strcpy(reply, "OK");
|
||||
} else {
|
||||
strcpy(reply, "Error: invalid hex characters in public key");
|
||||
}
|
||||
} else {
|
||||
strcpy(reply, "Error: public key must be 64 hex characters (32 bytes)");
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
sprintf(reply, "unknown config: %s", config);
|
||||
|
||||
@@ -106,17 +106,12 @@ struct MQTTPrefs {
|
||||
uint16_t mqtt_port; // MQTT server port
|
||||
char mqtt_username[32]; // MQTT username
|
||||
char mqtt_password[64]; // MQTT password
|
||||
=======
|
||||
>>>>>>> 6f42dc3 (Implement Let's Mesh Analyzer integration in MQTT Bridge)
|
||||
|
||||
// Let's Mesh Analyzer settings
|
||||
uint8_t mqtt_analyzer_us_enabled; // Enable US analyzer server
|
||||
uint8_t mqtt_analyzer_eu_enabled; // Enable EU analyzer server
|
||||
<<<<<<< HEAD
|
||||
char mqtt_owner_public_key[65]; // Owner public key (hex string, same length as repeater public key)
|
||||
char mqtt_email[64]; // Owner email address for matching nodes with owners
|
||||
=======
|
||||
>>>>>>> 6f42dc3 (Implement Let's Mesh Analyzer integration in MQTT Bridge)
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
@@ -14,7 +14,9 @@ bool JWTHelper::createAuthToken(
|
||||
unsigned long issuedAt,
|
||||
unsigned long expiresIn,
|
||||
char* token,
|
||||
size_t tokenSize
|
||||
size_t tokenSize,
|
||||
const char* owner,
|
||||
const char* client
|
||||
) {
|
||||
Serial.printf("JWTHelper: Starting JWT creation for audience: %s\n", audience);
|
||||
|
||||
@@ -52,7 +54,7 @@ bool JWTHelper::createAuthToken(
|
||||
|
||||
// Create payload with HEX public key (not base64!)
|
||||
char payload[512];
|
||||
size_t payloadLen = createPayload(publicKeyHex, audience, issuedAt, expiresIn, payload, sizeof(payload));
|
||||
size_t payloadLen = createPayload(publicKeyHex, audience, issuedAt, expiresIn, payload, sizeof(payload), owner, client);
|
||||
if (payloadLen == 0) {
|
||||
Serial.printf("JWTHelper: Failed to create payload\n");
|
||||
return false;
|
||||
@@ -219,11 +221,19 @@ size_t JWTHelper::createPayload(
|
||||
unsigned long issuedAt,
|
||||
unsigned long expiresIn,
|
||||
char* output,
|
||||
size_t outputSize
|
||||
size_t outputSize,
|
||||
const char* owner,
|
||||
const char* client
|
||||
) {
|
||||
Serial.printf("JWTHelper: createPayload called with outputSize: %d\n", (int)outputSize);
|
||||
Serial.printf("JWTHelper: publicKey: %s, audience: %s, issuedAt: %lu, expiresIn: %lu\n",
|
||||
publicKey, audience, issuedAt, expiresIn);
|
||||
if (owner) {
|
||||
Serial.printf("JWTHelper: owner: %s\n", owner);
|
||||
}
|
||||
if (client) {
|
||||
Serial.printf("JWTHelper: client: %s\n", client);
|
||||
}
|
||||
|
||||
// Create JWT payload
|
||||
DynamicJsonDocument doc(512);
|
||||
@@ -235,6 +245,16 @@ size_t JWTHelper::createPayload(
|
||||
doc["exp"] = issuedAt + expiresIn;
|
||||
}
|
||||
|
||||
// Add optional owner field if provided
|
||||
if (owner && strlen(owner) > 0) {
|
||||
doc["owner"] = owner;
|
||||
}
|
||||
|
||||
// Add optional client field if provided
|
||||
if (client && strlen(client) > 0) {
|
||||
doc["client"] = client;
|
||||
}
|
||||
|
||||
// Use temporary buffer for JSON
|
||||
char jsonBuffer[512];
|
||||
size_t len = serializeJson(doc, jsonBuffer, sizeof(jsonBuffer));
|
||||
|
||||
+10
-2
@@ -20,6 +20,8 @@ public:
|
||||
* @param expiresIn Expiration time in seconds (0 for no expiration)
|
||||
* @param token Buffer to store the resulting token
|
||||
* @param tokenSize Size of the token buffer
|
||||
* @param owner Optional owner public key in hex format (nullptr if not set)
|
||||
* @param client Optional client string (nullptr if not set)
|
||||
* @return true if token was created successfully
|
||||
*/
|
||||
static bool createAuthToken(
|
||||
@@ -28,7 +30,9 @@ public:
|
||||
unsigned long issuedAt = 0,
|
||||
unsigned long expiresIn = 0,
|
||||
char* token = nullptr,
|
||||
size_t tokenSize = 0
|
||||
size_t tokenSize = 0,
|
||||
const char* owner = nullptr,
|
||||
const char* client = nullptr
|
||||
);
|
||||
|
||||
private:
|
||||
@@ -61,6 +65,8 @@ private:
|
||||
* @param expiresIn Expiration time in seconds (0 for no expiration)
|
||||
* @param output Output buffer
|
||||
* @param outputSize Size of output buffer
|
||||
* @param owner Optional owner public key in hex format (nullptr if not set)
|
||||
* @param client Optional client string (nullptr if not set)
|
||||
* @return Length of payload, or 0 on error
|
||||
*/
|
||||
static size_t createPayload(
|
||||
@@ -69,7 +75,9 @@ private:
|
||||
unsigned long issuedAt,
|
||||
unsigned long expiresIn,
|
||||
char* output,
|
||||
size_t outputSize
|
||||
size_t outputSize,
|
||||
const char* owner = nullptr,
|
||||
const char* client = nullptr
|
||||
);
|
||||
|
||||
};
|
||||
|
||||
@@ -999,12 +999,35 @@ bool MQTTBridge::createAuthToken() {
|
||||
bool us_token_created = false;
|
||||
bool eu_token_created = false;
|
||||
|
||||
// Get current time for expiration tracking
|
||||
unsigned long current_time = time(nullptr);
|
||||
unsigned long expires_in = 86400; // 24 hours
|
||||
|
||||
// Prepare owner public key (if set) - convert to uppercase hex
|
||||
const char* owner_key = nullptr;
|
||||
char owner_key_uppercase[65];
|
||||
if (_prefs->mqtt_owner_public_key[0] != '\0') {
|
||||
// Copy and convert to uppercase
|
||||
strncpy(owner_key_uppercase, _prefs->mqtt_owner_public_key, sizeof(owner_key_uppercase) - 1);
|
||||
owner_key_uppercase[sizeof(owner_key_uppercase) - 1] = '\0';
|
||||
for (int i = 0; owner_key_uppercase[i]; i++) {
|
||||
owner_key_uppercase[i] = toupper(owner_key_uppercase[i]);
|
||||
}
|
||||
owner_key = owner_key_uppercase;
|
||||
MQTT_DEBUG_PRINTLN("Using owner public key: %s", owner_key);
|
||||
}
|
||||
|
||||
// Build client version string (same format as used in status messages)
|
||||
char client_version[64];
|
||||
snprintf(client_version, sizeof(client_version), "meshcoretomqtt/%s", _build_date);
|
||||
|
||||
// Create JWT token for US server
|
||||
if (_analyzer_us_enabled) {
|
||||
MQTT_DEBUG_PRINTLN("Creating JWT token for US server...");
|
||||
if (JWTHelper::createAuthToken(
|
||||
*_identity, "mqtt-us-v1.letsmesh.net",
|
||||
0, 86400, _auth_token_us, sizeof(_auth_token_us))) {
|
||||
0, expires_in, _auth_token_us, sizeof(_auth_token_us),
|
||||
owner_key, client_version)) {
|
||||
MQTT_DEBUG_PRINTLN("Created auth token for US server");
|
||||
us_token_created = true;
|
||||
} else {
|
||||
@@ -1017,7 +1040,8 @@ bool MQTTBridge::createAuthToken() {
|
||||
MQTT_DEBUG_PRINTLN("Creating JWT token for EU server...");
|
||||
if (JWTHelper::createAuthToken(
|
||||
*_identity, "mqtt-eu-v1.letsmesh.net",
|
||||
0, 86400, _auth_token_eu, sizeof(_auth_token_eu))) {
|
||||
0, expires_in, _auth_token_eu, sizeof(_auth_token_eu),
|
||||
owner_key, client_version)) {
|
||||
MQTT_DEBUG_PRINTLN("Created auth token for EU server");
|
||||
eu_token_created = true;
|
||||
} else {
|
||||
@@ -1302,9 +1326,199 @@ void MQTTBridge::publishStatusToAnalyzerClient(PsychicMqttClient* client, const
|
||||
}
|
||||
|
||||
void MQTTBridge::maintainAnalyzerConnections() {
|
||||
<<<<<<< HEAD
|
||||
// PsychicMqttClient handles connection maintenance and reconnection automatically
|
||||
// No manual maintenance needed - the library manages this internally
|
||||
// Connection state changes are handled via the onConnect/onDisconnect callbacks
|
||||
=======
|
||||
if (!_identity) {
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned long current_time = time(nullptr);
|
||||
// If time is not synced (time() returns 0 or very small value), skip expiration checks
|
||||
// Tokens will still work but we can't track expiration properly
|
||||
// If expiration time was set before time sync, it will be a small value, so we'll renew
|
||||
bool time_synced = (current_time >= 1000000000); // After year 2001
|
||||
|
||||
const unsigned long RENEWAL_BUFFER = 3600; // Renew tokens 1 hour before expiration
|
||||
const unsigned long RENEWAL_THROTTLE_MS = 60000; // Don't attempt renewal more than once per minute
|
||||
|
||||
unsigned long now_millis = millis();
|
||||
|
||||
// Check and renew US server token if needed
|
||||
if (_analyzer_us_enabled && _analyzer_us_client) {
|
||||
// Check if token is expired or will expire soon
|
||||
// If time wasn't synced when token was created, expiration time will be invalid, so renew
|
||||
bool token_needs_renewal = (_token_us_expires_at == 0) ||
|
||||
!time_synced ||
|
||||
!(_token_us_expires_at >= 1000000000) || // Expiration time invalid
|
||||
(time_synced && current_time >= _token_us_expires_at) ||
|
||||
(time_synced && current_time >= (_token_us_expires_at - RENEWAL_BUFFER));
|
||||
|
||||
// Throttle renewal attempts - don't try more than once per minute to avoid blocking
|
||||
bool can_attempt_renewal = (now_millis - _last_token_renewal_attempt_us) >= RENEWAL_THROTTLE_MS;
|
||||
|
||||
// Check if client is disconnected and needs reconnection with new token
|
||||
bool needs_reconnect = !_analyzer_us_client->connected();
|
||||
|
||||
if (token_needs_renewal && can_attempt_renewal) {
|
||||
_last_token_renewal_attempt_us = now_millis;
|
||||
MQTT_DEBUG_PRINTLN("US token expired or expiring soon (expires_at: %lu, current: %lu), renewing...",
|
||||
_token_us_expires_at, current_time);
|
||||
|
||||
// Prepare owner public key (if set) - convert to uppercase hex
|
||||
const char* owner_key = nullptr;
|
||||
char owner_key_uppercase[65];
|
||||
if (_prefs->mqtt_owner_public_key[0] != '\0') {
|
||||
// Copy and convert to uppercase
|
||||
strncpy(owner_key_uppercase, _prefs->mqtt_owner_public_key, sizeof(owner_key_uppercase) - 1);
|
||||
owner_key_uppercase[sizeof(owner_key_uppercase) - 1] = '\0';
|
||||
for (int i = 0; owner_key_uppercase[i]; i++) {
|
||||
owner_key_uppercase[i] = toupper(owner_key_uppercase[i]);
|
||||
}
|
||||
owner_key = owner_key_uppercase;
|
||||
}
|
||||
|
||||
// Build client version string (same format as used in status messages)
|
||||
char client_version[64];
|
||||
snprintf(client_version, sizeof(client_version), "meshcoretomqtt/%s", _build_date);
|
||||
|
||||
// Renew the token
|
||||
if (JWTHelper::createAuthToken(
|
||||
*_identity, "mqtt-us-v1.letsmesh.net",
|
||||
0, 86400, _auth_token_us, sizeof(_auth_token_us),
|
||||
owner_key, client_version)) {
|
||||
unsigned long expires_in = 86400; // 24 hours
|
||||
_token_us_expires_at = current_time + expires_in;
|
||||
MQTT_DEBUG_PRINTLN("US token renewed, new expiration: %lu", _token_us_expires_at);
|
||||
|
||||
// Update client credentials with new token
|
||||
_analyzer_us_client->setCredentials(_analyzer_username, _auth_token_us);
|
||||
|
||||
// Reconnect to apply new token (whether currently connected or not)
|
||||
// If connected, disconnect first to ensure new token is used
|
||||
if (_analyzer_us_client->connected()) {
|
||||
MQTT_DEBUG_PRINTLN("Disconnecting US server to apply new token...");
|
||||
_analyzer_us_client->disconnect();
|
||||
}
|
||||
MQTT_DEBUG_PRINTLN("Reconnecting to US server with renewed token...");
|
||||
_last_reconnect_attempt_us = now_millis; // Update reconnect timestamp to throttle subsequent attempts
|
||||
_analyzer_us_client->connect();
|
||||
} else {
|
||||
MQTT_DEBUG_PRINTLN("Failed to renew US token");
|
||||
_token_us_expires_at = 0;
|
||||
}
|
||||
} else if (needs_reconnect) {
|
||||
// Token is still valid but connection is lost - reconnect with existing token
|
||||
// Throttle reconnection attempts to avoid spamming
|
||||
unsigned long reconnect_elapsed = (now_millis >= _last_reconnect_attempt_us) ?
|
||||
(now_millis - _last_reconnect_attempt_us) :
|
||||
(ULONG_MAX - _last_reconnect_attempt_us + now_millis + 1);
|
||||
if (reconnect_elapsed >= RECONNECT_THROTTLE_MS) {
|
||||
_last_reconnect_attempt_us = now_millis;
|
||||
MQTT_DEBUG_PRINTLN("US server disconnected but token still valid, reconnecting...");
|
||||
_analyzer_us_client->connect();
|
||||
} else {
|
||||
// Throttled - only log periodically to avoid spam (every 5 minutes max)
|
||||
static unsigned long last_throttle_log_us = 0;
|
||||
if (now_millis - last_throttle_log_us > 300000) {
|
||||
MQTT_DEBUG_PRINTLN("US server reconnection throttled (last attempt %lu ms ago, need %lu ms)",
|
||||
reconnect_elapsed, RECONNECT_THROTTLE_MS);
|
||||
last_throttle_log_us = now_millis;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check and renew EU server token if needed
|
||||
if (_analyzer_eu_enabled && _analyzer_eu_client) {
|
||||
// Check if token is expired or will expire soon
|
||||
// If time wasn't synced when token was created, expiration time will be invalid, so renew
|
||||
bool token_needs_renewal = (_token_eu_expires_at == 0) ||
|
||||
!time_synced ||
|
||||
!(_token_eu_expires_at >= 1000000000) || // Expiration time invalid
|
||||
(time_synced && current_time >= _token_eu_expires_at) ||
|
||||
(time_synced && current_time >= (_token_eu_expires_at - RENEWAL_BUFFER));
|
||||
|
||||
// Throttle renewal attempts - don't try more than once per minute to avoid blocking
|
||||
bool can_attempt_renewal = (now_millis - _last_token_renewal_attempt_eu) >= RENEWAL_THROTTLE_MS;
|
||||
|
||||
// Check if client is disconnected and needs reconnection with new token
|
||||
bool needs_reconnect = !_analyzer_eu_client->connected();
|
||||
|
||||
if (token_needs_renewal && can_attempt_renewal) {
|
||||
_last_token_renewal_attempt_eu = now_millis;
|
||||
MQTT_DEBUG_PRINTLN("EU token expired or expiring soon (expires_at: %lu, current: %lu), renewing...",
|
||||
_token_eu_expires_at, current_time);
|
||||
|
||||
// Prepare owner public key (if set) - convert to uppercase hex
|
||||
const char* owner_key = nullptr;
|
||||
char owner_key_uppercase[65];
|
||||
if (_prefs->mqtt_owner_public_key[0] != '\0') {
|
||||
// Copy and convert to uppercase
|
||||
strncpy(owner_key_uppercase, _prefs->mqtt_owner_public_key, sizeof(owner_key_uppercase) - 1);
|
||||
owner_key_uppercase[sizeof(owner_key_uppercase) - 1] = '\0';
|
||||
for (int i = 0; owner_key_uppercase[i]; i++) {
|
||||
owner_key_uppercase[i] = toupper(owner_key_uppercase[i]);
|
||||
}
|
||||
owner_key = owner_key_uppercase;
|
||||
}
|
||||
|
||||
// Build client version string (same format as used in status messages)
|
||||
char client_version[64];
|
||||
snprintf(client_version, sizeof(client_version), "meshcoretomqtt/%s", _build_date);
|
||||
|
||||
// Renew the token
|
||||
if (JWTHelper::createAuthToken(
|
||||
*_identity, "mqtt-eu-v1.letsmesh.net",
|
||||
0, 86400, _auth_token_eu, sizeof(_auth_token_eu),
|
||||
owner_key, client_version)) {
|
||||
unsigned long expires_in = 86400; // 24 hours
|
||||
_token_eu_expires_at = current_time + expires_in;
|
||||
MQTT_DEBUG_PRINTLN("EU token renewed, new expiration: %lu", _token_eu_expires_at);
|
||||
|
||||
// Update client credentials with new token
|
||||
_analyzer_eu_client->setCredentials(_analyzer_username, _auth_token_eu);
|
||||
|
||||
// Reconnect to apply new token (whether currently connected or not)
|
||||
// If connected, disconnect first to ensure new token is used
|
||||
if (_analyzer_eu_client->connected()) {
|
||||
MQTT_DEBUG_PRINTLN("Disconnecting EU server to apply new token...");
|
||||
_analyzer_eu_client->disconnect();
|
||||
}
|
||||
MQTT_DEBUG_PRINTLN("Reconnecting to EU server with renewed token...");
|
||||
_last_reconnect_attempt_eu = now_millis; // Update reconnect timestamp to throttle subsequent attempts
|
||||
_analyzer_eu_client->connect();
|
||||
} else {
|
||||
MQTT_DEBUG_PRINTLN("Failed to renew EU token");
|
||||
_token_eu_expires_at = 0;
|
||||
}
|
||||
} else if (needs_reconnect) {
|
||||
// Token is still valid but connection is lost - reconnect with existing token
|
||||
// Throttle reconnection attempts to avoid spamming
|
||||
unsigned long reconnect_elapsed = (now_millis >= _last_reconnect_attempt_eu) ?
|
||||
(now_millis - _last_reconnect_attempt_eu) :
|
||||
(ULONG_MAX - _last_reconnect_attempt_eu + now_millis + 1);
|
||||
if (reconnect_elapsed >= RECONNECT_THROTTLE_MS) {
|
||||
_last_reconnect_attempt_eu = now_millis;
|
||||
MQTT_DEBUG_PRINTLN("EU server disconnected but token still valid, reconnecting...");
|
||||
_analyzer_eu_client->connect();
|
||||
} else {
|
||||
// Throttled - only log periodically to avoid spam (every 5 minutes max)
|
||||
static unsigned long last_throttle_log_eu = 0;
|
||||
if (now_millis - last_throttle_log_eu > 300000) {
|
||||
MQTT_DEBUG_PRINTLN("EU server reconnection throttled (last attempt %lu ms ago, need %lu ms)",
|
||||
reconnect_elapsed, RECONNECT_THROTTLE_MS);
|
||||
last_throttle_log_eu = now_millis;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Note: PsychicMqttClient handles automatic reconnection internally,
|
||||
// but we need to ensure tokens are renewed before reconnection attempts
|
||||
>>>>>>> 1ebe417c (Enhance CommonCLI and JWTHelper for MQTT owner public key support)
|
||||
}
|
||||
|
||||
void MQTTBridge::setMessageTypes(bool status, bool packets, bool raw) {
|
||||
|
||||
@@ -117,8 +117,8 @@ private:
|
||||
// Let's Mesh Analyzer support
|
||||
bool _analyzer_us_enabled;
|
||||
bool _analyzer_eu_enabled;
|
||||
char _auth_token_us[512]; // JWT token for US server authentication
|
||||
char _auth_token_eu[512]; // JWT token for EU server authentication
|
||||
char _auth_token_us[768]; // JWT token for US server authentication (increased for owner/client fields)
|
||||
char _auth_token_eu[768]; // JWT token for EU server authentication (increased for owner/client fields)
|
||||
char _analyzer_username[70]; // Username in format v1_{UPPERCASE_PUBLIC_KEY}
|
||||
|
||||
// Device identity for JWT token creation
|
||||
|
||||
Reference in New Issue
Block a user