mip_client/protocol/
header.rs1use 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()); 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}