From b87392caa37f0870d45903d002fae22fe79c33dd Mon Sep 17 00:00:00 2001 From: Kayh Date: Tue, 19 Dec 2023 09:29:33 -0500 Subject: [PATCH] add Data trait + JsonData --- Cargo.lock | 19 ++++++++++++ dwn-server/tests/messages.rs | 4 +-- dwn/Cargo.toml | 1 + dwn/src/data.rs | 60 ++++++++++++++++++++++++++++++++++++ dwn/src/lib.rs | 1 + dwn/src/request.rs | 44 ++++++++++---------------- dwn/src/util.rs | 1 - 7 files changed, 99 insertions(+), 31 deletions(-) create mode 100644 dwn/src/data.rs diff --git a/Cargo.lock b/Cargo.lock index bea8a53..b302f1f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -370,6 +370,7 @@ dependencies = [ "iana-media-types", "libipld-cbor", "libipld-core", + "libipld-json", "libipld-pb", "multihash-codetable", "serde", @@ -798,6 +799,18 @@ dependencies = [ "thiserror", ] +[[package]] +name = "libipld-json" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25856def940047b07b25c33d4e66d248597049ab0202085215dc4dca0487731c" +dependencies = [ + "libipld-core", + "multihash 0.18.1", + "serde", + "serde_json", +] + [[package]] name = "libipld-pb" version = "0.16.0" @@ -887,10 +900,16 @@ version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfd8a792c1694c6da4f68db0a9d707c72bd260994da179e6030a5dcee00bb815" dependencies = [ + "blake2b_simd", + "blake2s_simd", + "blake3", "core2", + "digest", "multihash-derive 0.8.0", "serde", "serde-big-array", + "sha2", + "sha3", "unsigned-varint 0.7.2", ] diff --git a/dwn-server/tests/messages.rs b/dwn-server/tests/messages.rs index 04419b6..c88d206 100644 --- a/dwn-server/tests/messages.rs +++ b/dwn-server/tests/messages.rs @@ -1,4 +1,5 @@ use dwn::{ + data::JsonData, features::FeatureDetection, request::{ media_types::{Application, MediaType}, @@ -35,12 +36,11 @@ async fn send_post(data: RequestBody, port: u16) -> Response { } fn empty_message() -> Message { - let builder = MessageBuilder { + let builder = MessageBuilder:: { data: None, descriptor: DescriptorBuilder { method: Method::FeatureDetectionRead, interface: Interface::FeatureDetection, - data_format: None, }, }; diff --git a/dwn/Cargo.toml b/dwn/Cargo.toml index 0f08f39..723d8ba 100644 --- a/dwn/Cargo.toml +++ b/dwn/Cargo.toml @@ -12,6 +12,7 @@ cid = "0.11.0" iana-media-types = "0.1.2" libipld-cbor = "0.16.0" libipld-core = "0.16.0" +libipld-json = "0.16.0" libipld-pb = "0.16.0" multihash-codetable = { version = "0.1.1", features = ["digest", "sha2"] } serde = { version = "1.0.193", features = ["derive"] } diff --git a/dwn/src/data.rs b/dwn/src/data.rs new file mode 100644 index 0000000..854426e --- /dev/null +++ b/dwn/src/data.rs @@ -0,0 +1,60 @@ +use base64::Engine; +use iana_media_types::Application; +use libipld_core::{codec::Codec, ipld::Ipld}; +use libipld_json::DagJsonCodec; +use serde::{Deserialize, Serialize}; +use serde_json::Value; + +use crate::request::DataFormat; + +pub trait Data { + /// Returns the data as a base64url-encoded string. + fn to_base64url(&self) -> String; + /// Returns the data as an IPLD object. + fn to_ipld(&self) -> Ipld; + /// Returns the data format of this data. + fn data_format(&self) -> DataFormat; +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct JsonData(Value); + +impl Data for JsonData { + fn to_base64url(&self) -> String { + base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(self.0.to_string()) + } + + fn to_ipld(&self) -> Ipld { + let json = self.0.to_string(); + let bytes = json.as_bytes(); + DagJsonCodec.decode(bytes).expect("Failed to decode JSON") + } + + fn data_format(&self) -> DataFormat { + DataFormat::MediaType(Application::Json.into()) + } +} + +#[cfg(test)] +mod tests { + use super::{Data, JsonData}; + use libipld_core::codec::Codec; + + #[test] + fn test_json_data() { + let data = JsonData(serde_json::json!({ + "foo": "bar", + })); + + assert_eq!(data.to_base64url(), "eyJmb28iOiJiYXIifQ"); + assert_eq!(data.data_format().to_string(), "\"application/json\""); + + let ipld = data.to_ipld(); + let encoded = libipld_json::DagJsonCodec + .encode(&ipld) + .expect("Failed to encode IPLD"); + let encoded_string = String::from_utf8(encoded).expect("Failed to convert to string"); + + assert_eq!(encoded_string, "{\"foo\":\"bar\"}"); + } +} diff --git a/dwn/src/lib.rs b/dwn/src/lib.rs index 0c90310..78b959e 100644 --- a/dwn/src/lib.rs +++ b/dwn/src/lib.rs @@ -1,3 +1,4 @@ +pub mod data; pub mod features; pub mod request; pub mod response; diff --git a/dwn/src/request.rs b/dwn/src/request.rs index bb72c28..936fa35 100644 --- a/dwn/src/request.rs +++ b/dwn/src/request.rs @@ -1,11 +1,9 @@ -use base64::Engine; pub use iana_media_types as media_types; use libipld_cbor::DagCborCodec; use serde::{Deserialize, Serialize}; -use serde_json::Value; use std::fmt::Display; -use crate::util::cid_from_bytes; +use crate::{data::Data, util::cid_from_bytes}; #[derive(Clone, Debug, Deserialize, Serialize)] pub struct RequestBody { @@ -21,12 +19,12 @@ pub struct Message { pub descriptor: Descriptor, } -pub struct MessageBuilder { - pub data: Option, +pub struct MessageBuilder { + pub data: Option, pub descriptor: DescriptorBuilder, } -impl MessageBuilder { +impl MessageBuilder { pub fn build(&self) -> Result> { let data = self.data.as_ref().map(|d| d.to_base64url()); let descriptor = self.descriptor.build(self.data.as_ref())?; @@ -47,22 +45,6 @@ impl MessageBuilder { } } -#[derive(Clone, Debug, Deserialize, Serialize)] -#[serde(untagged)] -pub enum Data { - Json(Value), -} - -impl Data { - pub fn to_base64url(&self) -> String { - match self { - Data::Json(value) => { - base64::engine::general_purpose::URL_SAFE.encode(value.to_string()) - } - } - } -} - #[derive(Serialize)] pub struct RecordIdGenerator { #[serde(rename = "descriptorCid")] @@ -130,7 +112,7 @@ impl Display for Method { } } -#[derive(Clone, Debug, Deserialize, Serialize)] +#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)] #[serde(untagged)] pub enum DataFormat { /// JSON Web Token formatted Verifiable Credential @@ -157,20 +139,26 @@ impl From<&DataFormat> for String { pub struct DescriptorBuilder { pub interface: Interface, pub method: Method, - pub data_format: Option, } impl DescriptorBuilder { - pub fn build(&self, data: Option<&Data>) -> Result> { - let data_cid = data.map(|_d| { - "".to_string() // TODO: Generate CID + pub fn build( + &self, + data: Option<&T>, + ) -> Result> { + let data_cid = data.map(|d| { + // TODO: Generate CID + let pb = d.to_ipld(); + "TODO".to_string() }); + let data_format = data.map(|d| d.data_format()); + Ok(Descriptor { interface: self.interface.clone(), method: self.method.clone(), data_cid, - data_format: self.data_format.clone(), + data_format, }) } } diff --git a/dwn/src/util.rs b/dwn/src/util.rs index 1944d4c..58e70e1 100644 --- a/dwn/src/util.rs +++ b/dwn/src/util.rs @@ -1,5 +1,4 @@ use cid::Cid; - use multihash_codetable::{Code, MultihashDigest}; pub fn cid_from_bytes(codec: u64, bytes: &[u8]) -> Cid {