From 685e35d302873d3047ef86dd8904e769202d23cf Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 20 May 2020 11:20:12 +0200 Subject: Unite ipfs-api client abstraction into one "Model" type Signed-off-by: Matthias Beyer --- src/app.rs | 8 +-- src/main.rs | 4 +- src/model.rs | 151 +++++++++++++++++++++++++++++++++++++++++++ src/repository/client.rs | 133 ------------------------------------- src/repository/mod.rs | 2 - src/repository/repository.rs | 71 -------------------- src/types/block.rs | 4 +- src/types/content.rs | 4 +- src/types/payload.rs | 4 +- 9 files changed, 163 insertions(+), 218 deletions(-) create mode 100644 src/model.rs delete mode 100644 src/repository/client.rs delete mode 100644 src/repository/mod.rs delete mode 100644 src/repository/repository.rs diff --git a/src/app.rs b/src/app.rs index b31839f..d356dca 100644 --- a/src/app.rs +++ b/src/app.rs @@ -8,7 +8,7 @@ use crate::types::util::IPFSHash; use crate::types::util::MimeType; use crate::types::util::IPNSHash; use crate::types::block::Block; -use crate::repository::repository::Repository; +use crate::model::Model; use crate::types::content::Content; use crate::types::payload::Payload; use crate::types::util::Timestamp; @@ -16,7 +16,7 @@ use crate::version::protocol_version; #[derive(Debug, Clone)] pub struct App { - repo: Repository, + repo: Model, device_name: IPNSHash, publishing_key: String } @@ -24,10 +24,10 @@ pub struct App { impl App { pub fn load(device_name: IPNSHash, publishing_key: String, host: &str, port: u16) -> Result { - Repository::new(host, port).map(|repo| App { repo, device_name, publishing_key }) + Model::new(host, port).map(|repo| App { repo, device_name, publishing_key }) } - pub async fn new_profile(repo: Repository, publishing_key: &str, names: Vec) -> Result { + pub async fn new_profile(repo: Model, publishing_key: &str, names: Vec) -> Result { let payload = Payload::Profile { names, picture: None, diff --git a/src/main.rs b/src/main.rs index b624bd8..0e91afd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -33,7 +33,7 @@ mod app; mod cli; mod configuration; mod gui; -mod repository; +mod model; mod server; mod types; mod version; @@ -57,7 +57,7 @@ use env_logger::Env; use crate::app::App; use crate::cli::*; use crate::configuration::Configuration; -use crate::repository::repository::Repository; +use crate::model::Model; use crate::types::block::Block; use crate::types::content::Content; use crate::types::payload::Payload; diff --git a/src/model.rs b/src/model.rs new file mode 100644 index 0000000..b81ea17 --- /dev/null +++ b/src/model.rs @@ -0,0 +1,151 @@ +//! The "model" module implements the Database-layer of the application + +use std::io::Cursor; +use std::ops::Deref; +use std::result::Result as RResult; +use std::sync::Arc; + +use anyhow::Error; +use chrono::NaiveDateTime; +use failure::Fail; +use futures::future::Future; +use futures::future::FutureExt; +use futures::stream::Stream; +use futures::stream::StreamExt; +use futures::stream::TryStreamExt; +use ipfs_api::IpfsClient; +use ipfs_api::TryFromUri; +use serde::Serialize; +use serde::de::DeserializeOwned; +use serde_json::from_str as serde_json_from_str; +use serde_json::to_string as serde_json_to_str; + +use crate::types::block::Block; +use crate::types::content::Content; +use crate::types::payload::Payload; +use crate::types::util::IPFSHash; +use crate::types::util::IPNSHash; + +#[derive(Clone)] +pub struct Model(Arc); + +impl std::fmt::Debug for Model{ + fn fmt(&self, f: &mut std::fmt::Formatter) -> RResult<(), std::fmt::Error> { + write!(f, "Model") + } +} + +impl Model { + pub fn new(host: &str, port: u16) -> Result { + debug!("Creating new Model object: {}:{}", host, port); + IpfsClient::from_str(&format!("{}:{}", host, port)) + .map(Arc::new) + .map(|c| Model(c)) + .map_err(|e| Error::from(e.compat())) + } + + + // + // + // Low-level interface to the ipfs-api + // + // + + pub(crate) async fn get_raw_bytes>(&self, hash: H) -> Result, Error> { + debug!("Get: {}", hash.as_ref()); + self.0 + .clone() + .cat(hash.as_ref()) + .map_ok(|b| b.to_vec()) + .try_concat() + .map(|r| r.map_err(|e| anyhow!("UNIMPLEMENTED!()"))) + .await + } + + pub(crate) async fn put_raw_bytes(&self, data: Vec) -> Result { + debug!("Put: {:?}", data); + self.0 + .clone() + .add(Cursor::new(data)) + .await + .map(|res| IPFSHash::from(res.hash)) + .map_err(|e| anyhow!("UNIMPLEMENTED!()")) + } + + pub(crate) async fn publish(&self, key: &str, hash: &str) -> Result { + debug!("Publish: {:?} -> {:?}", key, hash); + self.0 + .clone() + .name_publish(hash, false, None, None, Some(key)) + .await + .map(|res| IPNSHash::from(res.value)) + .map_err(|e| anyhow!("UNIMPLEMENTED!()")) + } + + pub(crate) async fn resolve(&self, ipns: IPNSHash) -> Result { + self.0 + .clone() + .name_resolve(Some(&ipns), true, false) + .await + .map(|res| IPFSHash::from(res.path)) + .map_err(|e| anyhow!("UNIMPLEMENTED!()")) + } + + // + // + // Generic typed interface + // + // + + pub(crate) async fn get_typed(&self, hash: H) -> Result + where H: AsRef, + D: DeserializeOwned + { + self.get_raw_bytes(hash) + .await + .and_then(|data| { + debug!("Got data, building object: {:?}", data); + + serde_json::from_slice(&data).map_err(|e| Error::from(e.compat())) + }) + } + + pub(crate) async fn put_typed(&self, data: &S) -> Result + where S: AsRef, + Ser: Serialize + { + let data = serde_json_to_str(data.as_ref())?; + self.put_raw_bytes(data.into_bytes()).await + } + + // + // + // Typed interface + // + // + + pub async fn get_block(&self, hash: H) -> Result + where H: AsRef + { + self.get_typed(hash).await + } + + pub async fn put_block(&self, b: B) -> Result + where B: AsRef + { + self.put_typed(b.as_ref()).await + } + + pub async fn get_content(&self, hash: H) -> Result + where H: AsRef + { + self.get_typed(hash).await + } + + pub async fn put_content(&self, c: C) -> Result + where C: AsRef + { + self.put_typed(c.as_ref()).await + } + +} diff --git a/src/repository/client.rs b/src/repository/client.rs deleted file mode 100644 index 4466e05..0000000 --- a/src/repository/client.rs +++ /dev/null @@ -1,133 +0,0 @@ -use std::io::Cursor; -use std::sync::Arc; -use std::ops::Deref; -use std::result::Result as RResult; - -use ipfs_api::IpfsClient; -use ipfs_api::TryFromUri; -use anyhow::Error; -use futures::future::Future; -use futures::future::FutureExt; -use futures::stream::Stream; -use futures::stream::StreamExt; -use futures::stream::TryStreamExt; -use failure::Fail; - -use serde_json::from_str as serde_json_from_str; -use serde_json::to_string as serde_json_to_str; -use serde::Serialize; -use serde::de::DeserializeOwned; -use chrono::NaiveDateTime; - -use crate::types::block::Block; -use crate::types::content::Content; -use crate::types::payload::Payload; -use crate::types::util::IPFSHash; -use crate::types::util::IPNSHash; - - -/// Internal ClientFassade types -/// -/// Abstracts the procedural interface of IpfsClient calls. -#[derive(Clone)] -pub struct ClientFassade(Arc); - -impl std::fmt::Debug for ClientFassade { - fn fmt(&self, f: &mut std::fmt::Formatter) -> RResult<(), std::fmt::Error> { - write!(f, "ClientFassade") - } -} - -impl ClientFassade { - fn new(host: &str, port: u16) -> Result { - debug!("Creating new ClientFassade object: {}:{}", host, port); - IpfsClient::from_str(&format!("{}:{}", host, port)) - .map(Arc::new) - .map(|c| ClientFassade(c)) - .map_err(|e| Error::from(e.compat())) - } - - pub async fn get_raw_bytes>(&self, hash: H) -> Result, Error> { - debug!("Get: {}", hash.as_ref()); - self.0 - .clone() - .cat(hash.as_ref()) - .map_ok(|b| b.to_vec()) - .try_concat() - .map(|r| r.map_err(|e| anyhow!("UNIMPLEMENTED!()"))) - .await - } - - pub async fn put_raw_bytes(&self, data: Vec) -> Result { - debug!("Put: {:?}", data); - self.0 - .clone() - .add(Cursor::new(data)) - .await - .map(|res| IPFSHash::from(res.hash)) - .map_err(|e| anyhow!("UNIMPLEMENTED!()")) - } - - pub async fn publish(&self, key: &str, hash: &str) -> Result { - debug!("Publish: {:?} -> {:?}", key, hash); - self.0 - .clone() - .name_publish(hash, false, None, None, Some(key)) - .await - .map(|res| IPNSHash::from(res.value)) - .map_err(|e| anyhow!("UNIMPLEMENTED!()")) - } - - pub async fn resolve(&self, ipns: IPNSHash) -> Result { - self.0 - .clone() - .name_resolve(Some(&ipns), true, false) - .await - .map(|res| IPFSHash::from(res.path)) - .map_err(|e| anyhow!("UNIMPLEMENTED!()")) - } -} - -/// Client wrapper for working with types directly on the client -#[derive(Debug, Clone)] -pub struct TypedClientFassade(ClientFassade); - -impl Deref for TypedClientFassade { - type Target = ClientFassade; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl TypedClientFassade { - pub fn new(host: &str, port: u16) -> Result { - ClientFassade::new(host, port).map(TypedClientFassade) - } - - pub async fn get_typed(&self, hash: H) -> Result - where H: AsRef, - D: DeserializeOwned - { - self.0 - .clone() - .get_raw_bytes(hash) - .await - .and_then(|data| { - debug!("Got data, building object: {:?}", data); - - serde_json::from_slice(&data).map_err(|e| Error::from(e.compat())) - }) - } - - pub async fn put_typed(&self, data: &S) -> Result - where S: AsRef, - Ser: Serialize - { - let client = self.0.clone(); - - let data = serde_json_to_str(data.as_ref())?; - client.put_raw_bytes(data.into_bytes()).await - } - -} diff --git a/src/repository/mod.rs b/src/repository/mod.rs deleted file mode 100644 index dc00895..0000000 --- a/src/repository/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod client; -pub mod repository; diff --git a/src/repository/repository.rs b/src/repository/repository.rs deleted file mode 100644 index cc940c6..0000000 --- a/src/repository/repository.rs +++ /dev/null @@ -1,71 +0,0 @@ -use std::io::Cursor; -use std::sync::Arc; -use std::ops::Deref; - -use ipfs_api::IpfsClient; -use anyhow::Error; -use futures::future::Future; -use futures::stream::Stream; - -use serde_json::from_str as serde_json_from_str; -use serde_json::to_string as serde_json_to_str; -use serde::Serialize; -use serde::de::DeserializeOwned; -use chrono::NaiveDateTime; - -use crate::types::block::Block; -use crate::types::content::Content; -use crate::types::payload::Payload; -use crate::types::util::IPFSHash; -use crate::types::util::IPNSHash; -use crate::repository::client::TypedClientFassade; - - -/// High-level Client abstraction -/// -/// Still a low-level interface though, because we're still operating on the repository directly. -/// -/// Should not be used too extensively, but rather through the "Profile" type, which represents the -/// profile of a user. -#[derive(Debug, Clone)] -pub struct Repository(TypedClientFassade); - -impl Deref for Repository { - type Target = TypedClientFassade; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl Repository { - pub fn new(host: &str, port: u16) -> Result { - TypedClientFassade::new(host, port).map(Repository) - } - - pub async fn get_block(&self, hash: H) -> Result - where H: AsRef - { - self.0.get_typed(hash).await - } - - pub async fn put_block(&self, b: B) -> Result - where B: AsRef - { - self.0.put_typed(b.as_ref()).await - } - - pub async fn get_content(&self, hash: H) -> Result - where H: AsRef - { - self.0.get_typed(hash).await - } - - pub async fn put_content(&self, c: C) -> Result - where C: AsRef - { - self.0.put_typed(c.as_ref()).await - } - -} - diff --git a/src/types/block.rs b/src/types/block.rs index 1927d55..c70ceef 100644 --- a/src/types/block.rs +++ b/src/types/block.rs @@ -3,7 +3,7 @@ use crate::types::util::Version; use crate::types::content::Content; use crate::types::payload::*; use crate::types::content::LoadedContent; -use crate::repository::repository::Repository; +use crate::model::Model; use anyhow::Error; @@ -42,7 +42,7 @@ impl Block { &self.content } - pub async fn load(self, r: &Repository) -> Result { + pub async fn load(self, r: &Model) -> Result { Ok({ LoadedBlock { version: self.version, diff --git a/src/types/content.rs b/src/types/content.rs index 4812abd..8b6eb4d 100644 --- a/src/types/content.rs +++ b/src/types/content.rs @@ -8,7 +8,7 @@ use crate::types::util::MimeType; use crate::types::util::Timestamp; use crate::types::payload::Payload; use crate::types::payload::LoadedPayload; -use crate::repository::repository::Repository; +use crate::model::Model; #[derive(Serialize, Deserialize, Debug)] pub struct Content { @@ -63,7 +63,7 @@ impl Content { self.devices.push(dev); } - pub async fn load(self, r: &Repository) -> Result { + pub async fn load(self, r: &Model) -> Result { Ok({ LoadedContent { devices: self.devices, diff --git a/src/types/payload.rs b/src/types/payload.rs index 2d85c22..47f28a6 100644 --- a/src/types/payload.rs +++ b/src/types/payload.rs @@ -6,7 +6,7 @@ use crate::types::util::IPFSHash; use crate::types::util::IPNSHash; use crate::types::util::MimeType; use crate::types::util::Timestamp; -use crate::repository::repository::Repository; +use crate::model::Model; /// The Payload type represents the Payload of a Content object @@ -166,7 +166,7 @@ impl Payload { } } - pub async fn load(self, r: &Repository) -> Result { + pub async fn load(self, r: &Model) -> Result { match self { Payload::None => Ok(LoadedPayload::None), Payload::Post { -- cgit v1.2.3 From f3e5201c497dfcbd8982a45e0066dbd3a2bd234d Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 20 May 2020 11:21:11 +0200 Subject: Remove unused module Signed-off-by: Matthias Beyer --- src/profile.rs | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 src/profile.rs diff --git a/src/profile.rs b/src/profile.rs deleted file mode 100644 index 870db08..0000000 --- a/src/profile.rs +++ /dev/null @@ -1,6 +0,0 @@ - -#[derive(Serialize, Deserialize, Debug)] -struct Profile { - device_name: String, - other_devices: Vec, -} -- cgit v1.2.3