-
-
Notifications
You must be signed in to change notification settings - Fork 538
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
package version | ||
|
||
import ( | ||
"io" | ||
"net/http" | ||
"sync" | ||
"time" | ||
|
||
goversion "github.com/hashicorp/go-version" | ||
log "github.com/sirupsen/logrus" | ||
) | ||
|
||
const ( | ||
versionURL = "https://pkgs.netbird.io/releases/latest/version" | ||
) | ||
|
||
type Update struct { | ||
uiVersion *goversion.Version | ||
daemonVersion *goversion.Version | ||
lastAvailable *goversion.Version | ||
versionsLock sync.Mutex | ||
|
||
onUpdateListener func(version string) | ||
listenerLock sync.Mutex | ||
} | ||
|
||
func NewUpdate() *Update { | ||
currentVersion, err := goversion.NewVersion(version) | ||
if err != nil { | ||
currentVersion, _ = goversion.NewVersion("0.0.0") | ||
} | ||
|
||
lastAvailable, _ := goversion.NewVersion("0.0.0") | ||
|
||
u := &Update{ | ||
lastAvailable: lastAvailable, | ||
uiVersion: currentVersion, | ||
} | ||
|
||
go u.startFetcher() | ||
return u | ||
} | ||
|
||
func (u *Update) SetDaemonVersion(newVersion string) { | ||
daemonVersion, err := goversion.NewVersion(newVersion) | ||
if err != nil { | ||
daemonVersion, _ = goversion.NewVersion("0.0.0") | ||
} | ||
|
||
u.versionsLock.Lock() | ||
if u.daemonVersion != nil && u.daemonVersion.Equal(daemonVersion) { | ||
u.versionsLock.Unlock() | ||
return | ||
} | ||
|
||
u.daemonVersion = daemonVersion | ||
u.versionsLock.Unlock() | ||
u.checkUpdate() | ||
return | ||
Check failure on line 59 in version/update.go GitHub Actions / lint (macos-latest)
|
||
} | ||
|
||
func (u *Update) SetOnUpdateListener(updateFn func(version string)) { | ||
u.listenerLock.Lock() | ||
defer u.listenerLock.Unlock() | ||
|
||
u.onUpdateListener = updateFn | ||
if u.isUpdateAvailable() { | ||
u.onUpdateListener(version) | ||
} | ||
} | ||
|
||
func (u *Update) startFetcher() { | ||
changed := u.fetchVersion() | ||
if changed { | ||
u.checkUpdate() | ||
} | ||
|
||
uptimeTicker := time.NewTicker(30 * time.Minute) | ||
for { | ||
Check failure on line 79 in version/update.go GitHub Actions / lint (macos-latest)
|
||
select { | ||
case <-uptimeTicker.C: | ||
changed := u.fetchVersion() | ||
if changed { | ||
u.checkUpdate() | ||
} | ||
|
||
} | ||
} | ||
|
||
} | ||
|
||
func (u *Update) fetchVersion() bool { | ||
resp, err := http.Get(versionURL) | ||
if err != nil { | ||
log.Error("failed to fetch version info: %s", err) | ||
Check failure on line 95 in version/update.go GitHub Actions / test (jsonfile)
Check failure on line 95 in version/update.go GitHub Actions / lint (macos-latest)
Check failure on line 95 in version/update.go GitHub Actions / test (sqlite)
Check failure on line 95 in version/update.go GitHub Actions / test (386, jsonfile)
Check failure on line 95 in version/update.go GitHub Actions / lint (ubuntu-latest)
Check failure on line 95 in version/update.go GitHub Actions / test (386, sqlite)
Check failure on line 95 in version/update.go GitHub Actions / test (amd64, jsonfile)
|
||
return false | ||
} | ||
defer resp.Body.Close() | ||
|
||
if resp.StatusCode != http.StatusOK { | ||
log.Errorf("invalid status code: %d", resp.StatusCode) | ||
return false | ||
} | ||
|
||
if resp.ContentLength > 100 { | ||
log.Errorf("too large response: %d", resp.ContentLength) | ||
return false | ||
} | ||
|
||
content, err := io.ReadAll(resp.Body) | ||
if err != nil { | ||
log.Errorf("failed to read content: %s", err) | ||
return false | ||
} | ||
|
||
lastAvailable, err := goversion.NewVersion(string(content)) | ||
if err != nil { | ||
log.Errorf("faield to parse the version string: %s", err) | ||
return false | ||
} | ||
|
||
u.versionsLock.Lock() | ||
defer u.versionsLock.Unlock() | ||
|
||
if u.lastAvailable.Equal(lastAvailable) { | ||
return false | ||
} | ||
u.lastAvailable = lastAvailable | ||
|
||
return true | ||
} | ||
|
||
func (u *Update) checkUpdate() { | ||
if !u.isUpdateAvailable() { | ||
return | ||
} | ||
|
||
u.listenerLock.Lock() | ||
defer u.listenerLock.Unlock() | ||
if u.onUpdateListener == nil { | ||
return | ||
} | ||
|
||
u.onUpdateListener(u.lastAvailable.String()) | ||
} | ||
|
||
func (u *Update) isUpdateAvailable() bool { | ||
u.versionsLock.Lock() | ||
defer u.versionsLock.Unlock() | ||
|
||
if u.lastAvailable.GreaterThan(u.uiVersion) { | ||
return true | ||
} | ||
|
||
if u.daemonVersion == nil { | ||
return false | ||
} | ||
|
||
if u.lastAvailable.GreaterThan(u.daemonVersion) { | ||
return true | ||
} | ||
return false | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package version | ||
|
||
import ( | ||
"os/exec" | ||
"runtime" | ||
) | ||
|
||
const ( | ||
downloadURL = "https://app.netbird.io/install" | ||
macIntelURL = "https://pkgs.netbird.io/macos/amd64" | ||
macM1M2URL = "https://pkgs.netbird.io/macos/arm64" | ||
) | ||
|
||
func DownloadUrl() string { | ||
switch runtime.GOOS { | ||
case "windows": | ||
return downloadURL | ||
case "darwin": | ||
return darwinDownloadUrl() | ||
case "linux": | ||
return downloadURL | ||
default: | ||
return downloadURL | ||
} | ||
} | ||
|
||
func darwinDownloadUrl() string { | ||
cmd := exec.Command("brew", "list --formula | grep -i netbird") | ||
if err := cmd.Start(); err != nil { | ||
goto PKGINSTALL | ||
} | ||
|
||
if err := cmd.Wait(); err == nil { | ||
return downloadURL | ||
} | ||
|
||
PKGINSTALL: | ||
switch runtime.GOARCH { | ||
case "amd64": | ||
return macIntelURL | ||
case "arm64": | ||
return macM1M2URL | ||
default: | ||
return downloadURL | ||
} | ||
} |