1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
//! Multi-host client SDK.
//!
//! A consumer that wants to talk to two or more AHP hosts at once would
//! otherwise have to hand-roll N independent [`crate::Client`]s, N
//! transports, N reconnect supervisors, a per-host metadata registry,
//! and a fan-in of inbound events tagged with host of origin. This
//! module ships that machinery as [`MultiHostClient`].
//!
//! Single-host consumers are not left out: [`MultiHostClient::single`]
//! is a one-line constructor that yields the same [`HostHandle`]
//! abstraction without the consumer ever touching registry concepts.
//!
//! # Anatomy
//!
//! - [`HostId`] — opaque, stable, consumer-supplied identifier per host.
//! - [`HostConfig`] — what the multi-host client needs to open a host:
//! id, label, [`HostTransportFactory`], reconnect policy, `clientId`,
//! initial subscriptions, [`crate::ClientConfig`].
//! - [`HostHandle`] — observable snapshot per host: connection state,
//! protocol version, last error (a typed [`crate::ClientError`]),
//! agents, session summaries, etc. This is the surface UIs render.
//! - [`HostClientHandle`] — generation-checked escape hatch. Wraps the
//! underlying single-host [`crate::Client`] and refuses to dispatch
//! through a connection that has since been replaced.
//! - [`HostSubscriptionEvent`] — fan-in event tagged with host id and
//! resource URI.
//! - [`HostEvent`] — connection-level event for UX (state changes,
//! reconnect attempts, etc.).
//! - [`MultiHostClient`] — the public API.
//!
//! # `clientId`
//!
//! Each host needs a stable `clientId` so the AHP `reconnect` flow
//! works. [`HostConfig::new`] generates a session-stable UUID by
//! default; for cross-launch identity persist the value yourself (e.g.
//! in your app's keychain) and pass it via
//! [`HostConfig::with_client_id`] on subsequent launches.
//!
//! # Quickstart (single-host)
//!
//! ```no_run
//! # use ahp::transport::BoxedTransport;
//! # use ahp::TransportError;
//! # use ahp::hosts::HostError;
//! # async fn open(_: ahp::hosts::HostId) -> Result<BoxedTransport, TransportError> {
//! # unimplemented!()
//! # }
//! # async fn run() -> Result<(), HostError> {
//! use ahp::hosts::{HostConfig, MultiHostClient};
//!
//! let config = HostConfig::new("local", "Local sessions server", open);
//! let (client, handle) = MultiHostClient::single(config).await?;
//! println!("connected to {}: {:?}", handle.label, handle.state);
//! # let _ = client; Ok(()) }
//! ```
//!
//! # Quickstart (multi-host)
//!
//! ```no_run
//! # use ahp::transport::BoxedTransport;
//! # use ahp::TransportError;
//! # use ahp::hosts::HostError;
//! # async fn open_local(_: ahp::hosts::HostId) -> Result<BoxedTransport, TransportError> { unimplemented!() }
//! # async fn open_remote(_: ahp::hosts::HostId) -> Result<BoxedTransport, TransportError> { unimplemented!() }
//! # async fn run() -> Result<(), HostError> {
//! use ahp::hosts::{HostConfig, MultiHostClient};
//!
//! let multi = MultiHostClient::new();
//! multi.add_host(HostConfig::new("local", "Local", open_local)).await?;
//! multi.add_host(HostConfig::new("remote", "Tunnel", open_remote)).await?;
//!
//! let mut events = multi.events();
//! while let Some(event) = events.recv().await {
//! println!("[{}] {:?}", event.host_id, event.event);
//! }
//! # Ok(()) }
//! ```
//!
//! # Reconnect, generation, and ownership
//!
//! Each host runs in its own internal task — the
//! [`HostRuntime`](runtime::HostRuntime) (private) — that owns the
//! current [`crate::Client`], retries the configured
//! [`ReconnectPolicy`], and re-subscribes to known URIs across
//! reconnects. Every reconnect bumps the host's `generation`. Any
//! [`HostClientHandle`] you obtained from a previous connection refuses
//! to dispatch on the new connection and returns
//! [`HostError::HostReconnected`] — you must request a fresh handle
//! via [`MultiHostClient::client`].
pub use ;
pub use HostTransportFactory;
pub use MultiHostClient;
pub use ;
pub use ;