slozhn_session/lib.rs
1//! Session layer (spec §8): transparent stream recovery across disconnects.
2//! Foundations: TCP seq/ack + MQTT QoS1 + SignalR buffered reconnect.
3//!
4//! Layering: the session transport owns the Hello handshake and physical
5//! reconnects; the frame connection is brought up via `bind_pre_negotiated`
6//! and lives on top of the changing physical connections, noticing nothing.
7//!
8//! Known limitation: Ping/Pong is outside the session — a ping lost in a
9//! disconnect hangs; ping is liveness of one physical connection, not the session.
10
11pub mod client;
12pub mod core;
13#[cfg(not(target_arch = "wasm32"))]
14pub mod server;
15
16use std::time::Duration;
17
18#[derive(Clone)]
19pub struct SessionConfig {
20 /// Max bytes of unacknowledged frames; overflow kills the session.
21 pub replay_buffer_bytes: usize,
22 /// Ack after this many received seq frames…
23 pub ack_every: u32,
24 /// …or this long after the first unacknowledged one.
25 pub ack_delay: Duration,
26 /// First reconnect backoff (jittered, doubles per attempt).
27 pub initial_backoff: Duration,
28 /// Backoff ceiling.
29 pub max_backoff: Duration,
30 /// Physical-transport keepalive: the client pings while Active and treats
31 /// a missing Pong as a break (goes into reconnect); the server treats
32 /// prolonged silence as a break (detaches and waits for resume).
33 /// `None` disables liveness detection.
34 pub keepalive_interval: Option<Duration>,
35 /// How long the client waits for Pong before reconnecting.
36 pub keepalive_timeout: Duration,
37}
38
39impl Default for SessionConfig {
40 fn default() -> Self {
41 Self {
42 replay_buffer_bytes: 1024 * 1024,
43 ack_every: 16,
44 ack_delay: Duration::from_millis(250),
45 initial_backoff: Duration::from_millis(100),
46 max_backoff: Duration::from_secs(5),
47 keepalive_interval: Some(Duration::from_secs(30)),
48 keepalive_timeout: Duration::from_secs(10),
49 }
50 }
51}
52
53#[derive(Debug, thiserror::Error)]
54#[non_exhaustive]
55pub enum SessionError {
56 #[error("replay buffer overflow — session killed (spec §8: no silent drop)")]
57 BufferOverflow,
58 #[error("resume rejected by peer")]
59 ResumeRejected,
60 #[error("handshake failed: {0}")]
61 Handshake(String),
62}