use super::error::SignalError;
use parking_lot::RwLock;
use std::sync::Arc;
#[async_trait::async_trait]
pub trait SignalMiddleware<T: Send + Sync + 'static>: Send + Sync {
async fn before_send(&self, _instance: &T) -> Result<bool, SignalError> {
Ok(true)
}
async fn after_send(
&self,
instance: &T,
results: &[Result<(), SignalError>],
) -> Result<(), SignalError> {
let _ = (instance, results);
Ok(())
}
async fn before_receiver(
&self,
instance: &T,
dispatch_uid: Option<&str>,
) -> Result<bool, SignalError> {
let _ = (instance, dispatch_uid);
Ok(true)
}
async fn after_receiver(
&self,
instance: &T,
dispatch_uid: Option<&str>,
result: &Result<(), SignalError>,
) -> Result<(), SignalError> {
let _ = (instance, dispatch_uid, result);
Ok(())
}
}
pub type MiddlewareFn<T> = Arc<dyn SignalMiddleware<T>>;
#[derive(Debug, Clone)]
pub struct SignalCall {
pub signal_sent: bool,
pub receivers_called: usize,
pub errors: Vec<String>,
}
pub struct SignalSpy<T: Send + Sync + 'static> {
calls: Arc<RwLock<Vec<SignalCall>>>,
instances: Arc<RwLock<Vec<Arc<T>>>>,
}
impl<T: Send + Sync + 'static> SignalSpy<T> {
pub fn new() -> Self {
Self {
calls: Arc::new(RwLock::new(Vec::new())),
instances: Arc::new(RwLock::new(Vec::new())),
}
}
pub fn call_count(&self) -> usize {
self.calls.read().len()
}
pub fn calls(&self) -> Vec<SignalCall> {
self.calls.read().clone()
}
pub fn instances(&self) -> Vec<Arc<T>> {
self.instances.read().clone()
}
pub fn last_instance(&self) -> Option<Arc<T>> {
self.instances.read().last().cloned()
}
pub fn was_called(&self) -> bool {
self.call_count() > 0
}
pub fn was_called_with_count(&self, count: usize) -> bool {
self.call_count() == count
}
pub fn reset(&self) {
self.calls.write().clear();
self.instances.write().clear();
}
pub fn total_receivers_called(&self) -> usize {
self.calls.read().iter().map(|c| c.receivers_called).sum()
}
pub fn has_errors(&self) -> bool {
self.calls.read().iter().any(|c| !c.errors.is_empty())
}
pub fn errors(&self) -> Vec<String> {
self.calls
.read()
.iter()
.flat_map(|c| c.errors.clone())
.collect()
}
}
impl<T: Send + Sync + 'static> Clone for SignalSpy<T> {
fn clone(&self) -> Self {
Self {
calls: Arc::clone(&self.calls),
instances: Arc::clone(&self.instances),
}
}
}
impl<T: Send + Sync + 'static> Default for SignalSpy<T> {
fn default() -> Self {
Self::new()
}
}
#[async_trait::async_trait]
impl<T: Send + Sync + 'static> SignalMiddleware<T> for SignalSpy<T> {
async fn before_send(&self, _instance: &T) -> Result<bool, SignalError> {
Ok(true)
}
async fn after_send(
&self,
_instance: &T,
results: &[Result<(), SignalError>],
) -> Result<(), SignalError> {
let errors: Vec<String> = results
.iter()
.filter_map(|r| r.as_ref().err().map(|e| e.message.clone()))
.collect();
let call = SignalCall {
signal_sent: true,
receivers_called: results.len(),
errors,
};
self.calls.write().push(call);
Ok(())
}
async fn before_receiver(
&self,
_instance: &T,
_dispatch_uid: Option<&str>,
) -> Result<bool, SignalError> {
Ok(true)
}
async fn after_receiver(
&self,
_instance: &T,
_dispatch_uid: Option<&str>,
_result: &Result<(), SignalError>,
) -> Result<(), SignalError> {
Ok(())
}
}