summaryrefslogtreecommitdiffstats
path: root/lib/src/types/payload.rs
blob: a11b215c60409d4f2877eb3978e262e5199ff5f1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
use std::convert::TryFrom;

use anyhow::Result;

use crate::types::DateTime;

#[derive(Debug, Eq, PartialEq, getset::Getters)]
pub struct Payload {
    // TODO: Make this a mime::Mime, but as this type does not impl Serialize/Deserialize, we
    // cannot do this trivially yet
    #[getset(get = "pub")]
    mime: String,

    #[getset(get = "pub")]
    timestamp: DateTime,

    content: ipfs::Cid,
}

impl Into<ipfs::Ipld> for Payload {
    fn into(self) -> ipfs::Ipld {
        let mut map = std::collections::BTreeMap::new();
        map.insert(String::from("mime"), ipfs::Ipld::String(self.mime));
        map.insert(String::from("timestamp"), self.timestamp.into());
        map.insert(String::from("content"), ipfs::Ipld::Link(self.content));
        ipfs::Ipld::Map(map)
    }
}

impl TryFrom<ipfs::Ipld> for Payload {
    type Error = anyhow::Error;

    fn try_from(ipld: ipfs::Ipld) -> Result<Self> {
        let missing_field = |name: &'static str| move || anyhow::anyhow!("Missing field {}", name);
        let field_wrong_type = |name: &str, expty: &str| anyhow::bail!("Field {} has wrong type, expected {}", name, expty);
        match ipld {
            ipfs::Ipld::Map(map) => {
                let mime = match map.get("mime").ok_or_else(missing_field("mime"))? {
                    ipfs::Ipld::String(s) => s.to_owned(),
                    _ => return field_wrong_type("mime", "String")
                };

                let timestamp = map.get("timestamp")
                    .ok_or_else(missing_field("timestamp"))?;
                let timestamp = DateTime::try_from(timestamp.clone())?; // TODO dont clone

                let content = match map.get("content").ok_or_else(missing_field("content"))? {
                    ipfs::Ipld::Link(cid) => cid.clone(),
                    _ => return field_wrong_type("content", "Link")
                };

                Ok(Payload {
                    mime,
                    timestamp,
                    content
                })
            },

            _ => anyhow::bail!("Unexpected type, expected map"),
        }
    }
}

impl Payload {
    pub fn new(mime: String, timestamp: DateTime, content: ipfs::Cid) -> Self {
        Self { mime, timestamp, content: content.into() }
    }

    pub fn content(&self) -> ipfs::Cid {
        self.content.clone()
    }
}