use crate::{actions::Action, types::TypedData, varint::encode_varint};
use nom::error::ErrorKind;
use std::collections::HashMap;
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
pub enum FrameType {
HaproxyHello = 1,
HaproxyDisconnect = 2,
Notify = 3,
AgentHello = 101,
AgentDisconnect = 102,
Ack = 103,
}
impl FrameType {
pub const fn from_u8(value: u8) -> Result<Self, ErrorKind> {
match value {
1 => Ok(Self::HaproxyHello),
2 => Ok(Self::HaproxyDisconnect),
3 => Ok(Self::Notify),
101 => Ok(Self::AgentHello),
102 => Ok(Self::AgentDisconnect),
103 => Ok(Self::Ack),
_ => Err(ErrorKind::Alt),
}
}
pub const fn to_u8(&self) -> u8 {
match self {
Self::HaproxyHello => 1,
Self::HaproxyDisconnect => 2,
Self::Notify => 3,
Self::AgentHello => 101,
Self::AgentDisconnect => 102,
Self::Ack => 103,
}
}
}
#[derive(Debug, Clone, Default)]
pub struct Metadata {
pub flags: FrameFlags,
pub stream_id: u64,
pub frame_id: u64,
}
impl Metadata {
pub fn serialize(&self) -> Vec<u8> {
let mut serialized = Vec::new();
serialized.extend_from_slice(&self.flags.to_be_bytes());
serialized.extend(encode_varint(self.stream_id));
serialized.extend(encode_varint(self.frame_id));
serialized
}
}
#[derive(Debug)]
pub enum FramePayload {
ListOfMessages(Vec<Message>),
ListOfActions(Vec<Action>),
KVList(HashMap<String, TypedData>),
}
#[derive(Debug, Clone)]
pub struct Message {
pub name: String,
pub args: HashMap<String, TypedData>,
}
#[derive(Debug, Clone, Default)]
pub struct FrameFlags(u32);
impl FrameFlags {
pub const fn new(is_fin: bool, is_abort: bool) -> Self {
let mut flags = 0u32;
if is_fin {
flags |= 0x00000001;
}
if is_abort {
flags |= 0x00000002;
}
Self(flags)
}
pub const fn is_fin(&self) -> bool {
self.0 & 0x00000001u32 != 0
}
pub const fn is_abort(&self) -> bool {
self.0 & 0x00000002u32 != 0
}
pub const fn from_u32(value: u32) -> Result<Self, ErrorKind> {
if value & 0x00000001 == 0 {
return Err(ErrorKind::Verify); }
if value & 0xFFFFFFFC != 0 {
return Err(ErrorKind::Alt); }
Ok(Self(value))
}
pub const fn to_be_bytes(&self) -> [u8; 4] {
self.0.to_be_bytes()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_frame_type_from_u8() {
assert_eq!(FrameType::from_u8(0), Err(ErrorKind::Alt));
assert_eq!(FrameType::from_u8(1), Ok(FrameType::HaproxyHello));
assert_eq!(FrameType::from_u8(2), Ok(FrameType::HaproxyDisconnect));
assert_eq!(FrameType::from_u8(3), Ok(FrameType::Notify));
assert_eq!(FrameType::from_u8(101), Ok(FrameType::AgentHello));
assert_eq!(FrameType::from_u8(102), Ok(FrameType::AgentDisconnect));
assert_eq!(FrameType::from_u8(103), Ok(FrameType::Ack));
}
#[test]
fn test_frame_type_to_u8() {
assert_eq!(FrameType::HaproxyHello.to_u8(), 1);
assert_eq!(FrameType::HaproxyDisconnect.to_u8(), 2);
assert_eq!(FrameType::Notify.to_u8(), 3);
assert_eq!(FrameType::AgentHello.to_u8(), 101);
assert_eq!(FrameType::AgentDisconnect.to_u8(), 102);
assert_eq!(FrameType::Ack.to_u8(), 103);
}
#[test]
fn test_frameflags() {
let flags = FrameFlags(0x00000001);
assert!(flags.is_fin());
let flags = FrameFlags(0x00000000);
assert!(!flags.is_fin());
let flags = FrameFlags(0x00000002);
assert!(flags.is_abort());
let flags = FrameFlags(0x00000003);
assert!(flags.is_fin());
assert!(flags.is_abort());
}
#[test]
fn test_frameflags_new() {
let flags = FrameFlags::new(true, false);
assert_eq!(flags.0, 0x00000001);
let flags = FrameFlags::new(false, true);
assert_eq!(flags.0, 0x00000002);
let flags = FrameFlags::new(true, true);
assert_eq!(flags.0, 0x00000003);
}
}