Skip to main content

rings_core/swarm/
builder.rs

1#![deny(missing_docs)]
2//! This module provider [SwarmBuilder] and it's interface for
3//! [Swarm]
4
5use std::sync::Arc;
6use std::sync::RwLock;
7
8use rings_transport::webrtc_config::WebrtcUdpPortRange;
9
10use crate::chunk::ReassemblyLimits;
11use crate::dht::EntryStorage;
12use crate::dht::PeerRing;
13use crate::dht::VirtualNodeConfig;
14use crate::dht::DEFAULT_FINGER_TABLE_SIZE;
15use crate::dht::DEFAULT_STORAGE_VIRTUAL_POSITIONS_PER_OWNER;
16use crate::measure::MeasureImpl;
17use crate::session::SessionSk;
18use crate::swarm::callback::SharedSwarmCallback;
19use crate::swarm::callback::SwarmCallback;
20use crate::swarm::transport::SwarmTransport;
21use crate::swarm::transport::SwarmTransportSettings;
22use crate::swarm::transport::SwarmWebrtcConfig;
23use crate::swarm::Swarm;
24
25struct DefaultCallback;
26impl SwarmCallback for DefaultCallback {}
27
28/// Creates a SwarmBuilder to configure a Swarm.
29pub struct SwarmBuilder {
30    network_id: u32,
31    ice_servers: String,
32    external_address: Option<String>,
33    webrtc_udp_port_range: Option<WebrtcUdpPortRange>,
34    dht_succ_max: u8,
35    dht_finger_table_size: usize,
36    dht_storage_redundancy: u16,
37    dht_virtual_nodes: u16,
38    reassembly_limits: ReassemblyLimits,
39    dht_storage: EntryStorage,
40    session_sk: SessionSk,
41    session_ttl: Option<usize>,
42    measure: Option<MeasureImpl>,
43    callback: Option<SharedSwarmCallback>,
44}
45
46impl SwarmBuilder {
47    /// Creates new instance of [SwarmBuilder]
48    pub fn new(
49        network_id: u32,
50        ice_servers: &str,
51        dht_storage: EntryStorage,
52        session_sk: SessionSk,
53    ) -> Self {
54        SwarmBuilder {
55            network_id,
56            ice_servers: ice_servers.to_string(),
57            external_address: None,
58            webrtc_udp_port_range: None,
59            dht_succ_max: 3,
60            dht_finger_table_size: DEFAULT_FINGER_TABLE_SIZE,
61            dht_storage_redundancy: 1,
62            dht_virtual_nodes: DEFAULT_STORAGE_VIRTUAL_POSITIONS_PER_OWNER,
63            reassembly_limits: default_reassembly_limits(),
64            dht_storage,
65            session_sk,
66            session_ttl: None,
67            measure: None,
68            callback: None,
69        }
70    }
71
72    /// Sets up the maximum length of successors in the DHT.
73    pub fn dht_succ_max(mut self, succ_max: u8) -> Self {
74        self.dht_succ_max = succ_max;
75        self
76    }
77
78    /// Sets up the number of slots in the DHT finger table.
79    ///
80    /// `Did` is 160-bit, so values above `DEFAULT_FINGER_TABLE_SIZE` are clamped
81    /// by `FingerTable::new`. A size of zero disables finger maintenance.
82    pub fn dht_finger_table_size(mut self, size: usize) -> Self {
83        self.dht_finger_table_size = size;
84        self
85    }
86
87    /// Sets up the redundancy used by storage repair and anti-entropy.
88    pub fn dht_storage_redundancy(mut self, redundancy: u16) -> Self {
89        self.dht_storage_redundancy = redundancy;
90        self
91    }
92
93    /// Sets storage-only Chord virtual positions derived per physical peer.
94    ///
95    /// By default, Rings follows the Chord paper's O(log N) virtual-node
96    /// guidance through [`crate::dht::DEFAULT_STORAGE_VIRTUAL_POSITIONS_PER_OWNER`].
97    /// A value of zero disables virtual-node storage ownership. Values above
98    /// [`crate::dht::MAX_STORAGE_VIRTUAL_POSITIONS_PER_OWNER`] are normalized
99    /// once during [`Self::build`]. The same bounded value is used for both
100    /// storage ownership and advertised protocol mode.
101    pub fn dht_virtual_nodes(mut self, positions_per_peer: u16) -> Self {
102        self.dht_virtual_nodes = positions_per_peer;
103        self
104    }
105
106    /// Sets inbound chunk reassembly limits.
107    pub fn reassembly_limits(mut self, limits: ReassemblyLimits) -> Self {
108        self.reassembly_limits = limits;
109        self
110    }
111
112    /// Sets up the external address for swarm transport.
113    /// This will be used to configure the transport to listen for WebRTC connections in "HOST" mode.
114    pub fn external_address(mut self, external_address: String) -> Self {
115        self.external_address = Some(external_address);
116        self
117    }
118
119    /// Sets the native WebRTC UDP port range used during ICE gathering.
120    ///
121    /// Invariant: a present range has already proven `1 <= min <= max`.
122    /// Browser transports ignore this native deployment setting.
123    pub fn webrtc_udp_port_range(mut self, range: WebrtcUdpPortRange) -> Self {
124        self.webrtc_udp_port_range = Some(range);
125        self
126    }
127
128    /// Setup timeout for session.
129    pub fn session_ttl(mut self, ttl: usize) -> Self {
130        self.session_ttl = Some(ttl);
131        self
132    }
133
134    /// Bind measurement function for Swarm.
135    pub fn measure(mut self, implement: MeasureImpl) -> Self {
136        self.measure = Some(implement);
137        self
138    }
139
140    /// Bind callback for Swarm.
141    pub fn callback(mut self, callback: SharedSwarmCallback) -> Self {
142        self.callback = Some(callback);
143        self
144    }
145
146    /// Try build for `Swarm`.
147    pub fn build(self) -> Swarm {
148        let dht_did = self.session_sk.account_did();
149        let storage_virtual_node_config =
150            VirtualNodeConfig::new(self.network_id, self.dht_virtual_nodes);
151
152        let dht = Arc::new(
153            PeerRing::new_with_storage_finger_table_size_and_virtual_nodes(
154                dht_did,
155                self.dht_succ_max,
156                self.dht_storage,
157                self.dht_finger_table_size,
158                storage_virtual_node_config,
159            ),
160        );
161
162        let callback = RwLock::new(
163            self.callback
164                .unwrap_or_else(|| Arc::new(DefaultCallback {})),
165        );
166
167        let transport = Arc::new(SwarmTransport::new(
168            self.network_id,
169            SwarmWebrtcConfig::new(
170                self.ice_servers,
171                self.external_address,
172                self.webrtc_udp_port_range,
173            ),
174            self.session_sk,
175            dht.clone(),
176            self.measure,
177            SwarmTransportSettings::new(
178                self.dht_storage_redundancy,
179                storage_virtual_node_config,
180                self.reassembly_limits,
181            ),
182        ));
183
184        Swarm {
185            dht,
186            transport,
187            callback,
188        }
189    }
190}
191
192#[cfg(not(all(feature = "wasm", target_family = "wasm")))]
193fn default_reassembly_limits() -> ReassemblyLimits {
194    ReassemblyLimits::production()
195}
196
197#[cfg(all(feature = "wasm", target_family = "wasm"))]
198fn default_reassembly_limits() -> ReassemblyLimits {
199    ReassemblyLimits::constrained()
200}