dwn_core/message/descriptor/
mod.rs

1use std::fmt::Display;
2
3use serde::{Deserialize, Deserializer, Serialize};
4use serde_json::Value;
5
6mod protocols;
7mod records;
8
9pub use protocols::*;
10pub use records::*;
11use time::OffsetDateTime;
12
13use super::cid::{compute_cid_cbor, CidGenerationError};
14
15#[derive(Serialize, Debug, Clone, PartialEq, Eq)]
16#[serde(untagged)]
17pub enum Descriptor {
18    ProtocolsConfigure(Box<ProtocolsConfigure>),
19    ProtocolsQuery(Box<ProtocolsQuery>),
20    RecordsQuery(Box<RecordsQuery>),
21    RecordsRead(Box<RecordsRead>),
22    RecordsSync(Box<RecordsSync>),
23    RecordsWrite(Box<RecordsWrite>),
24}
25
26impl Descriptor {
27    pub fn compute_entry_id(&self) -> Result<String, CidGenerationError> {
28        #[derive(Serialize)]
29        #[serde(rename_all = "camelCase")]
30        struct RecordIdGeneration {
31            descriptor_cid: String,
32        }
33
34        let generator = RecordIdGeneration {
35            descriptor_cid: compute_cid_cbor(self)?,
36        };
37
38        compute_cid_cbor(&generator)
39    }
40
41    pub fn message_timestamp(&self) -> Option<&OffsetDateTime> {
42        match self {
43            Descriptor::ProtocolsConfigure(_) => None,
44            Descriptor::ProtocolsQuery(_) => None,
45            Descriptor::RecordsQuery(d) => Some(&d.message_timestamp),
46            Descriptor::RecordsRead(d) => Some(&d.message_timestamp),
47            Descriptor::RecordsSync(d) => Some(&d.message_timestamp),
48            Descriptor::RecordsWrite(d) => Some(&d.message_timestamp),
49        }
50    }
51}
52
53impl<'de> Deserialize<'de> for Descriptor {
54    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
55    where
56        D: Deserializer<'de>,
57    {
58        let raw = Value::deserialize(deserializer)?;
59
60        let Some(interface) = raw.get("interface") else {
61            return Err(serde::de::Error::custom("no interface"));
62        };
63        let interface = serde_json::from_value::<Interface>(interface.clone())
64            .map_err(|_| serde::de::Error::custom("unsupported interface"))?;
65
66        let Some(method) = raw.get("method") else {
67            return Err(serde::de::Error::custom("no method"));
68        };
69        let method = serde_json::from_value::<Method>(method.clone())
70            .map_err(|_| serde::de::Error::custom("unsupported method"))?;
71
72        match (interface, method) {
73            (Interface::Records, Method::Query) => {
74                let desc: RecordsQuery =
75                    serde_json::from_value(raw).map_err(serde::de::Error::custom)?;
76                Ok(Descriptor::RecordsQuery(Box::new(desc)))
77            }
78            (Interface::Records, Method::Read) => {
79                let desc: RecordsRead =
80                    serde_json::from_value(raw).map_err(serde::de::Error::custom)?;
81                Ok(Descriptor::RecordsRead(Box::new(desc)))
82            }
83            (Interface::Records, Method::Sync) => {
84                let desc: RecordsSync =
85                    serde_json::from_value(raw).map_err(serde::de::Error::custom)?;
86                Ok(Descriptor::RecordsSync(Box::new(desc)))
87            }
88            (Interface::Records, Method::Write) => {
89                let desc: RecordsWrite =
90                    serde_json::from_value(raw).map_err(serde::de::Error::custom)?;
91                Ok(Descriptor::RecordsWrite(Box::new(desc)))
92            }
93            _ => Err(serde::de::Error::custom(
94                "Unsupported interface / method combination",
95            )),
96        }
97    }
98}
99
100#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
101pub enum Interface {
102    Protocols,
103    Records,
104}
105
106impl Display for Interface {
107    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
108        write!(f, "{:?}", self)
109    }
110}
111
112#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
113pub enum Method {
114    Query,
115    Read,
116    Sync,
117    Write,
118}
119
120impl Display for Method {
121    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
122        write!(f, "{:?}", self)
123    }
124}
125
126#[cfg(test)]
127mod test {
128    use mime::TEXT_PLAIN;
129    use semver::Version;
130
131    use crate::message::Message;
132
133    use super::*;
134
135    #[test]
136    fn test_serialize_records_query() {
137        let msg = RecordsQueryBuilder::default()
138            .schema("schema".to_string())
139            .protocol("protocol".to_string(), Version::new(1, 2, 3))
140            .record_id("record id".to_string())
141            .parent_id("parent id".to_string())
142            .build()
143            .unwrap();
144        let ser = serde_json::to_string_pretty(&msg).unwrap();
145        println!("{}", ser);
146        let des = serde_json::from_str::<Message>(&ser).unwrap();
147        assert_eq!(des, msg);
148    }
149
150    #[test]
151    fn test_serialize_records_read() {
152        let msg = RecordsReadBuilder::new("test".to_string()).build().unwrap();
153        let ser = serde_json::to_string_pretty(&msg).unwrap();
154        println!("{}", ser);
155        let des = serde_json::from_str::<Message>(&ser).unwrap();
156        assert_eq!(des, msg);
157    }
158
159    #[test]
160    fn test_serialize_records_write() {
161        let msg = RecordsWriteBuilder::default()
162            .data(TEXT_PLAIN, vec![0, 1, 2, 3])
163            .schema("schema".to_string())
164            .protocol("protocol".to_string(), Version::new(1, 2, 3))
165            .record_id("record id".to_string())
166            .parent_id("parent id".to_string())
167            .published(true)
168            .build()
169            .unwrap();
170        let ser = serde_json::to_string_pretty(&msg).unwrap();
171        println!("{}", ser);
172        let des = serde_json::from_str::<Message>(&ser).unwrap();
173        assert_eq!(des, msg);
174    }
175}