1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
//! Socketioxide is a socket.io server implementation that works as a tower layer/service.
//! It integrates nicely with the rest of the [`tower`](https://docs.rs/tower/latest/tower/)/[`tokio`]/[`hyper`](https://docs.rs/hyper/latest/hyper/) ecosystem.
//!
//! ## Table of contents
//! * [Features](#features)
//! * [Compatibility](#compatibility)
//! * [Usage](#usage)
//! * [Initialisation](#initialisation)
//! * [Handlers](#handlers)
//! * [Extractors](#extractors)
//! * [Events](#events)
//! * [Middlewares](#middlewares)
//! * [Emiting data](#emiting-data)
//! * [Acknowledgements](#acknowledgements)
//! * [State management](#state-management)
//! * [Adapters](#adapters)
//! * [Parsers](#parsers)
//! * [Feature flags](#feature-flags)
//!
//! ## Features
//! * Easy to use flexible axum-like API
//! * Fully compatible with the official [socket.io client](https://socket.io/docs/v4/client-api/)
//! * Support for the previous version of the protocol (v4).
//! * State Management
//! * Namespaces
//! * Rooms
//! * Acknowledgements
//! * Common and Msgpack parsers
//! * Polling & Websocket transports
//!
//! ## Compatibility
//! Because it works as a tower [`layer`](tower_layer::Layer)/[`service`](tower_service::Service) or an hyper [`service`](hyper::service::Service)
//! you can use it with any http server frameworks that works with tower/hyper:
//! * [Axum](https://docs.rs/axum/latest/axum/)
//! * [Warp](https://docs.rs/warp/latest/warp/) (Not supported with socketioxide >= 0.9.0 as long as warp doesn't migrate to hyper v1)
//! * [Hyper](https://docs.rs/hyper/latest/hyper/)
//! * [Salvo](https://docs.rs/salvo/latest/salvo/)
//!
//! Check the [examples](http://github.com/totodore/socketioxide/tree/main/examples) for
//! more details on frameworks integration.
//!
//! ## Usage
//! The API tries to mimic the equivalent JS API as much as possible.
//! The main difference is that the default namespace `/` is not created automatically,
//! you need to create it manually.
//!
//! #### Basic example with axum:
//! ```no_run
//! use axum::routing::get;
//! use socketioxide::{
//! extract::SocketRef,
//! SocketIo,
//! };
//! #[tokio::main]
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let (layer, io) = SocketIo::new_layer();
//!
//! // Register a handler for the default namespace
//! io.ns("/", async |s: SocketRef| {
//! // For each "message" event received, send a "message-back" event with the "Hello World!" event
//! s.on("message", async |s: SocketRef| {
//! s.emit("message-back", "Hello World!").ok();
//! });
//! });
//!
//! let app = axum::Router::new()
//! .route("/", get(async || "Hello, World!"))
//! .layer(layer);
//!
//! let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
//! axum::serve(listener, app).await.unwrap();
//!
//! Ok(())
//! }
//! ```
//! ## Initialisation
//! The [`SocketIo`] struct is the main entry point of the library. It is used to create
//! a [`Layer`](tower_layer::Layer) or a [`Service`](tower_service::Service).
//! Later it can be used as the equivalent of the `io` object in the JS API.
//!
//! When creating your [`SocketIo`] instance, you can use the builder pattern to configure it with the [`SocketIoBuilder`] struct.
//! * See the [`SocketIoBuilder`] doc for more details on the available configuration options.
//! * See the [`layer`] module doc for more details on layers.
//! * See the [`service`] module doc for more details on services.
//!
//! #### Tower layer example with custom configuration:
//! ```
//! use socketioxide::SocketIo;
//! let (layer, io) = SocketIo::builder()
//! .max_payload(10_000_000) // Max HTTP payload size of 10M
//! .max_buffer_size(10_000) // Max number of packets in the buffer
//! .build_layer();
//! ```
//!
//! #### Tower _standalone_ service example with default configuration:
//! ```
//! use socketioxide::SocketIo;
//! let (svc, io) = SocketIo::new_svc();
//! ```
//!
//! ## Handlers
//! Handlers are async functions or clonable async closures that are given to the `io.ns`, the `socket.on` and the `socket.on_disconnect` fns.
//! They can take from 0 to 16 arguments that implements the [`FromConnectParts`]
//! trait for the [`ConnectHandler`], the [`FromMessageParts`] for
//! the [`MessageHandler`] and the [`FromDisconnectParts`] for the [`DisconnectHandler`].
//! They are greatly inspired by the axum handlers.
//!
//! A new task will be spawned for each incoming connection/message so it doesn't block the event management task.
//!
//! * Check the [`handler::connect`] module doc for more details on the connect handler and connect middlewares.
//! * Check the [`handler::message`] module doc for more details on the message handler.
//! * Check the [`handler::disconnect`] module doc for more details on the disconnect handler.
//! * Check the [`extract`] module doc for more details on the extractors.
//!
//! ## Extractors
//! Handlers params are called extractors and are used to extract data from the incoming connection/message. They are inspired by the axum extractors.
//! An extractor is a struct that implements the [`FromConnectParts`] trait for the [`ConnectHandler`]
//! the [`FromMessageParts`] for the [`MessageHandler`] and the
//! [`FromDisconnectParts`] for the [`DisconnectHandler`].
//!
//! They can be used to extract data from the context of the handler and get specific params. Here are some examples of extractors:
//! * [`Data`](extract::Data): extracts and deserialize from any receieved data, if a deserialization error occurs the handler won't be called:
//! - for [`ConnectHandler`]: extracts and deserialize from the incoming auth data
//! - for [`ConnectMiddleware`](handler::ConnectMiddleware): extract and deserialize from the incoming auth data.
//! In case of error, the middleware chain stops and a `connect_error` event is sent.
//! - for [`MessageHandler`]: extracts and deserialize from the incoming message data
//! * [`TryData`](extract::TryData): extracts and deserialize from the any received data but with a `Result` type in case of error:
//! - for [`ConnectHandler`] and [`ConnectMiddleware`](handler::ConnectMiddleware): extracts and deserialize from the incoming auth data
//! - for [`MessageHandler`]: extracts and deserialize from the incoming message data
//! * [`SocketRef`]: extracts a reference to the [`Socket`](socket::Socket)
//! * [`AckSender`]: Can be used to send an ack response to the current message event
//! * [`ProtocolVersion`]: extracts the protocol version of the socket
//! * [`TransportType`]: extracts the transport type of the socket
//! * [`DisconnectReason`](crate::socket::DisconnectReason): extracts the reason of the disconnection
//! * [`State`]: extracts a [`Clone`] of a state previously set with [`SocketIoBuilder::with_state`](crate::io::SocketIoBuilder).
//! * [`Extension`](extract::Extension): extracts a clone of the corresponding socket extension
//! * [`MaybeExtension`](extract::MaybeExtension): extracts a clone of the corresponding socket extension if it exists
//! * [`HttpExtension`](extract::HttpExtension): extracts a clone of the http request extension
//! * [`MaybeHttpExtension`](extract::MaybeHttpExtension): extracts a clone of the http request extension if it exists
//! * [`SocketIo`]: extracts a reference to the [`SocketIo`] handle
//!
//! ### Extractor order
//! Extractors are run in the order of their declaration in the handler signature.
//! If an extractor returns an error, the handler won't be called and a `tracing::error!` call
//! will be emitted if the `tracing` feature is enabled.
//!
//! For the [`MessageHandler`], some extractors require to _consume_ the event and therefore
//! only implement the [`FromMessage`](handler::FromMessage) trait.
//!
//! Note that any extractors that implement the [`FromMessageParts`] also implement by default
//! the [`FromMessage`](handler::FromMessage) trait.
//!
//! ## Events
//! There are three types of events:
//! * The connect event is emitted when a new connection is established. It can be handled with the
//! [`ConnectHandler`] and the `io.ns` method.
//! * The message event is emitted when a new message is received. It can be handled with the
//! [`MessageHandler`] and the `socket.on` method.
//! * The disconnect event is emitted when a socket is closed. It can be handled with the
//! [`DisconnectHandler`] and the `socket.on_disconnect` method.
//!
//! Only one handler can exist for an event so registering a new handler for an event will replace the previous one.
//!
//! ## Middlewares
//! When providing a [`ConnectHandler`] for a namespace you can add any number of
//! [`ConnectMiddleware`](handler::ConnectMiddleware) in front of it. It is useful to add authentication or logging middlewares.
//!
//! A middleware *must* return a `Result<(), E> where E: Display`.
//! * If the result is `Ok(())`, the next middleware is called or if there is no more middleware,
//! the socket is connected and the [`ConnectHandler`] is called.
//! * If the result is an error, the namespace connection will be refused and the error will be returned with a
//! [`connect_error` event and a `message`](https://socket.io/docs/v4/middlewares/#handling-middleware-error) field with the error.
//!
//! <div class="warning">
//! Because the socket is not yet connected to the namespace,
//! you can't send messages to it from the middleware.
//! </div>
//!
//! See the [`handler::connect`](handler::connect#middleware) module doc for more details
//! on middlewares and examples.
//!
//! ## [Emiting data](#emiting-data)
//! Data can be emitted to a socket with the [`Socket::emit`](socket::Socket) method. It takes an event name and a data argument.
//! The data argument can be any type that implements the [`serde::Serialize`] trait.
//!
//! You can emit from the [`SocketIo`] handle or the [`SocketRef`].
//! The difference is that you can move the [`io`] handle everywhere because it is a cheaply cloneable struct.
//! The [`SocketRef`] is a reference to the socket and you should avoid storing it in your own code (e.g. in HashMap/Vec).
//! If you do so, you will have to remove the socket reference when the socket is disconnected to avoid memory leaks.
//!
//! Moreover the [`io`] handle can emit to any namespace while the [`SocketRef`] can only emit to the namespace of the socket.
//!
//! When using any `emit` fn, if you provide tuple-like data (tuple, arrays), it will be considered as multiple emit arguments.
//! If you send a vector it will be considered as a single argument.
//!
//! #### Emitting binary data
//! To emit binary data, you must use a data type that implements [`Serialize`] as binary data.
//! Currently if you use `Vec<u8>` it will be considered as a number sequence and not binary data.
//! To counter that you must either use a special type like [`Bytes`] or use the [`serde_bytes`] crate.
//! If you want to emit generic binary data, use [`rmpv::Value`] rather than [`serde_json::Value`] otherwise
//! the binary data will also be serialized as a number sequence.
//!
//! [`Serialize`]: serde::Serialize
//! [`serde_bytes`]: https://docs.rs/serde_bytes
//! [`Bytes`]: bytes::Bytes
//! [`rmpv::Value`]: https://docs.rs/rmpv
//! [`serde_json::Value`]: https://docs.rs/serde_json/latest/serde_json/value
//!
//! #### Emit errors
//! If the data can't be serialized, a [`ParserError`] will be returned.
//!
//! If the socket is disconnected or the internal channel is full, a [`SendError`] will be returned.
//! Moreover, a tracing log will be emitted if the `tracing` feature is enabled.
//!
//! #### Emitting with operators
//! To configure the emit, you can chain [`Operators`](operators) methods to the emit call. With that you can easily configure the following options:
//! * rooms: emit, join, leave to specific rooms
//! * namespace: emit to a specific namespace (only from the [`SocketIo`] handle)
//! * timeout: set a custom timeout when waiting for an ack
//! * binary: emit a binary payload with the message
//! * local: broadcast only to the current node (in case of a cluster)
//!
//! Check the [`operators`] module doc for more details on operators.
//!
//! ## Acknowledgements
//! You can ensure that a message has been received by the client/server with acknowledgements.
//!
//! #### Server acknowledgements
//! They are implemented with the [`AckSender`] extractor.
//! You can send an ack response with an optional binary payload with the [`AckSender::send`] method.
//! If the client doesn't send an ack id to respond to, the [`AckSender::send`] method will do nothing.
//!
//! #### Client acknowledgements
//! If you want to emit/broadcast a message and await for a/many client(s) acknowledgment(s) you can use:
//! * [`SocketRef::emit_with_ack`] for a single client
//! * [`BroadcastOperators::emit_with_ack`] for broadcasting or [emit configuration](#emiting-data).
//! * [`SocketIo::emit_with_ack`] for broadcasting to an entire namespace.
//!
//! [`SocketRef::emit_with_ack`]: crate::extract::SocketRef#method.emit_with_ack
//! [`BroadcastOperators::emit_with_ack`]: crate::operators::BroadcastOperators#method.emit_with_ack
//! [`SocketIo::emit_with_ack`]: SocketIo#method.emit_with_ack
//! [`AckStream`]: crate::ack::AckStream
//! [`ParserError`]: crate::parser::ParserError
//!
//! ## [State management](#state-management)
//! There are two ways to manage the state of the server:
//!
//! #### Per socket state
//! You can enable the `extensions` feature and use the [`extensions`](socket::Socket::extensions) field on any socket to manage
//! the state of each socket. It is backed by a [`RwLock<HashMap>>`](std::sync::RwLock) so you can safely access it
//! from multiple threads. However, the value must be [`Clone`] and `'static`.
//! When calling get, or using the [`Extension`](extract::Extension)/[`MaybeExtension`](extract::MaybeExtension) extractor,
//! the value will always be cloned.
//! See the [`extensions`] module doc for more details.
//!
//! #### Global state
//! You can enable the `state` feature and use [`SocketIoBuilder::with_state`](SocketIoBuilder) method to set
//! multiple global states for the server. You can then access them from any handler with the [`State`] extractor.
//!
//! The state is stored in the [`SocketIo`] handle and is shared between all the sockets. The only limitation is that all the
//! provided state types must be clonable.
//! Therefore it is recommended to use the [`Arc`](std::sync::Arc) type to share the state between the handlers.
//!
//! You can then use the [`State`] extractor to access the state in the handlers.
//!
//! ## Adapters
//! This library is designed to support clustering through the use of adapters.
//! Adapters enable broadcasting messages and managing socket room memberships across nodes
//! without requiring changes to your code. The [`Adapter`] trait abstracts the underlying system,
//! making it easy to integrate with different implementations.
//!
//! Adapters typically interact with third-party systems like Redis, Postgres, Kafka, etc.,
//! to facilitate message exchange between nodes.
//!
//! The default adapter is the [`LocalAdapter`], a simple in-memory implementation. If you intend
//! to use a different adapter, ensure that extractors are either generic over the adapter type
//! or explicitly specify the adapter type for each extractor that requires it.
//!
//! #### Write this:
//! ```
//! # use socketioxide::{SocketIo, adapter::Adapter, extract::SocketRef};
//! async fn my_handler<A: Adapter>(s: SocketRef<A>, io: SocketIo<A>) { }
//! let (layer, io) = SocketIo::new_layer();
//! io.ns("/", my_handler);
//! ```
//! #### Instead of that:
//! ```
//! # use socketioxide::{SocketIo, adapter::Adapter, extract::SocketRef};
//! async fn my_handler(s: SocketRef, io: SocketIo) { }
//! let (layer, io) = SocketIo::new_layer();
//! io.ns("/", my_handler);
//! ```
//!
//! Refer to the [README](https://github.com/totodore/socketioxide) for a list of available adapters and
//! the [examples](https://github.com/totodore/socketioxide/tree/main/examples) for detailed usage guidance.
//! You can also consult specific adapter crate documentation for more information.
//!
//! ## Parsers
//! This library uses the socket.io common parser which is the default for all the socket.io implementations.
//! Socketioxide also provided a msgpack parser. It is faster and more efficient than the default parser especially
//! for binary data or payloads with a lot of numbers.
//! To enable it, you must enable the [`msgpack`](#feature-flags) feature and then use the
//! [`with_parser`](SocketIoBuilder#method.with_parser) fn to set the parser to [`ParserConfig::msgpack`](ParserConfig#method.msgpack).
//!
//! ## [Feature flags](#feature-flags)
//! * `v4`: enable support for the socket.io protocol v4
//! * `tracing`: enable logging with [`tracing`] calls
//! * `extensions`: enable per-socket state with the [`extensions`] module
//! * `state`: enable global state management
//! * `msgpack`: enable msgpack custom parser
//!
//! [`Adapter`]: adapter::Adapter
//! [`LocalAdapter`]: adapter::LocalAdapter
//! [`SocketRef`]: extract::SocketRef
//! [`State`]: extract::State
//! [`Data`]: extract::Data
//! [`TryData`]: extract::TryData
//! [`ConnectHandler`]: handler::ConnectHandler
//! [`Ì€ConnectMiddleware`]: handler::ConnectMiddleware
//! [`MessageHandler`]: handler::MessageHandler
//! [`DisconnectHandler`]: handler::DisconnectHandler
//! [`FromMessage`]: handler::FromMessage
//! [`FromMessageParts`]: handler::FromMessageParts
//! [`FromDisconnectParts`]: handler::FromDisconnectParts
//! [`FromConnectParts`]: handler::FromConnectParts
//! [`AckSender`]: extract::AckSender
//! [`AckSender::send`]: extract::AckSender#method.send
//! [`io`]: SocketIo
pub use TransportType;
pub use ;
pub use ;
/// Socket.IO protocol version.
/// It is accessible with the [`Socket::protocol`](socket::Socket) method or as an extractor
///
/// **Note**: The socket.io protocol version does not correspond to the engine.io protocol version.