diff options
author | Matthias Beyer <mail@beyermatthias.de> | 2021-12-04 17:03:09 +0100 |
---|---|---|
committer | Matthias Beyer <mail@beyermatthias.de> | 2021-12-04 21:16:37 +0100 |
commit | e5d610270bed47a91ecca8d51adc705bed58cda7 (patch) | |
tree | 52a5d63edbbf5f8bbf154757969877bce17c3725 /src/types | |
parent | 3a3b342a4ae5a90003b6ef9faa65ca7f0a025962 (diff) |
Rewrite using "ipfs" crate
Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
Diffstat (limited to 'src/types')
-rw-r--r-- | src/types/datetime.rs | 23 | ||||
-rw-r--r-- | src/types/encodable_cid.rs | 28 | ||||
-rw-r--r-- | src/types/mod.rs | 2 | ||||
-rw-r--r-- | src/types/node.rs | 83 | ||||
-rw-r--r-- | src/types/payload.rs | 58 |
5 files changed, 140 insertions, 54 deletions
diff --git a/src/types/datetime.rs b/src/types/datetime.rs index 6735731..00d739a 100644 --- a/src/types/datetime.rs +++ b/src/types/datetime.rs @@ -1,9 +1,32 @@ +use std::convert::TryFrom; use anyhow::Error; +use anyhow::Result; #[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)] #[serde(transparent)] pub struct DateTime(chrono::DateTime<chrono::Utc>); +impl Into<ipfs::Ipld> for DateTime { + fn into(self) -> ipfs::Ipld { + ipfs::Ipld::String(self.0.to_rfc3339()) + } +} + +impl TryFrom<ipfs::Ipld> for DateTime { + type Error = Error; + + fn try_from(ipld: ipfs::Ipld) -> Result<DateTime> { + match ipld { + ipfs::Ipld::String(s) => chrono::DateTime::parse_from_rfc3339(&s) + .map(|dt| dt.with_timezone(&chrono::Utc)) + .map(DateTime) + .map_err(Error::from), + _ => anyhow::bail!("Expected string for timestamp"), + } + } +} + + impl From<chrono::DateTime<chrono::Utc>> for DateTime { fn from(dt: chrono::DateTime<chrono::Utc>) -> Self { DateTime(dt) diff --git a/src/types/encodable_cid.rs b/src/types/encodable_cid.rs deleted file mode 100644 index 014d661..0000000 --- a/src/types/encodable_cid.rs +++ /dev/null @@ -1,28 +0,0 @@ -use std::collections::HashMap; - -/// An DAG-JSON encodable cid -/// -/// this is a hack. DAG-JSON expects a linked CID to be of the form -/// -/// "/": "<cid hash>" -/// -/// (see https://ipld.io/docs/codecs/known/dag-json/) -/// -/// so we have a wrapper type here to make the CID encodable -#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)] -pub struct EncodableCid(HashMap<String, crate::cid::Cid>); - -impl From<crate::cid::Cid> for EncodableCid { - fn from(cid: crate::cid::Cid) -> Self { - let mut hm = HashMap::new(); - hm.insert(String::from("/"), cid); - Self(hm) - } -} - -impl Into<crate::cid::Cid> for EncodableCid { - fn into(self) -> crate::cid::Cid { - self.0.get("/").unwrap().clone() - } -} - diff --git a/src/types/mod.rs b/src/types/mod.rs index 228c363..7382f16 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -1,5 +1,3 @@ -mod encodable_cid; - mod node; pub use node::*; diff --git a/src/types/node.rs b/src/types/node.rs index aead32c..eb5679b 100644 --- a/src/types/node.rs +++ b/src/types/node.rs @@ -1,43 +1,88 @@ -#[derive(Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, getset::Getters)] +use anyhow::Result; + +use std::convert::TryFrom; + +#[derive(Debug, Eq, PartialEq, getset::Getters)] pub struct Node { /// Version - #[serde(rename = "v")] #[getset(get = "pub")] version: String, /// Parent Nodes, identified by cid - parents: Vec<crate::types::encodable_cid::EncodableCid>, + parents: Vec<ipfs::Cid>, /// The actual payload of the node, which is stored in another document identified by this cid - payload: crate::types::encodable_cid::EncodableCid, + payload: ipfs::Cid, +} + +impl Into<ipfs::Ipld> for Node { + fn into(self) -> ipfs::Ipld { + let mut map = std::collections::BTreeMap::new(); + map.insert(String::from("version"), ipfs::Ipld::String(self.version)); + map.insert(String::from("parents"), ipfs::Ipld::List(self.parents.into_iter().map(ipfs::Ipld::Link).collect())); + map.insert(String::from("payload"), ipfs::Ipld::Link(self.payload)); + ipfs::Ipld::Map(map) + } } -impl daglib::Node for Node { - type Id = crate::cid::Cid; +impl TryFrom<ipfs::Ipld> for Node { + type Error = anyhow::Error; - fn parent_ids(&self) -> Vec<Self::Id> { - self.parents() + 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 version = match map.get("version").ok_or_else(missing_field("version"))? { + ipfs::Ipld::String(s) => s.to_string(), + _ => return field_wrong_type("version", "String") + }; + + let parents = match map.get("parents").ok_or_else(missing_field("parents"))? { + ipfs::Ipld::List(s) => { + s.into_iter() + .map(|parent| -> Result<ipfs::Cid> { + match parent { + ipfs::Ipld::Link(cid) => Ok(cid.clone()), + _ => anyhow::bail!("Field in parents has wrong type, expected Link"), + } + }) + .collect::<Result<Vec<ipfs::Cid>>>()? + }, + _ => return field_wrong_type("parents", "Vec<Link>") + }; + + let payload = match map.get("payload").ok_or_else(missing_field("payload"))? { + ipfs::Ipld::Link(cid) => cid.clone(), + _ => return field_wrong_type("payload", "Link") + }; + + Ok(Node { + version, + parents, + payload + }) + } + + _ => anyhow::bail!("Unexpected type, expected map") + } } } impl Node { - pub fn new(version: String, parents: Vec<crate::cid::Cid>, payload: crate::cid::Cid) -> Self { + pub fn new(version: String, parents: Vec<ipfs::Cid>, payload: ipfs::Cid) -> Self { Self { version, - parents: parents.into_iter().map(crate::types::encodable_cid::EncodableCid::from).collect(), - payload: payload.into() + parents, + payload, } } - pub fn parents(&self) -> Vec<crate::cid::Cid> { - self.parents - .clone() - .into_iter() - .map(crate::types::encodable_cid::EncodableCid::into) - .collect() + pub fn parents(&self) -> Vec<ipfs::Cid> { + self.parents.clone() } - pub fn payload(&self) -> crate::cid::Cid { - self.payload.clone().into() + pub fn payload(&self) -> ipfs::Cid { + self.payload.clone() } } diff --git a/src/types/payload.rs b/src/types/payload.rs index cb12845..a11b215 100644 --- a/src/types/payload.rs +++ b/src/types/payload.rs @@ -1,6 +1,10 @@ +use std::convert::TryFrom; + +use anyhow::Result; + use crate::types::DateTime; -#[derive(Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, getset::Getters)] +#[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 @@ -10,15 +14,59 @@ pub struct Payload { #[getset(get = "pub")] timestamp: DateTime, - content: crate::types::encodable_cid::EncodableCid, + 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: crate::cid::Cid) -> Self { + pub fn new(mime: String, timestamp: DateTime, content: ipfs::Cid) -> Self { Self { mime, timestamp, content: content.into() } } - pub fn content(&self) -> crate::cid::Cid { - self.content.clone().into() + pub fn content(&self) -> ipfs::Cid { + self.content.clone() } } |