diff --git a/gateway/src/node/helpers.rs b/gateway/src/node/helpers.rs index d0862f1688..d87b02afed 100644 --- a/gateway/src/node/helpers.rs +++ b/gateway/src/node/helpers.rs @@ -5,6 +5,8 @@ use async_trait::async_trait; use nym_sdk::{NymApiTopologyProvider, NymApiTopologyProviderConfig, UserAgent}; use nym_topology::{gateway, NymTopology, TopologyProvider}; use std::sync::Arc; +use std::time::Duration; +use time::OffsetDateTime; use tokio::sync::Mutex; use tracing::debug; use url::Url; @@ -17,6 +19,7 @@ pub struct GatewayTopologyProvider { impl GatewayTopologyProvider { pub fn new( gateway_node: gateway::LegacyNode, + cache_ttl: Duration, user_agent: UserAgent, nym_api_url: Vec, ) -> GatewayTopologyProvider { @@ -31,6 +34,9 @@ impl GatewayTopologyProvider { env!("CARGO_PKG_VERSION").to_string(), Some(user_agent), ), + cache_ttl, + cached_at: OffsetDateTime::UNIX_EPOCH, + cached: None, gateway_node, })), } @@ -39,25 +45,53 @@ impl GatewayTopologyProvider { struct GatewayTopologyProviderInner { inner: NymApiTopologyProvider, + cache_ttl: Duration, + cached_at: OffsetDateTime, + cached: Option, gateway_node: gateway::LegacyNode, } +impl GatewayTopologyProviderInner { + fn cached_topology(&self) -> Option { + if let Some(cached_topology) = &self.cached { + if self.cached_at + self.cache_ttl > OffsetDateTime::now_utc() { + return Some(cached_topology.clone()); + } + } + + None + } + + async fn update_cache(&mut self) -> Option { + let updated_cache = match self.inner.get_new_topology().await { + None => None, + Some(mut base) => { + if !base.gateway_exists(&self.gateway_node.identity_key) { + debug!( + "{} didn't exist in topology. inserting it.", + self.gateway_node.identity_key + ); + base.insert_gateway(self.gateway_node.clone()); + } + Some(base) + } + }; + + self.cached_at = OffsetDateTime::now_utc(); + self.cached = updated_cache.clone(); + + updated_cache + } +} + #[async_trait] impl TopologyProvider for GatewayTopologyProvider { async fn get_new_topology(&mut self) -> Option { let mut guard = self.inner.lock().await; - match guard.inner.get_new_topology().await { - None => None, - Some(mut base) => { - if !base.gateway_exists(&guard.gateway_node.identity_key) { - debug!( - "{} didn't exist in topology. inserting it.", - guard.gateway_node.identity_key - ); - base.insert_gateway(guard.gateway_node.clone()); - } - Some(base) - } + // check the cache + if let Some(cached) = guard.cached_topology() { + return Some(cached); } + guard.update_cache().await } } diff --git a/gateway/src/node/mod.rs b/gateway/src/node/mod.rs index 48e7975018..90e60f5bfc 100644 --- a/gateway/src/node/mod.rs +++ b/gateway/src/node/mod.rs @@ -30,6 +30,7 @@ use std::net::{IpAddr, Ipv4Addr, SocketAddr}; use std::path::PathBuf; use std::process; use std::sync::Arc; +use std::time::Duration; use tracing::*; pub(crate) mod client_handling; @@ -148,8 +149,11 @@ impl Gateway { } fn gateway_topology_provider(&self) -> GatewayTopologyProvider { + // TODO: make topology ttl configurable + // (to be done in reeses with the final smooshing) GatewayTopologyProvider::new( self.as_topology_node(), + Duration::from_secs(5 * 60), self.user_agent.clone(), self.config.gateway.nym_api_urls.clone(), )