1use std::sync::Arc;
2
3use thiserror::Error;
4use tokio::sync::mpsc::{error::SendError, Sender};
5use uuid::Uuid;
6
7use crate::service::{BoxedError, PinnedBoxedFutureResult};
8
9pub enum Callback<T>
10where
11 T: Send + Sync + 'static,
12{
13 Channel(Sender<Arc<T>>),
14 Closure(Box<dyn Fn(Arc<T>) -> Result<(), BoxedError> + Send + Sync>),
15 AsyncClosure(Box<dyn Fn(Arc<T>) -> PinnedBoxedFutureResult<()> + Send + Sync>),
16}
17
18#[derive(Debug, Error)]
19pub enum DispatchError<T>
20where
21 T: Send + Sync + 'static,
22{
23 #[error("Failed to send data to channel: {0}")]
24 ChannelSend(#[from] SendError<Arc<T>>),
25
26 #[error("Failed to dispatch data to closure: {0}")]
27 Closure(BoxedError),
28
29 #[error("Failed to dispatch data to async closure: {0}")]
30 AsyncClosure(BoxedError),
31}
32
33pub struct Subscriber<T>
34where
35 T: Send + Sync + 'static,
36{
37 pub name: String,
38 pub log_on_error: bool,
39 pub remove_on_error: bool,
40 pub callback: Callback<T>,
41
42 pub uuid: Uuid,
43}
44
45impl<T> Subscriber<T>
46where
47 T: Send + Sync + 'static,
48{
49 pub fn new<S>(name: S, log_on_error: bool, remove_on_error: bool, callback: Callback<T>) -> Self
50 where
51 S: Into<String>,
52 {
53 Self {
54 name: name.into(),
55 log_on_error,
56 remove_on_error,
57 callback,
58 uuid: Uuid::new_v4(),
59 }
60 }
61
62 pub async fn dispatch(&self, data: Arc<T>) -> Result<(), DispatchError<T>> {
63 match &self.callback {
64 Callback::Channel(sender) => {
65 sender.send(data).await.map_err(DispatchError::ChannelSend)
66 }
67 Callback::Closure(closure) => closure(data).map_err(DispatchError::Closure),
68 Callback::AsyncClosure(closure) => {
69 closure(data).await.map_err(DispatchError::AsyncClosure)
70 }
71 }
72 }
73}
74
75impl<T> PartialEq for Subscriber<T>
76where
77 T: Send + Sync + 'static,
78{
79 fn eq(&self, other: &Self) -> bool {
80 self.uuid == other.uuid
81 }
82}
83
84impl<T> Eq for Subscriber<T> where T: Send + Sync {}