git.sr.ht/~pingoo/stdx@v0.0.0-20240218134121-094174641f6e/selfupdate/updater.go (about) 1 package selfupdate 2 3 import ( 4 "errors" 5 "net/http" 6 "sync" 7 8 "git.sr.ht/~pingoo/stdx/httpx" 9 "git.sr.ht/~pingoo/stdx/semver" 10 ) 11 12 type Config struct { 13 ZingPublicKey string 14 // BaseURL is the URL of the folder containing the manifest 15 // e.g. https://downloads.example.com/myapp 16 BaseURL string 17 CurrentVersion string 18 ReleaseChannel string 19 20 // Default: 300 seconds 21 AutoupdateInterval int64 22 // Verbose logs actions with the INFO level 23 Verbose bool 24 UserAgent *string 25 HttpClient *http.Client 26 } 27 28 type Updater struct { 29 httpClient *http.Client 30 baseUrl string 31 zingPublicKey string 32 currentVersion string 33 userAgent string 34 releaseChannel string 35 updateInProgress sync.Mutex 36 latestVersionAvailable string 37 latestVersionInstalled string 38 autoupdateInterval int64 39 verbose bool 40 41 Updated chan struct{} 42 } 43 44 func NewUpdater(config Config) (updater *Updater, err error) { 45 if config.HttpClient == nil { 46 config.HttpClient = httpx.DefaultClient() 47 } 48 49 if config.BaseURL == "" { 50 err = errors.New("selfupdate: BaseURL is empty") 51 return 52 } 53 54 if config.ZingPublicKey == "" { 55 err = errors.New("selfupdate: ZingPublicKey is empty") 56 return 57 } 58 59 if config.CurrentVersion == "" { 60 err = errors.New("selfupdate: CurrentVersion is empty") 61 return 62 } 63 64 if config.AutoupdateInterval == 0 { 65 config.AutoupdateInterval = 300 66 } 67 68 userAgent := DefaultUserAgent 69 if config.UserAgent != nil { 70 userAgent = *config.UserAgent 71 } 72 73 updater = &Updater{ 74 httpClient: config.HttpClient, 75 baseUrl: config.BaseURL, 76 zingPublicKey: config.ZingPublicKey, 77 currentVersion: config.CurrentVersion, 78 userAgent: userAgent, 79 releaseChannel: config.ReleaseChannel, 80 updateInProgress: sync.Mutex{}, 81 latestVersionAvailable: config.CurrentVersion, 82 latestVersionInstalled: config.CurrentVersion, 83 autoupdateInterval: config.AutoupdateInterval, 84 verbose: config.Verbose, 85 Updated: make(chan struct{}), 86 } 87 return 88 } 89 90 func (updater *Updater) RestartRequired() bool { 91 return updater.latestVersionInstalled != updater.currentVersion 92 } 93 94 // UpdateAvailable returns true if the latest avaiable version is > to the latest install version 95 func (updater *Updater) UpdateAvailable() bool { 96 return semver.Compare(updater.latestVersionAvailable, updater.latestVersionInstalled) > 0 97 }