Skip to main content

xmtp_content_types/
multi_remote_attachment.rs

1use std::collections::HashMap;
2
3use crate::{CodecError, ContentCodec};
4use prost::Message;
5use xmtp_proto::xmtp::mls::message_contents::{
6    ContentTypeId, EncodedContent, content_types::MultiRemoteAttachment,
7};
8
9pub struct MultiRemoteAttachmentCodec {}
10
11impl MultiRemoteAttachmentCodec {
12    const AUTHORITY_ID: &'static str = "xmtp.org";
13    pub const TYPE_ID: &'static str = "multiRemoteStaticAttachment";
14    pub const MAJOR_VERSION: u32 = 1;
15    pub const MINOR_VERSION: u32 = 0;
16}
17
18impl MultiRemoteAttachmentCodec {
19    fn fallback(_: &MultiRemoteAttachment) -> Option<String> {
20        Some(
21            "Can't display this content. This app doesn't support multiple remote attachments."
22                .to_string(),
23        )
24    }
25}
26
27impl ContentCodec<MultiRemoteAttachment> for MultiRemoteAttachmentCodec {
28    fn content_type() -> ContentTypeId {
29        ContentTypeId {
30            authority_id: MultiRemoteAttachmentCodec::AUTHORITY_ID.to_string(),
31            type_id: MultiRemoteAttachmentCodec::TYPE_ID.to_string(),
32            version_major: MultiRemoteAttachmentCodec::MAJOR_VERSION,
33            version_minor: MultiRemoteAttachmentCodec::MINOR_VERSION,
34        }
35    }
36
37    fn encode(data: MultiRemoteAttachment) -> Result<EncodedContent, CodecError> {
38        let mut buf = Vec::new();
39        data.encode(&mut buf)
40            .map_err(|e| CodecError::Encode(e.to_string()))?;
41
42        Ok(EncodedContent {
43            r#type: Some(MultiRemoteAttachmentCodec::content_type()),
44            parameters: HashMap::new(),
45            fallback: Self::fallback(&data),
46            compression: None,
47            content: buf,
48        })
49    }
50
51    fn decode(content: EncodedContent) -> Result<MultiRemoteAttachment, CodecError> {
52        let decoded = MultiRemoteAttachment::decode(content.content.as_slice())
53            .map_err(|e| CodecError::Decode(e.to_string()))?;
54
55        Ok(decoded)
56    }
57
58    fn should_push() -> bool {
59        true
60    }
61}
62
63#[cfg(test)]
64pub(crate) mod tests {
65    use xmtp_proto::xmtp::mls::message_contents::content_types::RemoteAttachmentInfo;
66
67    use super::*;
68
69    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
70    #[cfg_attr(not(target_arch = "wasm32"), test)]
71    fn test_encode_decode() {
72        let attachment_info_1 = RemoteAttachmentInfo {
73            content_digest: "0123456789abcdef".to_string(),
74            secret: vec![0; 32],
75            nonce: vec![0; 16],
76            salt: vec![0; 16],
77            scheme: "https".to_string(),
78            url: "https://example.com/attachment".to_string(),
79            content_length: Some(1000),
80            filename: Some("attachment_1.jpg".to_string()),
81        };
82        let attachment_info_2 = RemoteAttachmentInfo {
83            content_digest: "0123456789abcdef".to_string(),
84            secret: vec![0; 32],
85            nonce: vec![0; 16],
86            salt: vec![0; 16],
87            scheme: "https".to_string(),
88            url: "https://example.com/attachment".to_string(),
89            content_length: Some(1000),
90            filename: Some("attachment_2.jpg".to_string()),
91        };
92
93        // Store the filenames before moving the attachment_info structs
94        let filename_1 = attachment_info_1.filename.clone();
95        let filename_2 = attachment_info_2.filename.clone();
96
97        let new_multi_remote_attachment_data: MultiRemoteAttachment = MultiRemoteAttachment {
98            attachments: vec![attachment_info_1.clone(), attachment_info_2.clone()],
99        };
100
101        let encoded = MultiRemoteAttachmentCodec::encode(new_multi_remote_attachment_data).unwrap();
102        assert_eq!(
103            encoded.clone().r#type.unwrap().type_id,
104            "multiRemoteStaticAttachment"
105        );
106        assert!(!encoded.content.is_empty());
107
108        let decoded = MultiRemoteAttachmentCodec::decode(encoded).unwrap();
109        assert_eq!(decoded.attachments[0].filename, filename_1);
110        assert_eq!(decoded.attachments[1].filename, filename_2);
111        assert_eq!(decoded.attachments[0].content_length, Some(1000));
112        assert_eq!(decoded.attachments[1].content_length, Some(1000));
113    }
114}