Skip to main content

fips_core/config/transport/
webrtc.rs

1//! WebRTC transport configuration.
2
3use serde::{Deserialize, Serialize};
4
5/// Default WebRTC data-channel MTU.
6const DEFAULT_WEBRTC_MTU: u16 = 1200;
7
8/// Default WebRTC connection timeout in milliseconds.
9const DEFAULT_WEBRTC_CONNECT_TIMEOUT_MS: u64 = 30_000;
10
11/// Default non-trickle ICE gathering timeout in milliseconds.
12const DEFAULT_WEBRTC_ICE_GATHER_TIMEOUT_MS: u64 = 2_000;
13
14/// Default maximum simultaneous WebRTC peer connections.
15const DEFAULT_WEBRTC_MAX_CONNECTIONS: usize = 6;
16
17/// Default WebRTC data channel label.
18const DEFAULT_WEBRTC_DATA_CHANNEL_LABEL: &str = "fips";
19
20/// WebRTC transport instance configuration.
21///
22/// WebRTC negotiates over an existing authenticated FIPS session and carries
23/// ordinary FIPS datagrams over an SCTP data channel.
24#[derive(Debug, Clone, Default, Serialize, Deserialize)]
25#[serde(deny_unknown_fields)]
26pub struct WebRtcConfig {
27    /// Whether this transport should be advertised on Nostr overlay discovery.
28    /// Default: false.
29    #[serde(default, skip_serializing_if = "Option::is_none")]
30    pub advertise_on_nostr: Option<bool>,
31
32    /// Whether to automatically connect to discovered WebRTC peers.
33    /// Default: false.
34    #[serde(default, skip_serializing_if = "Option::is_none")]
35    pub auto_connect: Option<bool>,
36
37    /// Accept inbound WebRTC offers. Defaults to `advertise_on_nostr`: a
38    /// non-advertising adapter has no inbound listener policy unless enabled.
39    #[serde(default, skip_serializing_if = "Option::is_none")]
40    pub accept_connections: Option<bool>,
41
42    /// Data-channel MTU. Defaults to 1200.
43    #[serde(default, skip_serializing_if = "Option::is_none")]
44    pub mtu: Option<u16>,
45
46    /// Maximum simultaneous WebRTC peer connections. Defaults to 6 and is
47    /// additionally bounded by the configured ICE socket budget.
48    #[serde(default, skip_serializing_if = "Option::is_none")]
49    pub max_connections: Option<usize>,
50
51    /// Outbound connect timeout in milliseconds. Defaults to 30000.
52    #[serde(default, skip_serializing_if = "Option::is_none")]
53    pub connect_timeout_ms: Option<u64>,
54
55    /// Non-trickle ICE gathering timeout in milliseconds. Defaults to 2000.
56    #[serde(default, skip_serializing_if = "Option::is_none")]
57    pub ice_gather_timeout_ms: Option<u64>,
58
59    /// Data channel label. Defaults to "fips".
60    #[serde(default, skip_serializing_if = "Option::is_none")]
61    pub data_channel_label: Option<String>,
62
63    /// Ordered data channel delivery. Default: true.
64    #[serde(default, skip_serializing_if = "Option::is_none")]
65    pub ordered: Option<bool>,
66
67    /// Maximum retransmits for partial reliability. Default: unset, which uses
68    /// WebRTC's reliable data-channel mode. Set to 0 for datagram-like delivery.
69    #[serde(default, skip_serializing_if = "Option::is_none")]
70    pub max_retransmits: Option<u16>,
71
72    /// Override STUN servers for this transport. Supports up to three `stun:`
73    /// URLs. When unset, `node.discovery.nostr.stun_servers` is used.
74    #[serde(default, skip_serializing_if = "Option::is_none")]
75    pub stun_servers: Option<Vec<String>>,
76
77    /// Resolve browser `.local` ICE candidates through one shared mDNS owner.
78    /// Every peer connection keeps its own ICE mDNS mode disabled. Default:
79    /// true. Disable this for environments where multicast DNS is unavailable.
80    #[serde(default, skip_serializing_if = "Option::is_none")]
81    pub resolve_mdns_candidates: Option<bool>,
82}
83
84impl WebRtcConfig {
85    /// Whether this WebRTC transport should be advertised on Nostr discovery.
86    pub fn advertise_on_nostr(&self) -> bool {
87        self.advertise_on_nostr.unwrap_or(false)
88    }
89
90    /// Whether this transport auto-connects to discovered peers.
91    pub fn auto_connect(&self) -> bool {
92        self.auto_connect.unwrap_or(false)
93    }
94
95    /// Whether this transport accepts inbound offers.
96    pub fn accept_connections(&self) -> bool {
97        self.accept_connections
98            .unwrap_or_else(|| self.advertise_on_nostr())
99    }
100
101    /// Get the data-channel MTU.
102    pub fn mtu(&self) -> u16 {
103        self.mtu.unwrap_or(DEFAULT_WEBRTC_MTU)
104    }
105
106    /// Get the maximum number of peer connections.
107    pub fn max_connections(&self) -> usize {
108        self.max_connections
109            .unwrap_or(DEFAULT_WEBRTC_MAX_CONNECTIONS)
110    }
111
112    /// Get the connect timeout in milliseconds.
113    pub fn connect_timeout_ms(&self) -> u64 {
114        self.connect_timeout_ms
115            .unwrap_or(DEFAULT_WEBRTC_CONNECT_TIMEOUT_MS)
116    }
117
118    /// Get the ICE gathering timeout in milliseconds.
119    pub fn ice_gather_timeout_ms(&self) -> u64 {
120        self.ice_gather_timeout_ms
121            .unwrap_or(DEFAULT_WEBRTC_ICE_GATHER_TIMEOUT_MS)
122    }
123
124    /// Get the data channel label.
125    pub fn data_channel_label(&self) -> &str {
126        self.data_channel_label
127            .as_deref()
128            .unwrap_or(DEFAULT_WEBRTC_DATA_CHANNEL_LABEL)
129    }
130
131    /// Whether the data channel is ordered.
132    pub fn ordered(&self) -> bool {
133        self.ordered.unwrap_or(true)
134    }
135
136    /// Get the configured max retransmits. None uses WebRTC's reliable mode.
137    pub fn max_retransmits(&self) -> Option<u16> {
138        self.max_retransmits
139    }
140
141    /// Whether browser `.local` ICE candidates should be resolved.
142    pub fn resolve_mdns_candidates(&self) -> bool {
143        self.resolve_mdns_candidates.unwrap_or(true)
144    }
145
146    /// Resolve STUN servers, falling back to node discovery STUN servers.
147    pub fn stun_servers<'a>(&'a self, fallback: &'a [String]) -> Vec<String> {
148        self.stun_servers
149            .as_ref()
150            .cloned()
151            .unwrap_or_else(|| fallback.to_vec())
152    }
153}