diff --git a/common/client-core/config-types/src/lib.rs b/common/client-core/config-types/src/lib.rs index 5af519cabf8..e2629c4b251 100644 --- a/common/client-core/config-types/src/lib.rs +++ b/common/client-core/config-types/src/lib.rs @@ -39,6 +39,10 @@ const DEFAULT_MAX_STARTUP_TOPOLOGY_WAITING_PERIOD: Duration = Duration::from_sec // bandwidth bridging protocol, we can come back to a smaller timeout value const DEFAULT_GATEWAY_RESPONSE_TIMEOUT: Duration = Duration::from_secs(5 * 60); +// Mirrors the `Connection` defaults in `nym-gateway-client`, which this crate does not depend on. +const DEFAULT_GATEWAY_RECONNECTION_ATTEMPTS: usize = 10; +const DEFAULT_GATEWAY_RECONNECTION_BACKOFF: Duration = Duration::from_secs(5); + const DEFAULT_COVER_TRAFFIC_PRIMARY_SIZE_RATIO: f64 = 0.70; // reply-surbs related: @@ -490,12 +494,22 @@ pub struct GatewayConnection { /// before giving up on it. #[serde(with = "humantime_serde")] pub gateway_response_timeout: Duration, + + /// How many times we try to reconnect to the gateway after losing the connection, before + /// giving up. The last attempt always runs, so `0` behaves like `1`. + pub gateway_reconnection_attempts: usize, + + /// How long we wait between reconnection attempts. + #[serde(with = "humantime_serde")] + pub gateway_reconnection_backoff: Duration, } impl Default for GatewayConnection { fn default() -> Self { GatewayConnection { gateway_response_timeout: DEFAULT_GATEWAY_RESPONSE_TIMEOUT, + gateway_reconnection_attempts: DEFAULT_GATEWAY_RECONNECTION_ATTEMPTS, + gateway_reconnection_backoff: DEFAULT_GATEWAY_RECONNECTION_BACKOFF, } } } diff --git a/common/client-core/config-types/src/old/v6.rs b/common/client-core/config-types/src/old/v6.rs index 14c9bab61b8..7441df7b081 100644 --- a/common/client-core/config-types/src/old/v6.rs +++ b/common/client-core/config-types/src/old/v6.rs @@ -140,6 +140,7 @@ impl From for Config { .debug .gateway_connection .gateway_response_timeout, + ..Default::default() }, acknowledgements: Acknowledgements { average_ack_delay: value.debug.acknowledgements.average_ack_delay, diff --git a/common/client-core/src/client/base_client/mod.rs b/common/client-core/src/client/base_client/mod.rs index 607982d782d..dd3c17e24e8 100644 --- a/common/client-core/src/client/base_client/mod.rs +++ b/common/client-core/src/client/base_client/mod.rs @@ -571,10 +571,7 @@ where let cfg = GatewayConfig::new(details.gateway_id, details.published_data.listeners); GatewayClient::new( GatewayClientConfig::new_default() - .with_disabled_credentials_mode(config.client.disabled_credentials_mode) - .with_response_timeout( - config.debug.gateway_connection.gateway_response_timeout, - ), + .with_disabled_credentials_mode(config.client.disabled_credentials_mode), cfg, managed_keys.identity_keypair(), Some(details.shared_key), @@ -587,6 +584,11 @@ where ) }; + apply_gateway_connection_settings( + &mut gateway_client.cfg, + &config.debug.gateway_connection, + ); + let gateway_failure = |err| { tracing::error!("Could not authenticate and start up the gateway connection - {err}"); ClientCoreError::GatewayClientError { @@ -1209,6 +1211,18 @@ where } } +/// Applies `debug.gateway_connection` to the gateway client config. Runs after both construction +/// paths in `start_gateway_client` converge: a client upgraded from the registration handshake +/// keeps the config it registered with, which was built without them. +fn apply_gateway_connection_settings( + cfg: &mut GatewayClientConfig, + settings: &config::GatewayConnection, +) { + cfg.connection.response_timeout_duration = settings.gateway_response_timeout; + cfg.connection.reconnection_attempts = settings.gateway_reconnection_attempts; + cfg.connection.reconnection_backoff = settings.gateway_reconnection_backoff; +} + pub struct BaseClient { pub address: Recipient, pub identity_keys: Arc, @@ -1225,6 +1239,43 @@ pub struct BaseClient { mod tests { use super::*; use nym_network_defaults::{ApiUrl, NymNetworkDetails}; + use std::time::Duration; + + #[test] + fn test_gateway_connection_settings_apply_reconnection_attempts() { + let settings = config::GatewayConnection { + gateway_reconnection_attempts: 3, + ..Default::default() + }; + let mut cfg = GatewayClientConfig::new_default(); + apply_gateway_connection_settings(&mut cfg, &settings); + assert_eq!(cfg.connection.reconnection_attempts, 3); + } + + #[test] + fn test_gateway_connection_settings_apply_reconnection_backoff() { + let settings = config::GatewayConnection { + gateway_reconnection_backoff: Duration::from_secs(1), + ..Default::default() + }; + let mut cfg = GatewayClientConfig::new_default(); + apply_gateway_connection_settings(&mut cfg, &settings); + assert_eq!(cfg.connection.reconnection_backoff, Duration::from_secs(1)); + } + + #[test] + fn test_gateway_connection_settings_apply_response_timeout() { + let settings = config::GatewayConnection { + gateway_response_timeout: Duration::from_secs(7), + ..Default::default() + }; + let mut cfg = GatewayClientConfig::new_default(); + apply_gateway_connection_settings(&mut cfg, &settings); + assert_eq!( + cfg.connection.response_timeout_duration, + Duration::from_secs(7) + ); + } #[test] fn test_network_details_with_multiple_urls() { diff --git a/common/wasm/client-core/src/config/mod.rs b/common/wasm/client-core/src/config/mod.rs index b912cb42604..7b8ecc11ff2 100644 --- a/common/wasm/client-core/src/config/mod.rs +++ b/common/wasm/client-core/src/config/mod.rs @@ -302,6 +302,13 @@ pub struct GatewayConnectionWasm { /// How long we're willing to wait for a response to a message sent to the gateway, /// before giving up on it. pub gateway_response_timeout_ms: u32, + + /// How many times we try to reconnect to the gateway after losing the connection, before + /// giving up. The last attempt always runs, so `0` behaves like `1`. + pub gateway_reconnection_attempts: u32, + + /// How long we wait between reconnection attempts. + pub gateway_reconnection_backoff_ms: u32, } impl Default for GatewayConnectionWasm { @@ -316,6 +323,11 @@ impl From for ConfigGatewayConnection { gateway_response_timeout: Duration::from_millis( gateway_connection.gateway_response_timeout_ms as u64, ), + gateway_reconnection_attempts: gateway_connection.gateway_reconnection_attempts + as usize, + gateway_reconnection_backoff: Duration::from_millis( + gateway_connection.gateway_reconnection_backoff_ms as u64, + ), } } } @@ -325,6 +337,10 @@ impl From for GatewayConnectionWasm { GatewayConnectionWasm { gateway_response_timeout_ms: gateway_connection.gateway_response_timeout.as_millis() as u32, + gateway_reconnection_attempts: gateway_connection.gateway_reconnection_attempts as u32, + gateway_reconnection_backoff_ms: gateway_connection + .gateway_reconnection_backoff + .as_millis() as u32, } } } diff --git a/common/wasm/client-core/src/config/override.rs b/common/wasm/client-core/src/config/override.rs index bc5824c9578..94f414ee672 100644 --- a/common/wasm/client-core/src/config/override.rs +++ b/common/wasm/client-core/src/config/override.rs @@ -201,6 +201,15 @@ pub struct GatewayConnectionWasmOverride { /// before giving up on it. #[tsify(optional)] pub gateway_response_timeout_ms: Option, + + /// How many times we try to reconnect to the gateway after losing the connection, before + /// giving up. The last attempt always runs, so `0` behaves like `1`. + #[tsify(optional)] + pub gateway_reconnection_attempts: Option, + + /// How long we wait between reconnection attempts. + #[tsify(optional)] + pub gateway_reconnection_backoff_ms: Option, } impl From for GatewayConnectionWasm { @@ -211,6 +220,12 @@ impl From for GatewayConnectionWasm { gateway_response_timeout_ms: value .gateway_response_timeout_ms .unwrap_or(def.gateway_response_timeout_ms), + gateway_reconnection_attempts: value + .gateway_reconnection_attempts + .unwrap_or(def.gateway_reconnection_attempts), + gateway_reconnection_backoff_ms: value + .gateway_reconnection_backoff_ms + .unwrap_or(def.gateway_reconnection_backoff_ms), } } }