fips_core/endpoint/
builder.rs1use super::*;
2
3#[derive(Debug, Clone)]
5pub struct FipsEndpointBuilder {
6 config: Config,
7 identity_nsec: Option<String>,
8 discovery_scope: Option<String>,
9 local_rendezvous: bool,
10 local_instance_roles: Vec<crate::discovery::local::LocalInstanceCapability>,
11 disable_system_networking: bool,
12 packet_channel_capacity: usize,
13}
14
15const DEFAULT_ENDPOINT_PACKET_CHANNEL_CAPACITY: usize = 4096;
16
17impl Default for FipsEndpointBuilder {
18 fn default() -> Self {
19 Self {
20 config: Config::new(),
21 identity_nsec: None,
22 discovery_scope: None,
23 local_rendezvous: false,
24 local_instance_roles: Vec::new(),
25 disable_system_networking: true,
26 packet_channel_capacity: DEFAULT_ENDPOINT_PACKET_CHANNEL_CAPACITY,
27 }
28 }
29}
30
31impl FipsEndpointBuilder {
32 pub fn config(mut self, config: Config) -> Self {
34 self.config = config;
35 self
36 }
37
38 pub fn identity_nsec(mut self, nsec: impl Into<String>) -> Self {
40 self.identity_nsec = Some(nsec.into());
41 self
42 }
43
44 pub fn discovery_scope(mut self, scope: impl Into<String>) -> Self {
54 self.discovery_scope = Some(scope.into());
55 self
56 }
57
58 pub fn local_rendezvous(mut self) -> Self {
60 self.local_rendezvous = true;
61 self
62 }
63
64 pub fn local_role(mut self, name: impl Into<String>, priority: i16) -> Self {
67 let name = name.into().trim().to_string();
68 if crate::discovery::local_udp::local_capability_name_is_valid(&name)
69 && self.local_instance_roles.len()
70 < crate::discovery::local_udp::LOCAL_CAPABILITY_MAX_COUNT
71 {
72 self.local_instance_roles.push(
73 crate::discovery::local::LocalInstanceCapability::role(name)
74 .with_priority(priority),
75 );
76 }
77 self
78 }
79
80 pub fn without_system_tun(mut self) -> Self {
82 self.disable_system_networking = true;
83 self
84 }
85
86 pub fn packet_channel_capacity(mut self, capacity: usize) -> Self {
88 self.packet_channel_capacity = capacity.max(1);
89 self
90 }
91
92 pub(super) fn prepared_config(&self) -> Config {
93 let mut config = self.config.clone();
94 if let Some(nsec) = &self.identity_nsec {
95 config.node.identity = IdentityConfig {
96 nsec: Some(nsec.clone()),
97 persistent: false,
98 };
99 }
100 if self.disable_system_networking {
101 config.tun.enabled = false;
102 config.dns.enabled = false;
103 config.node.system_files_enabled = false;
104 }
105 if self.local_rendezvous {
106 config.node.discovery.local.enabled = true;
107 }
108 if let Some(scope) = self.discovery_scope.as_deref() {
109 if config
110 .node
111 .discovery
112 .lan
113 .scope
114 .as_deref()
115 .is_none_or(|scope| scope.trim().is_empty())
116 {
117 config.node.discovery.lan.scope = Some(scope.to_string());
118 }
119 apply_default_scoped_discovery(&mut config, scope);
120 }
121 config
122 }
123
124 pub async fn bind(self) -> Result<FipsEndpoint, FipsEndpointError> {
126 self.bind_inner(None).await
127 }
128
129 pub async fn bind_with_direct_receiver(
131 self,
132 ) -> Result<(FipsEndpoint, FipsEndpointDirectReceiver), FipsEndpointError> {
133 let (sink, receiver) = FipsEndpointDirectReceiver::channel();
134 let endpoint = self.bind_with_direct_sink(sink).await?;
135 Ok((endpoint, receiver))
136 }
137
138 pub async fn bind_with_direct_sink<S>(self, sink: S) -> Result<FipsEndpoint, FipsEndpointError>
144 where
145 S: FipsEndpointDirectSink,
146 {
147 self.bind_inner(Some(EndpointDirectSink::new(sink))).await
148 }
149
150 async fn bind_inner(
151 self,
152 direct_sink: Option<EndpointDirectSink>,
153 ) -> Result<FipsEndpoint, FipsEndpointError> {
154 let config = self.prepared_config();
155
156 let mut node = Node::new(config)?;
157 node.set_local_instance_roles(self.local_instance_roles);
158 let identity = PeerIdentity::from_pubkey_full(node.identity().pubkey_full());
159 let npub = identity.npub();
160 let node_addr = *identity.node_addr();
161 let address = *identity.address();
162 let packet_io = node.attach_external_packet_io(self.packet_channel_capacity)?;
163 let endpoint_data_io = match direct_sink {
164 Some(sink) => {
165 node.attach_endpoint_data_io_with_direct_sink(self.packet_channel_capacity, sink)?
166 }
167 None => node.attach_endpoint_data_io(self.packet_channel_capacity)?,
168 };
169 node.start().await?;
170 let local_capability_directory = node.local_capability_directory();
171
172 let (shutdown_tx, shutdown_rx) = oneshot::channel();
173 let task = spawn_node_task(node, shutdown_rx);
174 let endpoint_control_tx = endpoint_data_io.control_tx;
175 let endpoint_data_batches = endpoint_data_io.data_batch_tx;
176 let inbound_service_tx = endpoint_data_io.service_event_tx;
177
178 Ok(FipsEndpoint {
179 identity,
180 npub,
181 node_addr,
182 address,
183 discovery_scope: self.discovery_scope,
184 local_capability_directory,
185 outbound_packets: packet_io.outbound_tx,
186 delivered_packets: Arc::new(Mutex::new(packet_io.inbound_rx)),
187 endpoint_control_tx,
188 endpoint_data_batches,
189 inbound_endpoint_tx: endpoint_data_io.event_tx,
190 inbound_endpoint_rx: Arc::new(Mutex::new(EndpointReceiveState::new(
191 endpoint_data_io.event_rx,
192 ))),
193 inbound_service_tx,
194 inbound_service_rx: Arc::new(Mutex::new(ServiceReceiveState::new(
195 endpoint_data_io.service_event_rx,
196 ))),
197 registered_services: Arc::new(StdMutex::new(HashMap::new())),
198 service_channel_capacity: self.packet_channel_capacity,
199 shutdown_tx: std::sync::Mutex::new(Some(shutdown_tx)),
200 task: std::sync::Mutex::new(Some(task)),
201 })
202 }
203}