use std::fmt;
use std::io::{Error, Read, Write};
use byteorder::{ReadBytesExt, WriteBytesExt};
use crate::*;
#[derive(Clone, Debug)]
pub struct Notification {
pub major_err_code: u8,
pub minor_err_code: u8,
pub data: Vec<u8>,
}
impl Notification {
pub fn parse(header: &Header, stream: &mut impl Read) -> Result<Notification, Error> {
let major_err_code = stream.read_u8()?;
let minor_err_code = stream.read_u8()?;
let data = if header.length > 21 {
let remaining_length = header.length as usize - 21;
let mut data = vec![0; remaining_length as usize];
stream.read_exact(&mut data)?;
data
} else {
vec![]
};
Ok(Notification {
major_err_code,
minor_err_code,
data,
})
}
pub fn encode(&self, buf: &mut impl Write) -> Result<(), Error> {
buf.write_u8(self.major_err_code)?;
buf.write_u8(self.minor_err_code)?;
buf.write_all(&self.data)
}
pub fn major(&self) -> String {
match self.major_err_code {
1 => "Message Header Error".to_string(),
2 => "OPEN Message Error".to_string(),
3 => "UPDATE Message Error".to_string(),
4 => "Hold Timer Expired".to_string(),
5 => "Finite State Machine".to_string(),
6 => "Cease".to_string(),
_ => format!("Major Code {}", self.major_err_code),
}
}
pub fn minor(&self) -> String {
format!("{}", self.minor_err_code)
}
pub fn message(&self) -> Option<String> {
String::from_utf8(self.data.clone()).ok()
}
}
impl fmt::Display for Notification {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{} / {} {}",
self.major(),
self.minor(),
self.message().unwrap_or_else(|| "".to_string())
)
}
}
#[test]
fn test_notification_display() {
let notification = Notification {
major_err_code: 6,
minor_err_code: 3,
data: vec![],
};
assert_eq!(¬ification.to_string(), "Cease / 3 ");
let notification = Notification {
major_err_code: 2,
minor_err_code: 1,
data: b"Unsupported Capability".to_vec(),
};
assert_eq!(
¬ification.to_string(),
"OPEN Message Error / 1 Unsupported Capability"
);
}