Skip to main content

wireforge_app/mqtt/
builder.rs

1//! MQTT packet builder.
2
3use 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]; // Connect
14        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; // Publish
24        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]; // Subscribe
43        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}