A better Rust ATProto crate

tested one commit too late

Orual 05de6ab5 a867fc82

Changed files
+56 -10
crates
jacquard
+1 -1
Cargo.lock
···
[[package]]
name = "jacquard"
-
version = "0.2.0"
dependencies = [
"async-trait",
"bon",
···
[[package]]
name = "jacquard"
+
version = "0.2.1"
dependencies = [
"async-trait",
"bon",
+5 -3
crates/jacquard/Cargo.toml
···
name = "jacquard"
description.workspace = true
edition.workspace = true
-
version.workspace = true
authors.workspace = true
repository.workspace = true
keywords.workspace = true
···
license.workspace = true
[features]
-
default = ["api_all", "dns"]
derive = ["dep:jacquard-derive"]
api = ["jacquard-api/com_atproto"]
api_all = ["api", "jacquard-api/app_bsky", "jacquard-api/chat_bsky", "jacquard-api/tools_ozone"]
dns = ["dep:hickory-resolver"]
[lib]
name = "jacquard"
···
[[bin]]
name = "jacquard"
path = "src/main.rs"
[dependencies]
bon = "3"
···
jacquard-api = { version = "0.2.0", path = "../jacquard-api" }
jacquard-common = { version = "0.2.0", path = "../jacquard-common" }
jacquard-derive = { version = "0.2.0", path = "../jacquard-derive", optional = true }
-
miette.workspace = true
reqwest = { workspace = true, features = ["charset", "http2", "json", "system-proxy", "gzip", "rustls-tls"] }
serde.workspace = true
serde_html_form.workspace = true
···
name = "jacquard"
description.workspace = true
edition.workspace = true
+
version = "0.2.1"
authors.workspace = true
repository.workspace = true
keywords.workspace = true
···
license.workspace = true
[features]
+
default = ["api_all", "dns", "fancy"]
derive = ["dep:jacquard-derive"]
api = ["jacquard-api/com_atproto"]
api_all = ["api", "jacquard-api/app_bsky", "jacquard-api/chat_bsky", "jacquard-api/tools_ozone"]
dns = ["dep:hickory-resolver"]
+
fancy = ["miette/fancy"]
[lib]
name = "jacquard"
···
[[bin]]
name = "jacquard"
path = "src/main.rs"
+
[dependencies]
bon = "3"
···
jacquard-api = { version = "0.2.0", path = "../jacquard-api" }
jacquard-common = { version = "0.2.0", path = "../jacquard-common" }
jacquard-derive = { version = "0.2.0", path = "../jacquard-derive", optional = true }
+
miette = { workspace = true }
reqwest = { workspace = true, features = ["charset", "http2", "json", "system-proxy", "gzip", "rustls-tls"] }
serde.workspace = true
serde_html_form.workspace = true
+49 -5
crates/jacquard/src/identity/resolver.rs
···
//! Parsing returns a `DidDocResponse` so callers can borrow from the response buffer
//! and optionally validate the document `id` against the requested DID.
// use crate::CowStr; // not currently needed directly here
use crate::client::XrpcExt;
use bon::Builder;
use bytes::Bytes;
-
use jacquard_common::IntoStatic;
use miette::Diagnostic;
use percent_encoding::percent_decode_str;
use reqwest::StatusCode;
···
/// Parse as borrowed DidDocument<'_>
pub fn parse<'b>(&'b self) -> Result<DidDocument<'b>, IdentityError> {
if self.status.is_success() {
-
serde_json::from_slice::<DidDocument<'b>>(&self.buffer).map_err(IdentityError::from)
} else {
Err(IdentityError::HttpStatus(self.status))
}
···
/// Parse as owned DidDocument<'static>
pub fn into_owned(self) -> Result<DidDocument<'static>, IdentityError> {
if self.status.is_success() {
-
serde_json::from_slice::<DidDocument<'_>>(&self.buffer)
-
.map(|d| d.into_static())
-
.map_err(IdentityError::from)
} else {
Err(IdentityError::HttpStatus(self.status))
}
···
//! Parsing returns a `DidDocResponse` so callers can borrow from the response buffer
//! and optionally validate the document `id` against the requested DID.
+
use std::collections::BTreeMap;
+
use std::str::FromStr;
+
// use crate::CowStr; // not currently needed directly here
use crate::client::XrpcExt;
use bon::Builder;
use bytes::Bytes;
+
use jacquard_common::types::did_doc::Service;
+
use jacquard_common::types::string::AtprotoStr;
+
use jacquard_common::types::uri::Uri;
+
use jacquard_common::types::value::Data;
+
use jacquard_common::{CowStr, IntoStatic};
use miette::Diagnostic;
use percent_encoding::percent_decode_str;
use reqwest::StatusCode;
···
/// Parse as borrowed DidDocument<'_>
pub fn parse<'b>(&'b self) -> Result<DidDocument<'b>, IdentityError> {
if self.status.is_success() {
+
if let Ok(doc) = serde_json::from_slice::<DidDocument<'b>>(&self.buffer) {
+
Ok(doc)
+
} else if let Ok(mini_doc) = serde_json::from_slice::<MiniDoc<'b>>(&self.buffer) {
+
Ok(DidDocument {
+
id: mini_doc.did,
+
also_known_as: Some(vec![CowStr::from(mini_doc.handle)]),
+
verification_method: None,
+
service: Some(vec![Service {
+
id: CowStr::new_static("#atproto_pds"),
+
r#type: CowStr::new_static("AtprotoPersonalDataServer"),
+
service_endpoint: Some(Data::String(AtprotoStr::Uri(Uri::Https(
+
Url::from_str(&mini_doc.pds).unwrap(),
+
)))),
+
extra_data: BTreeMap::new(),
+
}]),
+
extra_data: BTreeMap::new(),
+
})
+
} else {
+
Err(IdentityError::MissingPdsEndpoint)
+
}
} else {
Err(IdentityError::HttpStatus(self.status))
}
···
/// Parse as owned DidDocument<'static>
pub fn into_owned(self) -> Result<DidDocument<'static>, IdentityError> {
if self.status.is_success() {
+
if let Ok(doc) = serde_json::from_slice::<DidDocument<'_>>(&self.buffer) {
+
Ok(doc.into_static())
+
} else if let Ok(mini_doc) = serde_json::from_slice::<MiniDoc<'_>>(&self.buffer) {
+
Ok(DidDocument {
+
id: mini_doc.did,
+
also_known_as: Some(vec![CowStr::from(mini_doc.handle)]),
+
verification_method: None,
+
service: Some(vec![Service {
+
id: CowStr::new_static("#atproto_pds"),
+
r#type: CowStr::new_static("AtprotoPersonalDataServer"),
+
service_endpoint: Some(Data::String(AtprotoStr::Uri(Uri::Https(
+
Url::from_str(&mini_doc.pds).unwrap(),
+
)))),
+
extra_data: BTreeMap::new(),
+
}]),
+
extra_data: BTreeMap::new(),
+
}
+
.into_static())
+
} else {
+
Err(IdentityError::MissingPdsEndpoint)
+
}
} else {
Err(IdentityError::HttpStatus(self.status))
}
+1 -1
crates/jacquard/src/main.rs
···
use jacquard::api::app_bsky::feed::get_timeline::GetTimeline;
use jacquard::api::com_atproto::server::create_session::CreateSession;
use jacquard::client::{BasicClient, Session};
-
use jacquard::identity::resolver::{slingshot_resolver_default, IdentityResolver};
use jacquard::types::string::Handle;
use miette::IntoDiagnostic;
···
use jacquard::api::app_bsky::feed::get_timeline::GetTimeline;
use jacquard::api::com_atproto::server::create_session::CreateSession;
use jacquard::client::{BasicClient, Session};
+
use jacquard::identity::resolver::{IdentityResolver, slingshot_resolver_default};
use jacquard::types::string::Handle;
use miette::IntoDiagnostic;