Skip to content

Commit

Permalink
feat(api): Implement CidLink, BlobRef types (#96)
Browse files Browse the repository at this point in the history
* Implement CidLink, BlobRef types

* Replace BlobRef

* Update dependencies, tests

* Fix codegen, update API codes

* Remove unused code
  • Loading branch information
sugyan authored Feb 8, 2024
1 parent 0978304 commit d1c19a4
Show file tree
Hide file tree
Showing 17 changed files with 552 additions and 19 deletions.
5 changes: 4 additions & 1 deletion .github/workflows/api.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,7 @@ jobs:
- name: Build
run: cargo build -p atrium-api --verbose
- name: Run tests
run: cargo test -p atrium-api --verbose
run: |
cargo test -p atrium-api --lib
cargo test -p atrium-api --lib --no-default-features
cargo test -p atrium-api --lib --all-features
5 changes: 4 additions & 1 deletion atrium-api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,24 @@ keywords = ["atproto", "bluesky"]
[dependencies]
atrium-xrpc = "0.8.0"
async-trait = "0.1.68"
cid = { version = "0.10.1", features = ["serde-codec"] }
http = "0.2.9"
serde = { version = "1.0.160", features = ["derive"] }
serde_bytes = "0.11.9"
tokio = { version = "1.33.0", default-features = false, optional = true }
cid = { version = "0.10.1", optional = true }
libipld-core = { version = "0.16.0", optional = true }

[features]
default = ["agent"]
agent = ["tokio/sync"]
dag-cbor = ["cid/serde-codec", "libipld-core/serde-codec"]

[dev-dependencies]
atrium-xrpc-client = "0.2.0"
futures = "0.3.28"
serde_json = "1.0.107"
tokio = { version = "1.33.0", features = ["macros", "rt-multi-thread"] }
serde_ipld_dagcbor = { git = "https://github.com/sugyan/serde_ipld_dagcbor.git", rev = "345b240" }

[package.metadata.docs.rs]
all-features = true
Expand Down
194 changes: 194 additions & 0 deletions atrium-api/benches/cid-link.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
#![feature(test)]

extern crate test;
use serde::Deserialize;
use test::Bencher;

const JSON_STR: &str = r#"{
"$link": "bafkreibme22gw2h7y2h7tg2fhqotaqjucnbc24deqo72b6mkl2egezxhvy"
}"#;

const CBOR_CID: [u8; 41] = [
0xd8, 0x2a, 0x58, 0x25, 0x00, 0x01, 0x55, 0x12, 0x20, 0x2c, 0x26, 0xb4, 0x6b, 0x68, 0xff, 0xc6,
0x8f, 0xf9, 0x9b, 0x45, 0x3c, 0x1d, 0x30, 0x41, 0x34, 0x13, 0x42, 0x2d, 0x70, 0x64, 0x83, 0xbf,
0xa0, 0xf9, 0x8a, 0x5e, 0x88, 0x62, 0x66, 0xe7, 0xae,
];

mod via_ipld {
use super::*;
use libipld_core::ipld::Ipld;

#[derive(PartialEq, Eq, Debug)]
pub struct CidLink(pub cid::Cid);

impl<'de> Deserialize<'de> for CidLink {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let ipld = Ipld::deserialize(deserializer)?;
match &ipld {
Ipld::Link(cid) => {
return Ok(Self(*cid));
}
Ipld::Map(map) => {
if map.len() == 1 {
if let Some(Ipld::String(link)) = map.get("$link") {
return Ok(Self(
cid::Cid::try_from(link.as_str())
.map_err(serde::de::Error::custom)?,
));
}
}
}
_ => {}
}
Err(serde::de::Error::custom("Invalid cid-link"))
}
}
}

mod untagged_1 {
use super::*;

#[derive(Deserialize, PartialEq, Eq, Debug)]
#[serde(untagged)]
pub enum CidLink {
Raw(cid::Cid),
Object {
#[serde(rename = "$link")]
link: String,
},
}
}

mod untagged_2 {
use super::*;

#[derive(Deserialize, PartialEq, Eq, Debug)]
#[serde(untagged)]
pub enum CidLink {
Object {
#[serde(rename = "$link")]
link: String,
},
Raw(cid::Cid),
}
}

mod only_json {
use super::*;

#[derive(Deserialize, PartialEq, Eq, Debug)]

pub struct CidLink {
#[serde(rename = "$link")]
pub link: String,
}
}

mod only_cbor {
use super::*;

#[derive(Deserialize, PartialEq, Eq, Debug)]

pub struct CidLink(pub cid::Cid);
}

fn cid() -> cid::Cid {
serde_ipld_dagcbor::from_slice::<cid::Cid>(&CBOR_CID).expect("failed to deserialize cid")
}

#[bench]
fn bench_cbor_untagged_1(b: &mut Bencher) {
let expected = untagged_1::CidLink::Raw(cid());

b.iter(|| {
let result = serde_ipld_dagcbor::from_slice::<untagged_1::CidLink>(&CBOR_CID)
.expect("failed to deserialize cid_link");
assert_eq!(result, expected);
});
}

#[bench]
fn bench_json_untagged_1(b: &mut Bencher) {
let expected = untagged_1::CidLink::Object {
link: cid().to_string(),
};

b.iter(|| {
let result = serde_json::from_str::<untagged_1::CidLink>(JSON_STR)
.expect("failed to deserialize cid_link");
assert_eq!(result, expected);
});
}

#[bench]
fn bench_cbor_untagged_2(b: &mut Bencher) {
let expected = untagged_2::CidLink::Raw(cid());

b.iter(|| {
let result = serde_ipld_dagcbor::from_slice::<untagged_2::CidLink>(&CBOR_CID)
.expect("failed to deserialize cid_link");
assert_eq!(result, expected);
});
}

#[bench]
fn bench_json_untagged_2(b: &mut Bencher) {
let expected = untagged_2::CidLink::Object {
link: cid().to_string(),
};

b.iter(|| {
let result = serde_json::from_str::<untagged_2::CidLink>(JSON_STR)
.expect("failed to deserialize cid_link");
assert_eq!(result, expected);
});
}

#[bench]
fn bench_cbor_via_ipld(b: &mut Bencher) {
let expected = via_ipld::CidLink(cid());

b.iter(|| {
let result = serde_ipld_dagcbor::from_slice::<via_ipld::CidLink>(&CBOR_CID)
.expect("failed to deserialize cid_link");
assert_eq!(result, expected);
});
}

#[bench]
fn bench_json_via_ipld(b: &mut Bencher) {
let expected = via_ipld::CidLink(cid());

b.iter(|| {
let result = serde_json::from_str::<via_ipld::CidLink>(JSON_STR)
.expect("failed to deserialize cid_link");
assert_eq!(result, expected);
});
}

#[bench]
fn bench_json_only(b: &mut Bencher) {
let expected = only_json::CidLink {
link: cid().to_string(),
};

b.iter(|| {
let result = serde_json::from_str::<only_json::CidLink>(JSON_STR)
.expect("failed to deserialize cid_link");
assert_eq!(result, expected);
});
}

#[bench]
fn bench_cbor_only(b: &mut Bencher) {
let expected = only_cbor::CidLink(cid());

b.iter(|| {
let result = serde_ipld_dagcbor::from_slice::<only_cbor::CidLink>(&CBOR_CID)
.expect("failed to deserialize cid_link");
assert_eq!(result, expected);
});
}
4 changes: 2 additions & 2 deletions atrium-api/src/app/bsky/actor/profile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
#[serde(rename_all = "camelCase")]
pub struct Record {
#[serde(skip_serializing_if = "Option::is_none")]
pub avatar: Option<crate::blob::BlobRef>,
pub avatar: Option<crate::types::BlobRef>,
#[serde(skip_serializing_if = "Option::is_none")]
pub banner: Option<crate::blob::BlobRef>,
pub banner: Option<crate::types::BlobRef>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
Expand Down
2 changes: 1 addition & 1 deletion atrium-api/src/app/bsky/embed/external.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub struct Main {
pub struct External {
pub description: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub thumb: Option<crate::blob::BlobRef>,
pub thumb: Option<crate::types::BlobRef>,
pub title: String,
pub uri: String,
}
Expand Down
2 changes: 1 addition & 1 deletion atrium-api/src/app/bsky/embed/images.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pub struct Image {
pub alt: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub aspect_ratio: Option<AspectRatio>,
pub image: crate::blob::BlobRef,
pub image: crate::types::BlobRef,
}
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
Expand Down
2 changes: 1 addition & 1 deletion atrium-api/src/app/bsky/feed/generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#[serde(rename_all = "camelCase")]
pub struct Record {
#[serde(skip_serializing_if = "Option::is_none")]
pub avatar: Option<crate::blob::BlobRef>,
pub avatar: Option<crate::types::BlobRef>,
pub created_at: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
Expand Down
2 changes: 1 addition & 1 deletion atrium-api/src/app/bsky/graph/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#[serde(rename_all = "camelCase")]
pub struct Record {
#[serde(skip_serializing_if = "Option::is_none")]
pub avatar: Option<crate::blob::BlobRef>,
pub avatar: Option<crate::types::BlobRef>,
pub created_at: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
Expand Down
1 change: 1 addition & 0 deletions atrium-api/src/com/atproto/label/subscribe_labels.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// This file is generated by atrium-codegen. DO NOT EDIT.
//!Definitions for the `com.atproto.label.subscribeLabels` namespace.
pub const NSID: &str = "com.atproto.label.subscribeLabels";
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct Parameters {
Expand Down
2 changes: 1 addition & 1 deletion atrium-api/src/com/atproto/repo/upload_blob.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct Output {
pub blob: crate::blob::BlobRef,
pub blob: crate::types::BlobRef,
}
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
#[serde(tag = "error", content = "message")]
Expand Down
9 changes: 5 additions & 4 deletions atrium-api/src/com/atproto/sync/subscribe_repos.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// This file is generated by atrium-codegen. DO NOT EDIT.
//!Definitions for the `com.atproto.sync.subscribeRepos` namespace.
pub const NSID: &str = "com.atproto.sync.subscribeRepos";
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct Parameters {
Expand All @@ -16,14 +17,14 @@ pub enum Error {
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct Commit {
pub blobs: Vec<cid::Cid>,
pub blobs: Vec<crate::types::CidLink>,
///CAR file containing relevant blocks.
#[serde(with = "serde_bytes")]
pub blocks: Vec<u8>,
pub commit: cid::Cid,
pub commit: crate::types::CidLink,
pub ops: Vec<RepoOp>,
#[serde(skip_serializing_if = "Option::is_none")]
pub prev: Option<cid::Cid>,
pub prev: Option<crate::types::CidLink>,
pub rebase: bool,
pub repo: String,
///The rev of the emitted commit.
Expand Down Expand Up @@ -65,7 +66,7 @@ pub struct Migrate {
pub struct RepoOp {
pub action: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub cid: Option<cid::Cid>,
pub cid: Option<crate::types::CidLink>,
pub path: String,
}
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
Expand Down
2 changes: 1 addition & 1 deletion atrium-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ pub use atrium_xrpc as xrpc;
#[cfg(feature = "agent")]
pub mod agent;
pub mod app;
pub mod blob;
pub mod client;
pub mod com;
pub mod did_doc;
pub mod records;
pub mod types;
Loading

0 comments on commit d1c19a4

Please sign in to comment.