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

Merge branch 'xrpc_backlinks_count'

+150 -1
+1
.gitignore
··· 1 1 /target 2 2 local/ 3 + rocks.test
+4
.prettierrc
··· 1 + { 2 + "tabWidth": 2, 3 + "useTabs": false 4 + }
+48
constellation/src/server/mod.rs
··· 66 66 } 67 67 }), 68 68 ) 69 + // deprecated 69 70 .route( 70 71 "/links/count", 71 72 get({ 72 73 let store = store.clone(); 73 74 move |accept, query| async { 74 75 spawn_blocking(|| count_links(accept, query, store)) 76 + .await 77 + .map_err(to500)? 78 + } 79 + }), 80 + ) 81 + .route( 82 + "/xrpc/blue.microcosm.links.getBacklinksCount", 83 + get({ 84 + let store = store.clone(); 85 + move |accept, query| async { 86 + spawn_blocking(|| get_backlink_counts(accept, query, store)) 75 87 .await 76 88 .map_err(to500)? 77 89 } ··· 343 355 #[serde(skip_serializing)] 344 356 query: GetLinksCountQuery, 345 357 } 358 + #[deprecated] 346 359 fn count_links( 347 360 accept: ExtractAccept, 348 361 query: Query<GetLinksCountQuery>, ··· 361 374 } 362 375 363 376 #[derive(Clone, Deserialize)] 377 + struct GetItemsCountQuery { 378 + subject: String, 379 + source: String, 380 + } 381 + #[derive(Template, Serialize)] 382 + #[template(path = "get-backlinks-count.html.j2")] 383 + struct GetItemsCountResponse { 384 + total: u64, 385 + #[serde(skip_serializing)] 386 + query: GetItemsCountQuery, 387 + } 388 + fn get_backlink_counts( 389 + accept: ExtractAccept, 390 + query: axum_extra::extract::Query<GetItemsCountQuery>, 391 + store: impl LinkReader, 392 + ) -> Result<impl IntoResponse, http::StatusCode> { 393 + let Some((collection, path)) = query.source.split_once(':') else { 394 + return Err(http::StatusCode::BAD_REQUEST); 395 + }; 396 + let path = format!(".{path}"); 397 + let total = store 398 + .get_count(&query.subject, collection, &path) 399 + .map_err(|_| http::StatusCode::INTERNAL_SERVER_ERROR)?; 400 + 401 + Ok(acceptable( 402 + accept, 403 + GetItemsCountResponse { 404 + total, 405 + query: (*query).clone(), 406 + }, 407 + )) 408 + } 409 + 410 + #[derive(Clone, Deserialize)] 364 411 struct GetDidsCountQuery { 365 412 target: String, 366 413 collection: String, ··· 668 715 #[serde(skip_serializing)] 669 716 query: GetAllLinksQuery, 670 717 } 718 + #[deprecated] 671 719 fn count_all_links( 672 720 accept: ExtractAccept, 673 721 query: Query<GetAllLinksQuery>,
+14 -1
constellation/templates/hello.html.j2
··· 121 121 {% call try_it::dids("at://did:plc:vc7f4oafdgxsihk4cry2xpze/app.bsky.feed.post/3lgwdn7vd722r", "app.bsky.feed.like", ".subject.uri") %} 122 122 123 123 124 - <h3 class="route"><code>GET /links/count</code></h3> 124 + <h3 class="route deprecated"><code>[deprecated] GET /links/count</code></h3> 125 125 126 126 <p>The total number of links pointing at a given target.</p> 127 127 ··· 137 137 <p style="margin-bottom: 0"><strong>Try it:</strong></p> 138 138 {% call try_it::links_count("did:plc:vc7f4oafdgxsihk4cry2xpze", "app.bsky.graph.block", ".subject") %} 139 139 140 + <h3 class="route"><code>GET /xrpc/blue.microcosm.links.getBacklinksCount</code></h3> 141 + 142 + <p>The total number of links pointing at a given target.</p> 143 + 144 + <h4>Query parameters:</h4> 145 + 146 + <ul> 147 + <li><code>subject</code>: required, must url-encode. The target being linked to. Example: <code>did:plc:vc7f4oafdgxsihk4cry2xpze</code> or <code>at://did:plc:vc7f4oafdgxsihk4cry2xpze/app.bsky.feed.post/3lgwdn7vd722r</code></li> 148 + <li><code>source</code>: required. Collection and path specification for the primary link. Example: <code>app.bsky.feed.like:subject.uri</code></li> 149 + </ul> 150 + 151 + <p style="margin-bottom: 0"><strong>Try it:</strong></p> 152 + {% call try_it::get_backlinks_count("did:plc:vc7f4oafdgxsihk4cry2xpze", "app.bsky.graph.block:subject") %} 140 153 141 154 <h3 class="route"><code>GET /links/count/distinct-dids</code></h3> 142 155
+7
constellation/templates/try-it-macros.html.j2
··· 104 104 </form> 105 105 {% endmacro %} 106 106 107 + {% macro get_backlinks_count(subject, source) %} 108 + <form method="get" action="/xrpc/blue.microcosm.links.getBacklinksCount"> 109 + <pre class="code"><strong>GET</strong> /xrpc/blue.microcosm.links.getBacklinksCount 110 + ?subject= <input type="text" name="subject" value="{{ subject }}" placeholder="subject" /> 111 + &source= <input type="text" name="source" value="{{ source }}" placeholder="source" /> <button type="submit">get links count</button></pre> 112 + </form> 113 + {% endmacro %} 107 114 108 115 {% macro links_count(target, collection, path) %} 109 116 <form method="get" action="/links/count">
+38
lexicons/blue.microcosm/links/getBacklinksCount.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "blue.microcosm.links.getBacklinksCount", 4 + "defs": { 5 + "main": { 6 + "type": "query", 7 + "description": "count records that link to another record", 8 + "parameters": { 9 + "type": "params", 10 + "required": ["subject", "source"], 11 + "properties": { 12 + "subject": { 13 + "type": "string", 14 + "format": "uri", 15 + "description": "the primary target being linked to (at-uri, did, or uri)" 16 + }, 17 + "source": { 18 + "type": "string", 19 + "description": "collection and path specification for the primary link" 20 + } 21 + } 22 + }, 23 + "output": { 24 + "encoding": "application/json", 25 + "schema": { 26 + "type": "object", 27 + "required": ["total"], 28 + "properties": { 29 + "total": { 30 + "type": "integer", 31 + "description": "total number of matching links" 32 + } 33 + } 34 + } 35 + } 36 + } 37 + } 38 + }