use microsandbox_protocol::codec::RawFrame;
use microsandbox_protocol::message::{Message, MessageType};
use serde::Serialize;
use crate::{AgentClientError, AgentClientResult};
#[derive(Debug, Clone)]
pub struct TypedMessage<T> {
pub message_type: MessageType,
pub payload: T,
}
#[derive(Debug, Clone)]
pub struct EncodedMessage {
pub message_type: MessageType,
pub payload: Vec<u8>,
}
#[derive(Debug, Clone)]
pub struct OutboundMessage {
pub message_type: MessageType,
pub flags: u8,
pub body: Vec<u8>,
}
pub trait IntoOutboundMessage {
fn into_outbound_message(
self,
protocol_version: u8,
negotiated_version: u8,
) -> AgentClientResult<OutboundMessage>;
}
impl<T> TypedMessage<T> {
pub fn new(message_type: MessageType, payload: T) -> Self {
Self {
message_type,
payload,
}
}
}
impl EncodedMessage {
pub fn new(message_type: MessageType, payload: impl Into<Vec<u8>>) -> Self {
Self {
message_type,
payload: payload.into(),
}
}
}
impl OutboundMessage {
pub fn into_raw_frame(self, id: u32) -> RawFrame {
RawFrame {
id,
flags: self.flags,
body: self.body,
}
}
}
impl<T> IntoOutboundMessage for TypedMessage<T>
where
T: Serialize,
{
fn into_outbound_message(
self,
protocol_version: u8,
negotiated_version: u8,
) -> AgentClientResult<OutboundMessage> {
let mut payload = Vec::new();
ciborium::into_writer(&self.payload, &mut payload)
.map_err(|error| AgentClientError::Cbor(error.to_string()))?;
EncodedMessage::new(self.message_type, payload)
.into_outbound_message(protocol_version, negotiated_version)
}
}
impl IntoOutboundMessage for EncodedMessage {
fn into_outbound_message(
self,
protocol_version: u8,
negotiated_version: u8,
) -> AgentClientResult<OutboundMessage> {
if !self.message_type.is_available_at(negotiated_version) {
return Err(AgentClientError::UnsupportedOperation {
msg_type: self.message_type.as_str(),
needs: self.message_type.min_protocol_version(),
peer: negotiated_version,
});
}
let flags = self.message_type.flags();
let message = Message {
v: protocol_version,
t: self.message_type,
id: 0,
flags,
p: self.payload,
};
let mut body = Vec::new();
ciborium::into_writer(&message, &mut body)
.map_err(|error| AgentClientError::Cbor(error.to_string()))?;
Ok(OutboundMessage {
message_type: self.message_type,
flags,
body,
})
}
}