update core: signed release.json (Ed25519) per channel, ETag check, resumable download with sha256, Auto/Ask/Off policy, appliers for the install.sh layout, AppImage, NSIS installer (keeps the replaced setup.exe for Restore) and .app, trial run with rollback.
Editor and launcher: banner, status bar, Help commands, Task Center download, install on restart.
CLI: aego update, aego release keygen|manifest, aego export --release-json.
Games: modules/update with update { url publicKey }, settings and the aego/update script API.
release.sh refuses to publish without AEGO_RELEASE_KEY and AEGO_UPDATE_KEY; install.sh lays out versions; make test-update runs a real v1 -> v2 update.
64 lines
1.5 KiB
Go
64 lines
1.5 KiB
Go
package update
|
|
|
|
import (
|
|
"slices"
|
|
"time"
|
|
)
|
|
|
|
// Mode is how a copy updates: download in the background and install on restart, ask first, or only when asked.
|
|
type Mode string
|
|
|
|
const (
|
|
Auto Mode = "auto"
|
|
Ask Mode = "ask"
|
|
Off Mode = "off"
|
|
)
|
|
|
|
// Every is how often a long session checks again.
|
|
const Every = 6 * time.Hour
|
|
|
|
// Policy is the user's choice, kept in prefs.aetext for the editor and in the player's settings for a game.
|
|
type Policy struct {
|
|
Mode Mode
|
|
Channel Channel
|
|
Skipped []string
|
|
LastCheck time.Time
|
|
}
|
|
|
|
// Due reports whether a check is due: at start, then every six hours; Off never checks on its own.
|
|
func (p *Policy) Due(now time.Time, started bool) bool {
|
|
if p.Mode == Off {
|
|
return false
|
|
}
|
|
return !started || now.Sub(p.LastCheck) >= Every
|
|
}
|
|
|
|
// Wants reports whether the release is offered: newer than the build, not skipped, and reachable from it.
|
|
func (p *Policy) Wants(r *Release, b Build) bool {
|
|
return r != nil && r.Newer(b) && !slices.Contains(p.Skipped, r.Version)
|
|
}
|
|
|
|
// Skip stops offering a version; the next one is offered again.
|
|
func (p *Policy) Skip(version string) {
|
|
if !slices.Contains(p.Skipped, version) {
|
|
p.Skipped = append(p.Skipped, version)
|
|
}
|
|
}
|
|
|
|
// ParseMode reads a mode, Auto for anything it does not know.
|
|
func ParseMode(s string) Mode {
|
|
switch Mode(s) {
|
|
case Ask, Off:
|
|
return Mode(s)
|
|
}
|
|
return Auto
|
|
}
|
|
|
|
// ParseChannel reads a channel, Stable for anything it does not know.
|
|
func ParseChannel(s string) Channel {
|
|
if Channel(s) == Nightly {
|
|
return Nightly
|
|
}
|
|
return Stable
|
|
}
|