use crate::{Broadcast, CallCenter, MakeCallOn, Phone, TelephoneOperation};
use std::{collections::HashMap, hash::Hash, sync::Arc};
use tokio::sync::{RwLock, RwLockWriteGuard};
pub struct BroadcastCenter<Cc: CallCenter, Top: PartialEq + Clone + Hash + Eq> {
broadcasts: Arc<RwLock<HashMap<Top, Broadcast<Cc>>>>,
}
impl<Cc: CallCenter, Top: PartialEq + Clone + Hash + Eq> Default for BroadcastCenter<Cc, Top> {
fn default() -> Self {
BroadcastCenter::new()
}
}
impl<Cc: CallCenter, Top: PartialEq + Clone + Hash + Eq> BroadcastCenter<Cc, Top> {
pub fn new() -> Self {
Self {
broadcasts: Default::default(),
}
}
fn clean_broadcasts(rwlock: &mut RwLockWriteGuard<HashMap<Top, Broadcast<Cc>>>) {
rwlock.retain(|_, brc| !brc.is_empty());
}
pub async fn attach_to_broadcast(&self, topic: Top, phone: Phone<Cc>) {
let mut broadcasts = self.broadcasts.write().await;
let for_topic = broadcasts.entry(topic).or_insert(Default::default());
for_topic.attach_phone(phone);
Self::clean_broadcasts(&mut broadcasts);
}
pub async fn call_topic<Operation>(
&self,
topic: Top,
parameters: Operation::Parameters,
) -> Vec<Operation::ReturnValue>
where
Operation: TelephoneOperation + MakeCallOn<Cc>,
{
let broadcasts = self.broadcasts.read().await;
let for_topic = broadcasts.get(&topic);
if let Some(for_topic) = for_topic {
for_topic.call::<Operation>(parameters).await
} else {
vec![]
}
}
pub async fn call_topic_no_response<Operation>(
&self,
topic: Top,
parameters: Operation::Parameters,
) where
Operation: TelephoneOperation + MakeCallOn<Cc>,
{
let broadcasts = self.broadcasts.read().await;
let for_topic = broadcasts.get(&topic);
if let Some(for_topic) = for_topic {
for_topic.call_no_response::<Operation>(parameters).await;
}
}
}