0.2.45 - Server side git commits

This commit is contained in:
ponzischeme89
2026-08-10 20:54:00 +12:00
parent 4c47a5f8a0
commit dd2dd497f2
11 changed files with 170 additions and 63 deletions
+26 -17
View File
@@ -17,12 +17,6 @@ import (
// speaks, next to the build's own version.
const ProtocolVersion = 1
// forcedUpdateFloor retires builds whose update behaviour is no longer reliable enough
// to leave optional. The floor only takes effect once an enabled policy points at this
// version (or a newer one) and carries a download URL, so deploying the gateway before
// publishing the APK cannot lock televisions out.
const forcedUpdateFloor = "0.2.44"
// updatePolicyCache keeps the policy in memory. It is read on every home request, and a
// database round trip per home load to answer "nothing to say" would be wasteful.
type updatePolicyCache struct {
@@ -96,16 +90,30 @@ func compatibilityFor(r *http.Request) (bool, string) {
return true, ""
}
// effectiveUpdatePolicy applies the server-owned emergency floor without weakening a
// higher minimum the operator has already selected.
// destructiveUpdateFloor returns the operator-selected compatibility floor once an
// actionable release at or above it exists. This keeps a policy saved ahead of its APK
// from locking televisions out.
func destructiveUpdateFloor(policy appupdate.Policy) string {
if !policy.Enabled || strings.TrimSpace(policy.DownloadURL) == "" {
return ""
}
floor := strings.TrimSpace(policy.RetireBelowVersion)
if floor == "" || appupdate.CompareVersions(policy.LatestVersion, floor) < 0 {
return ""
}
return floor
}
// effectiveUpdatePolicy applies the destructive floor without weakening a higher
// non-destructive minimum the operator has already selected.
func effectiveUpdatePolicy(policy appupdate.Policy) appupdate.Policy {
if !policy.Enabled || strings.TrimSpace(policy.DownloadURL) == "" ||
appupdate.CompareVersions(policy.LatestVersion, forcedUpdateFloor) < 0 {
floor := destructiveUpdateFloor(policy)
if floor == "" {
return policy
}
if strings.TrimSpace(policy.MinimumVersion) == "" ||
appupdate.CompareVersions(policy.MinimumVersion, forcedUpdateFloor) < 0 {
policy.MinimumVersion = forcedUpdateFloor
appupdate.CompareVersions(policy.MinimumVersion, floor) < 0 {
policy.MinimumVersion = floor
}
return policy
}
@@ -116,10 +124,10 @@ func (s *Server) updateDecision(r *http.Request) appupdate.Decision {
// mustRetireForUpdate is narrower than "mandatory": an operator may temporarily force a
// newer release without wanting every otherwise supported session destroyed. Only builds
// below the permanent compatibility floor are signed out.
func mustRetireForUpdate(decision appupdate.Decision, version string) bool {
// below the active destructive floor are signed out.
func mustRetireForUpdate(decision appupdate.Decision, version, floor string) bool {
return decision.Status == appupdate.StatusMandatory && decision.DownloadURL != "" &&
appupdate.CompareVersions(version, forcedUpdateFloor) < 0
strings.TrimSpace(floor) != "" && appupdate.CompareVersions(version, floor) < 0
}
// requireSupportedClient prevents a retired build from signing straight back in after
@@ -127,8 +135,9 @@ func mustRetireForUpdate(decision appupdate.Decision, version string) bool {
// available and will keep returning the actionable mandatory verdict.
func (s *Server) requireSupportedClient(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
decision := s.updateDecision(r)
if mustRetireForUpdate(decision, clientVersion(r)) {
policy := s.updatePolicy.get()
decision := appupdate.Decide(effectiveUpdatePolicy(policy), clientVersion(r))
if mustRetireForUpdate(decision, clientVersion(r), destructiveUpdateFloor(policy)) {
w.Header().Set("X-Memby-Update-Required", decision.Version)
writeJSON(w, http.StatusUpgradeRequired, decision)
return