From fa3e9812524fb2322adb181b01852f61980b3fe0 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Sat, 27 Nov 2021 12:58:34 +0100 Subject: Implement putting in a text block and fetching it again Signed-off-by: Matthias Beyer --- Cargo.toml | 1 + src/cid.rs | 1 - src/client.rs | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/types/datetime.rs | 2 +- src/types/node.rs | 12 ++++++--- src/types/payload.rs | 6 ++++- 6 files changed, 86 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7da53ef..ddfc31c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,3 +41,4 @@ ed25519-dalek = "*" http = "0.2" serde = "1" serde_json = "1" +getset = "0.1" diff --git a/src/cid.rs b/src/cid.rs index fe2d0f3..e89ef75 100644 --- a/src/cid.rs +++ b/src/cid.rs @@ -11,7 +11,6 @@ use anyhow::Result; #[serde(transparent)] pub struct Cid(String); -#[cfg(test)] impl AsRef for Cid { fn as_ref(&self) -> &str { self.0.as_ref() diff --git a/src/client.rs b/src/client.rs index f984dfa..5523666 100644 --- a/src/client.rs +++ b/src/client.rs @@ -3,6 +3,7 @@ use std::io::Cursor; use anyhow::Result; use futures::FutureExt; use futures::TryFutureExt; +use futures::TryStreamExt; use ipfs_api_backend_hyper::IpfsApi; use crate::cid::Cid; @@ -85,6 +86,35 @@ impl Client { .map_err(anyhow::Error::from) .and_then(crate::ipfs_client::backend::response::DagPutResponse::try_to_cid) } + + pub async fn get_node(&self, cid: Cid) -> Result { + self.get_deserializeable::(cid).await + } + + pub async fn get_payload(&self, cid: Cid) -> Result { + self.get_deserializeable::(cid).await + } + + async fn get_deserializeable(&self, cid: Cid) -> Result { + let bytes = self.ipfs + .dag_get(cid.as_ref()) + .map_ok(|chunk| chunk.to_vec()) + .try_concat() + .await?; + + let s = String::from_utf8(bytes)?; + serde_json::from_str(&s).map_err(anyhow::Error::from) + } + + pub async fn get_content_text(&self, cid: Cid) -> Result { + let bytes = self.ipfs + .cat(cid.as_ref()) + .map_ok(|chunk| chunk.to_vec()) + .try_concat() + .await?; + + String::from_utf8(bytes).map_err(anyhow::Error::from) + } } fn now() -> DateTime { @@ -128,4 +158,45 @@ mod tests { assert_eq!(cid.unwrap().as_ref(), "bafyreifqa7jqsazxvl53jb6sflzbk4nkv4j7b5jos6hlzh4fq55bjbvk3m"); } + #[tokio::test] + async fn test_post_text_node_roundtrip() { + use chrono::TimeZone; + + let _ = env_logger::try_init(); + let ipfs = IpfsClient::from_str("http://localhost:5001").unwrap(); + let config = Config::default(); + let client = Client::new(ipfs, config); + + let datetime: crate::types::DateTime = chrono::prelude::Utc.ymd(2021, 11, 27) + .and_hms(12, 30, 0) + .into(); + + let text = "text-roundtrip"; + + let cid = client.post_text_node_with_datetime(Vec::new(), String::from(text), datetime.clone()).await; + assert!(cid.is_ok()); + let cid = cid.unwrap(); + assert_eq!(cid.as_ref(), "bafyreibenqhh2fqf33mdvm4b4k7kpymnyhuduebwdmaxraxttld7i2bbbi"); + + let node = client.get_node(cid).await; + assert!(node.is_ok()); + let node = node.unwrap(); + + assert_eq!(*node.version(), crate::consts::protocol_version()); + assert!(node.parents().is_empty()); + + let payload = client.get_payload(node.payload().clone()).await; + assert!(payload.is_ok()); + let payload = payload.unwrap(); + + assert_eq!(payload.mime(), mime::TEXT_PLAIN_UTF_8.as_ref()); + assert_eq!(payload.timestamp(), &datetime); + + let content = client.get_content_text(payload.content().clone()).await; + assert!(content.is_ok()); + let content = content.unwrap(); + + assert_eq!(content, text); + } + } diff --git a/src/types/datetime.rs b/src/types/datetime.rs index 9034c26..6735731 100644 --- a/src/types/datetime.rs +++ b/src/types/datetime.rs @@ -1,6 +1,6 @@ use anyhow::Error; -#[derive(Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)] +#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)] #[serde(transparent)] pub struct DateTime(chrono::DateTime); diff --git a/src/types/node.rs b/src/types/node.rs index 60b10d1..278fa7f 100644 --- a/src/types/node.rs +++ b/src/types/node.rs @@ -1,12 +1,16 @@ -#[derive(Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)] +#[derive(Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, getset::Getters)] pub struct Node { /// Version - v: String, + #[serde(rename = "v")] + #[getset(get = "pub")] + version: String, /// Parent Nodes, identified by cid + #[getset(get = "pub")] parents: Vec, /// The actual payload of the node, which is stored in another document identified by this cid + #[getset(get = "pub")] payload: crate::cid::Cid, } @@ -19,7 +23,7 @@ impl daglib::Node for Node { } impl Node { - pub fn new(v: String, parents: Vec, payload: crate::cid::Cid) -> Self { - Self { v, parents, payload } + pub fn new(version: String, parents: Vec, payload: crate::cid::Cid) -> Self { + Self { version, parents, payload } } } diff --git a/src/types/payload.rs b/src/types/payload.rs index 5b6cfb1..e6ddb0f 100644 --- a/src/types/payload.rs +++ b/src/types/payload.rs @@ -1,12 +1,16 @@ use crate::types::DateTime; -#[derive(Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)] +#[derive(Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, 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, + + #[getset(get = "pub")] content: crate::cid::Cid, } -- cgit v1.2.3