summaryrefslogtreecommitdiffstats
path: root/src/types
diff options
context:
space:
mode:
authorMatthias Beyer <mail@beyermatthias.de>2021-12-04 17:03:09 +0100
committerMatthias Beyer <mail@beyermatthias.de>2021-12-04 21:16:37 +0100
commite5d610270bed47a91ecca8d51adc705bed58cda7 (patch)
tree52a5d63edbbf5f8bbf154757969877bce17c3725 /src/types
parent3a3b342a4ae5a90003b6ef9faa65ca7f0a025962 (diff)
Rewrite using "ipfs" crate
Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
Diffstat (limited to 'src/types')
-rw-r--r--src/types/datetime.rs23
-rw-r--r--src/types/encodable_cid.rs28
-rw-r--r--src/types/mod.rs2
-rw-r--r--src/types/node.rs83
-rw-r--r--src/types/payload.rs58
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()
}
}