wireforge_app/mqtt/
builder.rs1use super::parser::write_remaining_length;
4
5pub struct MqttPacketBuilder;
6
7impl MqttPacketBuilder {
8 pub fn connect(client_id: &str) -> Vec<u8> {
9 let mut payload = vec![0x00, 0x04, b'M', b'Q', b'T', b'T', 4u8, 0x02u8];
10 payload.extend_from_slice(&60u16.to_be_bytes());
11 payload.extend_from_slice(&(client_id.len() as u16).to_be_bytes());
12 payload.extend_from_slice(client_id.as_bytes());
13 let mut pkt = vec![0x10u8]; pkt.extend_from_slice(&write_remaining_length(payload.len() as u32));
15 pkt.extend_from_slice(&payload);
16 pkt
17 }
18
19 pub fn publish(topic: &str, payload: &[u8], qos: u8, retain: bool) -> Vec<u8> {
20 let mut vh = vec![];
21 vh.extend_from_slice(&(topic.len() as u16).to_be_bytes());
22 vh.extend_from_slice(topic.as_bytes());
23 let mut type_byte = 0x30; type_byte |= (qos & 0x03) << 1;
25 if retain { type_byte |= 0x01; }
26 let total = vh.len() + payload.len();
27 let mut pkt = vec![type_byte];
28 pkt.extend_from_slice(&write_remaining_length(total as u32));
29 pkt.extend_from_slice(&vh);
30 pkt.extend_from_slice(payload);
31 pkt
32 }
33
34 pub fn subscribe(packet_id: u16, topics: &[(&str, u8)]) -> Vec<u8> {
35 let mut payload = vec![];
36 payload.extend_from_slice(&packet_id.to_be_bytes());
37 for (topic, qos) in topics {
38 payload.extend_from_slice(&(topic.len() as u16).to_be_bytes());
39 payload.extend_from_slice(topic.as_bytes());
40 payload.push(*qos & 0x03);
41 }
42 let mut pkt = vec![0x82u8]; pkt.extend_from_slice(&write_remaining_length(payload.len() as u32));
44 pkt.extend_from_slice(&payload);
45 pkt
46 }
47}
48
49#[cfg(test)]
50mod tests {
51 use super::*;
52 use crate::mqtt::parser::MqttPacket;
53 use crate::mqtt::types::MqttPacketType;
54
55 #[test]
56 fn build_connect_roundtrip() {
57 let pkt = MqttPacketBuilder::connect("sensor1");
58 let parsed = MqttPacket::parse(&pkt).unwrap();
59 assert_eq!(parsed.packet_type(), MqttPacketType::Connect);
60 }
61}