1use gbp::CodecError;
4use serde::{Deserialize, Serialize};
5use serde_bytes::ByteBuf;
6
7#[repr(u8)]
9#[derive(Copy, Clone, Debug, PartialEq, Eq)]
10pub enum GtpContentType {
11 Plain = 0,
13 Markdown = 1,
15 Binary = 2,
17 AttachmentRef = 3,
19}
20
21#[derive(Clone, Debug, Serialize, Deserialize)]
23pub struct GtpMessage {
24 #[serde(rename = "mid")]
26 pub message_id: u64,
27 #[serde(rename = "sid")]
29 pub sender_id: u32,
30 #[serde(rename = "ts")]
32 pub timestamp_ms: u64,
33 #[serde(rename = "rid")]
35 pub request_id: u32,
36 #[serde(rename = "fl")]
38 pub flags: u8,
39 #[serde(rename = "ct")]
41 pub content_type: u8,
42 #[serde(rename = "len")]
44 pub content_length: u32,
45 #[serde(rename = "body")]
47 pub content: ByteBuf,
48}
49
50impl GtpMessage {
51 pub fn plain(sender_id: u32, message_id: u64, text: &str) -> Self {
53 let body = text.as_bytes().to_vec();
54 Self {
55 message_id,
56 sender_id,
57 timestamp_ms: 0,
58 request_id: 0,
59 flags: 0x01,
60 content_type: GtpContentType::Plain as u8,
61 content_length: body.len() as u32,
62 content: ByteBuf::from(body),
63 }
64 }
65
66 pub fn to_cbor(&self) -> Vec<u8> {
68 let mut buf = Vec::new();
69 ciborium::into_writer(self, &mut buf).expect("cbor encode");
70 buf
71 }
72
73 pub fn from_cbor(data: &[u8]) -> Result<Self, CodecError> {
75 let m: Self = ciborium::from_reader(data).map_err(|e| CodecError::Decode(e.to_string()))?;
76 if m.content_length as usize != m.content.len() {
77 return Err(CodecError::PayloadSizeMismatch);
78 }
79 Ok(m)
80 }
81
82 pub fn text(&self) -> Option<&str> {
84 std::str::from_utf8(&self.content).ok()
85 }
86}