Skip to content

Commit

Permalink
refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
AhMyth committed Apr 19, 2022
1 parent 10870d7 commit ef361da
Showing 1 changed file with 52 additions and 60 deletions.
112 changes: 52 additions & 60 deletions selfupdate/selfupdate.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ import (
"errors"
"fmt"
"github.com/blang/semver"
"github.com/kr/binarydist"
"io"
"io/ioutil"
"math/rand"
Expand All @@ -52,11 +51,9 @@ const (
plat = runtime.GOOS + "-" + runtime.GOARCH
)

const devValidTime = 7 * 24 * time.Hour

var ErrHashMismatch = errors.New("new file hash mismatch after patch")
var ErrNoAvailableUpdates = errors.New("no available updates")
var ErrNotNowHolder = errors.New("")
var up = update.New()
var defaultHTTPRequester = HTTPRequester{}

Expand All @@ -71,23 +68,22 @@ var defaultHTTPRequester = HTTPRequester{}
// ApiURL: "http://updates.yourdomain.com/",
// BinURL: "http://updates.yourdownmain.com/",
// DiffURL: "http://updates.yourdomain.com/",
// Dir: "update/",
// CmdName: "myapp", // app name
// DirName: "update/",
// AppName: "myapp", // app name
// }
// if updater != nil {
// go updater.BackgroundRun()
// go updater.Update()
// }
type Updater struct {
CurrentVersion string // Currently running version.
ApiURL string // Base URL for API requests (json files).
AppName string // Application name
DirName string // Directory name is appended to the ApiURL like http://apiurl/DirName/. This represents one binary.
BinURL string // Base URL for full binary downloads.
DiffURL string // Base URL for diff downloads.
LocalStateDir string // Directory to store selfupdate state.
ForceCheck bool // Check for update regardless of cktime timestamp
Requester Requester //Optional parameter to override existing http request handler
Info struct {
CheckInterval time.Duration
Info struct {
Version string
Sha256 []byte
}
Expand All @@ -99,40 +95,46 @@ func (u *Updater) getExecRelativeDir(dir string) string {
return path
}

// BackgroundRun starts the update check and apply cycle.
func (u *Updater) BackgroundRun() error {
// Update starts the update
// returns true if it gets updated
func (u *Updater) Update() (bool, error) {
if err := os.MkdirAll(u.getExecRelativeDir(u.LocalStateDir), 0777); err != nil {
// fail
return err
return false, err
}

if u.wantUpdate() {
if err := up.CanUpdate(); err != nil {
// fail
return err
return false, err
}

u.SetUpdateTime()

// TODO(bgentry): logger isn't on Windows. Replace w/ proper error reports.
if err := u.update(); err != nil {
return err
return false, err
}
return nil
}else{
return ErrNotNowHolder

return true, nil
}

return false, nil
}

func (u *Updater) wantUpdate() bool {
path := u.getExecRelativeDir(u.LocalStateDir + upcktimePath)
if u.CurrentVersion == "dev" || (!u.ForceCheck && readTime(path).After(time.Now())) {
if u.CurrentVersion == "dev" ||
(!u.ForceCheck && !u.NextUpdate().IsZero() &&
u.NextUpdate().After(time.Now())) {
return false
}
wait := 24*time.Hour + randDuration(24*time.Hour)
return writeTime(path, time.Now().Add(wait))


return true
}

//CheckIsThereNewVersion to check if there is an update without pulling the binary
func (u *Updater) CheckIsThereNewVersion()(*semver.Version,error){
//CheckVersion checks if there is an update without pulling the binary
func (u *Updater) CheckVersion()(*semver.Version,error){
if u.wantUpdate() {
err := u.fetchInfo()
if err != nil {
Expand All @@ -141,22 +143,25 @@ func (u *Updater) CheckIsThereNewVersion()(*semver.Version,error){

newVer := semver.MustParse(u.Info.Version)
currentVer := semver.MustParse(u.CurrentVersion)

//if current version is greater than or equal the new version dont update
if currentVer.GE(newVer) {
u.SetUpdateTime()
return nil, ErrNoAvailableUpdates
}

return &newVer, nil
}else {
return nil,ErrNotNowHolder
}

return nil, nil
}

func (u *Updater) update() (error) {
path, err := osext.Executable()
if err != nil {
return err
}

old, err := os.Open(path)
if err != nil {
return err
Expand All @@ -166,7 +171,7 @@ func (u *Updater) update() (error) {
//is check update called before!!?
//to avoid double check request to the endpoint
if u.Info.Version == ""{
_, err := u.CheckIsThereNewVersion(); if err != nil{
_, err := u.CheckVersion(); if err != nil{
return err
}
}
Expand All @@ -192,7 +197,7 @@ func (u *Updater) update() (error) {
}

func (u *Updater) fetchInfo() error {
r, err := u.fetch(u.ApiURL + url.QueryEscape(u.DirName) + "/" + url.QueryEscape(plat) + ".json")
r, err := u.fetch(u.ApiURL + "/" + url.QueryEscape(plat) + ".json")
if err != nil {
return err
}
Expand All @@ -207,28 +212,6 @@ func (u *Updater) fetchInfo() error {
return nil
}

func (u *Updater) fetchAndVerifyPatch(old io.Reader) ([]byte, error) {
bin, err := u.fetchAndApplyPatch(old)
if err != nil {
return nil, err
}
if !verifySha(bin, u.Info.Sha256) {
return nil, ErrHashMismatch
}
return bin, nil
}

func (u *Updater) fetchAndApplyPatch(old io.Reader) ([]byte, error) {
r, err := u.fetch(u.DiffURL + url.QueryEscape(u.DirName) + "/" + url.QueryEscape(u.CurrentVersion) + "/" + url.QueryEscape(u.Info.Version) + "/" + url.QueryEscape(plat))
if err != nil {
return nil, err
}
defer r.Close()
var buf bytes.Buffer
err = binarydist.Patch(old, &buf, r)
return buf.Bytes(), err
}

func (u *Updater) fetchAndVerifyFullBin() ([]byte, error) {
bin, err := u.fetchBin()
if err != nil {
Expand All @@ -242,7 +225,7 @@ func (u *Updater) fetchAndVerifyFullBin() ([]byte, error) {
}

func (u *Updater) fetchBin() ([]byte, error) {
r, err := u.fetch(u.BinURL + url.QueryEscape(u.DirName) + "/" + url.QueryEscape(u.AppName)+"-"+url.QueryEscape(plat) + ".zip")
r, err := u.fetch(u.BinURL + "/" + url.QueryEscape(u.AppName)+"-"+url.QueryEscape(plat) + ".zip")
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -289,27 +272,36 @@ func (u *Updater) fetch(url string) (io.ReadCloser, error) {
return readCloser, nil
}

func readTime(path string) time.Time {
func (u *Updater) readTime(path string) time.Time {
p, err := ioutil.ReadFile(path)
if os.IsNotExist(err) {
return time.Time{}
}
if err != nil {
return time.Now().Add(1000 * time.Hour)
}

t, err := time.Parse(time.RFC3339, string(p))
if err != nil {
return time.Now().Add(1000 * time.Hour)
return time.Time{}
}

return t
}
// NextUpdate returns the next time update should be checked
func (u *Updater) NextUpdate() time.Time {
path := u.getExecRelativeDir(u.LocalStateDir + upcktimePath)
nextTime := u.readTime(path)

return nextTime
}

// SetUpdateTime writes the next update time to the state file
func (u *Updater) SetUpdateTime() {
path := u.getExecRelativeDir(u.LocalStateDir + upcktimePath)

ioutil.WriteFile(path, []byte(time.Now().Add(u.CheckInterval).Format(time.RFC3339)), 0644)
}

func verifySha(bin []byte, sha []byte) bool {
h := sha256.New()
h.Write(bin)
return bytes.Equal(h.Sum(nil), sha)
}

func writeTime(path string, t time.Time) bool {
return ioutil.WriteFile(path, []byte(t.Format(time.RFC3339)), 0644) == nil
}
}

0 comments on commit ef361da

Please sign in to comment.