From 2955a03386fc4d032dee0189fd3122f4e93e8e16 Mon Sep 17 00:00:00 2001 From: pleb Date: Sun, 8 Nov 2026 21:02:00 -0800 Subject: [PATCH] Record phase 4 website, ArcViewer and Caddy results in the plan Co-Authored-By: Claude Opus 5.5 --- docs/plan.md | 76 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 72 insertions(+), 4 deletions(-) diff --git a/docs/plan.md b/docs/plan.md index c3d7d5e..09b753c 100644 --- a/docs/plan.md +++ b/docs/plan.md @@ -625,6 +625,68 @@ on the profile. ### Phase 4: Website, viewer, Caddy +**Steps 1–2 done and both checks passed 2026-11-08**, on a dev stand-in for +the vhost: the importer into `.data/plebleader/dev/db/`, the API on 8042 +(`PublicBaseUrl=http://127.0.0.1:8890`), and an ad-hoc `nix shell +nixpkgs#caddy` on `http://127.0.0.1:8890` with the routes below +(`.data/plebleader/dev/{run-api.sh,Caddyfile}`). Use `127.0.0.1`, not +`localhost`: the website sends `localhost` to the real upstream API. Commits: +server `7cc964a`, website `f5194ee3`, `9ebe84ea`, `8d540642`, all local +(not pushed yet). Step 3 (nix-pleb) is still open. + +- **Phase 3 check passed.** `/u/pleb`: 11,608.35pp, #3,861 global, US #1,643, + 672 ranked and 3,565 total scores, unranked difficulties with stars (8.33★ + on the Phase 1 test map), the skill triangle with monthly history. The + leaderboard page and `/score/{id}` (accuracy graphs from local score stats) + work too. +- **Server fix:** the profile page calls `GET /v2/player/{id}/hydrate`, which + the live API has and the public source doesn't (404, "Player not found"). + `Controllers/MirrorHydrateController.cs` rebuilds it from + `PlayerController.Get` plus the `profile` object that the website's + `process-hydrate.js` reads. +- **Server run note:** `dotnet build` doesn't copy `wwwroot/` into `bin/`. + Without it `PreviewController`'s constructor throws on `/images/Star.png`, + and any controller that depends on it (`/user`, `/user/config`) returns 500. + The dev run passes `--webroot /wwwroot`; the Nix package uses `dotnet + publish`, which copies it. +- **Website, as built:** `IS_MIRROR` in `api-queue.js` is true when the API + resolves to `/cors/blapi/`. In that case `BL_REPLAYS_URL` is `/watch/` and + score stats come from `/cdn/scorestats/`. Every hardcoded + `allpoland.github.io/ArcViewer/` link points at `/watch/` (except the clan + page's embed). `public/watch/index.html` takes BL replay-viewer or ArcViewer + parameters (`link`, `replayURL`, `scoreId`, `id`, optional `hash`) and + redirects to `/arcviewer/?replayURL=…&url=/cdn/maps/.zip&noProxy=true`. + It reads the hash from the replay filename + (`----.bsor`); for `scoreId` it first asks + `/cors/blapi/score/{id}` for the replay URL. Phase 5 can pass `hash=` for + `.dat` replays. The analyzer icons are off by default (an upstream Patreon + service). Clans, events, the socket page and the star-rating graph are still + visible; they just show nothing. +- **ArcViewer facts:** without `noProxy=true` it routes every non-whitelisted + URL through `cors.bsmg.dev`, which can't reach a LAN host. When both `id` + and `url` are given, `id` wins, so never send both. With no map parameter + it looks up the replay's own hash on BeatSaver. The `deploy` build ships + uncompressed `Build/` files, so no `Content-Encoding` headers are needed. + Its own calls to `api.beatleader.com` (player card, leaderboard info) fail + from this origin, so the player card stays blank; fixing that needs a Unity + build, so it's left as is. +- **Map zips:** BeatSaver's CDN serves `https://r2cdn.beatsaver.com/.zip` + with `Access-Control-Allow-Origin: *` (it rejects HEAD, use GET). Caddy + redirects to it when the archive has no zip, so the website always links + the local path and the ~630 older maps outside `--maps-since` still play. +- **Nix:** the website fork's `flake.nix` builds `packages.default` (yarn + v1 offline, ~16 s; deps hash `sha256-ThGvMJfU…`). Its `postPatch` turns the + themes' Google Fonts `@import url(...)` into `@import (css) url(...)`, + because less would fetch them at build time. ArcViewer `deploy` at + `c776256497b66f7c91a74162cfcd943b0f45ee2e` is + `sha256-4A+aVnFrKyWQjFnH2N/CwoVIlwrcgV2fYYrtaOiodo0=` for `fetchFromGitHub`. + +Still open for step 3: push both forks to Gitea, add the website flake as a +nix-pleb input (nix-pleb currently has an uncommitted, staged `flake.lock` +change that isn't ours), and give Caddy read access to the state dir +(`StateDirectoryMode=0750` and `caddy` in group `plebleader`, phase 7). The +vhost below is the tested version. + 1. In the website fork, point `BL_REPLAYS_URL` (and the "watch replay" links) at `/arcviewer/?replayURL=&url=.zip>`. Fall back to `id=` only for hashes that have no local zip. Hide or stub @@ -645,20 +707,26 @@ on the profile. @plebleader_allowed remote_ip 127.0.0.1/32 ::1/128 192.168.1.36/32 192.168.254.21/32 handle @plebleader_allowed { handle_path /cors/blapi/* { reverse_proxy http://127.0.0.1:8042 } - handle_path /cdn/maps/* { root * /var/lib/plebleader/archive/beatsaver/zips; file_server } + handle_path /cdn/maps/* { + root * /var/lib/plebleader/archive/beatsaver/zips + @nozip not file + redir @nozip https://r2cdn.beatsaver.com{path} 302 + file_server + } handle_path /cdn/* { root * /var/lib/plebleader/storage; file_server } handle_path /arcviewer/* { root * ${arcviewer}; file_server } handle_path /cors/cdn-assets-bl/* { reverse_proxy https://cdn.assets.beatleader.com { header_up Host {upstream_hostport} } } handle_path /cors/cdnbeatsaver/* { reverse_proxy https://cdn.beatsaver.com { header_up Host {upstream_hostport} } } - handle { root * ${plebleader-website}; try_files {path} /index.html; file_server } + # {path}/index.html serves /watch/; without it the SPA's 404 answers + handle { root * ${plebleader-website}; try_files {path} {path}/index.html /index.html; file_server } } handle { respond "Forbidden" 403 } ''; }; ``` - ArcViewer's WebGL build may need `Content-Encoding` headers for `.br`/`.gz` - files in `Build/`. Check which ones the `deploy` branch ships. + Checked: the `deploy` branch ships uncompressed `Build/` files, so no + `Content-Encoding` headers are needed. **Check:** in Chromium, `https://incineroar.brenise.dev:4442/u/pleb` shows the profile and scores, and a replay opens in ArcViewer.