1use once_cell::sync::Lazy;
2use parking_lot::RwLock;
3use std::sync::{
4 atomic::{AtomicPtr, Ordering},
5 Arc,
6};
7
8use crate::{config::Config, error::KoraError, signer::SignerPool};
9
10static GLOBAL_SIGNER_POOL: Lazy<RwLock<Option<Arc<SignerPool>>>> = Lazy::new(|| RwLock::new(None));
12
13static GLOBAL_CONFIG: AtomicPtr<Config> = AtomicPtr::new(std::ptr::null_mut());
15
16pub fn get_request_signer_with_signer_key(
18 signer_key: Option<&str>,
19) -> Result<Arc<solana_keychain::Signer>, KoraError> {
20 let pool = get_signer_pool()?;
21
22 if let Some(signer_key) = signer_key {
24 return pool.get_signer_by_pubkey(signer_key);
25 }
26
27 pool.get_next_signer()
29 .map_err(|e| KoraError::InternalServerError(format!("Failed to get signer from pool: {e}")))
30}
31
32pub fn init_signer_pool(pool: SignerPool) -> Result<(), KoraError> {
34 let mut pool_guard = GLOBAL_SIGNER_POOL.write();
35 if pool_guard.is_some() {
36 return Err(KoraError::InternalServerError("Signer pool already initialized".to_string()));
37 }
38
39 log::info!(
40 "Initializing global signer pool with {} signers using {:?} strategy",
41 pool.len(),
42 pool.strategy()
43 );
44
45 *pool_guard = Some(Arc::new(pool));
46 Ok(())
47}
48
49pub fn get_signer_pool() -> Result<Arc<SignerPool>, KoraError> {
51 let pool_guard = GLOBAL_SIGNER_POOL.read();
52 match &*pool_guard {
53 Some(pool) => Ok(Arc::clone(pool)),
54 None => Err(KoraError::InternalServerError("Signer pool not initialized".to_string())),
55 }
56}
57
58pub fn get_signers_info() -> Result<Vec<crate::signer::SignerInfo>, KoraError> {
60 let pool = get_signer_pool()?;
61 Ok(pool.get_signers_info())
62}
63
64#[cfg(test)]
66pub fn update_signer_pool(new_pool: SignerPool) -> Result<(), KoraError> {
67 let mut pool_guard = GLOBAL_SIGNER_POOL.write();
68
69 *pool_guard = Some(Arc::new(new_pool));
70
71 Ok(())
72}
73
74pub fn init_config(config: Config) -> Result<(), KoraError> {
76 let current_ptr = GLOBAL_CONFIG.load(Ordering::Acquire);
77 if !current_ptr.is_null() {
78 return Err(KoraError::InternalServerError("Config already initialized".to_string()));
79 }
80
81 let config_ptr = Box::into_raw(Box::new(config));
82 GLOBAL_CONFIG.store(config_ptr, Ordering::Release);
83 Ok(())
84}
85
86pub fn get_config() -> Result<&'static Config, KoraError> {
88 let config_ptr = GLOBAL_CONFIG.load(Ordering::Acquire);
89 if config_ptr.is_null() {
90 return Err(KoraError::InternalServerError("Config not initialized".to_string()));
91 }
92
93 Ok(unsafe { &*config_ptr })
95}
96
97#[cfg(test)]
99pub fn update_config(new_config: Config) -> Result<(), KoraError> {
100 let old_ptr = GLOBAL_CONFIG.load(Ordering::Acquire);
101 let new_ptr = Box::into_raw(Box::new(new_config));
102
103 GLOBAL_CONFIG.store(new_ptr, Ordering::Release);
104
105 if !old_ptr.is_null() {
107 unsafe {
108 let _ = Box::from_raw(old_ptr);
109 }
110 }
111
112 Ok(())
113}