feat(updates): the release lists through git-cdn.magicbean.dev first, so the update check works while git.magicbean.dev is down #76

Merged
HumanBean merged 1 commit from HumanBean/LongshotLauncher:feat/release-lists-cdn into main 2026-11-15 04:13:40 +00:00
Owner

Status: feat · low risk · not run yet (no .NET on the author's PC; CI runs the checks) · the git-cdn Worker change is deployed (version 68ca28f2)

When git.magicbean.dev is down, the launcher can't check for updates, even though the release files themselves already come from git-cdn.magicbean.dev. That's because the release lists still come from git.magicbean.dev. Every launcher's check at start also lands on Forgejo. With this change the lists come through Cloudflare's edge too: a list there may be up to a minute old, and it is still served while git.magicbean.dev is down.

What changed

CdnFetcher now sends the API's release list (/api/v1/repos/<owner>/<repo>/releases, any page) and a release by its tag (.../releases/tags/<tag>) to git-cdn.magicbean.dev first. It falls back to git.magicbean.dev on the same failures as a download: no answer, 403, 404 or 5xx. The rest of the API stays on git.magicbean.dev.

  • Core/CdnFetcher.cs: ListCdnOf(url) (which API links go to the CDN), and GetTextAsync tries the CDN first for them. LONGSHOT_LAUNCHER_NO_CDN=1 turns it off as before.
  • tests/launcher_core/CdnChecks.cs: which links count as a list (and which don't: a release by id, its assets, latest, other API paths, other hosts, http, another port, a link already on git-cdn). Also: a list from the CDN, each fallback status, a 400 not falling back, both failing (git.magicbean.dev's error is the one reported), and the CDN off. The fake fetcher's GetTextAsync can now fail.
  • README (LONGSHOT_LAUNCHER_NO_CDN row) and a comment in App/LauncherService.cs.

Server side (git-cdn's Worker, deployed 2026-11-14): for anonymous GETs of those two paths, the Worker keeps Forgejo's answer at the edge.

  • Under a minute old, the kept list is served as it is.
  • From 1 to 10 minutes old, it is served at once and refreshed in the background (stale-while-revalidate).
  • Older than that, Forgejo is asked first.
  • When Forgejo is down (no answer, 5xx, 429), any kept copy up to 7 days old is served (stale-if-error).
  • A 404 drops the kept copy.
  • Download lookups also fall back to their last answer while Forgejo is down, so files keep downloading too.
  • Forgejo has 5 s to answer before it counts as down, so one that hangs still lets the kept copy be served quickly.

Measurements

Nothing to measure in the game: this changes where the update check's two small JSON requests go, not the build or the game. Checked on the deployed Worker: X-Cache: MISS then HIT on https://git-cdn.magicbean.dev/api/v1/repos/MagicBeanDev/LongshotLauncher/releases?limit=50&page=1.

Testing

  • Not compiled or run on the author's PC (no .NET there): CI's test_launcher_core.py compiles Core/ and runs CdnChecks.
  • Safe in either order with the Worker: until the Worker change is live, git-cdn redirects API paths to git.magicbean.dev and HttpFetcher follows the redirect, so the check works as today.
  • Must be tested before merge: a launcher built from this PR starts and checks for updates, with the Worker deployed. Then LONGSHOT_LAUNCHER_NO_CDN=1 checks against git.magicbean.dev only.
  • Checked on the server: a list gives MISS then HIT, the tag lookup answers, other API paths and requests with a token still redirect to git.magicbean.dev, and a download still answers.

Risks

  • A list up to about a minute old, or longer while git.magicbean.dev is down. A new release shows in launchers a minute or two later. An old list can't install anything: an update only goes to a newer version, and every release is checked against its signed SHA256SUMS.
  • Pages kept at different times can repeat or skip one release where pages 1 and 2 meet, within that minute. The newest of each channel is on page 1 unless a channel's newest is more than 50 releases back. In that case the window could show the stable channel one version behind until the next check; it never moves a build backwards.
  • Compatibility: no change to saves, settings, caches or the release format.

🤖 Generated with Claude Code

**Status:** feat · low risk · not run yet (no .NET on the author's PC; CI runs the checks) · the git-cdn Worker change is deployed (version 68ca28f2) When git.magicbean.dev is down, the launcher can't check for updates, even though the release files themselves already come from git-cdn.magicbean.dev. That's because the release lists still come from git.magicbean.dev. Every launcher's check at start also lands on Forgejo. With this change the lists come through Cloudflare's edge too: a list there may be up to a minute old, and it is still served while git.magicbean.dev is down. ## What changed `CdnFetcher` now sends the API's release list (`/api/v1/repos/<owner>/<repo>/releases`, any page) and a release by its tag (`.../releases/tags/<tag>`) to git-cdn.magicbean.dev first. It falls back to git.magicbean.dev on the same failures as a download: no answer, 403, 404 or 5xx. The rest of the API stays on git.magicbean.dev. - `Core/CdnFetcher.cs`: `ListCdnOf(url)` (which API links go to the CDN), and `GetTextAsync` tries the CDN first for them. `LONGSHOT_LAUNCHER_NO_CDN=1` turns it off as before. - `tests/launcher_core/CdnChecks.cs`: which links count as a list (and which don't: a release by id, its assets, `latest`, other API paths, other hosts, http, another port, a link already on git-cdn). Also: a list from the CDN, each fallback status, a 400 not falling back, both failing (git.magicbean.dev's error is the one reported), and the CDN off. The fake fetcher's `GetTextAsync` can now fail. - README (`LONGSHOT_LAUNCHER_NO_CDN` row) and a comment in `App/LauncherService.cs`. **Server side** (git-cdn's Worker, deployed 2026-11-14): for anonymous `GET`s of those two paths, the Worker keeps Forgejo's answer at the edge. - Under a minute old, the kept list is served as it is. - From 1 to 10 minutes old, it is served at once and refreshed in the background (stale-while-revalidate). - Older than that, Forgejo is asked first. - When Forgejo is down (no answer, 5xx, 429), any kept copy up to 7 days old is served (stale-if-error). - A 404 drops the kept copy. - Download lookups also fall back to their last answer while Forgejo is down, so files keep downloading too. - Forgejo has 5 s to answer before it counts as down, so one that hangs still lets the kept copy be served quickly. ## Measurements Nothing to measure in the game: this changes where the update check's two small JSON requests go, not the build or the game. Checked on the deployed Worker: `X-Cache: MISS` then `HIT` on `https://git-cdn.magicbean.dev/api/v1/repos/MagicBeanDev/LongshotLauncher/releases?limit=50&page=1`. ## Testing - **Not compiled or run on the author's PC** (no .NET there): CI's `test_launcher_core.py` compiles `Core/` and runs `CdnChecks`. - **Safe in either order with the Worker:** until the Worker change is live, git-cdn redirects API paths to git.magicbean.dev and `HttpFetcher` follows the redirect, so the check works as today. - **Must be tested before merge:** a launcher built from this PR starts and checks for updates, with the Worker deployed. Then `LONGSHOT_LAUNCHER_NO_CDN=1` checks against git.magicbean.dev only. - **Checked on the server:** a list gives `MISS` then `HIT`, the tag lookup answers, other API paths and requests with a token still redirect to git.magicbean.dev, and a download still answers. ## Risks - **A list up to about a minute old**, or longer while git.magicbean.dev is down. A new release shows in launchers a minute or two later. An old list can't install anything: an update only goes to a newer version, and every release is checked against its signed `SHA256SUMS`. - **Pages kept at different times** can repeat or skip one release where pages 1 and 2 meet, within that minute. The newest of each channel is on page 1 unless a channel's newest is more than 50 releases back. In that case the window could show the stable channel one version behind until the next check; it never moves a build backwards. - **Compatibility:** no change to saves, settings, caches or the release format. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat(updates): the release lists through git-cdn.magicbean.dev first, so the update check works while git.magicbean.dev is down
All checks were successful
CI / Compile and test (pull_request) Has been skipped
CI / Conventional Commit title (pull_request) Successful in 14s
742613a0ea
Co-Authored-By: Claude Opus 5.5 <[email protected]>
HumanBean changed title from WIP: feat(updates): the release lists through git-cdn.magicbean.dev first, so the update check works while git.magicbean.dev is down to feat(updates): the release lists through git-cdn.magicbean.dev first, so the update check works while git.magicbean.dev is down 2026-11-15 04:13:36 +00:00
HumanBean deleted branch feat/release-lists-cdn 2026-11-15 04:13:40 +00:00
Author
Owner

The git-cdn Worker is deployed. Release lists on git-cdn now answer from the edge: MISS then HIT. Other API paths and requests with a token still redirect to git.magicbean.dev, and downloads still work. Forgejo now has 5 s to answer before it counts as down. This PR still waits for CI and for a launcher built from it to run an update check.

The git-cdn Worker is deployed. Release lists on git-cdn now answer from the edge: `MISS` then `HIT`. Other API paths and requests with a token still redirect to git.magicbean.dev, and downloads still work. Forgejo now has 5 s to answer before it counts as down. This PR still waits for CI and for a launcher built from it to run an update check.
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
MagicBeanDev/LongshotLauncher!76
No description provided.