Auto-Update¶
Section summary A non-disruptive update mechanism sourced from GitHub Releases. The pipeline — check → download → extract → user consent → apply-on-exit → restart — ensures that no actual files are overwritten until the user explicitly consents.
Components¶
| Component | Role |
|---|---|
UpdateService |
Handles check, download, extract, and preparing the files to apply |
| Update notice | When an update is ready, shows a centered banner just above the status bar with a Restart button and a dismiss button |
Settings (settings.json) |
AutoUpdateEnabled, LastUpdateCheck, SkippedVersions — check interval, last check time, and list of skipped versions |
Check and fetch flow¶
- Automatic check: When
AutoUpdateEnabled == true,UpdateService.Initialize()creates aTimerthat fires the first check 30 seconds after startup and then every 4 hours. As a rate-limit guard, any check within 30 minutes of the previous one is skipped (guarded by_lastCheckUtc). - Manual check: Control Deck → About → "Check for updates" calls
CheckForUpdatesAsync()immediately. The result is surfaced via a toast and theUpdateStatusproperty. - Two-stage version lookup:
- Primary: the Cloudflare Worker (
VersionCheckUrl), a cache layer to avoid GitHub API rate limits. - Fallback: if the Worker returns an
errorproperty or any HTTP failure occurs, the app automatically falls back to the GitHub API (releases/latest) viaCheckGitHubDirectAsync. - Download type priority (when
Autois specified): - Delta: used only when
DeltaFromVersion == AppVersionmatches. - Full: fallback when the delta cannot be used.
Skipping a version means the delta no longer matches, so the full package is downloaded automatically. Updating from a version that predates the move of the program files also always takes the full package, because a partial download would leave the required files incomplete (
ResolveDownloadType). - Download progress:
_downloadClient(no API headers, 5-minute timeout) streams the download, visualized in the GlowBar (10%–74%). After receipt,ZipFile.ExtractToDirectoryextracts into the temp directory (TempUpdateDir). Upon extract completion:IsReadyToRestart = trueandRaiseStateChanged().
User-consent gate (since v0.45.1)¶
If the app is closed before the user clicks Restart, the update will NOT be applied silently.
UpdateService.UserConsentedToApplyis set totrueonly byApplyAndRestart()(i.e., the popup's "Restart" button).- On exit,
App_Exit → UpdateService.ApplyOnExit()is guarded byif (!IsReadyToRestart || !UserConsentedToApply) return;. - If the user closes without consenting, the 30-second timer on next launch will re-check and the same popup reappears (the extracted files remain in
TempUpdateDir).
Apply batch and restart notification¶
LaunchUpdateBatch()generates a.batthat usesxcopy /s /y /qto overwriteappDirwith the contents ofextracted/, then restarts with the new binary.- The restarted process runs with the
--updatedcommand-line argument, which the app detects to show the "Update completed (vX.Y.Z)" toast and to callCleanupTempFiles()to remove the old cache.
Skip feature¶
Selecting "Skip this version" on the version-available dialog adds the target version to WindowSettings.SkippedVersions, and it will not be notified in future automatic checks (but still appears in manual checks).
Troubleshooting¶
| Symptom | Cause and fix |
|---|---|
| Popup doesn't appear | Check the logs (data/logs/*.log) for [Update] StateChanged raised and [Update] ShowRestartPopup called. If they are missing, suspect that _updateServiceSubscribed was never initialized |
| "rate limit" log appears | GitHub API (direct) hit its rate cap. The next check is automatically delayed by 6 hours. Downloads during rate limit fall back to opening the Releases page in the browser |
| Update doesn't apply after restart | The apply batch may have been blocked by antivirus. Check data/logs/ for [Update] ApplyAndRestart and [Update] ApplyOnExit values of IsReadyToRestart / UserConsentedToApply |
| Want to disable auto-update entirely | Control Deck → About → "Enable auto-update" → OFF. Saves WindowSettings.AutoUpdateEnabled = false and stops the timer via SetEnabled(false) |
Log spec¶
The main log prefix for update operations is [Update]. The following log points were added in v0.45.1:
[Update] Periodic check started / result: hasUpdate=...[Update] {typeLabel} (v... → v...)— download starts[Update] Download & extract complete IsReadyToRestart=true[Update] StateChanged raised: IsDownloading=..., IsReadyToRestart=..., AvailableVersion=...[Update] ShowRestartPopup called from {source}, version=...[Update] ApplyAndRestart: user consented, launching batch[Update] ApplyOnExit: IsReadyToRestart=..., UserConsentedToApply=...