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