hyper_usse/lib.rs
1//! A library for an SSE (server sent events) server, for use with Hyper.
2//!
3//! Start a server with `Server`, and use `EventBuilder` to generate events to send with `Server`.
4//! See [examples](https://github.com/koxiaet/hyper-usse/tree/master/examples) for usage examples.
5use futures::future;
6use hyper::body::{Bytes, Sender};
7use std::mem;
8use std::fmt::{self, Display, Formatter};
9
10/// A struct used to build server sent events.
11///
12/// # Examples
13/// Build an event with just data:
14/// ```
15/// # use hyper_usse::EventBuilder;
16/// EventBuilder::new("Data").build();
17/// ```
18/// Build an event with an ID:
19/// ```
20/// # use hyper_usse::EventBuilder;
21/// EventBuilder::new("Data").id("Id").build();
22/// ```
23/// Build an event with an event type:
24/// ```
25/// # use hyper_usse::EventBuilder;
26/// EventBuilder::new("Data").event_type("update").build();
27/// ```
28///
29/// Because `EventBuilder` implements `Into<Bytes>` you don't have to call `build` to pass it to
30/// the server.
31#[derive(Debug, Clone, Copy, PartialEq, Eq)]
32pub struct EventBuilder<'data, 'id, 'event> {
33 pub data: &'data str,
34 pub id: Option<&'id str>,
35 pub event_type: Option<&'event str>,
36}
37
38impl<'data, 'id, 'event> EventBuilder<'data, 'id, 'event> {
39 /// Create a new builder with data, no id and no event type.
40 pub fn new(data: &'data str) -> Self {
41 Self {
42 data,
43 id: None,
44 event_type: None,
45 }
46 }
47 /// Set the data.
48 pub fn data(mut self, data: &'data str) -> Self {
49 self.data = data;
50 self
51 }
52 /// Set the event id.
53 pub fn id(mut self, id: &'id str) -> Self {
54 self.id = Some(id);
55 self
56 }
57 /// Set the event type.
58 pub fn event_type(mut self, event_type: &'event str) -> Self {
59 self.event_type = Some(event_type);
60 self
61 }
62 /// Clear the event id.
63 pub fn clear_id(mut self) -> Self {
64 self.id = None;
65 self
66 }
67 /// Clear the event type.
68 pub fn clear_type(mut self) -> Self {
69 self.event_type = None;
70 self
71 }
72 /// Build the event.
73 pub fn build(self) -> String {
74 let mut event = String::with_capacity(
75 self.id.map(|id| 5 + id.len()).unwrap_or(0) +
76 self.event_type.map(|event| 8 + event.len()).unwrap_or(0) +
77 self.data.lines().count()*6 + self.data.len() +
78 1
79 );
80 if let Some(id) = self.id {
81 event.push_str("id: ");
82 event.push_str(id);
83 event.push('\n');
84 }
85 if let Some(event_type) = self.event_type {
86 event.push_str("event: ");
87 event.push_str(event_type);
88 event.push('\n');
89 }
90 for line in self.data.lines() {
91 event.push_str("data: ");
92 event.push_str(line);
93 event.push('\n');
94 }
95 event.push('\n');
96 event
97 }
98}
99
100impl<'data, 'id, 'event> Display for EventBuilder<'data, 'id, 'event> {
101 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
102 f.write_str(&self.build())
103 }
104}
105
106impl<'data, 'id, 'event> Into<Bytes> for EventBuilder<'data, 'id, 'event> {
107 fn into(self) -> Bytes {
108 self.build().into()
109 }
110}
111
112/// An SSE server.
113#[derive(Debug, Default)]
114pub struct Server {
115 clients: Vec<Sender>,
116}
117
118impl Server {
119 /// Create a new server with no clients.
120 pub fn new() -> Self {
121 Server {
122 clients: Vec::new(),
123 }
124 }
125
126 /// Add a client to a server. `Sender` can be obtained by calling `Body::channel()`.
127 pub fn add_client(&mut self, client: Sender) {
128 self.clients.push(client);
129 }
130
131 /// Send some text to the clients. Most often, this text is made using an
132 /// [EventBuilder](struct.EventBuilder.html). This will automatically remove all disconnected
133 /// clients.
134 ///
135 /// This function returns the number of currently connected clients.
136 pub async fn send_to_clients<B: Into<Bytes>>(&mut self, text: B) -> usize {
137 let bytes = text.into();
138 let mut sent = future::join_all(self.clients.iter_mut().map(|client| {
139 let bytes = bytes.slice(..);
140 async move { client.send_data(bytes).await.is_ok() }
141 })).await.into_iter();
142 self.clients.retain(|_| sent.next().unwrap());
143 self.clients.len()
144 }
145
146 /// Send a heartbeat (empty SSE) to all clients. This does not perform any action, but will
147 /// prevent your connection being timed out for lasting too long without any data being sent.
148 ///
149 /// This function returns the number of currently connected clients.
150 pub async fn send_heartbeat(&mut self) -> usize {
151 self.send_to_clients(":\n\n").await
152 }
153
154 /// Disconnect all clients that are currently connected to the server.
155 pub fn disconnect_all(&mut self) {
156 for client in mem::replace(&mut self.clients, Vec::new()) {
157 client.abort();
158 }
159 }
160
161 /// Count the number of currently held connections.
162 ///
163 /// Note that this may be an over-estimate of the number of currently connected clients, as
164 /// some clients may have disconnected since the last `send_to_clients` or `send_heartbeat`
165 /// (both of which prune the list of connections to those which still have a connected client).
166 pub fn connections(&self) -> usize {
167 self.clients.len()
168 }
169}