use std::{ any::Any, collections::{HashMap, HashSet}, mem, sync::{Arc, Mutex}, }; use web_push::{PartialVapidSignatureBuilder, SubscriptionInfo, WebPushError}; use crate::{error::failed::Failed, push::Publish}; #[derive(Clone)] pub struct Client { sent: Arc>>, failures: Arc>>, } impl Client { pub fn new() -> Self { Self { sent: Arc::default(), failures: Arc::default(), } } // Clears the list of sent messages (for all clones of this Client) when called, because we // can't clone `Publications`s, so we either need to move them or try to reconstruct them. pub fn sent(&self) -> Vec { let mut sent = self.sent.lock().unwrap(); mem::take(&mut sent) } pub fn fail_next(&self, subscription_info: &SubscriptionInfo, err: WebPushError) { let mut failures = self.failures.lock().unwrap(); failures.insert(subscription_info.clone(), err); } } impl Publish for Client { async fn publish( &self, message: M, _: PartialVapidSignatureBuilder, subscriptions: impl IntoIterator + Send, ) -> Result, Failed> where M: Send + 'static, { let message: Box = Box::new(message); let subscriptions = subscriptions.into_iter().collect(); let mut failures = Vec::new(); let mut planned_failures = self.failures.lock().unwrap(); for subscription in &subscriptions { if let Some(err) = planned_failures.remove(subscription) { failures.push((subscription.clone(), err)); } } let publication = Publication { message, subscriptions, }; self.sent.lock().unwrap().push(publication); Ok(failures) } } #[derive(Debug)] pub struct Publication { pub message: Box, pub subscriptions: HashSet, } impl Publication { pub fn message_eq(&self, candidate: &M) -> bool where M: PartialEq + 'static, { match self.message.downcast_ref::() { None => false, Some(message) => message == candidate, } } }