1#![allow(dead_code)]
49#![allow(clippy::missing_safety_doc)]
50
51#[cfg(feature = "mimalloc")]
53#[global_allocator]
54static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
55
56pub mod cork;
57pub mod error;
58pub mod frame;
59pub mod handshake;
60pub mod mask;
61pub mod protocol;
62pub mod pubsub;
63pub mod queue;
64pub mod simd;
65pub mod stream;
66pub mod utf8;
67
68#[cfg(any(feature = "http2", feature = "http3"))]
70pub mod extended_connect;
71pub mod transport;
72
73pub mod server;
74
75pub mod client;
76
77#[cfg(any(feature = "http2", feature = "http3"))]
78pub mod multiplex;
79
80#[cfg(feature = "permessage-deflate")]
81pub mod deflate;
82
83#[cfg(feature = "permessage-deflate")]
84pub mod compression;
85
86#[cfg(feature = "axum-integration")]
87pub mod axum_integration;
88
89#[cfg(feature = "http2")]
90pub mod http2;
91
92#[cfg(feature = "http3")]
93pub mod http3;
94
95#[cfg(all(feature = "io-uring", target_os = "linux"))]
96pub mod io_uring;
97
98pub use error::{Error, Result};
100pub use frame::{Frame, OpCode};
101pub use handshake::HandshakeResult;
102pub use protocol::{Message, Role};
103pub use pubsub::{PubSub, PubSubState, PublishResult, SubscriberId};
104pub use stream::{SplitReader, SplitWriter, Stream, WebSocketStream};
105
106#[cfg(feature = "permessage-deflate")]
107pub use stream::CompressedWebSocketStream;
108
109pub use transport::{Http1, Http2, Http3, Transport};
111
112#[cfg(any(feature = "http2", feature = "http3"))]
114pub use extended_connect::{
115 ExtendedConnectConfig, ExtendedConnectRequest, ExtendedConnectResponse,
116};
117#[cfg(any(feature = "http2", feature = "http3"))]
118pub use extended_connect::{build_extended_connect_error, build_extended_connect_response};
119
120#[cfg(any(feature = "http2", feature = "http3"))]
122pub use server::WebSocketServer;
123
124#[cfg(any(feature = "http2", feature = "http3"))]
125pub use client::WebSocketClient;
126
127#[cfg(any(feature = "http2", feature = "http3"))]
128pub use multiplex::MultiplexedConnection;
129
130#[cfg(feature = "permessage-deflate")]
133pub use compression::{CompressionContext, SharedCompressorPool, global_shared_pool};
134#[cfg(feature = "permessage-deflate")]
135pub use deflate::{DeflateConfig, DeflateContext};
136#[cfg(feature = "permessage-deflate")]
137pub use protocol::CompressedProtocol;
138
139pub const CACHE_LINE_SIZE: usize = 64;
141
142pub const CORK_BUFFER_SIZE: usize = 16 * 1024;
144
145pub const RECV_BUFFER_SIZE: usize = 64 * 1024;
147
148pub const MAX_FRAME_HEADER_SIZE: usize = 14;
150
151pub const SMALL_MESSAGE_THRESHOLD: usize = 125;
153
154pub const MEDIUM_MESSAGE_THRESHOLD: usize = 65535;
156
157pub const WS_GUID: &str = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
159
160#[cfg(feature = "http2")]
166#[derive(Debug, Clone)]
167pub struct Http2Config {
168 pub initial_stream_window_size: u32,
170 pub initial_connection_window_size: u32,
172 pub max_concurrent_streams: u32,
174 pub enable_connect_protocol: bool,
176}
177
178#[cfg(feature = "http2")]
179impl Default for Http2Config {
180 fn default() -> Self {
181 Self {
182 initial_stream_window_size: 1024 * 1024, initial_connection_window_size: 2 * 1024 * 1024, max_concurrent_streams: 100,
185 enable_connect_protocol: true,
186 }
187 }
188}
189
190#[cfg(feature = "http3")]
192#[derive(Debug, Clone)]
193pub struct Http3Config {
194 pub max_idle_timeout_ms: u64,
196 pub initial_stream_window_size: u64,
198 pub enable_0rtt: bool,
200 pub enable_connect_protocol: bool,
202 pub max_udp_payload_size: u16,
204}
205
206#[cfg(feature = "http3")]
207impl Default for Http3Config {
208 fn default() -> Self {
209 Self {
210 max_idle_timeout_ms: 30_000,
211 initial_stream_window_size: 1024 * 1024, enable_0rtt: false,
213 enable_connect_protocol: true,
214 max_udp_payload_size: 1350,
215 }
216 }
217}
218
219#[cfg(all(feature = "io-uring", target_os = "linux"))]
221#[derive(Debug, Clone)]
222pub struct IoUringConfig {
223 pub registered_buffer_count: usize,
225 pub registered_buffer_size: usize,
227 pub sqpoll: bool,
229 pub sq_entries: u32,
231}
232
233#[cfg(all(feature = "io-uring", target_os = "linux"))]
234impl Default for IoUringConfig {
235 fn default() -> Self {
236 Self {
237 registered_buffer_count: 64,
238 registered_buffer_size: 64 * 1024, sqpoll: false,
240 sq_entries: 256,
241 }
242 }
243}
244
245#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
272pub enum Compression {
273 #[default]
275 Disabled,
276 Dedicated,
278 Shared,
280 Window256B,
282 Window1KB,
284 Window2KB,
286 Window4KB,
288 Window8KB,
290 Window16KB,
292 Window32KB,
294}
295
296impl Compression {
297 #[inline]
299 pub fn is_enabled(&self) -> bool {
300 !matches!(self, Compression::Disabled)
301 }
302
303 #[inline]
305 pub fn is_shared(&self) -> bool {
306 matches!(self, Compression::Shared)
307 }
308
309 #[inline]
311 pub fn is_dedicated(&self) -> bool {
312 !matches!(self, Compression::Disabled | Compression::Shared)
313 }
314
315 #[inline]
319 pub fn window_bits(&self) -> u8 {
320 match self {
321 Compression::Disabled => 0,
322 Compression::Window256B => 8,
323 Compression::Window1KB => 10,
324 Compression::Window2KB => 11,
325 Compression::Window4KB => 12,
326 Compression::Window8KB => 13,
327 Compression::Window16KB => 14,
328 Compression::Dedicated | Compression::Shared | Compression::Window32KB => 15,
329 }
330 }
331
332 #[inline]
337 pub fn compression_threshold(&self) -> usize {
338 match self {
339 Compression::Disabled => usize::MAX,
340 Compression::Window256B => 128,
341 Compression::Window1KB => 64,
342 Compression::Window2KB => 48,
343 Compression::Window4KB => 40,
344 Compression::Window8KB => 32,
345 Compression::Window16KB | Compression::Window32KB => 24,
346 Compression::Dedicated | Compression::Shared => 16,
347 }
348 }
349
350 #[inline]
357 pub fn context_takeover(&self) -> bool {
358 !matches!(
359 self,
360 Compression::Disabled
361 | Compression::Shared
362 | Compression::Window256B
363 | Compression::Window1KB
364 | Compression::Window2KB
365 )
366 }
367
368 #[cfg(feature = "permessage-deflate")]
370 pub fn to_deflate_config(&self) -> Option<crate::deflate::DeflateConfig> {
371 if !self.is_enabled() {
372 return None;
373 }
374
375 let window_bits = self.window_bits();
376 let no_context_takeover = !self.context_takeover();
377
378 Some(crate::deflate::DeflateConfig {
379 server_max_window_bits: window_bits,
380 client_max_window_bits: window_bits,
381 server_no_context_takeover: no_context_takeover,
382 client_no_context_takeover: no_context_takeover,
383 compression_level: match self {
384 Compression::Window256B | Compression::Window1KB => 1, Compression::Window2KB | Compression::Window4KB => 3, Compression::Window8KB | Compression::Window16KB => 5, _ => 6, },
389 compression_threshold: self.compression_threshold(),
390 })
391 }
392}
393
394#[derive(Debug, Clone)]
411pub struct Config {
412 pub max_message_size: usize,
415 pub max_frame_size: usize,
417 pub write_buffer_size: usize,
419 pub compression: Compression,
421 pub idle_timeout: u32,
424 pub max_backpressure: usize,
427 pub auto_ping: bool,
429 pub ping_interval: u32,
431 #[cfg(feature = "permessage-deflate")]
433 pub deflate: Option<crate::deflate::DeflateConfig>,
434
435 #[cfg(feature = "http2")]
438 pub http2: Http2Config,
439 #[cfg(feature = "http3")]
441 pub http3: Http3Config,
442 #[cfg(all(feature = "io-uring", target_os = "linux"))]
444 pub io_uring: IoUringConfig,
445}
446
447impl Default for Config {
448 fn default() -> Self {
449 Self {
450 max_message_size: 64 * 1024 * 1024,
451 max_frame_size: 16 * 1024 * 1024,
452 write_buffer_size: CORK_BUFFER_SIZE,
453 compression: Compression::Disabled,
454 idle_timeout: 120,
455 max_backpressure: 1024 * 1024,
456 auto_ping: true,
457 ping_interval: 30,
458 #[cfg(feature = "permessage-deflate")]
459 deflate: None,
460 #[cfg(feature = "http2")]
461 http2: Http2Config::default(),
462 #[cfg(feature = "http3")]
463 http3: Http3Config::default(),
464 #[cfg(all(feature = "io-uring", target_os = "linux"))]
465 io_uring: IoUringConfig::default(),
466 }
467 }
468}
469
470impl Config {
471 pub fn builder() -> ConfigBuilder {
473 ConfigBuilder::new()
474 }
475
476 pub fn uws_defaults() -> Self {
478 Self {
479 max_message_size: 16 * 1024,
480 max_frame_size: 16 * 1024,
481 write_buffer_size: CORK_BUFFER_SIZE,
482 compression: Compression::Shared,
483 idle_timeout: 10,
484 max_backpressure: 1024 * 1024,
485 auto_ping: true,
486 ping_interval: 30,
487 #[cfg(feature = "permessage-deflate")]
488 deflate: None,
489 #[cfg(feature = "http2")]
490 http2: Http2Config::default(),
491 #[cfg(feature = "http3")]
492 http3: Http3Config::default(),
493 #[cfg(all(feature = "io-uring", target_os = "linux"))]
494 io_uring: IoUringConfig::default(),
495 }
496 }
497}
498
499#[derive(Debug, Clone)]
501pub struct ConfigBuilder {
502 config: Config,
503}
504
505impl ConfigBuilder {
506 pub fn new() -> Self {
508 Self {
509 config: Config::default(),
510 }
511 }
512
513 pub fn compression(mut self, compression: Compression) -> Self {
515 self.config.compression = compression;
516 self
517 }
518
519 pub fn max_payload_length(mut self, size: usize) -> Self {
521 self.config.max_message_size = size;
522 self.config.max_frame_size = size;
523 self
524 }
525
526 pub fn max_message_size(mut self, size: usize) -> Self {
528 self.config.max_message_size = size;
529 self
530 }
531
532 pub fn max_frame_size(mut self, size: usize) -> Self {
534 self.config.max_frame_size = size;
535 self
536 }
537
538 pub fn idle_timeout(mut self, seconds: u32) -> Self {
541 self.config.idle_timeout = seconds;
542 self
543 }
544
545 pub fn max_backpressure(mut self, bytes: usize) -> Self {
547 self.config.max_backpressure = bytes;
548 self
549 }
550
551 pub fn write_buffer_size(mut self, size: usize) -> Self {
553 self.config.write_buffer_size = size;
554 self
555 }
556
557 pub fn auto_ping(mut self, enabled: bool) -> Self {
559 self.config.auto_ping = enabled;
560 self
561 }
562
563 pub fn ping_interval(mut self, seconds: u32) -> Self {
565 self.config.ping_interval = seconds;
566 self
567 }
568
569 #[cfg(feature = "permessage-deflate")]
575 pub fn enable_deflate(mut self) -> Self {
576 self.config.deflate = Some(crate::deflate::DeflateConfig::default());
577 self
578 }
579
580 #[cfg(feature = "permessage-deflate")]
582 pub fn deflate_config(mut self, config: crate::deflate::DeflateConfig) -> Self {
583 self.config.deflate = Some(config);
584 self
585 }
586
587 #[cfg(feature = "http2")]
593 pub fn http2_stream_window_size(mut self, size: u32) -> Self {
594 self.config.http2.initial_stream_window_size = size;
595 self
596 }
597
598 #[cfg(feature = "http2")]
600 pub fn http2_connection_window_size(mut self, size: u32) -> Self {
601 self.config.http2.initial_connection_window_size = size;
602 self
603 }
604
605 #[cfg(feature = "http2")]
607 pub fn http2_max_streams(mut self, count: u32) -> Self {
608 self.config.http2.max_concurrent_streams = count;
609 self
610 }
611
612 #[cfg(feature = "http2")]
614 pub fn http2_enable_connect_protocol(mut self, enabled: bool) -> Self {
615 self.config.http2.enable_connect_protocol = enabled;
616 self
617 }
618
619 #[cfg(feature = "http3")]
625 pub fn http3_idle_timeout(mut self, ms: u64) -> Self {
626 self.config.http3.max_idle_timeout_ms = ms;
627 self
628 }
629
630 #[cfg(feature = "http3")]
632 pub fn http3_stream_window_size(mut self, size: u64) -> Self {
633 self.config.http3.initial_stream_window_size = size;
634 self
635 }
636
637 #[cfg(feature = "http3")]
639 pub fn http3_enable_0rtt(mut self, enabled: bool) -> Self {
640 self.config.http3.enable_0rtt = enabled;
641 self
642 }
643
644 #[cfg(feature = "http3")]
646 pub fn http3_enable_connect_protocol(mut self, enabled: bool) -> Self {
647 self.config.http3.enable_connect_protocol = enabled;
648 self
649 }
650
651 #[cfg(feature = "http3")]
653 pub fn http3_max_udp_payload_size(mut self, size: u16) -> Self {
654 self.config.http3.max_udp_payload_size = size;
655 self
656 }
657
658 #[cfg(all(feature = "io-uring", target_os = "linux"))]
664 pub fn io_uring_buffers(mut self, count: usize, size: usize) -> Self {
665 self.config.io_uring.registered_buffer_count = count;
666 self.config.io_uring.registered_buffer_size = size;
667 self
668 }
669
670 #[cfg(all(feature = "io-uring", target_os = "linux"))]
672 pub fn io_uring_sqpoll(mut self, enabled: bool) -> Self {
673 self.config.io_uring.sqpoll = enabled;
674 self
675 }
676
677 #[cfg(all(feature = "io-uring", target_os = "linux"))]
679 pub fn io_uring_sq_entries(mut self, entries: u32) -> Self {
680 self.config.io_uring.sq_entries = entries;
681 self
682 }
683
684 pub fn build(self) -> Config {
686 self.config
687 }
688}
689
690impl Default for ConfigBuilder {
691 fn default() -> Self {
692 Self::new()
693 }
694}
695
696pub mod prelude {
698 pub use crate::Config;
699 pub use crate::error::{Error, Result};
700 pub use crate::frame::{Frame, OpCode};
701 pub use crate::protocol::{Message, Role};
702 pub use crate::pubsub::{PubSub, PublishResult, SubscriberId};
703 pub use crate::stream::WebSocketStream;
704 pub use crate::transport::{Http1, Http2, Http3, Transport};
705
706 #[cfg(any(feature = "http2", feature = "http3"))]
707 pub use crate::extended_connect::ExtendedConnectRequest;
708
709 #[cfg(any(feature = "http2", feature = "http3"))]
710 pub use crate::server::WebSocketServer;
711
712 #[cfg(any(feature = "http2", feature = "http3"))]
713 pub use crate::client::WebSocketClient;
714
715 #[cfg(any(feature = "http2", feature = "http3"))]
716 pub use crate::multiplex::MultiplexedConnection;
717}