forked from Silverfish/proton-bridge
GODT-1978: Auto-updates
This commit is contained in:
@ -74,6 +74,7 @@ type Bridge struct {
|
||||
// updater is the bridge's updater.
|
||||
updater Updater
|
||||
curVersion *semver.Version
|
||||
installCh chan installJob
|
||||
|
||||
// focusService is used to raise the bridge window when needed.
|
||||
focusService *focus.Service
|
||||
@ -241,6 +242,7 @@ func newBridge(
|
||||
|
||||
updater: updater,
|
||||
curVersion: curVersion,
|
||||
installCh: make(chan installJob, 1),
|
||||
|
||||
focusService: focusService,
|
||||
autostarter: autostarter,
|
||||
@ -340,18 +342,25 @@ func (bridge *Bridge) init(tlsReporter TLSReporter) error {
|
||||
defer bridge.goLoad()
|
||||
|
||||
// Check for updates when triggered.
|
||||
bridge.goUpdate = bridge.tasks.PeriodicOrTrigger(constants.UpdateCheckInterval, 0, func(context.Context) {
|
||||
bridge.goUpdate = bridge.tasks.PeriodicOrTrigger(constants.UpdateCheckInterval, 0, func(ctx context.Context) {
|
||||
logrus.Info("Checking for updates")
|
||||
|
||||
version, err := bridge.updater.GetVersionInfo(bridge.api, bridge.vault.GetUpdateChannel())
|
||||
version, err := bridge.updater.GetVersionInfo(ctx, bridge.api, bridge.vault.GetUpdateChannel())
|
||||
if err != nil {
|
||||
logrus.WithError(err).Error("Failed to get version info")
|
||||
} else if err := bridge.handleUpdate(version); err != nil {
|
||||
logrus.WithError(err).Error("Failed to handle update")
|
||||
logrus.WithError(err).Error("Failed to check for updates")
|
||||
} else {
|
||||
bridge.handleUpdate(version)
|
||||
}
|
||||
})
|
||||
defer bridge.goUpdate()
|
||||
|
||||
// Install updates when available.
|
||||
bridge.tasks.Once(func(ctx context.Context) {
|
||||
async.RangeContext(ctx, bridge.installCh, func(job installJob) {
|
||||
bridge.installUpdate(ctx, job)
|
||||
})
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@ -237,7 +237,8 @@ func TestBridge_CheckUpdate(t *testing.T) {
|
||||
MinAuto: v2_3_0,
|
||||
RolloutProportion: 1.0,
|
||||
},
|
||||
CanInstall: true,
|
||||
Silent: false,
|
||||
Compatible: true,
|
||||
}, <-updateCh)
|
||||
})
|
||||
})
|
||||
@ -259,13 +260,14 @@ func TestBridge_AutoUpdate(t *testing.T) {
|
||||
// Check for updates.
|
||||
bridge.CheckForUpdates()
|
||||
|
||||
// We should receive an event indicating that the update was installed.
|
||||
// We should receive an event indicating that the update was silently installed.
|
||||
require.Equal(t, events.UpdateInstalled{
|
||||
Version: updater.VersionInfo{
|
||||
Version: v2_4_0,
|
||||
MinAuto: v2_3_0,
|
||||
RolloutProportion: 1.0,
|
||||
},
|
||||
Silent: true,
|
||||
}, <-updateCh)
|
||||
})
|
||||
})
|
||||
@ -294,7 +296,8 @@ func TestBridge_ManualUpdate(t *testing.T) {
|
||||
MinAuto: v2_4_0,
|
||||
RolloutProportion: 1.0,
|
||||
},
|
||||
CanInstall: false,
|
||||
Silent: false,
|
||||
Compatible: false,
|
||||
}, <-updateCh)
|
||||
})
|
||||
})
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package bridge
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
@ -129,13 +130,13 @@ func (testUpdater *TestUpdater) SetLatestVersion(version, minAuto *semver.Versio
|
||||
}
|
||||
}
|
||||
|
||||
func (testUpdater *TestUpdater) GetVersionInfo(downloader updater.Downloader, channel updater.Channel) (updater.VersionInfo, error) {
|
||||
func (testUpdater *TestUpdater) GetVersionInfo(ctx context.Context, downloader updater.Downloader, channel updater.Channel) (updater.VersionInfo, error) {
|
||||
testUpdater.lock.RLock()
|
||||
defer testUpdater.lock.RUnlock()
|
||||
|
||||
return testUpdater.latest, nil
|
||||
}
|
||||
|
||||
func (testUpdater *TestUpdater) InstallUpdate(downloader updater.Downloader, update updater.VersionInfo) error {
|
||||
func (testUpdater *TestUpdater) InstallUpdate(ctx context.Context, downloader updater.Downloader, update updater.VersionInfo) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -18,6 +18,8 @@
|
||||
package bridge
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/ProtonMail/proton-bridge/v2/internal/updater"
|
||||
)
|
||||
|
||||
@ -51,6 +53,6 @@ type Autostarter interface {
|
||||
}
|
||||
|
||||
type Updater interface {
|
||||
GetVersionInfo(downloader updater.Downloader, channel updater.Channel) (updater.VersionInfo, error)
|
||||
InstallUpdate(downloader updater.Downloader, update updater.VersionInfo) error
|
||||
GetVersionInfo(context.Context, updater.Downloader, updater.Channel) (updater.VersionInfo, error)
|
||||
InstallUpdate(context.Context, updater.Downloader, updater.VersionInfo) error
|
||||
}
|
||||
|
||||
@ -18,43 +18,123 @@
|
||||
package bridge
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/ProtonMail/proton-bridge/v2/internal/events"
|
||||
"github.com/ProtonMail/proton-bridge/v2/internal/updater"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func (bridge *Bridge) CheckForUpdates() {
|
||||
bridge.goUpdate()
|
||||
}
|
||||
|
||||
func (bridge *Bridge) handleUpdate(version updater.VersionInfo) error {
|
||||
func (bridge *Bridge) InstallUpdate(version updater.VersionInfo) {
|
||||
log := logrus.WithFields(logrus.Fields{
|
||||
"version": version.Version,
|
||||
"current": bridge.curVersion,
|
||||
"channel": bridge.vault.GetUpdateChannel(),
|
||||
})
|
||||
|
||||
select {
|
||||
case bridge.installCh <- installJob{version: version, silent: false}:
|
||||
log.Info("The update will be installed manually")
|
||||
|
||||
default:
|
||||
log.Info("An update is already being installed")
|
||||
}
|
||||
}
|
||||
|
||||
func (bridge *Bridge) handleUpdate(version updater.VersionInfo) {
|
||||
log := logrus.WithFields(logrus.Fields{
|
||||
"version": version.Version,
|
||||
"current": bridge.curVersion,
|
||||
"channel": bridge.vault.GetUpdateChannel(),
|
||||
})
|
||||
|
||||
bridge.publish(events.UpdateLatest{
|
||||
Version: version,
|
||||
})
|
||||
|
||||
switch {
|
||||
case !version.Version.GreaterThan(bridge.curVersion):
|
||||
log.Debug("No update available")
|
||||
|
||||
bridge.publish(events.UpdateNotAvailable{})
|
||||
|
||||
case version.RolloutProportion < bridge.vault.GetUpdateRollout():
|
||||
log.Info("An update is available but has not been rolled out yet")
|
||||
|
||||
bridge.publish(events.UpdateNotAvailable{})
|
||||
|
||||
case bridge.curVersion.LessThan(version.MinAuto):
|
||||
log.Info("An update is available but is incompatible with this version")
|
||||
|
||||
bridge.publish(events.UpdateAvailable{
|
||||
Version: version,
|
||||
CanInstall: false,
|
||||
Compatible: false,
|
||||
Silent: false,
|
||||
})
|
||||
|
||||
case !bridge.vault.GetAutoUpdate():
|
||||
log.Info("An update is available but auto-update is disabled")
|
||||
|
||||
bridge.publish(events.UpdateAvailable{
|
||||
Version: version,
|
||||
CanInstall: true,
|
||||
Compatible: true,
|
||||
Silent: false,
|
||||
})
|
||||
|
||||
default:
|
||||
if err := bridge.updater.InstallUpdate(bridge.api, version); err != nil {
|
||||
return err
|
||||
log.Info("An update is available")
|
||||
|
||||
bridge.publish(events.UpdateAvailable{
|
||||
Version: version,
|
||||
Compatible: true,
|
||||
Silent: true,
|
||||
})
|
||||
|
||||
select {
|
||||
case bridge.installCh <- installJob{version: version, silent: true}:
|
||||
log.Info("The update will be installed silently")
|
||||
|
||||
default:
|
||||
log.Info("An update is already being installed")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type installJob struct {
|
||||
version updater.VersionInfo
|
||||
silent bool
|
||||
}
|
||||
|
||||
func (bridge *Bridge) installUpdate(ctx context.Context, job installJob) {
|
||||
log := logrus.WithFields(logrus.Fields{
|
||||
"version": job.version.Version,
|
||||
"current": bridge.curVersion,
|
||||
"channel": bridge.vault.GetUpdateChannel(),
|
||||
})
|
||||
|
||||
bridge.publish(events.UpdateInstalling{
|
||||
Version: job.version,
|
||||
Silent: job.silent,
|
||||
})
|
||||
|
||||
if err := bridge.updater.InstallUpdate(ctx, bridge.api, job.version); err != nil {
|
||||
log.Error("The update could not be installed")
|
||||
|
||||
bridge.publish(events.UpdateFailed{
|
||||
Version: job.version,
|
||||
Silent: job.silent,
|
||||
Error: err,
|
||||
})
|
||||
} else {
|
||||
log.Info("The update was installed successfully")
|
||||
|
||||
bridge.publish(events.UpdateInstalled{
|
||||
Version: version,
|
||||
Version: job.version,
|
||||
Silent: job.silent,
|
||||
})
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user