From 960c322586eceb9598bb0a9985a8dd987dc74807 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Fri, 22 Oct 2021 00:10:49 +0800 Subject: Refactor update checker to use AppState (#17387) We have the `AppState` module now, it can store app related data easily. We do not need to create separate tables for each feature. So the update checker can use `AppState` instead of a one-row dedicate table. And the code of update checker is moved from `models` to `modules`. --- models/migrations/migrations.go | 4 +- models/migrations/v199.go | 13 +--- models/migrations/v201.go | 15 ++++ models/update_checker.go | 121 -------------------------------- modules/cron/tasks_extended.go | 3 +- modules/updatechecker/update_checker.go | 98 ++++++++++++++++++++++++++ routers/web/admin/admin.go | 5 +- 7 files changed, 123 insertions(+), 136 deletions(-) create mode 100644 models/migrations/v201.go delete mode 100644 models/update_checker.go create mode 100644 modules/updatechecker/update_checker.go diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index b1c91beef6..2686dfb3cf 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -351,9 +351,11 @@ var migrations = []Migration{ // v198 -> v199 NewMigration("Add issue content history table", addTableIssueContentHistory), // v199 -> v200 - NewMigration("Add remote version table", addRemoteVersionTable), + NewMigration("No-op (remote version is using AppState now)", addRemoteVersionTableNoop), // v200 -> v201 NewMigration("Add table app_state", addTableAppState), + // v201 -> v202 + NewMigration("Drop table remote_version (if exists)", dropTableRemoteVersion), } // GetCurrentDBVersion returns the current db version diff --git a/models/migrations/v199.go b/models/migrations/v199.go index 64b21172c1..4351ba4fa8 100644 --- a/models/migrations/v199.go +++ b/models/migrations/v199.go @@ -5,19 +5,10 @@ package migrations import ( - "fmt" - "xorm.io/xorm" ) -func addRemoteVersionTable(x *xorm.Engine) error { - type RemoteVersion struct { - ID int64 `xorm:"pk autoincr"` - Version string `xorm:"VARCHAR(50)"` - } - - if err := x.Sync2(new(RemoteVersion)); err != nil { - return fmt.Errorf("Sync2: %v", err) - } +func addRemoteVersionTableNoop(x *xorm.Engine) error { + // we used to use a table `remote_version` to store information for updater, now we use `AppState`, so this migration task is a no-op now. return nil } diff --git a/models/migrations/v201.go b/models/migrations/v201.go new file mode 100644 index 0000000000..637c30617c --- /dev/null +++ b/models/migrations/v201.go @@ -0,0 +1,15 @@ +// Copyright 2021 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package migrations + +import ( + "xorm.io/xorm" +) + +func dropTableRemoteVersion(x *xorm.Engine) error { + // drop the orphaned table introduced in `v199`, now the update checker also uses AppState, do not need this table + _ = x.DropTables("remote_version") + return nil +} diff --git a/models/update_checker.go b/models/update_checker.go deleted file mode 100644 index 5b4fce69ec..0000000000 --- a/models/update_checker.go +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2021 The Gitea Authors. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -package models - -import ( - "encoding/json" - "fmt" - "io/ioutil" - "net/http" - - "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/modules/proxy" - "code.gitea.io/gitea/modules/setting" - - "github.com/hashicorp/go-version" -) - -// RemoteVersion stores the remote version from the JSON endpoint -type RemoteVersion struct { - ID int64 `xorm:"pk autoincr"` - Version string `xorm:"VARCHAR(50)"` -} - -func init() { - db.RegisterModel(new(RemoteVersion)) -} - -// GiteaUpdateChecker returns error when new version of Gitea is available -func GiteaUpdateChecker(httpEndpoint string) error { - httpClient := &http.Client{ - Transport: &http.Transport{ - Proxy: proxy.Proxy(), - }, - } - - req, err := http.NewRequest("GET", httpEndpoint, nil) - if err != nil { - return err - } - resp, err := httpClient.Do(req) - if err != nil { - return err - } - defer resp.Body.Close() - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - return err - } - - type v struct { - Latest struct { - Version string `json:"version"` - } `json:"latest"` - } - ver := v{} - err = json.Unmarshal(body, &ver) - if err != nil { - return err - } - - return UpdateRemoteVersion(ver.Latest.Version) - -} - -// UpdateRemoteVersion updates the latest available version of Gitea -func UpdateRemoteVersion(version string) (err error) { - sess := db.NewSession(db.DefaultContext) - defer sess.Close() - if err = sess.Begin(); err != nil { - return err - } - - currentVersion := &RemoteVersion{ID: 1} - has, err := sess.Get(currentVersion) - if err != nil { - return fmt.Errorf("get: %v", err) - } else if !has { - currentVersion.ID = 1 - currentVersion.Version = version - - if _, err = sess.InsertOne(currentVersion); err != nil { - return fmt.Errorf("insert: %v", err) - } - return nil - } - - if _, err = sess.Update(&RemoteVersion{ID: 1, Version: version}); err != nil { - return err - } - - return sess.Commit() -} - -// GetRemoteVersion returns the current remote version (or currently installed verson if fail to fetch from DB) -func GetRemoteVersion() string { - e := db.GetEngine(db.DefaultContext) - v := &RemoteVersion{ID: 1} - _, err := e.Get(&v) - if err != nil { - // return current version if fail to fetch from DB - return setting.AppVer - } - return v.Version -} - -// GetNeedUpdate returns true whether a newer version of Gitea is available -func GetNeedUpdate() bool { - curVer, err := version.NewVersion(setting.AppVer) - if err != nil { - // return false to fail silently - return false - } - remoteVer, err := version.NewVersion(GetRemoteVersion()) - if err != nil { - // return false to fail silently - return false - } - return curVer.LessThan(remoteVer) -} diff --git a/modules/cron/tasks_extended.go b/modules/cron/tasks_extended.go index 6645e71d2c..9a37c40faf 100644 --- a/modules/cron/tasks_extended.go +++ b/modules/cron/tasks_extended.go @@ -11,6 +11,7 @@ import ( "code.gitea.io/gitea/models" repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/updatechecker" ) func registerDeleteInactiveUsers() { @@ -145,7 +146,7 @@ func registerUpdateGiteaChecker() { HTTPEndpoint: "https://dl.gitea.io/gitea/version.json", }, func(ctx context.Context, _ *models.User, config Config) error { updateCheckerConfig := config.(*UpdateCheckerConfig) - return models.GiteaUpdateChecker(updateCheckerConfig.HTTPEndpoint) + return updatechecker.GiteaUpdateChecker(updateCheckerConfig.HTTPEndpoint) }) } diff --git a/modules/updatechecker/update_checker.go b/modules/updatechecker/update_checker.go new file mode 100644 index 0000000000..01242189fa --- /dev/null +++ b/modules/updatechecker/update_checker.go @@ -0,0 +1,98 @@ +// Copyright 2021 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package updatechecker + +import ( + "encoding/json" + "io/ioutil" + "net/http" + + "code.gitea.io/gitea/modules/appstate" + "code.gitea.io/gitea/modules/proxy" + "code.gitea.io/gitea/modules/setting" + + "github.com/hashicorp/go-version" +) + +// CheckerState stores the remote version from the JSON endpoint +type CheckerState struct { + LatestVersion string +} + +// Name returns the name of the state item for update checker +func (r *CheckerState) Name() string { + return "update-checker" +} + +// GiteaUpdateChecker returns error when new version of Gitea is available +func GiteaUpdateChecker(httpEndpoint string) error { + httpClient := &http.Client{ + Transport: &http.Transport{ + Proxy: proxy.Proxy(), + }, + } + + req, err := http.NewRequest("GET", httpEndpoint, nil) + if err != nil { + return err + } + resp, err := httpClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return err + } + + type respType struct { + Latest struct { + Version string `json:"version"` + } `json:"latest"` + } + respData := respType{} + err = json.Unmarshal(body, &respData) + if err != nil { + return err + } + + return UpdateRemoteVersion(respData.Latest.Version) + +} + +// UpdateRemoteVersion updates the latest available version of Gitea +func UpdateRemoteVersion(version string) (err error) { + return appstate.AppState.Set(&CheckerState{LatestVersion: version}) +} + +// GetRemoteVersion returns the current remote version (or currently installed verson if fail to fetch from DB) +func GetRemoteVersion() string { + item := new(CheckerState) + if err := appstate.AppState.Get(item); err != nil { + return "" + } + return item.LatestVersion +} + +// GetNeedUpdate returns true whether a newer version of Gitea is available +func GetNeedUpdate() bool { + curVer, err := version.NewVersion(setting.AppVer) + if err != nil { + // return false to fail silently + return false + } + remoteVerStr := GetRemoteVersion() + if remoteVerStr == "" { + // no remote version is known + return false + } + remoteVer, err := version.NewVersion(remoteVerStr) + if err != nil { + // return false to fail silently + return false + } + return curVer.LessThan(remoteVer) +} diff --git a/routers/web/admin/admin.go b/routers/web/admin/admin.go index ca5b157523..223114dae1 100644 --- a/routers/web/admin/admin.go +++ b/routers/web/admin/admin.go @@ -26,6 +26,7 @@ import ( "code.gitea.io/gitea/modules/queue" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/updatechecker" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/services/forms" "code.gitea.io/gitea/services/mailer" @@ -125,8 +126,8 @@ func Dashboard(ctx *context.Context) { ctx.Data["PageIsAdmin"] = true ctx.Data["PageIsAdminDashboard"] = true ctx.Data["Stats"] = models.GetStatistic() - ctx.Data["NeedUpdate"] = models.GetNeedUpdate() - ctx.Data["RemoteVersion"] = models.GetRemoteVersion() + ctx.Data["NeedUpdate"] = updatechecker.GetNeedUpdate() + ctx.Data["RemoteVersion"] = updatechecker.GetRemoteVersion() // FIXME: update periodically updateSystemStatus() ctx.Data["SysStatus"] = sysStatus -- cgit v1.2.3