mirror of
https://github.com/Noratrieb/haesli.git
synced 2026-01-16 20:55:03 +01:00
more things
This commit is contained in:
parent
9a819bc3f4
commit
b50634841d
6 changed files with 228 additions and 93 deletions
|
|
@ -1,13 +1,36 @@
|
|||
use crate::error::{ConException, ProtocolError, Result};
|
||||
use amqp_core::methods::FieldValue;
|
||||
use amqp_core::methods;
|
||||
use anyhow::Context;
|
||||
use bytes::Bytes;
|
||||
use smallvec::SmallVec;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||
use tracing::trace;
|
||||
|
||||
const REQUIRED_FRAME_END: u8 = 0xCE;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct ChannelId(u16);
|
||||
|
||||
impl ChannelId {
|
||||
pub fn num(self) -> u16 {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn is_zero(self) -> bool {
|
||||
self.0 == 0
|
||||
}
|
||||
|
||||
pub fn zero() -> Self {
|
||||
Self(0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for ChannelId {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
mod frame_type {
|
||||
pub const METHOD: u8 = 1;
|
||||
pub const HEADER: u8 = 2;
|
||||
|
|
@ -19,7 +42,7 @@ mod frame_type {
|
|||
pub struct Frame {
|
||||
/// The type of the frame including its parsed metadata.
|
||||
pub kind: FrameType,
|
||||
pub channel: u16,
|
||||
pub channel: ChannelId,
|
||||
/// Includes the whole payload, also including the metadata from each type.
|
||||
pub payload: Bytes,
|
||||
}
|
||||
|
|
@ -33,18 +56,84 @@ pub enum FrameType {
|
|||
Heartbeat = 8,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct BasicProperties {
|
||||
content_type: Option<methods::Shortstr>,
|
||||
content_encoding: Option<methods::Shortstr>,
|
||||
headers: Option<methods::Table>,
|
||||
delivery_mode: Option<methods::Octet>,
|
||||
priority: Option<methods::Octet>,
|
||||
correlation_id: Option<methods::Shortstr>,
|
||||
reply_to: Option<methods::Shortstr>,
|
||||
expiration: Option<methods::Shortstr>,
|
||||
message_id: Option<methods::Shortstr>,
|
||||
timestamp: Option<methods::Timestamp>,
|
||||
r#type: Option<methods::Shortstr>,
|
||||
user_id: Option<methods::Shortstr>,
|
||||
app_id: Option<methods::Shortstr>,
|
||||
reserved: Option<methods::Shortstr>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct ContentHeader {
|
||||
pub class_id: u16,
|
||||
pub weight: u16,
|
||||
pub body_size: u64,
|
||||
pub property_flags: SmallVec<[u16; 1]>,
|
||||
pub property_fields: Vec<FieldValue>,
|
||||
pub property_fields: BasicProperties,
|
||||
}
|
||||
|
||||
mod content_header_parse {
|
||||
use crate::error::TransError;
|
||||
use crate::frame::{BasicProperties, ContentHeader};
|
||||
use nom::number::complete::{u16, u64};
|
||||
use nom::number::Endianness::Big;
|
||||
|
||||
type IResult<'a, T> = nom::IResult<&'a [u8], T, TransError>;
|
||||
|
||||
pub fn basic_properties(_property_flags: u16, _input: &[u8]) -> IResult<'_, BasicProperties> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn header(input: &[u8]) -> IResult<'_, Box<ContentHeader>> {
|
||||
let (input, class_id) = u16(Big)(input)?;
|
||||
let (input, weight) = u16(Big)(input)?;
|
||||
let (input, body_size) = u64(Big)(input)?;
|
||||
|
||||
// I do not quite understand this here. Apparently, there can be more than 15 flags?
|
||||
// But the Basic class only specifies 15, so idk. Don't care about this for now
|
||||
let (input, property_flags) = u16(Big)(input)?;
|
||||
let (input, property_fields) = basic_properties(property_flags, input)?;
|
||||
|
||||
Ok((
|
||||
input,
|
||||
Box::new(ContentHeader {
|
||||
class_id,
|
||||
weight,
|
||||
body_size,
|
||||
property_fields,
|
||||
}),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl ContentHeader {
|
||||
pub fn new() -> Self {
|
||||
todo!()
|
||||
pub fn parse(input: &[u8]) -> Result<Box<Self>> {
|
||||
match content_header_parse::header(input) {
|
||||
Ok(([], header)) => Ok(header),
|
||||
Ok((_, _)) => {
|
||||
Err(
|
||||
ConException::SyntaxError(vec!["could not consume all input".to_string()])
|
||||
.into_trans(),
|
||||
)
|
||||
}
|
||||
Err(nom::Err::Incomplete(_)) => {
|
||||
Err(
|
||||
ConException::SyntaxError(vec!["there was not enough data".to_string()])
|
||||
.into_trans(),
|
||||
)
|
||||
}
|
||||
Err(nom::Err::Failure(err) | nom::Err::Error(err)) => Err(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -55,7 +144,7 @@ where
|
|||
trace!(?frame, "Sending frame");
|
||||
|
||||
w.write_u8(frame.kind as u8).await?;
|
||||
w.write_u16(frame.channel).await?;
|
||||
w.write_u16(frame.channel.num()).await?;
|
||||
w.write_u32(u32::try_from(frame.payload.len()).context("frame size too big")?)
|
||||
.await?;
|
||||
w.write_all(&frame.payload).await?;
|
||||
|
|
@ -70,6 +159,7 @@ where
|
|||
{
|
||||
let kind = r.read_u8().await.context("read type")?;
|
||||
let channel = r.read_u16().await.context("read channel")?;
|
||||
let channel = ChannelId(channel);
|
||||
let size = r.read_u32().await.context("read size")?;
|
||||
|
||||
let mut payload = vec![0; size.try_into().unwrap()];
|
||||
|
|
@ -98,16 +188,16 @@ where
|
|||
Ok(frame)
|
||||
}
|
||||
|
||||
fn parse_frame_type(kind: u8, channel: u16) -> Result<FrameType> {
|
||||
fn parse_frame_type(kind: u8, channel: ChannelId) -> Result<FrameType> {
|
||||
match kind {
|
||||
frame_type::METHOD => Ok(FrameType::Method),
|
||||
frame_type::HEADER => Ok(FrameType::Header),
|
||||
frame_type::BODY => Ok(FrameType::Body),
|
||||
frame_type::HEARTBEAT => {
|
||||
if channel != 0 {
|
||||
Err(ProtocolError::ConException(ConException::FrameError).into())
|
||||
} else {
|
||||
if channel.is_zero() {
|
||||
Ok(FrameType::Heartbeat)
|
||||
} else {
|
||||
Err(ProtocolError::ConException(ConException::FrameError).into())
|
||||
}
|
||||
}
|
||||
_ => Err(ConException::FrameError.into_trans()),
|
||||
|
|
@ -116,7 +206,7 @@ fn parse_frame_type(kind: u8, channel: u16) -> Result<FrameType> {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::frame::{Frame, FrameType};
|
||||
use crate::frame::{ChannelId, Frame, FrameType};
|
||||
use bytes::Bytes;
|
||||
|
||||
#[tokio::test]
|
||||
|
|
@ -145,7 +235,7 @@ mod tests {
|
|||
frame,
|
||||
Frame {
|
||||
kind: FrameType::Method,
|
||||
channel: 0,
|
||||
channel: ChannelId(0),
|
||||
payload: Bytes::from_static(&[1, 2, 3]),
|
||||
}
|
||||
);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue