Skip to main content

rns_ctl/
bridge.rs

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