Skip to main content

ferro_broadcast/
broadcast.rs

1//! Fluent API for broadcasting messages.
2
3use crate::broadcaster::Broadcaster;
4use crate::Error;
5use serde::Serialize;
6use std::sync::Arc;
7
8/// A fluent builder for broadcasting messages.
9///
10/// # Example
11///
12/// ```rust,ignore
13/// use ferro_broadcast::Broadcast;
14///
15/// Broadcast::channel("orders.1")
16///     .event("OrderUpdated")
17///     .data(&order)
18///     .send()
19///     .await?;
20/// ```
21pub struct Broadcast {
22    broadcaster: Arc<Broadcaster>,
23}
24
25impl Broadcast {
26    /// Create a new Broadcast with the given broadcaster.
27    pub fn new(broadcaster: Arc<Broadcaster>) -> Self {
28        Self { broadcaster }
29    }
30
31    /// Start building a broadcast to a channel.
32    pub fn channel(&self, name: impl Into<String>) -> BroadcastBuilder {
33        BroadcastBuilder {
34            broadcaster: self.broadcaster.clone(),
35            channel: name.into(),
36            event: None,
37            data: None,
38            except: None,
39        }
40    }
41
42    /// Get the underlying broadcaster.
43    pub fn broadcaster(&self) -> &Arc<Broadcaster> {
44        &self.broadcaster
45    }
46}
47
48/// Builder for constructing a broadcast message.
49pub struct BroadcastBuilder {
50    broadcaster: Arc<Broadcaster>,
51    channel: String,
52    event: Option<String>,
53    data: Option<serde_json::Value>,
54    except: Option<String>,
55}
56
57impl BroadcastBuilder {
58    /// Set the event name.
59    pub fn event(mut self, name: impl Into<String>) -> Self {
60        self.event = Some(name.into());
61        self
62    }
63
64    /// Set the data payload.
65    pub fn data<T: Serialize>(mut self, data: T) -> Self {
66        self.data = serde_json::to_value(data).ok();
67        self
68    }
69
70    /// Exclude a specific client from receiving the broadcast.
71    pub fn except(mut self, socket_id: impl Into<String>) -> Self {
72        self.except = Some(socket_id.into());
73        self
74    }
75
76    /// Send the broadcast.
77    pub async fn send(self) -> Result<(), Error> {
78        let event = self.event.unwrap_or_else(|| "message".into());
79        let data = self.data.unwrap_or(serde_json::Value::Null);
80
81        if let Some(except) = self.except {
82            self.broadcaster
83                .broadcast_except(&self.channel, &event, data, &except)
84                .await
85        } else {
86            self.broadcaster
87                .broadcast(&self.channel, &event, data)
88                .await
89        }
90    }
91}
92
93#[cfg(test)]
94mod tests {
95    use super::*;
96
97    #[tokio::test]
98    async fn test_broadcast_builder() {
99        let broadcaster = Arc::new(Broadcaster::new());
100        let broadcast = Broadcast::new(broadcaster);
101
102        // This won't send to anyone since no clients, but it should not error
103        let result = broadcast
104            .channel("orders.1")
105            .event("OrderUpdated")
106            .data(serde_json::json!({"id": 1}))
107            .send()
108            .await;
109
110        assert!(result.is_ok());
111    }
112}