Skip to main content

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}