engineioxide/
config.rs

1//! ## Configuration for the engine.io engine & transports
2//! #### Example :
3//! ```rust
4//! # use bytes::Bytes;
5//! # use engineioxide::config::EngineIoConfig;
6//! # use engineioxide::service::EngineIoService;
7//! # use engineioxide::handler::EngineIoHandler;
8//! # use std::time::Duration;
9//! # use engineioxide::{Socket, DisconnectReason, Str};
10//! # use std::sync::Arc;
11//! #[derive(Debug, Clone)]
12//! struct MyHandler;
13//!
14//! impl EngineIoHandler for MyHandler {
15//!     type Data = ();
16//!     fn on_connect(self: Arc<Self>, socket: Arc<Socket<()>>) { }
17//!     fn on_disconnect(&self, socket: Arc<Socket<()>>, reason: DisconnectReason) { }
18//!     fn on_message(self: &Arc<Self>, msg: Str, socket: Arc<Socket<()>>) { }
19//!     fn on_binary(self: &Arc<Self>, data: Bytes, socket: Arc<Socket<()>>) { }
20//! }
21//!
22//! let config = EngineIoConfig::builder()
23//!     .ping_interval(Duration::from_millis(300))  // Set the ping_interval to 300ms
24//!     .ping_timeout(Duration::from_millis(200))   // Set the ping timeout to 200ms
25//!     .max_payload(1e6 as u64)                    // Set the max payload to a given size
26//!     .max_buffer_size(1024)                      // Set a custom buffer size
27//!     .build();
28//!
29//! // Create an engine io service with a custom config
30//! let svc = EngineIoService::with_config(Arc::new(MyHandler), config);
31//! ```
32
33use std::{borrow::Cow, time::Duration};
34
35use crate::service::TransportType;
36
37/// Configuration for the engine.io engine & transports
38#[derive(Debug, Clone)]
39pub struct EngineIoConfig {
40    /// The path to listen for engine.io requests on.
41    /// Defaults to "/engine.io".
42    pub req_path: Cow<'static, str>,
43
44    /// The interval at which the server will send a ping packet to the client.
45    /// Defaults to 25 seconds.
46    pub ping_interval: Duration,
47
48    /// The amount of time the server will wait for a ping response from the client before closing the connection.
49    /// Defaults to 20 seconds.
50    pub ping_timeout: Duration,
51
52    /// The maximum number of packets that can be buffered per connection before being emitted to the client.
53    ///
54    /// If the buffer if full the `emit()` method will return an error
55    ///
56    /// Defaults to 128 packets
57    pub max_buffer_size: usize,
58
59    /// The maximum number of bytes that can be received per http request.
60    /// Defaults to 100KB.
61    pub max_payload: u64,
62
63    /// The size of the read buffer for the websocket transport.
64    /// You can tweak this value depending on your use case. By default it is set to 4KiB.
65    ///
66    /// Setting it to a higher value will improve performance on heavy read scenarios
67    /// but will consume more memory.
68    pub ws_read_buffer_size: usize,
69
70    /// Allowed transports on this server
71    /// It is represented as a bitfield to allow to combine any number of transports easily
72    pub transports: u8,
73}
74
75impl Default for EngineIoConfig {
76    fn default() -> Self {
77        Self {
78            req_path: "/engine.io".into(),
79            ping_interval: Duration::from_millis(25000),
80            ping_timeout: Duration::from_millis(20000),
81            max_buffer_size: 128,
82            max_payload: 1e5 as u64, // 100kb
83            ws_read_buffer_size: 4096,
84            transports: TransportType::Polling as u8 | TransportType::Websocket as u8,
85        }
86    }
87}
88
89impl EngineIoConfig {
90    /// Create a new builder with a default config
91    pub fn builder() -> EngineIoConfigBuilder {
92        EngineIoConfigBuilder::new()
93    }
94
95    /// Check if a [`TransportType`] is enabled in the [`EngineIoConfig`]
96    #[inline(always)]
97    pub fn allowed_transport(&self, transport: TransportType) -> bool {
98        self.transports & transport as u8 == transport as u8
99    }
100}
101
102/// Builder for [`EngineIoConfig`]
103pub struct EngineIoConfigBuilder {
104    config: EngineIoConfig,
105}
106
107impl EngineIoConfigBuilder {
108    /// Create a new builder with a default config
109    pub fn new() -> Self {
110        Self {
111            config: EngineIoConfig::default(),
112        }
113    }
114
115    /// The path to listen for engine.io requests on.
116    /// Defaults to "/engine.io".
117    pub fn req_path(mut self, req_path: impl Into<Cow<'static, str>>) -> Self {
118        self.config.req_path = req_path.into();
119        self
120    }
121
122    /// The interval at which the server will send a ping packet to the client.
123    /// Defaults to 25 seconds.
124    pub fn ping_interval(mut self, ping_interval: Duration) -> Self {
125        self.config.ping_interval = ping_interval;
126        self
127    }
128
129    // The amount of time the server will wait for a ping response from the client before closing the connection.
130    /// Defaults to 20 seconds.
131    pub fn ping_timeout(mut self, ping_timeout: Duration) -> Self {
132        self.config.ping_timeout = ping_timeout;
133        self
134    }
135
136    /// The maximum number of packets that can be buffered per connection before being emitted to the client.
137    ///
138    /// If the buffer if full the `emit()` method will return an error
139    /// ```
140    /// # use bytes::Bytes;
141    /// # use engineioxide::{
142    ///     Str,
143    ///     layer::EngineIoLayer,
144    ///     handler::EngineIoHandler,
145    ///     socket::{Socket, DisconnectReason},
146    /// };
147    /// # use std::sync::Arc;
148    /// #[derive(Debug, Clone)]
149    /// struct MyHandler;
150    ///
151    /// impl EngineIoHandler for MyHandler {
152    ///
153    ///     type Data = ();
154    ///     fn on_connect(self: Arc<Self>, socket: Arc<Socket<()>>) {
155    ///         println!("socket connect {}", socket.id);
156    ///     }
157    ///     fn on_disconnect(&self, socket: Arc<Socket<()>>, reason: DisconnectReason) {
158    ///         println!("socket disconnect {}", socket.id);
159    ///     }
160    ///
161    ///     fn on_message(self: &Arc<Self>, msg: Str, socket: Arc<Socket<()>>) {
162    ///         println!("Ping pong message {:?}", msg);
163    ///         socket.emit(msg).unwrap();
164    ///     }
165    ///
166    ///     fn on_binary(self: &Arc<Self>, data: Bytes, socket: Arc<Socket<()>>) {
167    ///         println!("Ping pong binary message {:?}", data);
168    ///         socket.emit_binary(data).unwrap();
169    ///     }
170    /// }
171    /// ```
172    pub fn max_buffer_size(mut self, max_buffer_size: usize) -> Self {
173        self.config.max_buffer_size = max_buffer_size;
174        self
175    }
176
177    /// The maximum number of bytes that can be received per http request.
178    /// Defaults to 100kb.
179    pub fn max_payload(mut self, max_payload: u64) -> Self {
180        self.config.max_payload = max_payload;
181        self
182    }
183
184    /// The size of the read buffer for the websocket transport.
185    /// You can tweak this value depending on your use case. Defaults to 4KiB.
186    ///
187    /// Setting it to a higher value will improve performance on heavy read scenarios
188    /// but will consume more memory.
189    pub fn ws_read_buffer_size(mut self, ws_read_buffer_size: usize) -> Self {
190        self.config.ws_read_buffer_size = ws_read_buffer_size;
191        self
192    }
193
194    /// Allowed transports on this server
195    ///
196    /// The `transports` array should have a size of 1 or 2
197    ///
198    /// Defaults to :
199    /// `[TransportType::Polling, TransportType::Websocket]`
200    pub fn transports<const N: usize>(mut self, transports: [TransportType; N]) -> Self {
201        assert!(N > 0 && N <= 2);
202        self.config.transports = 0;
203        for transport in transports {
204            self.config.transports |= transport as u8;
205        }
206        self
207    }
208
209    /// Build the config
210    pub fn build(self) -> EngineIoConfig {
211        self.config
212    }
213}
214impl Default for EngineIoConfigBuilder {
215    fn default() -> Self {
216        Self::new()
217    }
218}
219
220#[cfg(test)]
221mod tests {
222    use super::*;
223
224    #[test]
225    pub fn config_transports() {
226        let conf = EngineIoConfig::builder()
227            .transports([TransportType::Polling])
228            .build();
229        assert!(conf.allowed_transport(TransportType::Polling));
230        assert!(!conf.allowed_transport(TransportType::Websocket));
231
232        let conf = EngineIoConfig::builder()
233            .transports([TransportType::Websocket])
234            .build();
235        assert!(conf.allowed_transport(TransportType::Websocket));
236        assert!(!conf.allowed_transport(TransportType::Polling));
237        let conf = EngineIoConfig::builder()
238            .transports([TransportType::Polling, TransportType::Websocket])
239            .build();
240        assert!(conf.allowed_transport(TransportType::Polling));
241        assert!(conf.allowed_transport(TransportType::Websocket));
242    }
243}