use once_cell::sync::Lazy;
use parking_lot::RwLock;
use std::sync::{
atomic::{AtomicPtr, Ordering},
Arc,
};
use crate::{config::Config, error::KoraError, signer::SignerPool};
static GLOBAL_SIGNER_POOL: Lazy<RwLock<Option<Arc<SignerPool>>>> = Lazy::new(|| RwLock::new(None));
static GLOBAL_CONFIG: AtomicPtr<Config> = AtomicPtr::new(std::ptr::null_mut());
pub fn get_request_signer_with_signer_key(
signer_key: Option<&str>,
) -> Result<Arc<solana_keychain::Signer>, KoraError> {
let pool = get_signer_pool()?;
if let Some(signer_key) = signer_key {
return pool.get_signer_by_pubkey(signer_key);
}
pool.get_next_signer()
.map_err(|e| KoraError::InternalServerError(format!("Failed to get signer from pool: {e}")))
}
pub fn init_signer_pool(pool: SignerPool) -> Result<(), KoraError> {
let mut pool_guard = GLOBAL_SIGNER_POOL.write();
if pool_guard.is_some() {
return Err(KoraError::InternalServerError("Signer pool already initialized".to_string()));
}
log::info!(
"Initializing global signer pool with {} signers using {:?} strategy",
pool.len(),
pool.strategy()
);
*pool_guard = Some(Arc::new(pool));
Ok(())
}
pub fn get_signer_pool() -> Result<Arc<SignerPool>, KoraError> {
let pool_guard = GLOBAL_SIGNER_POOL.read();
match &*pool_guard {
Some(pool) => Ok(Arc::clone(pool)),
None => Err(KoraError::InternalServerError("Signer pool not initialized".to_string())),
}
}
pub fn get_signers_info() -> Result<Vec<crate::signer::SignerInfo>, KoraError> {
let pool = get_signer_pool()?;
Ok(pool.get_signers_info())
}
#[cfg(test)]
pub fn update_signer_pool(new_pool: SignerPool) -> Result<(), KoraError> {
let mut pool_guard = GLOBAL_SIGNER_POOL.write();
*pool_guard = Some(Arc::new(new_pool));
Ok(())
}
pub fn init_config(config: Config) -> Result<(), KoraError> {
let current_ptr = GLOBAL_CONFIG.load(Ordering::Acquire);
if !current_ptr.is_null() {
return Err(KoraError::InternalServerError("Config already initialized".to_string()));
}
let config_ptr = Box::into_raw(Box::new(config));
GLOBAL_CONFIG.store(config_ptr, Ordering::Release);
Ok(())
}
pub fn get_config() -> Result<&'static Config, KoraError> {
let config_ptr = GLOBAL_CONFIG.load(Ordering::Acquire);
if config_ptr.is_null() {
return Err(KoraError::InternalServerError("Config not initialized".to_string()));
}
Ok(unsafe { &*config_ptr })
}
#[cfg(test)]
pub fn update_config(new_config: Config) -> Result<(), KoraError> {
let old_ptr = GLOBAL_CONFIG.load(Ordering::Acquire);
let new_ptr = Box::into_raw(Box::new(new_config));
GLOBAL_CONFIG.store(new_ptr, Ordering::Release);
if !old_ptr.is_null() {
unsafe {
let _ = Box::from_raw(old_ptr);
}
}
Ok(())
}