freeswitch_esl_rs/
data.rs

1extern crate urldecode;
2
3use std::{io, str, error, fmt, string, num};
4use std::collections::HashMap;
5use std::io::{Read, BufReader};
6
7// Pdu (Packet data unit) from Freeswitch mod_event_socket.
8#[derive(Debug, Clone, PartialEq, Eq)]
9pub struct Pdu {
10    inner_header: HashMap<String, String>,
11    content: Vec<u8>
12}
13
14#[derive(Debug)]
15pub enum ParseError {
16    IOError(io::Error),
17    StrError(str::Utf8Error),
18    StringError(string::FromUtf8Error),
19    NumError(num::ParseIntError),
20    FromPduError(FromPduError)
21}
22
23impl fmt::Display for ParseError {
24    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25        write!(f, "{:?}", self)
26    }
27}
28
29impl error::Error for ParseError {
30    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
31        match self {
32            ParseError::IOError(e) => Some(e),
33            ParseError::StrError(e) => Some(e),
34            ParseError::StringError(e) => Some(e),
35            ParseError::NumError(e) => Some(e),
36            ParseError::FromPduError(e) => Some(e)
37        }
38    }
39}
40
41impl From<io::Error> for ParseError {
42    fn from(e: io::Error) -> Self {
43        ParseError::IOError(e)
44    }
45}
46
47impl From<str::Utf8Error> for ParseError {
48    fn from(e: str::Utf8Error) -> Self {
49        ParseError::StrError(e)
50    }
51}
52
53impl From<string::FromUtf8Error> for ParseError {
54    fn from(e: string::FromUtf8Error) -> Self {
55        ParseError::StringError(e)
56    }
57}
58
59impl From<num::ParseIntError> for ParseError {
60    fn from(e: num::ParseIntError) -> Self {
61        ParseError::NumError(e)
62    }
63}
64
65#[derive(Debug)]
66pub struct FromPduError(&'static str);
67
68impl fmt::Display for FromPduError {
69    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70        write!(f, "{:?}", self.0)
71    }
72}
73
74impl error::Error for FromPduError {
75    fn description(&self) -> &str {
76        &self.0
77    }
78}
79
80// casting to another type
81pub trait FromPdu: Sized {
82    type Err;
83
84    fn from_pdu(pdu: &Pdu) -> Result<Self, Self::Err>;
85}
86
87// Get Pdu content as String
88impl FromPdu for String {
89    type Err = ParseError;
90    
91    fn from_pdu(pdu: &Pdu) -> Result<Self, Self::Err> {
92        let content: String = str::from_utf8(&pdu.content)?.to_string();
93        Ok(content)
94    }
95}
96
97type Header = HashMap<String, String>;
98
99fn header_parse(content: String) -> Header {
100    let mut header = Header::new();
101
102    content
103        .split('\n')
104        .filter(|line| {
105            !line.is_empty()
106        })
107        .for_each(|line| {
108
109            let mut item = line.splitn(2, ':');
110            // TODO una libreria deberia hacer esto? pues no ome
111            let key = item.next().unwrap().trim().to_string();
112            let value = item.next().unwrap().trim().to_string();
113
114            header.insert(key, urldecode::decode(value));
115        });
116
117    header
118}
119
120impl Pdu {
121   pub fn header(&self, k: &str) -> String {
122        match self.inner_header.get(k) {
123            Some(v) => v.to_string(),
124            None => "".to_string()
125        }
126    }
127
128    pub fn is_empty(&self) -> bool {
129        self.content.len() == 0
130    }
131
132    // Parse Pdu to another type.
133    pub fn parse<F: FromPdu>(&self) -> Result<F, F::Err> {
134        FromPdu::from_pdu(self)
135    }
136
137    fn get(&self, k: &str) -> String {
138        match self.inner_header.get(k) {
139            Some(v) => v.to_string(),
140            None => "".to_string()
141        }
142    }
143}
144
145pub struct PduParser {
146}
147
148impl PduParser {
149    pub fn parse<R: Read>(reader: &mut BufReader<R>) -> Result<Pdu, ParseError> {
150        let header = Self::parse_header(reader)?;
151        let content = Self::parse_content(&header, reader)?;
152
153        let pdu = Pdu {
154            inner_header: header,
155            content: content
156        };
157
158        Ok(pdu)
159    }
160
161    fn parse_header(reader: &mut impl io::BufRead) -> Result<Header, ParseError> {
162        let raw = Self::get_header_content(reader)?;
163        let raw_str = String::from_utf8(raw)?;
164        let header = header_parse(raw_str);
165
166        Ok(header)
167    }
168
169    fn parse_content(header: &Header, reader: &mut impl io::BufRead) -> Result<Vec<u8>, ParseError> {
170        if let Some(length) = header.get("Content-Length") {
171            let length: usize = length.parse()?;
172
173            let mut content = vec![0u8; length];
174            reader.read_exact(&mut content)?;
175
176            return Ok(content)
177        }
178
179        Ok(vec![0u8; 0])
180    }
181
182    fn get_header_content(reader: &mut impl io::BufRead) -> io::Result<Vec<u8>> {
183        let mut raw: Vec<u8> = Vec::with_capacity(1024);
184        let mut buf: Vec<u8> = Vec::with_capacity(1024);
185
186        loop {
187            buf.clear();
188            let readed_bytes = reader.read_until(b'\n', &mut buf)?;
189
190            if readed_bytes == 0 {
191                // necesitamos reflejar el tamano
192                // de lo contraro raw queda inicializado
193                // en el tamano de la capacidad
194                raw.truncate(0);
195                break;
196            } else if readed_bytes == 1 && buf[0] == b'\n' {
197                break;
198            } else {
199                raw.append(&mut buf);
200            }
201        }
202
203        Ok(raw)
204    }
205}
206
207#[derive(Debug, Clone, PartialEq, Eq)]
208pub struct Event {
209    inner: Header,
210    length: usize
211}
212
213impl Event {
214    // Return value of [`k`]
215    pub fn get(&self, k: &str) -> Option<&String> {
216        self.inner.get(k)
217    }
218
219    // Returns the length of the event.
220    pub fn len(&self) -> usize {
221        self.length
222    }
223
224}
225
226impl Into<Header> for Event {
227    fn into(self) -> Header {
228        self.inner.clone()
229    }
230}
231
232impl FromPdu for Event {
233    type Err = ParseError;
234
235    fn from_pdu(pdu: &Pdu) -> Result<Self, Self::Err> {
236        if pdu.get("Content-Type") == "text/event-plain" {
237            let raw = str::from_utf8(&pdu.content)?;
238            let length = raw.len();
239            let content = String::from(raw);
240            let header = header_parse(content);
241            Ok(Event{inner: header, length: length})
242        } else {
243            Err(ParseError::FromPduError(FromPduError("invalid content-type expected text/event-plain")))
244        }
245    }
246}
247
248#[cfg(test)]
249mod tests {
250    use super::*;
251
252    #[test]
253    fn it_event_into_hashmap() -> Result<(), &'static str> {
254        let mut header = Header::new();
255        header.insert("Event-Name".to_string(), "TEST".to_string());
256        let event = Event{inner: header.clone(), length: 99};
257
258        let new_header: Header = event.into();
259        assert_eq!(header, new_header);
260        Ok(())
261    }
262}