Files
mux-rs/src/session.rs
T
swaits 903729ccbe feat: upgrade to donglora-client 0.2, fix org URLs, publish-ready
- Upgrade donglora-client from 0.1 (monorepo path dep) to 0.2 (crates.io)
- Import wire-level constants from donglora_client::protocol::*
- Fix repository URL to github.com/donglora/mux-rs
- Add homepage, rust-version, exclude to Cargo.toml
- Fix README (remove monorepo paths, add install instructions)
- Allow clippy unwrap in test module
2026-04-07 16:14:50 -06:00

54 lines
1.9 KiB
Rust

//! Per-client session state and bounded send queue.
//!
//! Each connected client gets a [`ClientSession`] that tracks its ID,
//! RX interest flag, and a bounded channel for outgoing COBS frames.
use std::sync::atomic::{AtomicU64, Ordering};
use tokio::sync::mpsc;
use tracing::warn;
/// Bounded send queue capacity per client.
const SEND_QUEUE_CAP: usize = 256;
/// Global client ID counter.
static NEXT_CLIENT_ID: AtomicU64 = AtomicU64::new(0);
/// Per-client state tracked by the mux daemon.
pub struct ClientSession {
/// Unique client identifier.
pub id: u64,
/// Whether this client has called StartRx.
pub rx_interested: bool,
/// Sender half of the bounded channel to the client's writer task.
tx: mpsc::Sender<Vec<u8>>,
}
impl ClientSession {
/// Create a new session. Returns the session and the receiver half
/// for the client's writer task to drain.
pub fn new() -> (Self, mpsc::Receiver<Vec<u8>>) {
let id = NEXT_CLIENT_ID.fetch_add(1, Ordering::Relaxed);
let (tx, rx) = mpsc::channel(SEND_QUEUE_CAP);
let session = Self { id, rx_interested: false, tx };
(session, rx)
}
/// Human-readable label for logging.
pub fn label(&self) -> String {
format!("client-{}", self.id)
}
/// Best-effort enqueue of a COBS frame for sending to this client.
///
/// If the channel is full (slow client), the frame is dropped with a warning.
/// This prevents backpressure from one slow client blocking the entire mux.
pub fn enqueue(&self, frame: Vec<u8>) {
if let Err(mpsc::error::TrySendError::Full(_)) = self.tx.try_send(frame) {
warn!("{}: send queue full, dropping frame", self.label());
}
// Closed channel (client disconnected) is silently ignored — the session
// will be cleaned up when the client handler task exits.
}
}