1pub mod tcp;
4pub mod tcp_server;
5pub mod udp;
6pub mod local;
7pub mod serial_iface;
8pub mod kiss_iface;
9pub mod pipe;
10pub mod rnode;
11pub mod backbone;
12pub mod auto;
13pub mod i2p;
14
15use std::io;
16
17use rns_core::transport::types::{InterfaceId, InterfaceInfo};
18use crate::ifac::IfacState;
19
20pub trait Writer: Send {
24 fn send_frame(&mut self, data: &[u8]) -> io::Result<()>;
25}
26
27const ANNOUNCE_SAMPLE_MAX: usize = 6;
29
30#[derive(Debug, Clone, Default)]
32pub struct InterfaceStats {
33 pub rxb: u64,
34 pub txb: u64,
35 pub rx_packets: u64,
36 pub tx_packets: u64,
37 pub started: f64,
38 pub ia_timestamps: Vec<f64>,
40 pub oa_timestamps: Vec<f64>,
42}
43
44impl InterfaceStats {
45 pub fn record_incoming_announce(&mut self, now: f64) {
47 self.ia_timestamps.push(now);
48 if self.ia_timestamps.len() > ANNOUNCE_SAMPLE_MAX {
49 self.ia_timestamps.remove(0);
50 }
51 }
52
53 pub fn record_outgoing_announce(&mut self, now: f64) {
55 self.oa_timestamps.push(now);
56 if self.oa_timestamps.len() > ANNOUNCE_SAMPLE_MAX {
57 self.oa_timestamps.remove(0);
58 }
59 }
60
61 fn compute_frequency(timestamps: &[f64]) -> f64 {
63 if timestamps.len() < 2 {
64 return 0.0;
65 }
66 let span = timestamps[timestamps.len() - 1] - timestamps[0];
67 if span <= 0.0 {
68 return 0.0;
69 }
70 (timestamps.len() - 1) as f64 / span
71 }
72
73 pub fn incoming_announce_freq(&self) -> f64 {
75 Self::compute_frequency(&self.ia_timestamps)
76 }
77
78 pub fn outgoing_announce_freq(&self) -> f64 {
80 Self::compute_frequency(&self.oa_timestamps)
81 }
82}
83
84pub struct InterfaceEntry {
86 pub id: InterfaceId,
87 pub info: InterfaceInfo,
88 pub writer: Box<dyn Writer>,
89 pub online: bool,
90 pub dynamic: bool,
93 pub ifac: Option<IfacState>,
95 pub stats: InterfaceStats,
97 pub interface_type: String,
99}
100
101#[cfg(test)]
102mod tests {
103 use super::*;
104 use rns_core::constants;
105
106 struct MockWriter {
107 sent: Vec<Vec<u8>>,
108 }
109
110 impl MockWriter {
111 fn new() -> Self {
112 MockWriter { sent: Vec::new() }
113 }
114 }
115
116 impl Writer for MockWriter {
117 fn send_frame(&mut self, data: &[u8]) -> io::Result<()> {
118 self.sent.push(data.to_vec());
119 Ok(())
120 }
121 }
122
123 #[test]
124 fn interface_entry_construction() {
125 let entry = InterfaceEntry {
126 id: InterfaceId(1),
127 info: InterfaceInfo {
128 id: InterfaceId(1),
129 name: String::new(),
130 mode: constants::MODE_FULL,
131 out_capable: true,
132 in_capable: true,
133 bitrate: None,
134 announce_rate_target: None,
135 announce_rate_grace: 0,
136 announce_rate_penalty: 0.0,
137 announce_cap: constants::ANNOUNCE_CAP,
138 is_local_client: false,
139 wants_tunnel: false,
140 tunnel_id: None,
141 },
142 writer: Box::new(MockWriter::new()),
143 online: false,
144 dynamic: false,
145 ifac: None,
146 stats: InterfaceStats::default(),
147 interface_type: String::new(),
148 };
149 assert_eq!(entry.id, InterfaceId(1));
150 assert!(!entry.online);
151 assert!(!entry.dynamic);
152 }
153
154 #[test]
155 fn mock_writer_captures_bytes() {
156 let mut writer = MockWriter::new();
157 writer.send_frame(b"hello").unwrap();
158 writer.send_frame(b"world").unwrap();
159 assert_eq!(writer.sent.len(), 2);
160 assert_eq!(writer.sent[0], b"hello");
161 assert_eq!(writer.sent[1], b"world");
162 }
163
164 #[test]
165 fn writer_send_frame_produces_output() {
166 let mut writer = MockWriter::new();
167 let data = vec![0x01, 0x02, 0x03];
168 writer.send_frame(&data).unwrap();
169 assert_eq!(writer.sent[0], data);
170 }
171}