docs: document client public API
This commit is contained in:
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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in new issue
Block a user