fips_core/node/
io_impl.rs1use super::*;
2
3impl Node {
4 pub fn attach_nostr_relay_io(
10 &mut self,
11 capacity: usize,
12 ) -> Result<crate::endpoint::NostrRelayIo, NodeError> {
13 if self.state != NodeState::Created {
14 return Err(NodeError::Config(ConfigError::Validation(
15 "Nostr relay I/O must be attached before node start".to_string(),
16 )));
17 }
18 if self.endpoint_control_rx.is_some() {
19 return Err(NodeError::Config(ConfigError::Validation(
20 "node application control I/O is already attached".to_string(),
21 )));
22 }
23
24 let (control_tx, control_rx) = tokio::sync::mpsc::channel(capacity.max(1));
25 self.endpoint_control_rx = Some(control_rx);
26 Ok(crate::endpoint::NostrRelayIo::new(
27 self.identity.npub(),
28 control_tx,
29 ))
30 }
31
32 pub fn tun_tx(&self) -> Option<&TunTx> {
36 self.tun_tx.as_ref()
37 }
38
39 pub fn attach_external_packet_io(
46 &mut self,
47 capacity: usize,
48 ) -> Result<ExternalPacketIo, NodeError> {
49 if self.state != NodeState::Created {
50 return Err(NodeError::Config(ConfigError::Validation(
51 "external packet I/O must be attached before node start".to_string(),
52 )));
53 }
54 if self.config.tun.enabled {
55 return Err(NodeError::Config(ConfigError::Validation(
56 "external packet I/O requires tun.enabled=false".to_string(),
57 )));
58 }
59
60 let capacity = capacity.max(1);
61 let (outbound_tx, outbound_rx) = crate::upper::tun::tun_outbound_channel(capacity);
62 let (inbound_tx, inbound_rx) = tokio::sync::mpsc::channel(capacity);
63 self.tun_outbound_rx = Some(outbound_rx);
64 self.external_packet_tx = Some(inbound_tx);
65
66 Ok(ExternalPacketIo {
67 outbound_tx,
68 inbound_rx,
69 })
70 }
71
72 pub(crate) fn attach_endpoint_data_io(
77 &mut self,
78 capacity: usize,
79 ) -> Result<EndpointDataIo, NodeError> {
80 self.attach_endpoint_data_io_inner(capacity, None)
81 }
82
83 pub(crate) fn attach_endpoint_data_io_with_direct_sink(
84 &mut self,
85 capacity: usize,
86 direct_sink: EndpointDirectSink,
87 ) -> Result<EndpointDataIo, NodeError> {
88 self.attach_endpoint_data_io_inner(capacity, Some(direct_sink))
89 }
90
91 fn attach_endpoint_data_io_inner(
92 &mut self,
93 capacity: usize,
94 direct_sink: Option<EndpointDirectSink>,
95 ) -> Result<EndpointDataIo, NodeError> {
96 if self.state != NodeState::Created {
97 return Err(NodeError::Config(ConfigError::Validation(
98 "endpoint data I/O must be attached before node start".to_string(),
99 )));
100 }
101
102 let command_capacity = capacity.max(1);
103 let (control_tx, control_rx) = tokio::sync::mpsc::channel(command_capacity);
104 let (data_batch_tx, data_rx) = endpoint_data_batch_channel(command_capacity);
105 let (event_tx, event_rx) =
109 EndpointEventSender::channel_with_direct_sink(capacity, direct_sink);
110 let (service_event_tx, service_event_rx) = EndpointServiceEventSender::channel(capacity);
111 self.endpoint_control_rx = Some(control_rx);
112 self.endpoint_data_rx = Some(data_rx);
113 self.endpoint_events.attach(event_tx.clone());
114
115 Ok(EndpointDataIo {
116 control_tx,
117 data_batch_tx,
118 event_rx,
119 event_tx,
120 service_event_rx,
121 service_event_tx,
122 })
123 }
124
125 pub(crate) fn pubkey_for_node_addr(&self, addr: &NodeAddr) -> Option<secp256k1::PublicKey> {
126 self.identity_cache.pubkey_for_node_addr(addr)
127 }
128
129 pub(crate) fn npub_for_node_addr(&self, addr: &NodeAddr) -> Option<String> {
130 self.identity_cache.npub_for_node_addr(addr)
131 }
132
133 pub(in crate::node) fn deliver_external_ipv6_packet(
134 &self,
135 src_addr: &NodeAddr,
136 packet: Vec<u8>,
137 ) {
138 let Some(external_packet_tx) = &self.external_packet_tx else {
139 return;
140 };
141 if packet.len() < 40 {
142 return;
143 }
144 let Ok(destination) = FipsAddress::from_slice(&packet[24..40]) else {
145 return;
146 };
147 let delivered = NodeDeliveredPacket {
148 source_node_addr: *src_addr,
149 source_npub: self.npub_for_node_addr(src_addr),
150 destination,
151 packet,
152 };
153 if let Err(error) = external_packet_tx.try_send(delivered) {
154 debug!(error = %error, "Failed to deliver packet to external app sink");
155 }
156 }
157
158 pub(in crate::node) fn note_local_send_outcome(
164 &mut self,
165 node_addr: &NodeAddr,
166 result: &Result<usize, TransportError>,
167 ) {
168 self.local_send_failures
169 .note_send_outcome(node_addr, result, std::time::Instant::now());
170 }
171
172 pub(in crate::node) fn note_candidate_send_outcome(
178 &mut self,
179 node_addr: &NodeAddr,
180 candidate_addr: &TransportAddr,
181 result: &Result<usize, TransportError>,
182 ) {
183 if result.is_ok() {
184 self.note_local_send_outcome(node_addr, result);
185 return;
186 }
187
188 let candidate_is_active_path = self
189 .peers
190 .get(node_addr)
191 .is_none_or(|peer| !peer.can_send() || peer.current_addr() == Some(candidate_addr));
192 if candidate_is_active_path {
193 self.note_local_send_outcome(node_addr, result);
194 }
195 }
196
197 pub(in crate::node) fn local_send_failure_dead_timeout_for_peer(
203 &self,
204 node_addr: &NodeAddr,
205 now: std::time::Instant,
206 dead_timeout: std::time::Duration,
207 fast_dead_timeout: std::time::Duration,
208 ) -> std::time::Duration {
209 self.local_send_failures.dead_timeout_for_peer(
210 node_addr,
211 now,
212 dead_timeout,
213 fast_dead_timeout,
214 )
215 }
216
217 pub(in crate::node) fn purge_expired_local_send_failures(&mut self, now: std::time::Instant) {
218 self.local_send_failures.purge_expired(now);
219 }
220
221 pub(in crate::node) fn mark_rx_loop_maintenance_timeout(&mut self) {
222 let now = std::time::Instant::now();
223 let grace = std::time::Duration::from_secs(self.config.node.link_dead_timeout_secs.max(1));
224 if self
225 .last_rx_loop_maintenance_timeout_at
226 .is_some_and(|started| now.duration_since(started) <= grace)
227 {
228 return;
229 }
230 self.last_rx_loop_maintenance_timeout_at = Some(now);
231 }
232
233 pub(in crate::node) fn rx_loop_maintenance_timed_out_recently(&self) -> bool {
234 let Some(t) = self.last_rx_loop_maintenance_timeout_at else {
235 return false;
236 };
237 let grace = std::time::Duration::from_secs(self.config.node.link_dead_timeout_secs.max(1));
238 std::time::Instant::now().duration_since(t) <= grace
239 }
240}