1use flood_rs::prelude::{InOctetStream, OutOctetStream};
6use hexify::format_hex;
7use log::trace;
8use metricator::{AggregateMetric, MinMaxAvg};
9
10use nimble_ordered_datagram::{DatagramOrderInError, OrderedIn, OrderedOut};
11use std::io;
12
13#[derive(Debug)]
14pub struct NimbleLayer {
15 ordered_datagram_out: OrderedOut,
16 ordered_in: OrderedIn,
17 datagram_drops: AggregateMetric<u16>,
18}
19
20impl Default for NimbleLayer {
21 fn default() -> Self {
22 Self {
23 ordered_datagram_out: OrderedOut::default(),
24 ordered_in: OrderedIn::default(),
25 datagram_drops: AggregateMetric::new(16).expect("threshold should be ok"),
26 }
27 }
28}
29
30#[derive(Debug)]
31pub enum NimbleLayerError {
32 IoError(io::Error),
33 DatagramInOrderError(DatagramOrderInError),
34 MillisFromLowerError,
35 AbsoluteTimeError,
36}
37
38impl From<DatagramOrderInError> for NimbleLayerError {
39 fn from(err: DatagramOrderInError) -> Self {
40 Self::DatagramInOrderError(err)
41 }
42}
43
44impl From<io::Error> for NimbleLayerError {
45 fn from(err: io::Error) -> Self {
46 Self::IoError(err)
47 }
48}
49
50const ORDERED_DATAGRAM_OCTETS: usize = 2;
51
52impl NimbleLayer {
53 #[must_use]
54 #[allow(clippy::missing_panics_doc)]
55 pub fn new() -> Self {
56 Self {
57 ordered_datagram_out: OrderedOut::default(),
58 ordered_in: OrderedIn::default(),
59 datagram_drops: AggregateMetric::<u16>::new(10).unwrap(),
60 }
61 }
62
63 pub fn send(&mut self, datagrams: &Vec<Vec<u8>>) -> Result<Vec<Vec<u8>>, io::Error> {
67 let mut packet = [0u8; 1200];
68 let mut out_datagrams: Vec<Vec<u8>> = vec![];
69
70 for datagram in datagrams {
71 let mut stream = OutOctetStream::new();
72
73 self.ordered_datagram_out.to_stream(&mut stream)?;
74
75 packet[0..ORDERED_DATAGRAM_OCTETS].copy_from_slice(stream.octets_ref());
76 packet[ORDERED_DATAGRAM_OCTETS..ORDERED_DATAGRAM_OCTETS + datagram.len()]
77 .copy_from_slice(datagram);
78
79 let complete_datagram = packet[0..ORDERED_DATAGRAM_OCTETS + datagram.len()].to_vec();
80 out_datagrams.push(complete_datagram);
81 self.ordered_datagram_out.commit();
82 }
83
84 Ok(out_datagrams)
85 }
86
87 pub fn receive<'a>(&mut self, datagram: &'a [u8]) -> Result<&'a [u8], NimbleLayerError> {
91 let mut in_stream = InOctetStream::new(datagram);
92 let dropped_packets = self.ordered_in.read_and_verify(&mut in_stream)?;
93 self.datagram_drops.add(dropped_packets.inner());
94
95 let slice = &datagram[ORDERED_DATAGRAM_OCTETS..];
96 trace!(
97 "nimble-layer host received without header\n{}",
98 format_hex(slice)
99 );
100 Ok(slice)
101 }
102
103 #[must_use]
104 pub fn datagram_drops(&self) -> Option<MinMaxAvg<u16>> {
105 self.datagram_drops.values()
106 }
107}