iroh_http_core/endpoint/mod.rs
1//! Iroh endpoint lifecycle — create, share, and close.
2//!
3//! [`IrohEndpoint`] is a thin façade over [`EndpointInner`], which is
4//! composed of the four named subsystems from ADR-014 D1:
5//!
6//! - [`transport::Transport`] — raw QUIC endpoint and stable identity.
7//! - [`http_runtime::HttpRuntime`] — pool, HTTP limits, in-flight counters.
8//! - [`session_runtime::SessionRuntime`] — serve loop, lifecycle signals,
9//! transport events, path subscriptions.
10//! - [`ffi_bridge::FfiBridge`] — the opaque-handle store reachable from JS.
11//!
12//! No business logic lives in this module — only orchestration and the
13//! public API surface. Sub-modules:
14//! - [`bind`] — `IrohEndpoint::bind()` constructor.
15//! - [`observe`] — observability and peer-info methods.
16//! - [`config`] — `NodeOptions` and friends.
17//! - [`stats`] — snapshot and event types.
18// `handles()` returns `&HandleStore` which is in the disallowed-types list.
19// The disallowed_types lint is used to prevent mod http from depending on mod
20// ffi; endpoint/ is neither mod http nor mod ffi, so the allow is correct here.
21#![allow(clippy::disallowed_types)]
22
23use std::sync::Arc;
24
25pub(in crate::endpoint) mod bind;
26pub(in crate::endpoint) mod ffi_bridge;
27pub(in crate::endpoint) mod http_runtime;
28pub(in crate::endpoint) mod lifecycle;
29pub(in crate::endpoint) mod observe;
30pub(in crate::endpoint) mod session_runtime;
31pub(in crate::endpoint) mod transport;
32
33pub mod config;
34pub mod stats;
35
36pub use bind::parse_direct_addrs;
37pub use config::{DiscoveryOptions, NetworkingOptions, NodeOptions, PoolOptions, StreamingOptions};
38pub use http::server::stack::CompressionOptions;
39pub use stats::{ConnectionEvent, EndpointStats, NodeAddrInfo, PathInfo, PeerStats};
40
41use crate::ffi::handles::HandleStore;
42use crate::http;
43use crate::http::transport::pool::ConnectionPool;
44
45use ffi_bridge::FfiBridge;
46use http_runtime::HttpRuntime;
47use transport::Transport;
48
49/// A shared Iroh endpoint.
50///
51/// Clone-able (cheap Arc clone). All fetch and serve calls on the same node
52/// share one endpoint and therefore one stable QUIC identity.
53#[derive(Clone)]
54pub struct IrohEndpoint {
55 pub(in crate::endpoint) inner: Arc<EndpointInner>,
56}
57
58/// Composition of the four ADR-014 D1 subsystems. No business logic; the
59/// public API on [`IrohEndpoint`] reaches into the appropriate subsystem.
60pub(in crate::endpoint) struct EndpointInner {
61 pub(in crate::endpoint) transport: Transport,
62 pub(in crate::endpoint) http: HttpRuntime,
63 pub(in crate::endpoint) session: session_runtime::SessionRuntime,
64 pub(in crate::endpoint) ffi: FfiBridge,
65}
66
67impl IrohEndpoint {
68 // ── Stable identity ──────────────────────────────────────────────────────
69
70 /// The node's public key as a lowercase base32 string.
71 pub fn node_id(&self) -> &str {
72 &self.inner.transport.node_id_str
73 }
74
75 /// The node's raw secret key bytes (32 bytes).
76 ///
77 /// # Security
78 ///
79 /// **These 32 bytes are the irrecoverable private key for this node.**
80 /// Anyone who obtains them can impersonate this node permanently.
81 /// Never log, print, or include in error payloads. Encrypt at rest.
82 /// Zeroize after use.
83 #[must_use]
84 pub fn secret_key_bytes(&self) -> [u8; 32] {
85 self.inner.transport.ep.secret_key().to_bytes()
86 }
87
88 // ── Handle store ─────────────────────────────────────────────────────────
89
90 /// Per-endpoint handle store.
91 pub fn handles(&self) -> &HandleStore {
92 &self.inner.ffi.handles
93 }
94
95 /// Immediately run a TTL sweep on all handle registries.
96 pub fn sweep_now(&self) {
97 let ttl = self.inner.ffi.handles.config.ttl;
98 if !ttl.is_zero() {
99 self.inner.ffi.handles.sweep(ttl);
100 }
101 }
102
103 // ── HTTP runtime accessors ────────────────────────────────────────────────
104
105 /// Maximum byte size of an HTTP/1.1 head.
106 pub fn max_header_size(&self) -> usize {
107 self.inner.http.max_header_size
108 }
109
110 /// Maximum decompressed response-body bytes accepted per outgoing fetch.
111 pub fn max_response_body_bytes(&self) -> usize {
112 self.inner.http.max_response_body_bytes
113 }
114
115 /// Compression options, if the `compression` feature is enabled.
116 pub fn compression(&self) -> Option<&CompressionOptions> {
117 self.inner.http.compression.as_ref()
118 }
119
120 /// Access the connection pool.
121 pub(crate) fn pool(&self) -> &ConnectionPool {
122 &self.inner.http.pool
123 }
124
125 /// Shared active-connections counter (used by the accept loop).
126 pub(crate) fn active_connections_arc(&self) -> Arc<std::sync::atomic::AtomicUsize> {
127 self.inner.http.active_connections.clone()
128 }
129
130 /// Shared active-requests counter (used by the accept loop).
131 pub(crate) fn active_requests_arc(&self) -> Arc<std::sync::atomic::AtomicUsize> {
132 self.inner.http.active_requests.clone()
133 }
134
135 // ── Lifecycle ─────────────────────────────────────────────────────────────
136
137 /// Closed-signal sender shared with the accept loop.
138 pub(crate) fn connection_closed_tx(&self) -> tokio::sync::watch::Sender<bool> {
139 self.inner.session.closed_tx.clone()
140 }
141
142 /// Access the raw Iroh endpoint.
143 pub fn raw(&self) -> &iroh::Endpoint {
144 &self.inner.transport.ep
145 }
146}