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

reflector: an any-domain did:web->service mapper

Changed files
+147 -45
reflector
+34 -44
Cargo.lock
···
[[package]]
name = "clap"
-
version = "4.5.46"
+
version = "4.5.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
-
checksum = "2c5e4fcf9c21d2e544ca1ee9d8552de13019a42aa7dbf32747fa7aaf1df76e57"
+
checksum = "7eac00902d9d136acd712710d71823fb8ac8004ca445a89e73a41d45aa712931"
dependencies = [
"clap_builder",
"clap_derive",
···
[[package]]
name = "clap_builder"
-
version = "4.5.46"
+
version = "4.5.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
-
checksum = "fecb53a0e6fcfb055f686001bc2e2592fa527efaf38dbe81a6a9563562e57d41"
+
checksum = "2ad9bbf750e73b5884fb8a211a9424a1906c1e156724260fdae972f31d70e1d6"
dependencies = [
"anstream",
"anstyle",
···
[[package]]
name = "clap_derive"
-
version = "4.5.45"
+
version = "4.5.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
-
checksum = "14cb31bb0a7d536caef2639baa7fad459e15c3144efefa6dbd1c84562c4739f6"
+
checksum = "bbfd7eae0b0f1a6e63d4b13c9c478de77c2eb546fba158ad50b4203dc24b9f9c"
dependencies = [
"heck",
"proc-macro2",
···
[[package]]
name = "log"
-
version = "0.4.27"
+
version = "0.4.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
-
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
+
checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
[[package]]
name = "loom"
···
[[package]]
name = "matchers"
-
version = "0.1.0"
+
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-
checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
+
checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9"
dependencies = [
-
"regex-automata 0.1.10",
+
"regex-automata",
[[package]]
···
[[package]]
name = "nu-ansi-term"
-
version = "0.46.0"
+
version = "0.50.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-
checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
+
checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399"
dependencies = [
-
"overload",
-
"winapi",
+
"windows-sys 0.52.0",
[[package]]
···
dependencies = [
"hashbrown 0.13.2",
-
-
[[package]]
-
name = "overload"
-
version = "0.1.1"
-
source = "registry+https://github.com/rust-lang/crates.io-index"
-
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
[[package]]
name = "p256"
···
[[package]]
+
name = "reflector"
+
version = "0.1.0"
+
dependencies = [
+
"clap",
+
"log",
+
"poem",
+
"serde",
+
"tokio",
+
"tracing-subscriber",
+
]
+
+
[[package]]
name = "regex"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
···
dependencies = [
"aho-corasick",
"memchr",
-
"regex-automata 0.4.9",
-
"regex-syntax 0.8.5",
-
]
-
-
[[package]]
-
name = "regex-automata"
-
version = "0.1.10"
-
source = "registry+https://github.com/rust-lang/crates.io-index"
-
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
-
dependencies = [
-
"regex-syntax 0.6.29",
+
"regex-automata",
+
"regex-syntax",
[[package]]
···
dependencies = [
"aho-corasick",
"memchr",
-
"regex-syntax 0.8.5",
+
"regex-syntax",
-
-
[[package]]
-
name = "regex-syntax"
-
version = "0.6.29"
-
source = "registry+https://github.com/rust-lang/crates.io-index"
-
checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
[[package]]
name = "regex-syntax"
···
[[package]]
name = "tokio"
-
version = "1.47.0"
+
version = "1.47.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-
checksum = "43864ed400b6043a4757a25c7a64a8efde741aed79a056a2fb348a406701bb35"
+
checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038"
dependencies = [
"backtrace",
"bytes",
···
[[package]]
name = "tracing-subscriber"
-
version = "0.3.19"
+
version = "0.3.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
-
checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008"
+
checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5"
dependencies = [
"matchers",
"nu-ansi-term",
"once_cell",
-
"regex",
+
"regex-automata",
"sharded-slab",
"smallvec",
"thread_local",
+1
Cargo.toml
···
"slingshot",
"quasar",
"pocket",
+
"reflector",
]
+8 -1
Makefile
···
cargo test --all-features
fmt:
-
cargo fmt --package links --package constellation --package ufos --package spacedust --package who-am-i --package slingshot --package pocket
+
cargo fmt --package links \
+
--package constellation \
+
--package ufos \
+
--package spacedust \
+
--package who-am-i \
+
--package slingshot \
+
--package pocket \
+
--package reflector
cargo +nightly fmt --package jetstream
clippy:
+12
reflector/Cargo.toml
···
+
[package]
+
name = "reflector"
+
version = "0.1.0"
+
edition = "2024"
+
+
[dependencies]
+
clap = { version = "4.5.47", features = ["derive"] }
+
log = "0.4.28"
+
poem = "3.1.12"
+
serde = { version = "1.0.219", features = ["derive"] }
+
tokio = "1.47.1"
+
tracing-subscriber = { version = "0.3.20", features = ["env-filter"] }
+9
reflector/readme.md
···
+
# reflector
+
+
a tiny did:web service server that maps subdomains to a single service endpoint
+
+
receiving requests from multiple subdomains is left as a problem for the reverse proxy to solve, since acme wildcard certificates (ie. letsencrypt) require the most complicated and involved challenge type (DNS).
+
+
caddy [has good support for](https://caddyserver.com/docs/caddyfile/patterns#wildcard-certificates) configuring the wildcard DNS challenge with various DNS providers, and also supports [on-demand](https://caddyserver.com/docs/automatic-https#using-on-demand-tls) provisioning via the simpler methods.
+
+
if you only need a small fixed number of subdomains, you can also use certbot or otherwise individually configure them in your reverse proxy.
+83
reflector/src/main.rs
···
+
use clap::Parser;
+
use poem::{
+
EndpointExt, Route, Server, get, handler,
+
listener::TcpListener,
+
middleware::{AddData, Tracing},
+
web::{Data, Json, TypedHeader, headers::Host},
+
};
+
use serde::Serialize;
+
+
#[handler]
+
fn hello() -> String {
+
"ɹoʇɔǝʅⅎǝɹ".to_string()
+
}
+
+
#[derive(Debug, Serialize)]
+
struct DidDoc {
+
id: String,
+
service: [DidService; 1],
+
}
+
+
#[derive(Debug, Clone, Serialize)]
+
struct DidService {
+
id: String,
+
r#type: String,
+
service_endpoint: String,
+
}
+
+
#[handler]
+
fn did_doc(TypedHeader(host): TypedHeader<Host>, service: Data<&DidService>) -> Json<DidDoc> {
+
Json(DidDoc {
+
id: format!("did:web:{}", host.hostname()),
+
service: [service.clone()],
+
})
+
}
+
+
/// Slingshot record edge cache
+
#[derive(Parser, Debug, Clone)]
+
#[command(version, about, long_about = None)]
+
struct Args {
+
/// The DID document service ID to serve
+
///
+
/// must start with a '#', like `#bsky_appview'
+
#[arg(long)]
+
id: String,
+
/// Service type
+
///
+
/// Not sure exactly what its requirements are. 'BlueskyAppview' for example
+
#[arg(long)]
+
r#type: String,
+
/// The HTTPS endpoint for the service
+
#[arg(long)]
+
service_endpoint: String,
+
}
+
+
impl From<Args> for DidService {
+
fn from(a: Args) -> Self {
+
Self {
+
id: a.id,
+
r#type: a.r#type,
+
service_endpoint: a.service_endpoint,
+
}
+
}
+
}
+
+
#[tokio::main(flavor = "current_thread")]
+
async fn main() {
+
tracing_subscriber::fmt::init();
+
log::info!("ɹoʇɔǝʅⅎǝɹ");
+
+
let args = Args::parse();
+
let service: DidService = args.into();
+
+
Server::new(TcpListener::bind("0.0.0.0:3001"))
+
.run(
+
Route::new()
+
.at("/", get(hello))
+
.at("/.well-known/did.json", get(did_doc))
+
.with(AddData::new(service))
+
.with(Tracing),
+
)
+
.await
+
.unwrap()
+
}