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
use super::*;
use std::convert::TryFrom;
use std::error::Error as stdError;

fn random_token(buffer: &[u8]) -> u16 {
    (buffer[1] as u16) << 8 | buffer[2] as u16
}

pub fn gateway_mac(buffer: &[u8]) -> MacAddress {
    MacAddress::new(array_ref![buffer, 0, 8])
}

pub trait Parser {
    fn parse(buffer: &[u8], num_recv: usize) -> std::result::Result<Packet, Box<dyn stdError>>;
}

impl Parser for Packet {
    fn parse(buffer: &[u8], num_recv: usize) -> std::result::Result<Packet, Box<dyn stdError>> {
        if buffer[0] != PROTOCOL_VERSION {
            Err(Error::InvalidProtocolVersion.into())
        } else if let Ok(id) = Identifier::try_from(buffer[3]) {
            // all packets have random_token
            let random_token = random_token(buffer);
            Ok(match id {
                // up packets
                Identifier::PullData => {
                    let gateway_mac = gateway_mac(&buffer[4..12]);
                    pull_data::Packet {
                        random_token,
                        gateway_mac,
                    }
                    .into()
                }
                Identifier::PushData => {
                    let gateway_mac = gateway_mac(&buffer[4..12]);
                    let json_str = std::str::from_utf8(&buffer[12..num_recv])?;
                    let data = serde_json::from_str(json_str)?;
                    push_data::Packet {
                        random_token,
                        gateway_mac,
                        data,
                    }
                    .into()
                }
                Identifier::TxAck => {
                    let gateway_mac = gateway_mac(&buffer[4..12]);
                    tx_ack::Packet {
                        random_token,
                        gateway_mac,
                    }
                    .into()
                }
                // down packets
                Identifier::PushAck => push_ack::Packet { random_token }.into(),
                Identifier::PullAck => pull_ack::Packet { random_token }.into(),
                Identifier::PullResp => {
                    let json_str = std::str::from_utf8(&buffer[4..num_recv])?;
                    let data = serde_json::from_str(json_str)?;
                    pull_resp::Packet { random_token, data }.into()
                }
            })
        } else {
            Err(Error::InvalidIdentifier.into())
        }
    }
}

use std::{fmt, str};

#[derive(Debug, Clone)]
pub enum Error {
    InvalidProtocolVersion,
    InvalidIdentifier,
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Error::InvalidProtocolVersion => {
                write!(f, "Invalid protocol version (byte 0 in UDP frame)")
            }
            Error::InvalidIdentifier => {
                write!(f, "Invalid message identifier (byte 3 in UDP frame)")
            }
        }
    }
}

impl stdError for Error {
    fn description(&self) -> &str {
        match self {
            Error::InvalidProtocolVersion => "Invalid protocol version (byte 0 in UDP frame)",
            Error::InvalidIdentifier => "Invalid message identifier (byte 3 in UDP frame)",
        }
    }

    fn cause(&self) -> Option<&dyn stdError> {
        // Generic error, underlying cause isn't tracked.
        None
    }
}