Record phase 4 website, ArcViewer and Caddy results in the plan
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+72
-4
@@ -625,6 +625,68 @@ on the profile.
|
|||||||
|
|
||||||
### Phase 4: Website, viewer, Caddy
|
### 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 <src>/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/<hash>.zip&noProxy=true`.
|
||||||
|
It reads the hash from the replay filename
|
||||||
|
(`<score>-<player>-<diff>-<mode>-<HASH>.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/<hash>.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)
|
1. In the website fork, point `BL_REPLAYS_URL` (and the "watch replay" links)
|
||||||
at `/arcviewer/?replayURL=<encoded local replay url>&url=<encoded /cdn/maps/<hash>.zip>`.
|
at `/arcviewer/?replayURL=<encoded local replay url>&url=<encoded /cdn/maps/<hash>.zip>`.
|
||||||
Fall back to `id=<bsr>` only for hashes that have no local zip. Hide or stub
|
Fall back to `id=<bsr>` 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
|
@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 @plebleader_allowed {
|
||||||
handle_path /cors/blapi/* { reverse_proxy http://127.0.0.1:8042 }
|
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 /cdn/* { root * /var/lib/plebleader/storage; file_server }
|
||||||
handle_path /arcviewer/* { root * ${arcviewer}; 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/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_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 }
|
handle { respond "Forbidden" 403 }
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
ArcViewer's WebGL build may need `Content-Encoding` headers for `.br`/`.gz`
|
Checked: the `deploy` branch ships uncompressed `Build/` files, so no
|
||||||
files in `Build/`. Check which ones the `deploy` branch ships.
|
`Content-Encoding` headers are needed.
|
||||||
|
|
||||||
**Check:** in Chromium, `https://incineroar.brenise.dev:4442/u/pleb` shows the
|
**Check:** in Chromium, `https://incineroar.brenise.dev:4442/u/pleb` shows the
|
||||||
profile and scores, and a replay opens in ArcViewer.
|
profile and scores, and a replay opens in ArcViewer.
|
||||||
|
|||||||
Reference in New Issue
Block a user