libaprs_engine/
transport.rs1use std::io::{self, Read};
2
3use crate::MAX_PACKET_LEN;
4
5pub const DEFAULT_TRANSPORT_READ_LIMIT: usize = 1024 * 1024;
7
8#[derive(Clone, Copy, Debug, Eq, PartialEq)]
10pub enum TransportErrorCode {
11 OversizedInput,
13 InvalidFrame,
15 UnexpectedEof,
17 Timeout,
19 Io,
21}
22
23impl TransportErrorCode {
24 #[must_use]
26 pub const fn code(self) -> &'static str {
27 match self {
28 Self::OversizedInput => "transport.oversized_input",
29 Self::InvalidFrame => "transport.invalid_frame",
30 Self::UnexpectedEof => "transport.unexpected_eof",
31 Self::Timeout => "transport.timeout",
32 Self::Io => "transport.io",
33 }
34 }
35}
36
37pub trait PacketSource {
39 type Error;
41
42 fn recv_packets(&mut self) -> Result<Vec<Vec<u8>>, Self::Error>;
44}
45
46pub trait PacketSink {
48 type Error;
50
51 fn send_packet(&mut self, packet: &[u8]) -> Result<(), Self::Error>;
53}
54
55pub fn read_all_with_limit(mut reader: impl Read, max_bytes: usize) -> io::Result<Vec<u8>> {
57 let mut input = Vec::new();
58 let mut limited = (&mut reader).take(max_bytes.saturating_add(1) as u64);
59 limited.read_to_end(&mut input)?;
60 if input.len() > max_bytes {
61 return Err(oversized_input_error());
62 }
63 Ok(input)
64}
65
66#[must_use]
68pub fn oversized_input_error() -> io::Error {
69 io::Error::new(
70 io::ErrorKind::InvalidData,
71 TransportErrorCode::OversizedInput.code(),
72 )
73}
74
75#[derive(Clone, Debug, Eq, PartialEq)]
77pub struct LineTransport<'a> {
78 input: &'a [u8],
79}
80
81impl<'a> LineTransport<'a> {
82 #[must_use]
84 pub fn new(input: &'a [u8]) -> Self {
85 Self { input }
86 }
87
88 #[must_use]
90 pub fn packets(&self) -> Vec<&'a [u8]> {
91 self.input
92 .split(|byte| *byte == b'\n')
93 .map(trim_trailing_carriage_return)
94 .filter(|line| !line.is_empty())
95 .collect()
96 }
97
98 pub fn packets_with_limit(&self, max_packet_len: usize) -> io::Result<Vec<&'a [u8]>> {
103 let mut packets = Vec::new();
104 for line in self
105 .input
106 .split(|byte| *byte == b'\n')
107 .map(trim_trailing_carriage_return)
108 .filter(|line| !line.is_empty())
109 {
110 if line.len() > max_packet_len {
111 return Err(oversized_input_error());
112 }
113 packets.push(line);
114 }
115 Ok(packets)
116 }
117}
118
119impl PacketSource for LineTransport<'_> {
120 type Error = io::Error;
121
122 fn recv_packets(&mut self) -> Result<Vec<Vec<u8>>, Self::Error> {
123 Ok(self
124 .packets_with_limit(MAX_PACKET_LEN)?
125 .into_iter()
126 .map(<[u8]>::to_vec)
127 .collect())
128 }
129}
130
131impl PacketSink for Vec<Vec<u8>> {
132 type Error = io::Error;
133
134 fn send_packet(&mut self, packet: &[u8]) -> Result<(), Self::Error> {
135 self.push(packet.to_vec());
136 Ok(())
137 }
138}
139
140fn trim_trailing_carriage_return(line: &[u8]) -> &[u8] {
141 line.strip_suffix(b"\r").unwrap_or(line)
142}