photon_decode/
lib.rs

1mod decode;
2mod error;
3mod layout;
4
5pub use decode::*;
6use error::*;
7pub use layout::*;
8
9use std::collections::HashMap;
10use std::convert::TryFrom;
11use std::io::Cursor;
12
13impl TryFrom<(&ReliableCommand, &mut Cursor<&[u8]>)> for Message {
14    type Error = PhotonDecodeError;
15
16    fn try_from(message: (&ReliableCommand, &mut Cursor<&[u8]>)) -> Result<Self, Self::Error> {
17        let (command, cursor) = message;
18        let _: u8 = cursor.decode()?;
19        let msg_type: u8 = cursor.decode()?;
20        match msg_type {
21            2 => {
22                let v = cursor.decode().map_err(|e| e.extend("Request".into()))?;
23                Ok(Message::Request(v))
24            }
25            3 => {
26                let v = cursor.decode().map_err(|e| e.extend("Response".into()))?;
27                Ok(Message::Response(v))
28            }
29            4 => {
30                let v = cursor.decode().map_err(|e| e.extend("Event".into()))?;
31                Ok(Message::Event(v))
32            }
33            _ => {
34                let msg_header_len = 2;
35                cursor.set_position(cursor.position() + command.msg_len as u64 - msg_header_len);
36                Err(PhotonDecodeError::from(format!(
37                    "Unknown message ({:#X})",
38                    msg_type
39                )))
40            }
41        }
42    }
43}
44
45pub struct Photon {
46    fragments: HashMap<u32, Vec<ReliableFragment>>,
47}
48
49impl Photon {
50    pub fn new() -> Self {
51        Self {
52            fragments: HashMap::new(),
53        }
54    }
55
56    pub fn try_decode(
57        &mut self,
58        payload: &[u8],
59    ) -> PhotonDecodeResult<Vec<PhotonDecodeResult<Message>>> {
60        let mut cursor = Cursor::new(payload);
61        Ok(
62            (0..Decode::<PhotonHeader>::decode(&mut cursor)?.command_count)
63                .into_iter()
64                .map(|_| {
65                    Decode::<Command>::decode(&mut cursor).map_or_else(
66                        |e| Some(Err(e)),
67                        |command| match command {
68                            Command::SendReliable(c) | Command::SendUnreliable(c) => Some(
69                                Message::try_from((&c, &mut cursor))
70                                    .map_err(|e| e.extend("SendReliable".into())),
71                            ),
72                            Command::SendReliableFragment(fragment) => {
73                                self.fragments
74                                    .entry(fragment.sequence_number)
75                                    .or_insert(vec![])
76                                    .push(fragment.clone());
77                                self.decode_reliable_fragment(&fragment).map(|msg| {
78                                    self.fragments.remove(&fragment.sequence_number).unwrap();
79                                    msg.map_err(|e| e.extend("Fragment".into()))
80                                })
81                            }
82                            _ => None,
83                        },
84                    )
85                })
86                .filter_map(|v| v)
87                .collect(),
88        )
89    }
90
91    pub fn decode(&mut self, payload: &[u8]) -> Vec<Message> {
92        if let Ok(messages) = self.try_decode(payload) {
93            return messages.into_iter().filter_map(Result::ok).collect();
94        }
95        vec![]
96    }
97
98    fn decode_reliable_fragment(
99        &mut self,
100        fragment: &ReliableFragment,
101    ) -> Option<PhotonDecodeResult<Message>> {
102        if let Some(fragments) = self.fragments.get(&fragment.sequence_number) {
103            if fragments.len() == fragment.fragment_count as usize {
104                let mut buf = Vec::<u8>::new();
105                for fragment in fragments {
106                    buf.extend(fragment.payload.iter());
107                }
108                let mut c = Cursor::new(&buf[..]);
109                return Some(Message::try_from((&fragment.reliable_command, &mut c)));
110            }
111        }
112        None
113    }
114}