docs: document client public API

This commit is contained in:
Nils Andreas Svee committed 2026-05-18 01:34:04 +07:00
1 parent 8fd0b803e9
commit 01c10e2e0d
8 files changed
+395 -1

No files matched your search

@@ -3,20 +3,31 @@ use std::sync::{
Arc,
};
/// Cloneable cooperative cancellation flag.
///
/// Managed sessions use this internally to ask their worker loop to stop. It is
/// exported for callers that want the same simple cancellation primitive in
/// code built around `irtt-client`.
#[derive(Debug, Clone, Default)]
pub struct CancellationToken {
cancelled: Arc<AtomicBool>,
}
impl CancellationToken {
/// Create a token in the non-cancelled state.
pub fn new() -> Self {
Self::default()
}
/// Mark the token as cancelled.
///
/// Cancellation is idempotent and is visible through all clones of the
/// token.
pub fn cancel(&self) {
self.cancelled.store(true, Ordering::SeqCst);
}
/// Return whether cancellation has been requested.
#[must_use]
pub fn is_cancelled(&self) -> bool {
self.cancelled.load(Ordering::SeqCst)
+24
View File
@@ -8,9 +8,17 @@ use std::{
use crate::{error::EventSubscriptionError, event::ClientEvent};
/// Configuration for one managed event subscriber.
///
/// Each subscriber has an independent bounded queue. The queue bounds memory
/// growth when event production is faster than that subscriber's consumer.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SubscriberConfig {
/// Maximum number of events buffered for this subscriber.
///
/// Must be greater than zero.
pub capacity: usize,
/// Policy applied when publishing to a full subscriber queue.
pub overflow: SubscriberOverflow,
}
@@ -37,6 +45,11 @@ pub enum SubscriberOverflow {
Disconnect,
}
/// Publish/subscribe fan-out for [`ClientEvent`] values.
///
/// `EventHub` is used by managed sessions internally and is also exported for
/// callers that want the same bounded subscription behavior around their own
/// event producer. Publishing clones each event once per subscriber.
#[derive(Debug, Clone)]
pub struct EventHub {
inner: Arc<HubInner>,
@@ -75,6 +88,7 @@ struct SubscriberState {
}
impl EventHub {
/// Create an empty event hub with no subscribers.
pub fn new() -> Self {
Self {
inner: Arc::new(HubInner {
@@ -84,6 +98,9 @@ impl EventHub {
}
}
/// Register a new subscriber with its own bounded queue.
///
/// Returns an error when `config.capacity` is zero.
pub fn subscribe(
&self,
config: SubscriberConfig,
@@ -116,6 +133,11 @@ impl EventHub {
})
}
/// Publish an event to all currently connected subscribers.
///
/// Slow subscribers are handled according to their
/// [`SubscriberOverflow`] policy. Publishing does not block waiting for a
/// subscriber to consume queued events.
pub fn publish(&self, event: ClientEvent) {
let subscribers: Vec<(u64, Arc<SubscriberInner>)> = self
.inner
@@ -149,6 +171,8 @@ impl EventHub {
}
}
/// Disconnect all subscribers after leaving their already queued events
/// available to drain.
pub fn disconnect_all(&self) {
let subscribers: Vec<Arc<SubscriberInner>> = self
.inner
+43
View File
@@ -21,6 +21,12 @@ const MANAGED_FINAL_DRAIN: Duration = Duration::from_millis(100);
const IDLE_SLEEP: Duration = Duration::from_millis(1);
const MAX_SLEEP: Duration = Duration::from_millis(20);
/// Entry point for running a client session on a worker thread.
///
/// The managed API owns the lower-level [`Client`](crate::Client) loop: it
/// opens the session, sends probes at the negotiated interval, receives
/// datagrams, publishes [`ClientEvent`] values, and closes the session when the
/// run completes or is cancelled.
#[derive(Debug)]
pub struct ManagedClient;
@@ -46,26 +52,49 @@ pub struct ManagedClientSession {
#[must_use = "managed session outcomes contain completion status and counters"]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SessionOutcome {
/// Why the managed loop stopped.
pub end_reason: SessionEndReason,
/// Number of echo requests sent by the client.
pub packets_sent: u64,
/// Number of first in-window echo replies received.
pub replies_received: u64,
/// Number of duplicate reply events emitted.
pub duplicates: u64,
/// Number of late reply events emitted.
pub late: u64,
/// Number of warning events emitted.
pub warning_events: u64,
}
/// Reason a managed client session ended.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SessionEndReason {
/// The negotiated finite test duration completed and the client closed the
/// session normally.
TestComplete,
/// Cancellation was requested through [`ManagedClientSession::stop`] or by
/// dropping the session handle.
Cancelled,
/// The session was opened in [`RunMode::NoTest`](crate::RunMode) and
/// completed after negotiation.
NoTestComplete,
}
impl ManagedClient {
/// Start a managed session without creating an initial event subscription.
///
/// The returned [`ManagedClientSession`] can still create subscriptions via
/// [`ManagedClientSession::subscribe`], but events emitted before a
/// subscriber is registered are not replayed.
pub fn start(config: ClientConfig) -> Result<ManagedClientSession, ClientError> {
Self::start_inner(config, None).map(|(session, _)| session)
}
/// Start a managed session and subscribe to events before the worker runs.
///
/// The initial subscription receives the open lifecycle event and
/// subsequent session events, subject to its queue capacity and overflow
/// policy.
pub fn start_with_subscription(
config: ClientConfig,
subscriber_config: SubscriberConfig,
@@ -114,14 +143,28 @@ impl ManagedClient {
}
impl ManagedClientSession {
/// Add another event subscriber to this running managed session.
///
/// The subscription receives only events published after it is registered.
pub fn subscribe(&self, config: SubscriberConfig) -> Result<EventSubscription, ClientError> {
self.hub.subscribe(config)
}
/// Request cooperative cancellation of the managed session.
///
/// Cancellation is observed by the worker loop between socket receive,
/// timeout polling, and send scheduling steps. Call [`join`](Self::join) to
/// wait for the worker and obtain the final [`SessionOutcome`].
pub fn stop(&self) {
self.cancellation.cancel();
}
/// Wait for the managed worker thread to finish.
///
/// On success, returns lifecycle counters for the completed session. If the
/// worker panicked, this returns [`ClientError::WorkerPanicked`]. Joining
/// also disconnects all event subscriptions while leaving already queued
/// events available to drain.
pub fn join(mut self) -> Result<SessionOutcome, ClientError> {
let worker = self
.worker