Skip to main content

rns_ctl/
bridge.rs

1use rns_core::transport::types::InterfaceId;
2use rns_core::types::{DestHash, IdentityHash, LinkId, PacketHash};
3use rns_net::destination::AnnouncedIdentity;
4use rns_net::Callbacks;
5
6use crate::encode::{to_base64, to_hex};
7use crate::state::*;
8
9/// Callbacks implementation that bridges rns-net events into shared state + WebSocket broadcast.
10pub struct CtlCallbacks {
11    state: SharedState,
12    ws_broadcast: WsBroadcast,
13}
14
15impl CtlCallbacks {
16    pub fn new(state: SharedState, ws_broadcast: WsBroadcast) -> Self {
17        CtlCallbacks {
18            state,
19            ws_broadcast,
20        }
21    }
22}
23
24impl Callbacks for CtlCallbacks {
25    fn on_announce(&mut self, announced: AnnouncedIdentity) {
26        let record = make_announce_record(&announced);
27        let event = WsEvent::announce(&record);
28        push_announce(&self.state, record);
29        broadcast(&self.ws_broadcast, event);
30    }
31
32    fn on_path_updated(&mut self, _dest_hash: DestHash, _hops: u8) {
33        // Path updates are queryable via GET /api/paths; no event record needed.
34    }
35
36    fn on_local_delivery(&mut self, dest_hash: DestHash, raw: Vec<u8>, packet_hash: PacketHash) {
37        let record = PacketRecord {
38            dest_hash: to_hex(&dest_hash.0),
39            packet_hash: to_hex(&packet_hash.0),
40            data_base64: to_base64(&raw),
41            received_at: rns_net::time::now(),
42        };
43        let event = WsEvent::packet(&record);
44        push_packet(&self.state, record);
45        broadcast(&self.ws_broadcast, event);
46    }
47
48    fn on_proof(&mut self, dest_hash: DestHash, packet_hash: PacketHash, rtt: f64) {
49        let record = ProofRecord {
50            dest_hash: to_hex(&dest_hash.0),
51            packet_hash: to_hex(&packet_hash.0),
52            rtt,
53        };
54        let event = WsEvent::proof(&record);
55        push_proof(&self.state, record);
56        broadcast(&self.ws_broadcast, event);
57    }
58
59    fn on_proof_requested(&mut self, _dest_hash: DestHash, _packet_hash: PacketHash) -> bool {
60        true
61    }
62
63    fn on_link_established(
64        &mut self,
65        link_id: LinkId,
66        _dest_hash: DestHash,
67        rtt: f64,
68        is_initiator: bool,
69    ) {
70        // Set resource strategy to AcceptAll so this node can receive resources on this link
71        let node_handle = {
72            let s = self.state.read().unwrap();
73            s.node_handle.clone()
74        };
75        if let Some(nh) = node_handle {
76            if let Some(node) = nh.lock().unwrap().as_ref() {
77                let _ = node.set_resource_strategy(link_id.0, 1); // 1 = AcceptAll
78            }
79        }
80
81        let record = LinkEventRecord {
82            link_id: to_hex(&link_id.0),
83            event_type: "established".into(),
84            is_initiator: Some(is_initiator),
85            rtt: Some(rtt),
86            identity_hash: None,
87            reason: None,
88        };
89        let event = WsEvent::link(&record);
90        push_link_event(&self.state, record);
91        broadcast(&self.ws_broadcast, event);
92    }
93
94    fn on_link_closed(&mut self, link_id: LinkId, reason: Option<rns_core::link::TeardownReason>) {
95        let record = LinkEventRecord {
96            link_id: to_hex(&link_id.0),
97            event_type: "closed".into(),
98            is_initiator: None,
99            rtt: None,
100            identity_hash: None,
101            reason: reason.map(|r| format!("{:?}", r)),
102        };
103        let event = WsEvent::link(&record);
104        push_link_event(&self.state, record);
105        broadcast(&self.ws_broadcast, event);
106    }
107
108    fn on_remote_identified(
109        &mut self,
110        link_id: LinkId,
111        identity_hash: IdentityHash,
112        _public_key: [u8; 64],
113    ) {
114        let record = LinkEventRecord {
115            link_id: to_hex(&link_id.0),
116            event_type: "identified".into(),
117            is_initiator: None,
118            rtt: None,
119            identity_hash: Some(to_hex(&identity_hash.0)),
120            reason: None,
121        };
122        let event = WsEvent::link(&record);
123        push_link_event(&self.state, record);
124        broadcast(&self.ws_broadcast, event);
125    }
126
127    fn on_resource_received(&mut self, link_id: LinkId, data: Vec<u8>, metadata: Option<Vec<u8>>) {
128        let record = ResourceEventRecord {
129            link_id: to_hex(&link_id.0),
130            event_type: "received".into(),
131            data_base64: Some(to_base64(&data)),
132            metadata_base64: metadata.as_ref().map(|m| to_base64(m)),
133            error: None,
134            received: None,
135            total: None,
136        };
137        let event = WsEvent::resource(&record);
138        push_resource_event(&self.state, record);
139        broadcast(&self.ws_broadcast, event);
140    }
141
142    fn on_resource_completed(&mut self, link_id: LinkId) {
143        let record = ResourceEventRecord {
144            link_id: to_hex(&link_id.0),
145            event_type: "completed".into(),
146            data_base64: None,
147            metadata_base64: None,
148            error: None,
149            received: None,
150            total: None,
151        };
152        let event = WsEvent::resource(&record);
153        push_resource_event(&self.state, record);
154        broadcast(&self.ws_broadcast, event);
155    }
156
157    fn on_resource_failed(&mut self, link_id: LinkId, error: String) {
158        let record = ResourceEventRecord {
159            link_id: to_hex(&link_id.0),
160            event_type: "failed".into(),
161            data_base64: None,
162            metadata_base64: None,
163            error: Some(error),
164            received: None,
165            total: None,
166        };
167        let event = WsEvent::resource(&record);
168        push_resource_event(&self.state, record);
169        broadcast(&self.ws_broadcast, event);
170    }
171
172    fn on_resource_progress(&mut self, link_id: LinkId, received: usize, total: usize) {
173        let record = ResourceEventRecord {
174            link_id: to_hex(&link_id.0),
175            event_type: "progress".into(),
176            data_base64: None,
177            metadata_base64: None,
178            error: None,
179            received: Some(received),
180            total: Some(total),
181        };
182        let event = WsEvent::resource(&record);
183        push_resource_event(&self.state, record);
184        broadcast(&self.ws_broadcast, event);
185    }
186
187    fn on_resource_accept_query(
188        &mut self,
189        _link_id: LinkId,
190        _resource_hash: Vec<u8>,
191        _transfer_size: u64,
192        _has_metadata: bool,
193    ) -> bool {
194        true
195    }
196
197    fn on_channel_message(&mut self, link_id: LinkId, msgtype: u16, payload: Vec<u8>) {
198        let record = PacketRecord {
199            dest_hash: format!("channel:{}:{}", to_hex(&link_id.0), msgtype),
200            packet_hash: String::new(),
201            data_base64: to_base64(&payload),
202            received_at: rns_net::time::now(),
203        };
204        let event = WsEvent::packet(&record);
205        push_packet(&self.state, record);
206        broadcast(&self.ws_broadcast, event);
207    }
208
209    fn on_response(&mut self, link_id: LinkId, request_id: [u8; 16], data: Vec<u8>) {
210        let record = PacketRecord {
211            dest_hash: format!("response:{}:{}", to_hex(&link_id.0), to_hex(&request_id)),
212            packet_hash: String::new(),
213            data_base64: to_base64(&data),
214            received_at: rns_net::time::now(),
215        };
216        let event = WsEvent::packet(&record);
217        push_packet(&self.state, record);
218        broadcast(&self.ws_broadcast, event);
219    }
220
221    fn on_direct_connect_established(&mut self, link_id: LinkId, interface_id: InterfaceId) {
222        let record = LinkEventRecord {
223            link_id: to_hex(&link_id.0),
224            event_type: "direct_established".into(),
225            is_initiator: None,
226            rtt: None,
227            identity_hash: None,
228            reason: Some(format!("interface_id={}", interface_id.0)),
229        };
230        let event = WsEvent::link(&record);
231        push_link_event(&self.state, record);
232        broadcast(&self.ws_broadcast, event);
233    }
234
235    fn on_direct_connect_failed(&mut self, link_id: LinkId, reason: u8) {
236        let record = LinkEventRecord {
237            link_id: to_hex(&link_id.0),
238            event_type: "direct_failed".into(),
239            is_initiator: None,
240            rtt: None,
241            identity_hash: None,
242            reason: Some(format!("reason_code={}", reason)),
243        };
244        let event = WsEvent::link(&record);
245        push_link_event(&self.state, record);
246        broadcast(&self.ws_broadcast, event);
247    }
248}