mirror of
https://github.com/ProtonMail/proton-bridge.git
synced 2025-12-11 05:06:51 +00:00
GODT-1978: Auto-updates
This commit is contained in:
@ -34,6 +34,7 @@ import (
|
||||
"github.com/ProtonMail/proton-bridge/v2/internal/crash"
|
||||
"github.com/ProtonMail/proton-bridge/v2/internal/events"
|
||||
"github.com/ProtonMail/proton-bridge/v2/internal/locations"
|
||||
"github.com/ProtonMail/proton-bridge/v2/internal/safe"
|
||||
"github.com/ProtonMail/proton-bridge/v2/internal/updater"
|
||||
"github.com/ProtonMail/proton-bridge/v2/pkg/restarter"
|
||||
"github.com/google/uuid"
|
||||
@ -63,11 +64,16 @@ type Service struct { // nolint:structcheck
|
||||
eventQueue []*StreamEvent
|
||||
eventQueueMutex sync.Mutex
|
||||
|
||||
panicHandler *crash.Handler
|
||||
restarter *restarter.Restarter
|
||||
bridge *bridge.Bridge
|
||||
eventCh <-chan events.Event
|
||||
newVersionInfo updater.VersionInfo
|
||||
panicHandler *crash.Handler
|
||||
restarter *restarter.Restarter
|
||||
bridge *bridge.Bridge
|
||||
eventCh <-chan events.Event
|
||||
|
||||
latest updater.VersionInfo
|
||||
latestLock safe.RWMutex
|
||||
|
||||
target updater.VersionInfo
|
||||
targetLock safe.RWMutex
|
||||
|
||||
authClient *liteapi.Client
|
||||
auth liteapi.Auth
|
||||
@ -82,6 +88,8 @@ type Service struct { // nolint:structcheck
|
||||
}
|
||||
|
||||
// NewService returns a new instance of the service.
|
||||
//
|
||||
// nolint:funlen
|
||||
func NewService(
|
||||
panicHandler *crash.Handler,
|
||||
restarter *restarter.Restarter,
|
||||
@ -121,6 +129,12 @@ func NewService(
|
||||
bridge: bridge,
|
||||
eventCh: eventCh,
|
||||
|
||||
latest: updater.VersionInfo{},
|
||||
latestLock: safe.NewRWMutex(),
|
||||
|
||||
target: updater.VersionInfo{},
|
||||
targetLock: safe.NewRWMutex(),
|
||||
|
||||
log: logrus.WithField("pkg", "grpc"),
|
||||
initializing: sync.WaitGroup{},
|
||||
initializationDone: sync.Once{},
|
||||
@ -178,33 +192,12 @@ func (s *Service) Loop() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) NotifyManualUpdate(version updater.VersionInfo, canInstall bool) {
|
||||
if canInstall {
|
||||
_ = s.SendEvent(NewUpdateManualReadyEvent(version.Version.String()))
|
||||
} else {
|
||||
_ = s.SendEvent(NewUpdateErrorEvent(UpdateErrorType_UPDATE_MANUAL_ERROR))
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) SetVersion(update updater.VersionInfo) {
|
||||
s.newVersionInfo = update
|
||||
_ = s.SendEvent(NewUpdateVersionChangedEvent())
|
||||
}
|
||||
|
||||
func (s *Service) NotifySilentUpdateInstalled() {
|
||||
_ = s.SendEvent(NewUpdateSilentRestartNeededEvent())
|
||||
}
|
||||
|
||||
func (s *Service) NotifySilentUpdateError(err error) {
|
||||
s.log.WithError(err).Error("In app update failed, asking for manual.")
|
||||
_ = s.SendEvent(NewUpdateErrorEvent(UpdateErrorType_UPDATE_SILENT_ERROR))
|
||||
}
|
||||
|
||||
func (s *Service) WaitUntilFrontendIsReady() {
|
||||
s.initializing.Wait()
|
||||
}
|
||||
|
||||
func (s *Service) watchEvents() { //nolint:funlen
|
||||
// nolint:funlen,gocyclo
|
||||
func (s *Service) watchEvents() {
|
||||
// GODT-1949 Better error events.
|
||||
for _, err := range s.bridge.GetErrors() {
|
||||
switch {
|
||||
@ -270,11 +263,43 @@ func (s *Service) watchEvents() { //nolint:funlen
|
||||
_ = s.SendEvent(NewUserDisconnectedEvent(user.Username))
|
||||
}
|
||||
|
||||
case events.TLSIssue:
|
||||
_ = s.SendEvent(NewMailApiCertIssue())
|
||||
case events.UpdateLatest:
|
||||
safe.RLock(func() {
|
||||
s.latest = event.Version
|
||||
}, s.latestLock)
|
||||
|
||||
case events.UpdateAvailable:
|
||||
switch {
|
||||
case !event.Compatible:
|
||||
_ = s.SendEvent(NewUpdateErrorEvent(UpdateErrorType_UPDATE_MANUAL_ERROR))
|
||||
|
||||
case !event.Silent:
|
||||
safe.RLock(func() {
|
||||
s.target = event.Version
|
||||
}, s.targetLock)
|
||||
|
||||
_ = s.SendEvent(NewUpdateManualReadyEvent(event.Version.Version.String()))
|
||||
}
|
||||
|
||||
case events.UpdateInstalled:
|
||||
if event.Silent {
|
||||
_ = s.SendEvent(NewUpdateSilentRestartNeededEvent())
|
||||
} else {
|
||||
_ = s.SendEvent(NewUpdateManualRestartNeededEvent())
|
||||
}
|
||||
|
||||
case events.UpdateFailed:
|
||||
if event.Silent {
|
||||
_ = s.SendEvent(NewUpdateErrorEvent(UpdateErrorType_UPDATE_SILENT_ERROR))
|
||||
} else {
|
||||
_ = s.SendEvent(NewUpdateErrorEvent(UpdateErrorType_UPDATE_MANUAL_ERROR))
|
||||
}
|
||||
|
||||
case events.UpdateForced:
|
||||
_ = s.SendEvent(NewUpdateForceEvent(s.newVersionInfo.Version.String()))
|
||||
_ = s.SendEvent(NewUpdateForceEvent(event.Version.Version.String()))
|
||||
|
||||
case events.TLSIssue:
|
||||
_ = s.SendEvent(NewMailApiCertIssue())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -26,7 +26,9 @@ import (
|
||||
"github.com/Masterminds/semver/v3"
|
||||
"github.com/ProtonMail/proton-bridge/v2/internal/bridge"
|
||||
"github.com/ProtonMail/proton-bridge/v2/internal/constants"
|
||||
"github.com/ProtonMail/proton-bridge/v2/internal/events"
|
||||
"github.com/ProtonMail/proton-bridge/v2/internal/frontend/theme"
|
||||
"github.com/ProtonMail/proton-bridge/v2/internal/safe"
|
||||
"github.com/ProtonMail/proton-bridge/v2/internal/updater"
|
||||
"github.com/ProtonMail/proton-bridge/v2/pkg/keychain"
|
||||
"github.com/ProtonMail/proton-bridge/v2/pkg/ports"
|
||||
@ -257,11 +259,17 @@ func (s *Service) DependencyLicensesLink(_ context.Context, _ *emptypb.Empty) (*
|
||||
}
|
||||
|
||||
func (s *Service) ReleaseNotesPageLink(ctx context.Context, _ *emptypb.Empty) (*wrapperspb.StringValue, error) {
|
||||
return wrapperspb.String(s.newVersionInfo.ReleaseNotesPage), nil
|
||||
s.latestLock.RLock()
|
||||
defer s.latestLock.RUnlock()
|
||||
|
||||
return wrapperspb.String(s.latest.ReleaseNotesPage), nil
|
||||
}
|
||||
|
||||
func (s *Service) LandingPageLink(_ context.Context, _ *emptypb.Empty) (*wrapperspb.StringValue, error) {
|
||||
return wrapperspb.String(s.newVersionInfo.LandingPage), nil
|
||||
s.latestLock.RLock()
|
||||
defer s.latestLock.RUnlock()
|
||||
|
||||
return wrapperspb.String(s.latest.LandingPage), nil
|
||||
}
|
||||
|
||||
func (s *Service) SetColorSchemeName(ctx context.Context, name *wrapperspb.StringValue) (*emptypb.Empty, error) {
|
||||
@ -486,15 +494,28 @@ func (s *Service) LoginAbort(ctx context.Context, loginAbort *LoginAbortRequest)
|
||||
return &emptypb.Empty{}, nil
|
||||
}
|
||||
|
||||
/*
|
||||
func (s *Service) CheckUpdate(context.Context, *emptypb.Empty) (*emptypb.Empty, error) {
|
||||
s.log.Debug("CheckUpdate")
|
||||
|
||||
go func() {
|
||||
defer s.panicHandler.HandlePanic()
|
||||
|
||||
s.checkUpdateAndNotify(true)
|
||||
updateCh, done := s.bridge.GetEvents(events.UpdateAvailable{}, events.UpdateNotAvailable{})
|
||||
defer done()
|
||||
|
||||
s.bridge.CheckForUpdates()
|
||||
|
||||
switch (<-updateCh).(type) {
|
||||
case events.UpdateAvailable:
|
||||
// ... this is handled by the main event loop
|
||||
|
||||
case events.UpdateNotAvailable:
|
||||
_ = s.SendEvent(NewUpdateIsLatestVersionEvent())
|
||||
}
|
||||
|
||||
_ = s.SendEvent(NewUpdateCheckFinishedEvent())
|
||||
}()
|
||||
|
||||
return &emptypb.Empty{}, nil
|
||||
}
|
||||
|
||||
@ -504,18 +525,18 @@ func (s *Service) InstallUpdate(ctx context.Context, _ *emptypb.Empty) (*emptypb
|
||||
go func() {
|
||||
defer s.panicHandler.HandlePanic()
|
||||
|
||||
s.installUpdate()
|
||||
safe.RLock(func() {
|
||||
s.bridge.InstallUpdate(s.latest)
|
||||
}, s.targetLock)
|
||||
}()
|
||||
|
||||
return &emptypb.Empty{}, nil
|
||||
}
|
||||
*/
|
||||
|
||||
func (s *Service) SetIsAutomaticUpdateOn(ctx context.Context, isOn *wrapperspb.BoolValue) (*emptypb.Empty, error) {
|
||||
s.log.WithField("isOn", isOn.Value).Debug("SetIsAutomaticUpdateOn")
|
||||
|
||||
currentlyOn := s.bridge.GetAutoUpdate()
|
||||
if currentlyOn == isOn.Value {
|
||||
if currentlyOn := s.bridge.GetAutoUpdate(); currentlyOn == isOn.Value {
|
||||
return &emptypb.Empty{}, nil
|
||||
}
|
||||
|
||||
@ -548,6 +569,7 @@ func (s *Service) SetDiskCachePath(ctx context.Context, newPath *wrapperspb.Stri
|
||||
}()
|
||||
|
||||
path := newPath.Value
|
||||
|
||||
//goland:noinspection GoBoolExpressions
|
||||
if (runtime.GOOS == "windows") && (path[0] == '/') {
|
||||
path = path[1:]
|
||||
|
||||
@ -1,85 +0,0 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail Bridge is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package grpc
|
||||
|
||||
/*
|
||||
func (s *Service) checkUpdate() {
|
||||
version, err := s.updater.Check()
|
||||
if err != nil {
|
||||
s.log.WithError(err).Error("An error occurred while checking for updates")
|
||||
s.SetVersion(updater.VersionInfo{})
|
||||
return
|
||||
}
|
||||
s.SetVersion(version)
|
||||
}
|
||||
|
||||
func (s *Service) updateForce() {
|
||||
s.updateCheckMutex.Lock()
|
||||
defer s.updateCheckMutex.Unlock()
|
||||
s.checkUpdate()
|
||||
_ = s.SendEvent(NewUpdateForceEvent(s.newVersionInfo.Version.String()))
|
||||
}
|
||||
|
||||
func (s *Service) checkUpdateAndNotify(isReqFromUser bool) {
|
||||
s.updateCheckMutex.Lock()
|
||||
defer func() {
|
||||
s.updateCheckMutex.Unlock()
|
||||
_ = s.SendEvent(NewUpdateCheckFinishedEvent())
|
||||
}()
|
||||
|
||||
s.checkUpdate()
|
||||
version := s.newVersionInfo
|
||||
if version.Version.String() == "" {
|
||||
if isReqFromUser {
|
||||
_ = s.SendEvent(NewUpdateErrorEvent(UpdateErrorType_UPDATE_MANUAL_ERROR))
|
||||
}
|
||||
return
|
||||
}
|
||||
if !s.updater.IsUpdateApplicable(s.newVersionInfo) {
|
||||
s.log.Info("No need to update")
|
||||
if isReqFromUser {
|
||||
_ = s.SendEvent(NewUpdateIsLatestVersionEvent())
|
||||
}
|
||||
} else if isReqFromUser {
|
||||
s.NotifyManualUpdate(s.newVersionInfo, s.updater.CanInstall(s.newVersionInfo))
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) installUpdate() {
|
||||
s.updateCheckMutex.Lock()
|
||||
defer s.updateCheckMutex.Unlock()
|
||||
|
||||
if !s.updater.CanInstall(s.newVersionInfo) {
|
||||
s.log.Warning("Skipping update installation, current version too old")
|
||||
_ = s.SendEvent(NewUpdateErrorEvent(UpdateErrorType_UPDATE_MANUAL_ERROR))
|
||||
return
|
||||
}
|
||||
|
||||
if err := s.updater.InstallUpdate(s.newVersionInfo); err != nil {
|
||||
if errors.Cause(err) == updater.ErrDownloadVerify {
|
||||
s.log.WithError(err).Warning("Skipping update installation due to temporary error")
|
||||
} else {
|
||||
s.log.WithError(err).Error("The update couldn't be installed")
|
||||
_ = s.SendEvent(NewUpdateErrorEvent(UpdateErrorType_UPDATE_MANUAL_ERROR))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
_ = s.SendEvent(NewUpdateSilentRestartNeededEvent())
|
||||
}
|
||||
*/
|
||||
Reference in New Issue
Block a user