use bytes::{Bytes, BytesMut};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum GrpcDirection {
ClientToUpstream,
UpstreamToClient,
}
#[derive(Debug, Clone)]
pub struct GrpcMessage {
pub compressed: bool,
pub payload: Bytes,
}
#[derive(Debug)]
pub enum GrpcMessageAction {
Forward(GrpcMessage),
Drop,
Error(u32, String),
}
pub fn parse_grpc_message(
buf: &mut BytesMut,
max_size: Option<usize>,
) -> Result<Option<GrpcMessage>, String> {
if buf.len() < 5 {
return Ok(None);
}
let compressed_flag = buf[0];
let length = u32::from_be_bytes([buf[1], buf[2], buf[3], buf[4]]) as usize;
if let Some(max) = max_size
&& length > max
{
return Err(format!(
"gRPC message size {} exceeds maximum allowed {}",
length, max
));
}
if buf.len() < 5 + length {
return Ok(None);
}
let compressed = compressed_flag == 1;
let _ = buf.split_to(5);
let payload = buf.split_to(length).freeze();
Ok(Some(GrpcMessage {
compressed,
payload,
}))
}
pub fn encode_grpc_message(msg: &GrpcMessage) -> Bytes {
let mut out = BytesMut::with_capacity(5 + msg.payload.len());
let compressed_flag: u8 = if msg.compressed { 1 } else { 0 };
out.extend_from_slice(&[compressed_flag]);
out.extend_from_slice(&(msg.payload.len() as u32).to_be_bytes());
out.extend_from_slice(&msg.payload);
out.freeze()
}