DEVELOPMENT ENVIRONMENT

~liljamo/emerwen

ref: 33e3c26e7068aa62b035e150b5e4e0d6014607ee emerwen/emerwen-protocol/src/payload.rs -rw-r--r-- 3.8 KiB
33e3c26eJonni Liljamo feat: initial monitoring work, protocol changes 14 days ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
use byteorder::{BigEndian, ReadBytesExt};

use crate::DecodeError;

/// Message Payload
///
/// Byte representation:
/// | [u8]                                     |
/// | content bytes, structure varies per type |
#[derive(Debug, PartialEq)]
pub enum MessagePayload {
    /// Master -> Worker authentication.
    Authentication { key: String },
    /// Master -> Worker target configuration.
    /*ConfigureTarget {
        target_id: u16,
        method: TargetMethod,
        addr: String
    },*/
    /// Worker -> Master target up.
    TargetUp {
        /// ID of the target.
        target_id: u16,
    },
    /// Worker -> Master target down.
    TargetDown {
        /// ID of the target.
        target_id: u16,
    },
    /// Worker -> Master target unknown.
    TargetUnknown {
        /// ID of the target.
        target_id: u16,
    },
}

impl From<&MessagePayload> for u8 {
    fn from(message: &MessagePayload) -> u8 {
        match message {
            MessagePayload::Authentication { .. } => 0,
            MessagePayload::TargetUp { .. } => 1,
            MessagePayload::TargetDown { .. } => 2,
            MessagePayload::TargetUnknown { .. } => 3,
        }
    }
}

impl MessagePayload {
    pub fn encode(&self) -> Vec<u8> {
        let mut buf: Vec<u8> = Vec::new();

        match self {
            MessagePayload::Authentication { key } => {
                // Key length
                buf.extend((key.len() as u32).to_be_bytes());
                // Key
                buf.extend(key.as_bytes());
            }
            MessagePayload::TargetUp { target_id } => {
                buf.extend(target_id.to_be_bytes());
            }
            MessagePayload::TargetDown { target_id } => {
                buf.extend(target_id.to_be_bytes());
            }
            MessagePayload::TargetUnknown { target_id } => {
                buf.extend(target_id.to_be_bytes());
            }
        }

        buf
    }

    pub fn decode(
        payload_type: u8,
        buf: &mut impl std::io::Read,
    ) -> Result<MessagePayload, Box<dyn std::error::Error>> {
        let payload = match payload_type {
            0 => {
                let key_length = buf.read_u32::<BigEndian>()?;
                let mut key_bytes = vec![0; key_length as usize];
                buf.read_exact(&mut key_bytes)?;
                MessagePayload::Authentication {
                    key: String::from_utf8(key_bytes)?,
                }
            }
            1 => MessagePayload::TargetUp {
                target_id: buf.read_u16::<BigEndian>()?,
            },
            2 => MessagePayload::TargetDown {
                target_id: buf.read_u16::<BigEndian>()?,
            },
            3 => MessagePayload::TargetUnknown {
                target_id: buf.read_u16::<BigEndian>()?,
            },
            _ => return Err(Box::new(DecodeError::InvalidPayloadType(payload_type))),
        };

        Ok(payload)
    }
}

#[test]
fn test_round_trip_payload_authentication() {
    let sent_payload = MessagePayload::Authentication {
        key: "this_is_a_key".to_owned(),
    };

    let sent_payload_bytes = sent_payload.encode();
    let sent_payload_type = (&sent_payload).into();

    let mut reader = std::io::Cursor::new(sent_payload_bytes);
    let received_payload = MessagePayload::decode(sent_payload_type, &mut reader).unwrap();

    assert_eq!(sent_payload, received_payload);
}

#[test]
fn test_round_trip_payload_target_up() {
    let sent_payload = MessagePayload::TargetUp { target_id: 42 };

    let sent_payload_bytes = sent_payload.encode();
    let sent_payload_type = (&sent_payload).into();

    let mut reader = std::io::Cursor::new(sent_payload_bytes);
    let received_payload = MessagePayload::decode(sent_payload_type, &mut reader).unwrap();

    assert_eq!(sent_payload, received_payload);
}