dittolive_ditto/store/attachment/
token.rs

1use std::{
2    collections::{BTreeMap, HashMap},
3    convert::TryFrom,
4};
5
6use serde::Deserialize;
7
8use crate::{
9    error::{DittoError, ErrorKind},
10    prelude::CborValue,
11};
12
13#[derive(Debug, Clone, Deserialize)]
14#[serde(try_from = "DittoAttachmentTokenStoredFormat")]
15/// Serves as a token for a specific attachment that you can pass to a call to
16/// [`fetch_attachment`](crate::store::Store::fetch_attachment).
17pub struct DittoAttachmentToken {
18    pub(crate) id: Box<[u8]>,
19    pub(crate) len: u64,
20    pub(crate) metadata: HashMap<String, String>,
21}
22
23impl DittoAttachmentToken {
24    /// Returns the `id` of this attachment, encoded so as to be compatible with DQL queries.
25    pub fn id(&self) -> String {
26        crate::utils::base64_encode_unpadded(&self.id)
27    }
28
29    /// Returns the size, in bytes, of this attachment's data.
30    #[allow(clippy::len_without_is_empty)]
31    pub fn len(&self) -> u64 {
32        self.len
33    }
34
35    /// Returns the metadata that was associated with this attachment file when the source peer
36    /// called [`new_attachment`][crate::store::Store::new_attachment].
37    pub fn metadata(&self) -> &HashMap<String, String> {
38        &self.metadata
39    }
40}
41
42impl TryFrom<DittoAttachmentTokenStoredFormat> for DittoAttachmentToken {
43    type Error = DittoError;
44
45    fn try_from(value: DittoAttachmentTokenStoredFormat) -> Result<Self, Self::Error> {
46        if value._type != (::ffi_sdk::DittoCrdtType::Attachment as u64) {
47            return Err(ErrorKind::Internal.into());
48        }
49        let ret = DittoAttachmentToken {
50            id: value._id,
51            len: value._len,
52            metadata: value._meta,
53        };
54        Ok(ret)
55    }
56}
57
58// Helper struct to help deserialize. This is to let us use
59// #[derive(Deserialize)] instead of manually implementing it.
60// See `impl serde::Serialize for DittoAttachment`
61#[derive(Deserialize)]
62struct DittoAttachmentTokenStoredFormat {
63    /// FIXME(Daniel): we have to use `alias` instead of `rename` so as to avoid
64    /// breakage with older Rust SDK versions using `_type` as the key name.
65    #[serde(alias = "_ditto_internal_type_jkb12973t4b")]
66    _type: u64,
67    #[serde(with = "serde_bytes")]
68    _id: Box<[u8]>,
69    _len: u64,
70    _meta: HashMap<String, String>,
71}
72
73/// Trait abstracting over [`DittoAttachmentToken`] and a
74/// [`QueryResultItem::value()`][crate::dql::QueryResultItem::value] matching an input
75/// [`DittoAttachment`][super::DittoAttachment].
76pub trait DittoAttachmentTokenLike {
77    /// Resolve the token-like object to a `DittoAttachmentToken`
78    fn parse_attachment_token(self) -> Result<DittoAttachmentToken, DittoError>;
79}
80
81impl DittoAttachmentTokenLike for DittoAttachmentToken {
82    fn parse_attachment_token(self) -> Result<DittoAttachmentToken, DittoError> {
83        Ok(self)
84    }
85}
86
87impl DittoAttachmentTokenLike for &'_ BTreeMap<CborValue, CborValue> {
88    fn parse_attachment_token(self) -> Result<DittoAttachmentToken, DittoError> {
89        #[derive(Deserialize)]
90        struct DittoAttachmentTokenStoredFormatInQueryResultItem {
91            id: Box<str>,
92            len: u64,
93            metadata: HashMap<String, String>,
94        }
95
96        let DittoAttachmentTokenStoredFormatInQueryResultItem { id, len, metadata } =
97            ::serde_cbor::from_slice(&::serde_cbor::to_vec(self)?)?;
98        let id = crate::utils::base64_decode_unpadded(&id).map_err(|err| {
99            DittoError::from_str(
100                ErrorKind::InvalidInput,
101                format!("expected base64 `.id` field, got: {err}"),
102            )
103        })?;
104        Ok(DittoAttachmentToken { id, len, metadata })
105    }
106}
107
108impl DittoAttachmentTokenLike for BTreeMap<CborValue, CborValue> {
109    fn parse_attachment_token(self) -> Result<DittoAttachmentToken, DittoError> {
110        (&self).parse_attachment_token()
111    }
112}