small bsky embedder @ boobsky.app - kinda mid but works - mirror of git.fomx.gay/rooot/embedthing

feat: resolve did:plc to fix embedding of non-bsky pds media

Signed-off-by: rooot <hey@rooot.gay>

+264 -5
+215 -1
Cargo.lock
··· 109 ] 110 111 [[package]] 112 name = "atrium-api" 113 version = "0.24.7" 114 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 256 checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 257 258 [[package]] 259 name = "chrono" 260 version = "0.4.38" 261 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 418 "dotenvy", 419 "ipld-core", 420 "lazy_static", 421 "rocket", 422 "serde", 423 "serde_json", ··· 631 ] 632 633 [[package]] 634 name = "hashbrown" 635 version = "0.15.0" 636 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 726 "futures-channel", 727 "futures-core", 728 "futures-util", 729 - "h2", 730 "http 0.2.12", 731 "http-body 0.4.6", 732 "httparse", ··· 749 "bytes", 750 "futures-channel", 751 "futures-util", 752 "http 1.1.0", 753 "http-body 1.0.1", 754 "httparse", ··· 757 "smallvec", 758 "tokio", 759 "want", 760 ] 761 762 [[package]] ··· 1268 checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac" 1269 1270 [[package]] 1271 name = "quote" 1272 version = "1.0.37" 1273 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1388 "async-compression", 1389 "base64", 1390 "bytes", 1391 "futures-core", 1392 "futures-util", 1393 "http 1.1.0", 1394 "http-body 1.0.1", 1395 "http-body-util", 1396 "hyper 1.5.0", 1397 "hyper-tls", 1398 "hyper-util", 1399 "ipnet", ··· 1404 "once_cell", 1405 "percent-encoding", 1406 "pin-project-lite", 1407 "rustls-pemfile", 1408 "serde", 1409 "serde_json", 1410 "serde_urlencoded", 1411 "sync_wrapper", 1412 "tokio", 1413 "tokio-native-tls", 1414 "tokio-util", 1415 "tower-service", 1416 "url", 1417 "wasm-bindgen", 1418 "wasm-bindgen-futures", 1419 "web-sys", 1420 "windows-registry", 1421 ] 1422 1423 [[package]] ··· 1508 checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" 1509 1510 [[package]] 1511 name = "rustix" 1512 version = "0.38.38" 1513 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1521 ] 1522 1523 [[package]] 1524 name = "rustls-pemfile" 1525 version = "2.2.0" 1526 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1534 version = "1.10.0" 1535 source = "registry+https://github.com/rust-lang/crates.io-index" 1536 checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" 1537 1538 [[package]] 1539 name = "rustversion" ··· 1740 ] 1741 1742 [[package]] 1743 name = "syn" 1744 version = "1.0.109" 1745 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1768 checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" 1769 dependencies = [ 1770 "futures-core", 1771 ] 1772 1773 [[package]] ··· 1898 ] 1899 1900 [[package]] 1901 name = "tokio-stream" 1902 version = "0.1.16" 1903 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2098 checksum = "eb066959b24b5196ae73cb057f45598450d2c5f71460e98c49b738086eff9c06" 2099 2100 [[package]] 2101 name = "url" 2102 version = "2.5.2" 2103 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2219 ] 2220 2221 [[package]] 2222 name = "winapi" 2223 version = "0.3.9" 2224 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2465 "quote", 2466 "syn 2.0.86", 2467 ]
··· 109 ] 110 111 [[package]] 112 + name = "atomic-waker" 113 + version = "1.1.2" 114 + source = "registry+https://github.com/rust-lang/crates.io-index" 115 + checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" 116 + 117 + [[package]] 118 name = "atrium-api" 119 version = "0.24.7" 120 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 262 checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 263 264 [[package]] 265 + name = "cfg_aliases" 266 + version = "0.2.1" 267 + source = "registry+https://github.com/rust-lang/crates.io-index" 268 + checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" 269 + 270 + [[package]] 271 name = "chrono" 272 version = "0.4.38" 273 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 430 "dotenvy", 431 "ipld-core", 432 "lazy_static", 433 + "reqwest", 434 "rocket", 435 "serde", 436 "serde_json", ··· 644 ] 645 646 [[package]] 647 + name = "h2" 648 + version = "0.4.6" 649 + source = "registry+https://github.com/rust-lang/crates.io-index" 650 + checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205" 651 + dependencies = [ 652 + "atomic-waker", 653 + "bytes", 654 + "fnv", 655 + "futures-core", 656 + "futures-sink", 657 + "http 1.1.0", 658 + "indexmap", 659 + "slab", 660 + "tokio", 661 + "tokio-util", 662 + "tracing", 663 + ] 664 + 665 + [[package]] 666 name = "hashbrown" 667 version = "0.15.0" 668 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 758 "futures-channel", 759 "futures-core", 760 "futures-util", 761 + "h2 0.3.26", 762 "http 0.2.12", 763 "http-body 0.4.6", 764 "httparse", ··· 781 "bytes", 782 "futures-channel", 783 "futures-util", 784 + "h2 0.4.6", 785 "http 1.1.0", 786 "http-body 1.0.1", 787 "httparse", ··· 790 "smallvec", 791 "tokio", 792 "want", 793 + ] 794 + 795 + [[package]] 796 + name = "hyper-rustls" 797 + version = "0.27.3" 798 + source = "registry+https://github.com/rust-lang/crates.io-index" 799 + checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" 800 + dependencies = [ 801 + "futures-util", 802 + "http 1.1.0", 803 + "hyper 1.5.0", 804 + "hyper-util", 805 + "rustls", 806 + "rustls-pki-types", 807 + "tokio", 808 + "tokio-rustls", 809 + "tower-service", 810 + "webpki-roots", 811 ] 812 813 [[package]] ··· 1319 checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac" 1320 1321 [[package]] 1322 + name = "quinn" 1323 + version = "0.11.5" 1324 + source = "registry+https://github.com/rust-lang/crates.io-index" 1325 + checksum = "8c7c5fdde3cdae7203427dc4f0a68fe0ed09833edc525a03456b153b79828684" 1326 + dependencies = [ 1327 + "bytes", 1328 + "pin-project-lite", 1329 + "quinn-proto", 1330 + "quinn-udp", 1331 + "rustc-hash", 1332 + "rustls", 1333 + "socket2", 1334 + "thiserror", 1335 + "tokio", 1336 + "tracing", 1337 + ] 1338 + 1339 + [[package]] 1340 + name = "quinn-proto" 1341 + version = "0.11.8" 1342 + source = "registry+https://github.com/rust-lang/crates.io-index" 1343 + checksum = "fadfaed2cd7f389d0161bb73eeb07b7b78f8691047a6f3e73caaeae55310a4a6" 1344 + dependencies = [ 1345 + "bytes", 1346 + "rand", 1347 + "ring", 1348 + "rustc-hash", 1349 + "rustls", 1350 + "slab", 1351 + "thiserror", 1352 + "tinyvec", 1353 + "tracing", 1354 + ] 1355 + 1356 + [[package]] 1357 + name = "quinn-udp" 1358 + version = "0.5.6" 1359 + source = "registry+https://github.com/rust-lang/crates.io-index" 1360 + checksum = "e346e016eacfff12233c243718197ca12f148c84e1e84268a896699b41c71780" 1361 + dependencies = [ 1362 + "cfg_aliases", 1363 + "libc", 1364 + "once_cell", 1365 + "socket2", 1366 + "tracing", 1367 + "windows-sys 0.52.0", 1368 + ] 1369 + 1370 + [[package]] 1371 name = "quote" 1372 version = "1.0.37" 1373 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1488 "async-compression", 1489 "base64", 1490 "bytes", 1491 + "encoding_rs", 1492 "futures-core", 1493 "futures-util", 1494 + "h2 0.4.6", 1495 "http 1.1.0", 1496 "http-body 1.0.1", 1497 "http-body-util", 1498 "hyper 1.5.0", 1499 + "hyper-rustls", 1500 "hyper-tls", 1501 "hyper-util", 1502 "ipnet", ··· 1507 "once_cell", 1508 "percent-encoding", 1509 "pin-project-lite", 1510 + "quinn", 1511 + "rustls", 1512 "rustls-pemfile", 1513 + "rustls-pki-types", 1514 "serde", 1515 "serde_json", 1516 "serde_urlencoded", 1517 "sync_wrapper", 1518 + "system-configuration", 1519 "tokio", 1520 "tokio-native-tls", 1521 + "tokio-rustls", 1522 "tokio-util", 1523 "tower-service", 1524 "url", 1525 "wasm-bindgen", 1526 "wasm-bindgen-futures", 1527 "web-sys", 1528 + "webpki-roots", 1529 "windows-registry", 1530 + ] 1531 + 1532 + [[package]] 1533 + name = "ring" 1534 + version = "0.17.8" 1535 + source = "registry+https://github.com/rust-lang/crates.io-index" 1536 + checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" 1537 + dependencies = [ 1538 + "cc", 1539 + "cfg-if", 1540 + "getrandom", 1541 + "libc", 1542 + "spin", 1543 + "untrusted", 1544 + "windows-sys 0.52.0", 1545 ] 1546 1547 [[package]] ··· 1632 checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" 1633 1634 [[package]] 1635 + name = "rustc-hash" 1636 + version = "2.0.0" 1637 + source = "registry+https://github.com/rust-lang/crates.io-index" 1638 + checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" 1639 + 1640 + [[package]] 1641 name = "rustix" 1642 version = "0.38.38" 1643 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1651 ] 1652 1653 [[package]] 1654 + name = "rustls" 1655 + version = "0.23.16" 1656 + source = "registry+https://github.com/rust-lang/crates.io-index" 1657 + checksum = "eee87ff5d9b36712a58574e12e9f0ea80f915a5b0ac518d322b24a465617925e" 1658 + dependencies = [ 1659 + "once_cell", 1660 + "ring", 1661 + "rustls-pki-types", 1662 + "rustls-webpki", 1663 + "subtle", 1664 + "zeroize", 1665 + ] 1666 + 1667 + [[package]] 1668 name = "rustls-pemfile" 1669 version = "2.2.0" 1670 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1678 version = "1.10.0" 1679 source = "registry+https://github.com/rust-lang/crates.io-index" 1680 checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" 1681 + 1682 + [[package]] 1683 + name = "rustls-webpki" 1684 + version = "0.102.8" 1685 + source = "registry+https://github.com/rust-lang/crates.io-index" 1686 + checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" 1687 + dependencies = [ 1688 + "ring", 1689 + "rustls-pki-types", 1690 + "untrusted", 1691 + ] 1692 1693 [[package]] 1694 name = "rustversion" ··· 1895 ] 1896 1897 [[package]] 1898 + name = "subtle" 1899 + version = "2.6.1" 1900 + source = "registry+https://github.com/rust-lang/crates.io-index" 1901 + checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" 1902 + 1903 + [[package]] 1904 name = "syn" 1905 version = "1.0.109" 1906 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1929 checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" 1930 dependencies = [ 1931 "futures-core", 1932 + ] 1933 + 1934 + [[package]] 1935 + name = "system-configuration" 1936 + version = "0.6.1" 1937 + source = "registry+https://github.com/rust-lang/crates.io-index" 1938 + checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" 1939 + dependencies = [ 1940 + "bitflags", 1941 + "core-foundation", 1942 + "system-configuration-sys", 1943 + ] 1944 + 1945 + [[package]] 1946 + name = "system-configuration-sys" 1947 + version = "0.6.0" 1948 + source = "registry+https://github.com/rust-lang/crates.io-index" 1949 + checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" 1950 + dependencies = [ 1951 + "core-foundation-sys", 1952 + "libc", 1953 ] 1954 1955 [[package]] ··· 2080 ] 2081 2082 [[package]] 2083 + name = "tokio-rustls" 2084 + version = "0.26.0" 2085 + source = "registry+https://github.com/rust-lang/crates.io-index" 2086 + checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" 2087 + dependencies = [ 2088 + "rustls", 2089 + "rustls-pki-types", 2090 + "tokio", 2091 + ] 2092 + 2093 + [[package]] 2094 name = "tokio-stream" 2095 version = "0.1.16" 2096 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2291 checksum = "eb066959b24b5196ae73cb057f45598450d2c5f71460e98c49b738086eff9c06" 2292 2293 [[package]] 2294 + name = "untrusted" 2295 + version = "0.9.0" 2296 + source = "registry+https://github.com/rust-lang/crates.io-index" 2297 + checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" 2298 + 2299 + [[package]] 2300 name = "url" 2301 version = "2.5.2" 2302 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2418 ] 2419 2420 [[package]] 2421 + name = "webpki-roots" 2422 + version = "0.26.6" 2423 + source = "registry+https://github.com/rust-lang/crates.io-index" 2424 + checksum = "841c67bff177718f1d4dfefde8d8f0e78f9b6589319ba88312f567fc5841a958" 2425 + dependencies = [ 2426 + "rustls-pki-types", 2427 + ] 2428 + 2429 + [[package]] 2430 name = "winapi" 2431 version = "0.3.9" 2432 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2673 "quote", 2674 "syn 2.0.86", 2675 ] 2676 + 2677 + [[package]] 2678 + name = "zeroize" 2679 + version = "1.8.1" 2680 + source = "registry+https://github.com/rust-lang/crates.io-index" 2681 + checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
+1
Cargo.toml
··· 14 serde = "1.0.213" 15 serde_json = "1.0.132" 16 url = "2.5.2"
··· 14 serde = "1.0.213" 15 serde_json = "1.0.132" 16 url = "2.5.2" 17 + reqwest = { version = "*", features = ["rustls-tls", "json"] }
+27 -3
src/bsky.rs
··· 1 use crate::meow::{ 2 - BotCheck, EmbedAuthor, EmbedMedia, EmbedResponse, EmbedSource, EmbedThingy, GenericError, 3 - MissingElementError, 4 }; 5 use crate::ManagedBskyAgent; 6 use bsky_sdk::api::app::bsky::embed::images::ImageData; ··· 97 if let Some(embeds) = record.get_key_value("embed") { 98 let embeds = embeds.1; 99 100 // multiple? images 101 let images = match embeds.get("images") { 102 Ok(Some(Ipld::List(images))) => { ··· 135 }; 136 137 for blob in blobs { 138 - let url = format!("https://bsky.social/xrpc/com.atproto.sync.getBlob?did={}&cid={}", did, blob.r#ref.0); 139 if blob.mime_type.starts_with("image/") { 140 media_embeds.push(EmbedMedia::Image(url)); 141 } else { ··· 172 Err(()) 173 } 174 }
··· 1 use crate::meow::{ 2 + BotCheck, DidPlcResponse, EmbedAuthor, EmbedMedia, EmbedResponse, EmbedSource, EmbedThingy, 3 + GenericError, MissingElementError, 4 }; 5 use crate::ManagedBskyAgent; 6 use bsky_sdk::api::app::bsky::embed::images::ImageData; ··· 97 if let Some(embeds) = record.get_key_value("embed") { 98 let embeds = embeds.1; 99 100 + // for bsky.social we're gonna take a shortcut, as we're pretty much 100% sure that the PDS will be at bsky.social 101 + let pds_endpoint = if name.ends_with(".bsky.social") { 102 + "https://bsky.social".to_string() 103 + } else { 104 + resolve_plc_did(did).await? 105 + }; 106 + 107 // multiple? images 108 let images = match embeds.get("images") { 109 Ok(Some(Ipld::List(images))) => { ··· 142 }; 143 144 for blob in blobs { 145 + let url = format!("{}/xrpc/com.atproto.sync.getBlob?did={}&cid={}", pds_endpoint, did, blob.r#ref.0); 146 if blob.mime_type.starts_with("image/") { 147 media_embeds.push(EmbedMedia::Image(url)); 148 } else { ··· 179 Err(()) 180 } 181 } 182 + 183 + async fn resolve_plc_did(did: &str) -> Result<String, GenericError> { 184 + let meow = reqwest::Client::new() 185 + .get(format!("https://plc.directory/{}", did)) 186 + .send() 187 + .await? 188 + .json::<DidPlcResponse>() 189 + .await?; 190 + 191 + let pds_service = meow 192 + .service 193 + .iter() 194 + .find(|service| service.id == "#atproto_pds") 195 + .ok_or(GenericError::TooTired)?; 196 + 197 + Ok(pds_service.service_endpoint.clone()) 198 + }
+21 -1
src/meow.rs
··· 5 use rocket::response::{Redirect, Responder}; 6 use rocket::{response, Request, Response}; 7 use serde::ser::SerializeMap; 8 - use serde::Serialize; 9 use thiserror::Error; 10 use url::Url; 11 ··· 217 218 #[error("bsky sdk error")] 219 Bsky(#[from] bsky_sdk::Error), 220 } 221 222 impl Serialize for GenericError { ··· 231 GenericError::GetBlob(e) => e.to_string(), 232 GenericError::InvalidCID(e) => e.to_string(), 233 GenericError::Bsky(e) => e.to_string(), 234 }; 235 let mut map = serializer.serialize_map(Some(2))?; 236 map.serialize_entry("error", &format!("{}: {}", self, &error_message))?; ··· 305 Outcome::Success(Self(false)) 306 } 307 }
··· 5 use rocket::response::{Redirect, Responder}; 6 use rocket::{response, Request, Response}; 7 use serde::ser::SerializeMap; 8 + use serde::{Deserialize, Serialize}; 9 use thiserror::Error; 10 use url::Url; 11 ··· 217 218 #[error("bsky sdk error")] 219 Bsky(#[from] bsky_sdk::Error), 220 + 221 + #[error("reqwest error")] 222 + Reqwest(#[from] reqwest::Error), 223 } 224 225 impl Serialize for GenericError { ··· 234 GenericError::GetBlob(e) => e.to_string(), 235 GenericError::InvalidCID(e) => e.to_string(), 236 GenericError::Bsky(e) => e.to_string(), 237 + _ => self.to_string(), 238 }; 239 let mut map = serializer.serialize_map(Some(2))?; 240 map.serialize_entry("error", &format!("{}: {}", self, &error_message))?; ··· 309 Outcome::Success(Self(false)) 310 } 311 } 312 + 313 + #[derive(Serialize, Deserialize)] 314 + pub struct PlcService { 315 + pub id: String, 316 + #[serde(rename = "type")] 317 + pub type_: String, 318 + 319 + #[serde(rename = "serviceEndpoint")] 320 + pub service_endpoint: String, 321 + } 322 + 323 + #[derive(Serialize, Deserialize)] 324 + pub struct DidPlcResponse { 325 + pub id: String, 326 + pub service: Vec<PlcService>, 327 + }