use crate::{BalancingCall,BalancingStrategy,Linker,Polling};
use std::sync::Arc;
use std::collections::HashMap;
use tokio::sync::RwLock;
use std::ops::DerefMut;
use std::hash::Hash;
pub struct Balancing<K,Req, Res>{
map:RwLock<HashMap<K,Box<dyn BalancingCall<Req, Res>+Send+Sync>>>,
strategy:Arc<dyn BalancingStrategy<K> + Send + Sync>,
linker:Option<Arc<dyn Linker<K> + Send + Sync>>,
}
impl<K:Clone + Eq + Hash + Send + Sync + 'static ,Req, Res> Balancing<K,Req, Res>{
pub fn new()->Self{
let map = RwLock::new(HashMap::new());
let strategy = Arc::new(Polling::<K>::new());
let linker = None;
Self{map,strategy,linker}
}
pub fn set_strategy<B>(mut self, strategy:B) ->Self
where B:BalancingStrategy<K> + Send + Sync + 'static
{
let strategy = Arc::new(strategy);
self.strategy = strategy;
self
}
pub fn set_strategy_linker<B>(mut self,strategy:B)->Self
where B:BalancingStrategy<K>+Linker<K> + Send + Sync + 'static
{
let strategy = Arc::new(strategy);
self.strategy = strategy.clone();
self.linker = Some(strategy);
self
}
pub async fn add<N:BalancingCall<Req, Res>+Send+Sync+'static>(&self,key:K,n:N,w:usize){
if w <= 0{
return;
}
let mut map = self.map.write().await;
let map = map.deref_mut();
map.insert(key.clone(),Box::new(n));
self.strategy.add(key,w).await;
}
pub async fn remove(&self, key:K) -> Option<Box<dyn BalancingCall<Req, Res>+Send+Sync>> {
let mut map = self.map.write().await;
let map = map.deref_mut();
let res = map.remove(&key);
self.strategy.remove(key).await;
res
}
pub async fn call(&self,reqs:Req)->Option<Res>{
let mut resp = None;
let map = self.map.read().await;
if let Some(k) = self.strategy.select().await {
if let Some(node) = map.get(&k) {
if let Some(ref s) = self.linker {
s.acquire(k.clone()).await
}
resp = node.call(reqs).await;
if let Some(ref s) = self.linker {
s.release(k).await
}
}
}
resp
}
}