diff --git a/cmd/OliveTin/main.go b/cmd/OliveTin/main.go index 838f0e27..4ca89814 100644 --- a/cmd/OliveTin/main.go +++ b/cmd/OliveTin/main.go @@ -149,7 +149,7 @@ func main() { entityfiles.AddListener(executor.RebuildActionMap) go entityfiles.SetupEntityFileWatchers(cfg) - go updatecheck.StartUpdateChecker(version, commit, cfg, cfg.GetDir()) + go updatecheck.StartUpdateChecker(cfg) go grpcapi.Start(cfg, executor) diff --git a/internal/httpservers/webuiServer.go b/internal/httpservers/webuiServer.go index ad71a5ee..f38b2d28 100644 --- a/internal/httpservers/webuiServer.go +++ b/internal/httpservers/webuiServer.go @@ -10,8 +10,8 @@ import ( "path/filepath" config "github.com/OliveTin/OliveTin/internal/config" + installationinfo "github.com/OliveTin/OliveTin/internal/installationinfo" sv "github.com/OliveTin/OliveTin/internal/stringvariables" - updatecheck "github.com/OliveTin/OliveTin/internal/updatecheck" ) var ( @@ -106,8 +106,8 @@ func generateWebUISettings(w http.ResponseWriter, r *http.Request) { ShowFooter: cfg.ShowFooter, ShowNavigation: cfg.ShowNavigation, ShowNewVersions: cfg.ShowNewVersions, - AvailableVersion: updatecheck.AvailableVersion, - CurrentVersion: updatecheck.CurrentVersion, + AvailableVersion: installationinfo.Runtime.AvailableVersion, + CurrentVersion: installationinfo.Build.Version, PageTitle: cfg.PageTitle, SectionNavigationStyle: cfg.SectionNavigationStyle, DefaultIconForBack: cfg.DefaultIconForBack, diff --git a/internal/installationinfo/runtimeinfo.go b/internal/installationinfo/runtimeinfo.go index 29f9782c..9b7a021b 100644 --- a/internal/installationinfo/runtimeinfo.go +++ b/internal/installationinfo/runtimeinfo.go @@ -19,6 +19,7 @@ type runtimeInfo struct { User string Uid string FoundSshKey string + AvailableVersion string } var Runtime = &runtimeInfo{ diff --git a/internal/updatecheck/updateCheck.go b/internal/updatecheck/updateCheck.go index 1968b68b..5bbd468d 100644 --- a/internal/updatecheck/updateCheck.go +++ b/internal/updatecheck/updateCheck.go @@ -1,11 +1,9 @@ package updatecheck import ( - "bytes" "encoding/json" config "github.com/OliveTin/OliveTin/internal/config" - installationinfo "github.com/OliveTin/OliveTin/internal/installationinfo" - "github.com/google/uuid" + "github.com/OliveTin/OliveTin/internal/installationinfo" "github.com/robfig/cron/v3" log "github.com/sirupsen/logrus" "io" @@ -13,99 +11,63 @@ import ( "os" ) -type updateRequest struct { - CurrentVersion string - CurrentCommit string - OS string - Arch string - InstallationID string - InContainer bool -} - -// AvailableVersion is updated when checking with the update service. -var AvailableVersion = "none" - -// CurrentVersion is set by the main cmd (which is in tern set as a compile constant) -var CurrentVersion = "?" - -func installationID(filename string) string { - var content string - contentBytes, err := os.ReadFile(filename) - - if err != nil { - fileHandle, err := os.OpenFile(filename, os.O_APPEND|os.O_CREATE|os.O_RDWR, 0644) - - if err != nil { - log.Warnf("Could not read + create installation ID file: %v", err) - return "cant-create" - } - - content = uuid.NewString() - fileHandle.WriteString(content) - fileHandle.Close() - } else { - content = string(contentBytes) - - _, err := uuid.Parse(content) - - if err != nil { - log.Errorf("Invalid installation ID, %v", err) - content = "invalid-installation-id" - } - } - - log.WithFields(log.Fields{ - "content": content, - "from": filename, - }).Infof("Installation ID") - - return content +type versionMapType struct { + ApiVersion int + Latest string + History map[string]string } // StartUpdateChecker will start a job that runs periodically, checking // for updates. -func StartUpdateChecker(currentVersion string, currentCommit string, cfg *config.Config, configDir string) { - CurrentVersion = currentVersion - +func StartUpdateChecker(cfg *config.Config) { if !cfg.CheckForUpdates { + installationinfo.Runtime.AvailableVersion = "none" log.Warn("Update checking is disabled") return } - payload := updateRequest{ - CurrentVersion: currentVersion, - CurrentCommit: currentCommit, - OS: installationinfo.Runtime.OS, - Arch: installationinfo.Runtime.Arch, - InstallationID: installationID(configDir + "/installation-id.txt"), - InContainer: installationinfo.Runtime.InContainer, - } - - s := cron.New(cron.WithSeconds()) + s := cron.New() // Several values have been tried here. // 1st: Every 24h - very spammy. // 2nd: Every 7d - (168 hours - much more reasonable, but it checks in at the same time/day each week. // Current: Every 100h is not so spammy, and has the advantage that the checkin time "shifts" hours. s.AddFunc("@every 100h", func() { - actualCheckForUpdate(payload) + actualCheckForUpdate() }) - go actualCheckForUpdate(payload) // On startup + go actualCheckForUpdate() // On startup go s.Start() } -func doRequest(jsonUpdateRequest []byte) string { - req, err := http.NewRequest("POST", "http://update-check.olivetin.app", bytes.NewBuffer(jsonUpdateRequest)) +func parseVersion(input []byte) string { + versionMap := &versionMapType{} + + err := json.Unmarshal(input, &versionMap) + + if err != nil { + log.Warnf("Update check unmarshal failure: %v", err) + return "error-during-check" + } else { + log.Infof("Update check remote version: %+v", versionMap) + + if installationinfo.Build.Version != versionMap.Latest { + return versionMap.Latest + } else { + return "none" + } + } +} + +func doRequest() string { + req, err := http.NewRequest("GET", "http://update-check.olivetin.app/versions.json", nil) if err != nil { log.Errorf("Update check failed %v", err) return "" } - req.Header.Set("Content-Type", "application/json") - resp, err := http.DefaultClient.Do(req) if err != nil { @@ -113,26 +75,22 @@ func doRequest(jsonUpdateRequest []byte) string { return "" } - newVersion, _ := io.ReadAll(resp.Body) + versionMap, _ := io.ReadAll(resp.Body) defer resp.Body.Close() - return string(newVersion) + return parseVersion(versionMap) } -func actualCheckForUpdate(payload updateRequest) { - jsonUpdateRequest, err := json.Marshal(payload) - - log.Debugf("Update request payload: %+v", payload) - - if err != nil { - log.Errorf("Update check failed %v", err) - return +func actualCheckForUpdate() { + if installationinfo.Build.Version == "dev" && os.Getenv("OLIVETIN_FORCE_UPDATE_CHECK") == "" { + installationinfo.Runtime.AvailableVersion = "you-are-using-a-dev-build" + } else { + installationinfo.Runtime.AvailableVersion = doRequest() } - AvailableVersion = doRequest(jsonUpdateRequest) - log.WithFields(log.Fields{ - "NewVersion": AvailableVersion, + "CurrentVersion": installationinfo.Build.Version, + "NewVersion": installationinfo.Runtime.AvailableVersion, }).Infof("Update check complete") }