Skip to main content

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}