From ce5aeb02be574471572583997532b4b2c440432d Mon Sep 17 00:00:00 2001 From: Anirudh Oppiliappan Date: Tue, 12 May 2026 22:34:59 +0300 Subject: [PATCH] sites: name-keyed worker after rkey/name split --- flake.nix | 14 ++++++-- sites/src/lib.rs | 84 ++++++++++++++++++++++++++++++++++++------------ 2 files changed, 76 insertions(+), 22 deletions(-) diff --git a/flake.nix b/flake.nix index b57ef502..977cedd9 100644 --- a/flake.nix +++ b/flake.nix @@ -182,9 +182,14 @@ devShells = forAllSystems (system: let pkgs = nixpkgsFor.${system}; packages' = self.packages.${system}; - staticShell = pkgs.mkShell.override { + staticShell = args: (pkgs.mkShell.override { stdenv = pkgs.pkgsStatic.stdenv; - }; + }) (args // { + nativeBuildInputs = args.nativeBuildInputs + ++ pkgs.lib.optionals pkgs.stdenv.isDarwin [ + pkgs.darwin.cctools + ]; + }); in { default = staticShell { nativeBuildInputs = [ @@ -220,6 +225,11 @@ cp -fr --no-preserve=ownership,mode ${packages'.appview-static-files}/* appview/pages/static export TANGLED_OAUTH_CLIENT_KID="$(date +%s)" export TANGLED_OAUTH_CLIENT_SECRET="$(${packages'.goat}/bin/goat key generate -t P-256 | grep -A1 "Secret Key" | tail -n1 | awk '{print $1}')" + # Make xcrun (Nix stub) able to find ld from the system Command Line Tools. + # Without this, worker-build/cargo fails with "error: tool 'ld' not found". + if [ -d /Library/Developer/CommandLineTools/usr/bin ]; then + export PATH=/Library/Developer/CommandLineTools/usr/bin:$PATH + fi ''; env.CGO_ENABLED = 1; }; diff --git a/sites/src/lib.rs b/sites/src/lib.rs index 6a3310a7..11dca419 100644 --- a/sites/src/lib.rs +++ b/sites/src/lib.rs @@ -7,30 +7,71 @@ use worker::*; /// /// Example KV entry: /// key: "foo.example.com" -/// value: {"did": "did:plc:...", "repos": {"my_repo": true, "other_repo": false}} +/// value: {"did": "did:plc:...", +/// "repos": {"my_repo": {"rkey": "3lk...", "is_index": true}, +/// "other_repo": {"rkey": "3ll...", "is_index": false}}} /// -/// The boolean on each repo indicates whether it is the index site for the -/// domain (true) or a sub-path site (false). At most one repo may be true. +/// The is_index flag on each entry indicates whether it is the index site +/// for the domain (true) or a sub-path site (false). At most one repo may +/// be true. The rkey identifies the {did}/{rkey}/ prefix in R2 where the +/// site's objects live. #[derive(Deserialize)] struct DomainMapping { + #[serde(default)] did: String, - /// repo name → is_index - repos: HashMap, + /// repo name → entry + #[serde(default)] + repos: HashMap, +} + +/// Deserialises from either {"rkey": "...", "is_index": bool} (new shape) +/// or a bare bool (old shape, where the map key itself was the rkey). +#[derive(Deserialize)] +#[serde(untagged)] +enum RepoEntry { + New { + rkey: String, + #[serde(default)] + is_index: bool, + }, + Legacy(bool), +} + +impl RepoEntry { + fn is_index(&self) -> bool { + match self { + RepoEntry::New { is_index, .. } => *is_index, + RepoEntry::Legacy(b) => *b, + } + } + + /// Returns the rkey, falling back to the map key (name) for the legacy + /// shape where the key itself was the rkey. + fn rkey<'a>(&'a self, name: &'a str) -> &'a str { + match self { + RepoEntry::New { rkey, .. } => rkey.as_str(), + RepoEntry::Legacy(_) => name, + } + } } impl DomainMapping { - /// Returns the repo that is marked as the index site, if any. - fn index_repo(&self) -> Option<&str> { - self.repos - .iter() - .find_map(|(name, &is_index)| if is_index { Some(name.as_str()) } else { None }) + /// Returns the (name, entry) pair for the index site, if any. + fn index_repo(&self) -> Option<(&str, &RepoEntry)> { + self.repos.iter().find_map(|(name, entry)| { + if entry.is_index() { + Some((name.as_str(), entry)) + } else { + None + } + }) } } -/// Build the R2 object key for a given did/repo and intra-site path. +/// Build the R2 object key for a given did/rkey and intra-site path. /// `site_path` should start with a `/` or be empty. -fn r2_key(did: &str, repo: &str, site_path: &str) -> String { - let base = format!("{}/{}/", did, repo); +fn r2_key(did: &str, rkey: &str, site_path: &str) -> String { + let base = format!("{}/{}/", did, rkey); if site_path.is_empty() || site_path == "/" { format!("{}index.html", base) } else { @@ -68,10 +109,13 @@ fn response_from_object(obj: Object) -> Result { .content_type .unwrap_or_else(|| "application/octet-stream".to_string()); - let body = obj.body().ok_or_else(|| Error::RustError("empty R2 body".into()))?; + let body = obj + .body() + .ok_or_else(|| Error::RustError("empty R2 body".into()))?; let mut resp = Response::from_body(body.response_body()?)?; resp.headers_mut().set("Content-Type", &content_type)?; - resp.headers_mut().set("Cache-Control", "public, max-age=60")?; + resp.headers_mut() + .set("Cache-Control", "public, max-age=60")?; Ok(resp) } @@ -122,15 +166,15 @@ async fn fetch(req: Request, env: Env, _ctx: Context) -> Result { // 1. sub-path site // If the first path segment matches a non-index repo, serve from it. if !first_segment.is_empty() { - if let Some(&is_index) = mapping.repos.get(&first_segment) { - if !is_index { + if let Some(entry) = mapping.repos.get(&first_segment) { + if !entry.is_index() { // Strip the leading "/{first_segment}" to get the intra-site path. let site_path = path .trim_start_matches('/') .trim_start_matches(&first_segment) .to_string(); - let key = r2_key(&mapping.did, &first_segment, &site_path); + let key = r2_key(&mapping.did, entry.rkey(&first_segment), &site_path); return match fetch_from_r2(&bucket, &key).await? { Some(obj) => response_from_object(obj), None => Response::error("Not Found", 404), @@ -141,8 +185,8 @@ async fn fetch(req: Request, env: Env, _ctx: Context) -> Result { // 2. index site // Fall back to the repo marked as the index site, serving the full path. - if let Some(index_repo) = mapping.index_repo() { - let key = r2_key(&mapping.did, index_repo, path); + if let Some((name, entry)) = mapping.index_repo() { + let key = r2_key(&mapping.did, entry.rkey(name), path); return match fetch_from_r2(&bucket, &key).await? { Some(obj) => response_from_object(obj), None => Response::error("Not Found", 404), -- 2.51.2