Nothing to see here

refactor: add 'com.atproto.repo.listRecords' to lexicon and use when fetching public keys

Signed-off-by: tjh <did:plc:65gha4t3avpfpzmvpbwovss7>

tjh.dev dbc910a2 0ff3397f

verified
Changed files
+77 -6
crates
knot
src
lexicon
src
+14 -6
crates/knot/src/model/knot_state.rs
··· 1 1 use identity::Did; 2 2 use identity::Resolver; 3 + use lexicon::com::atproto::repo::list_records; 3 4 use oauth::public_key::PublicKey; 4 5 use std::collections::HashMap; 5 6 use std::path::PathBuf; ··· 72 71 .ok_or(anyhow::anyhow!("DID document does not declare a pds"))? 73 72 .service_endpoint; 74 73 75 - let response: crate::atproto::Response<LexiconPublicKey> = self 74 + let response = self 76 75 .public_http 77 76 .get(list_records_url(pds.clone(), "sh.tangled.publicKey", did)) 78 77 .send() 79 78 .await? 80 - .json() 79 + .error_for_status()? 80 + .bytes() 81 81 .await?; 82 82 83 - Ok(response 84 - .records 85 - .into_iter() 86 - .filter_map(|rec| PublicKey::from_openssh(&rec.value.key).ok()) 83 + let result: list_records::Output<LexiconPublicKey> = serde_json::from_slice(&response)?; 84 + Ok(result 85 + .records() 86 + .filter_map(|rec| { 87 + PublicKey::from_openssh(&rec.value.key) 88 + .inspect_err(|e| { 89 + tracing::error!(?e, ?did, "failed to parse public key from collection") 90 + }) 91 + .ok() 92 + }) 87 93 .collect()) 88 94 } 89 95 }
+1
crates/lexicon/src/com.rs
··· 1 + pub mod atproto;
+1
crates/lexicon/src/com/atproto.rs
··· 1 + pub mod repo;
+60
crates/lexicon/src/com/atproto/repo.rs
··· 1 + pub mod list_records { 2 + //! 3 + //! List a range of records in a repository, matching a specific 4 + //! collection. Does not require auth. 5 + //! 6 + //! <https://docs.bsky.app/docs/api/com-atproto-repo-list-records> 7 + //! 8 + use serde::{Deserialize, Serialize}; 9 + use std::borrow::Cow; 10 + 11 + #[derive(Debug, Deserialize, Serialize)] 12 + pub struct Input<'a> { 13 + /// The handle or DID of the repo. 14 + #[serde(borrow)] 15 + pub repo: Cow<'a, str>, 16 + 17 + /// The NSID of the record type. 18 + #[serde(borrow)] 19 + pub collection: Cow<'a, str>, 20 + 21 + /// The number of records to return. 22 + /// 23 + /// Possible values: 0..=100. 24 + #[serde(skip_serializing_if = "Option::is_none")] 25 + pub limit: Option<usize>, 26 + 27 + #[serde(borrow, skip_serializing_if = "Option::is_none")] 28 + pub cursor: Option<Cow<'a, str>>, 29 + 30 + /// Flag to reverse the order of the returned records. 31 + #[serde(default)] 32 + pub reverse: bool, 33 + } 34 + 35 + #[derive(Debug, Deserialize, Serialize)] 36 + pub struct Output<'a, T> { 37 + #[serde(skip_serializing_if = "Option::is_none")] 38 + pub cursor: Option<Cow<'a, str>>, 39 + 40 + #[serde(borrow)] 41 + pub records: Vec<Record<'a, T>>, 42 + } 43 + 44 + #[derive(Debug, Deserialize, Serialize)] 45 + pub struct Record<'a, T> { 46 + #[serde(borrow)] 47 + pub uri: Cow<'a, str>, 48 + 49 + #[serde(borrow)] 50 + pub cid: Cow<'a, str>, 51 + 52 + pub value: T, 53 + } 54 + 55 + impl<'a, T> Output<'a, T> { 56 + pub fn records(&self) -> impl Iterator<Item = &Record<'a, T>> { 57 + self.records.iter() 58 + } 59 + } 60 + }
+1
crates/lexicon/src/lib.rs
··· 4 4 //! When you're too lazy to setup codegen, not lazy enough to not write them 5 5 //! all out manually. 6 6 //! 7 + pub mod com; 7 8 pub mod sh; 8 9 9 10 /// Types which aren't part of the lexicon, but are used for serializing