use std::collections::HashMap;
use std::sync::LazyLock;
use std::sync::atomic::{AtomicU64, Ordering};
use tokio::sync::RwLock;
use tonic::transport::Channel;
pub static GLOBAL_LOCAL_NODE_NAME: LazyLock<RwLock<String>> = LazyLock::new(|| RwLock::new("".to_string()));
pub static GLOBAL_RUSTFS_HOST: LazyLock<RwLock<String>> = LazyLock::new(|| RwLock::new("".to_string()));
pub static GLOBAL_RUSTFS_PORT: LazyLock<RwLock<String>> = LazyLock::new(|| RwLock::new("9000".to_string()));
pub static GLOBAL_RUSTFS_ADDR: LazyLock<RwLock<String>> = LazyLock::new(|| RwLock::new("".to_string()));
pub static GLOBAL_CONN_MAP: LazyLock<RwLock<HashMap<String, Channel>>> = LazyLock::new(|| RwLock::new(HashMap::new()));
pub static GLOBAL_ROOT_CERT: LazyLock<RwLock<Option<Vec<u8>>>> = LazyLock::new(|| RwLock::new(None));
pub static GLOBAL_MTLS_IDENTITY: LazyLock<RwLock<Option<MtlsIdentityPem>>> = LazyLock::new(|| RwLock::new(None));
pub static GLOBAL_OUTBOUND_TLS_GENERATION: LazyLock<AtomicU64> = LazyLock::new(|| AtomicU64::new(0));
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ConnectionEvictionLogLevel {
Warn,
Info,
Debug,
}
pub async fn set_global_local_node_name(name: &str) {
*GLOBAL_LOCAL_NODE_NAME.write().await = name.to_string();
}
pub async fn get_global_local_node_name() -> String {
GLOBAL_LOCAL_NODE_NAME.read().await.clone()
}
pub fn try_get_global_local_node_name() -> Option<String> {
GLOBAL_LOCAL_NODE_NAME
.try_read()
.ok()
.map(|name| name.clone())
.filter(|name| !name.is_empty())
}
pub async fn set_global_addr(addr: &str) {
*GLOBAL_RUSTFS_ADDR.write().await = addr.to_string();
}
pub async fn get_global_rustfs_host() -> String {
GLOBAL_RUSTFS_HOST.read().await.clone()
}
pub async fn get_global_addr() -> String {
GLOBAL_RUSTFS_ADDR.read().await.clone()
}
pub async fn set_global_root_cert(cert: Vec<u8>) {
*GLOBAL_ROOT_CERT.write().await = Some(cert);
}
pub async fn clear_global_root_cert() {
*GLOBAL_ROOT_CERT.write().await = None;
}
pub async fn get_global_root_cert() -> Option<Vec<u8>> {
GLOBAL_ROOT_CERT.read().await.clone()
}
pub async fn set_global_mtls_identity(identity: Option<MtlsIdentityPem>) {
*GLOBAL_MTLS_IDENTITY.write().await = identity;
}
pub async fn get_global_mtls_identity() -> Option<MtlsIdentityPem> {
GLOBAL_MTLS_IDENTITY.read().await.clone()
}
pub fn set_global_outbound_tls_generation(generation: u64) {
GLOBAL_OUTBOUND_TLS_GENERATION.store(generation, Ordering::Relaxed);
}
pub fn get_global_outbound_tls_generation() -> u64 {
GLOBAL_OUTBOUND_TLS_GENERATION.load(Ordering::Relaxed)
}
pub async fn evict_connection(addr: &str) {
evict_connection_with_log_level(addr, ConnectionEvictionLogLevel::Info).await;
}
pub async fn evict_connection_with_log_level(addr: &str, log_level: ConnectionEvictionLogLevel) {
let removed = GLOBAL_CONN_MAP.write().await.remove(addr);
if removed.is_some() {
match log_level {
ConnectionEvictionLogLevel::Warn => {
tracing::warn!(
addr = %addr,
"Removed cached gRPC connection so future RPCs will attempt to establish a fresh channel"
);
}
ConnectionEvictionLogLevel::Info => {
tracing::info!(
addr = %addr,
"Removed cached gRPC connection so future RPCs will attempt to establish a fresh channel"
);
}
ConnectionEvictionLogLevel::Debug => {
tracing::debug!(
addr = %addr,
"Removed cached gRPC connection so future RPCs will attempt to establish a fresh channel"
);
}
}
}
}
pub async fn cached_connection(addr: &str) -> Option<Channel> {
GLOBAL_CONN_MAP.read().await.get(addr).cloned()
}
pub async fn cache_connection(addr: String, channel: Channel) {
GLOBAL_CONN_MAP.write().await.insert(addr, channel);
}
pub async fn has_cached_connection(addr: &str) -> bool {
GLOBAL_CONN_MAP.read().await.contains_key(addr)
}
pub async fn clear_all_connections() {
let mut map = GLOBAL_CONN_MAP.write().await;
let count = map.len();
map.clear();
if count > 0 {
tracing::warn!("Cleared {} cached connections from global map", count);
}
}
#[derive(Clone, Debug)]
pub struct MtlsIdentityPem {
pub cert_pem: Vec<u8>,
pub key_pem: Vec<u8>,
}