Skip to main content

mip_client/protocol/
header.rs

1use std::convert::TryFrom;
2
3use bitflags::bitflags;
4
5pub const MSIP_MAGIC: [u8; 4] = *b"MSIP";
6pub const MSIP_VERSION: u8 = 1;
7pub const HEADER_SIZE: usize = 24;
8
9bitflags! {
10    #[derive(Debug, Clone, Copy)]
11    pub struct FrameFlags: u8 {
12        const NONE         = 0b0000_0000;
13        const ACK_REQUIRED = 0b0000_0001;
14        const COMPRESSED   = 0b0000_0010;
15        const URGENT       = 0b0000_0100;
16    }
17}
18
19#[repr(u16)]
20#[derive(Debug, Clone, Copy, PartialEq, Eq)]
21pub enum FrameType {
22    Hello = 0x0001,
23    Subscribe = 0x0002,
24    Unsubscribe = 0x0003,
25    Publish = 0x0004,
26    Event = 0x0005,
27    Ack = 0x0006,
28    Error = 0x0007,
29    Ping = 0x0008,
30    Pong = 0x0009,
31    Close = 0x000A,
32}
33
34impl TryFrom<u16> for FrameType {
35    type Error = ();
36
37    fn try_from(value: u16) -> Result<Self, <Self as TryFrom<u16>>::Error> {
38        Ok(match value {
39            0x0001 => Self::Hello,
40            0x0002 => Self::Subscribe,
41            0x0003 => Self::Unsubscribe,
42            0x0004 => Self::Publish,
43            0x0005 => Self::Event,
44            0x0006 => Self::Ack,
45            0x0007 => Self::Error,
46            0x0008 => Self::Ping,
47            0x0009 => Self::Pong,
48            0x000A => Self::Close,
49            _ => return Err(()),
50        })
51    }
52}
53
54#[repr(u16)]
55#[derive(Debug, Clone, Copy, PartialEq, Eq)]
56pub enum MessageKind {
57    Event = 0x0001,
58    Command = 0x0002,
59    State = 0x0003,
60    Log = 0x0004,
61    Metric = 0x0005,
62}
63
64impl TryFrom<u16> for MessageKind {
65    type Error = ();
66
67    fn try_from(value: u16) -> Result<Self, <Self as TryFrom<u16>>::Error> {
68        Ok(match value {
69            0x0001 => Self::Event,
70            0x0002 => Self::Command,
71            0x0003 => Self::State,
72            0x0004 => Self::Log,
73            0x0005 => Self::Metric,
74            _ => return Err(()),
75        })
76    }
77}
78
79#[derive(Debug, Clone)]
80pub struct Header {
81    pub magic: [u8; 4],
82    pub version: u8,
83    pub flags: FrameFlags,
84    pub frame_type: FrameType,
85    pub msg_kind: MessageKind,
86    pub payload_len: u32,
87    pub msg_id: u64,
88}
89
90impl Header {
91    pub fn new(
92        frame_type: FrameType,
93        msg_kind: MessageKind,
94        payload_len: u32,
95        msg_id: u64,
96        flags: FrameFlags,
97    ) -> Self {
98        Self {
99            magic: MSIP_MAGIC,
100            version: MSIP_VERSION,
101            flags,
102            frame_type,
103            msg_kind,
104            payload_len,
105            msg_id,
106        }
107    }
108
109    pub fn encode(&self) -> [u8; HEADER_SIZE] {
110        let mut buf = [0u8; HEADER_SIZE];
111
112        buf[0..4].copy_from_slice(&self.magic);
113        buf[4] = self.version;
114        buf[5] = self.flags.bits();
115
116        buf[6..8].copy_from_slice(&(self.frame_type as u16).to_be_bytes());
117        buf[8..10].copy_from_slice(&(self.msg_kind as u16).to_be_bytes());
118        buf[10..12].copy_from_slice(&0u16.to_be_bytes()); // reserved
119
120        buf[12..16].copy_from_slice(&self.payload_len.to_be_bytes());
121        buf[16..24].copy_from_slice(&self.msg_id.to_be_bytes());
122
123        buf
124    }
125}
126
127impl TryFrom<[u8; HEADER_SIZE]> for Header {
128    type Error = &'static str;
129
130    fn try_from(buf: [u8; HEADER_SIZE]) -> Result<Self, Self::Error> {
131        if buf[0..4] != MSIP_MAGIC {
132            return Err("invalid magic");
133        }
134
135        let version = buf[4];
136        if version != MSIP_VERSION {
137            return Err("unsupported version");
138        }
139
140        let flags = FrameFlags::from_bits_truncate(buf[5]);
141        if flags.bits() & !FrameFlags::all().bits() != 0 {
142            return Err("invalid flags");
143        }
144
145        let frame_type = FrameType::try_from(u16::from_be_bytes([buf[6], buf[7]]))
146            .map_err(|_| "invalid frame type")?;
147
148        let msg_kind = MessageKind::try_from(u16::from_be_bytes([buf[8], buf[9]]))
149            .map_err(|_| "invalid message kind")?;
150
151        Ok(Self {
152            magic: MSIP_MAGIC,
153            version: buf[4],
154            flags,
155            frame_type,
156            msg_kind,
157            payload_len: u32::from_be_bytes([buf[12], buf[13], buf[14], buf[15]]),
158            msg_id: u64::from_be_bytes([
159                buf[16], buf[17], buf[18], buf[19], buf[20], buf[21], buf[22], buf[23],
160            ]),
161        })
162    }
163}