Constellation, Spacedust, Slingshot, UFOs: atproto crates and services for microcosm

com.bad-example.repo.getUriRecord

Changed files
+80 -6
slingshot
+1
Cargo.lock
··· 4924 4924 "foyer", 4925 4925 "hickory-resolver", 4926 4926 "jetstream", 4927 + "links", 4927 4928 "log", 4928 4929 "metrics", 4929 4930 "metrics-exporter-prometheus 0.17.2",
+1
slingshot/Cargo.toml
··· 13 13 foyer = { version = "0.18.0", features = ["serde"] } 14 14 hickory-resolver = "0.25.2" 15 15 jetstream = { path = "../jetstream", features = ["metrics"] } 16 + links = { path = "../links" } 16 17 log = "0.4.27" 17 18 metrics = "0.24.2" 18 19 metrics-exporter-prometheus = { version = "0.17.1", features = ["http-listener"] }
+78 -6
slingshot/src/server.rs
··· 4 4 }; 5 5 use atrium_api::types::string::{Cid, Did, Handle, Nsid, RecordKey}; 6 6 use foyer::HybridCache; 7 + use links::at_uri::parse_at_uri as normalize_at_uri; 7 8 use serde::Serialize; 8 9 use std::path::PathBuf; 9 10 use std::str::FromStr; ··· 32 33 } 33 34 fn example_rkey() -> String { 34 35 "3lv4ouczo2b2a".to_string() 36 + } 37 + fn example_uri() -> String { 38 + format!( 39 + "at://{}/{}/{}", 40 + example_did(), 41 + example_collection(), 42 + example_rkey() 43 + ) 35 44 } 36 45 37 46 #[derive(Object)] ··· 84 93 impl Example for FoundRecordResponseObject { 85 94 fn example() -> Self { 86 95 Self { 87 - uri: format!( 88 - "at://{}/{}/{}", 89 - example_did(), 90 - example_collection(), 91 - example_rkey() 92 - ), 96 + uri: example_uri(), 93 97 cid: Some("bafyreialv3mzvvxaoyrfrwoer3xmabbmdchvrbyhayd7bga47qjbycy74e".to_string()), 94 98 value: serde_json::json!({ 95 99 "$type": "app.bsky.feed.like", ··· 157 161 /// found. That is: slingshot only retains the most recent version of a 158 162 /// record. (TODO: verify bsky behaviour for mismatched/old CID) 159 163 Query(cid): Query<Option<String>>, 164 + ) -> GetRecordResponse { 165 + self.get_record_impl(repo, collection, rkey, cid).await 166 + } 167 + 168 + /// com.bad-example.repo.getUriRecord 169 + /// 170 + /// Ergonomic complement to [`com.atproto.repo.getRecord`](https://docs.bsky.app/docs/api/com-atproto-repo-get-record) 171 + /// which accepts an at-uri instead of individual rep/collection/rkey params 172 + #[oai(path = "/com.bad-example.repo.getUriRecord", method = "get")] 173 + async fn get_uri_record( 174 + &self, 175 + /// The at-uri of the record 176 + /// 177 + /// The identifier can be a DID or an atproto handle, and the collection 178 + /// and rkey segments must be present. 179 + #[oai(example = "example_uri")] 180 + Query(at_uri): Query<String>, 181 + /// Optional: the CID of the version of the record. 182 + /// 183 + /// If not specified, then return the most recent version. 184 + /// 185 + /// If specified and a newer version of the record exists, returns 404 not 186 + /// found. That is: slingshot only retains the most recent version of a 187 + /// record. 188 + Query(cid): Query<Option<String>>, 189 + ) -> GetRecordResponse { 190 + let bad_at_uri = || { 191 + GetRecordResponse::BadRequest(xrpc_error( 192 + "InvalidRequest", 193 + "at-uri does not appear to be valid", 194 + )) 195 + }; 196 + 197 + let Some(normalized) = normalize_at_uri(&at_uri) else { 198 + return bad_at_uri(); 199 + }; 200 + 201 + // TODO: move this to links 202 + let Some(rest) = normalized.strip_prefix("at://") else { 203 + return bad_at_uri(); 204 + }; 205 + let Some((repo, rest)) = rest.split_once('/') else { 206 + return bad_at_uri(); 207 + }; 208 + let Some((collection, rest)) = rest.split_once('/') else { 209 + return bad_at_uri(); 210 + }; 211 + let rkey = if let Some((rkey, _rest)) = rest.split_once('?') { 212 + rkey 213 + } else { 214 + rest 215 + }; 216 + 217 + self.get_record_impl( 218 + repo.to_string(), 219 + collection.to_string(), 220 + rkey.to_string(), 221 + cid, 222 + ) 223 + .await 224 + } 225 + 226 + async fn get_record_impl( 227 + &self, 228 + repo: String, 229 + collection: String, 230 + rkey: String, 231 + cid: Option<String>, 160 232 ) -> GetRecordResponse { 161 233 let did = match Did::new(repo.clone()) { 162 234 Ok(did) => did,