Compare commits

..

10 Commits

Author SHA1 Message Date
71d7deb3b1 chore: Bridge Quebec 3.1.3 changelog 2023-05-09 11:36:35 +02:00
5630b7d2e6 fix(GODT-2616): Silence UID of order report
https://github.com/ProtonMail/gluon/pull/347
2023-05-08 10:27:37 +02:00
2ee4893325 fix(GODT-2614): Handle failed update during sync
The sync process was getting stuck since we never handled the case where
the update to Gluon failed. This caused the flush stage to exist, but
the sync process would continue until it eventually gets stuck due to
lack of progress.
2023-05-08 09:40:53 +02:00
2f7f898cee fix(GODT-2582): fix hash for changed boundary. 2023-04-26 14:00:45 +02:00
8d53ee855b chore: Bridge Quebec 3.1.2 changelog 2023-04-25 13:06:58 +02:00
ec0db47f32 fix(GODT-2582): Dedup recovered messages folder
same code as:
    * https://github.com/ProtonMail/gluon/pull/338
    * https://github.com/ProtonMail/gluon/pull/339
2023-04-25 11:36:21 +02:00
6fcea2ad83 chore: Bridge Quebec 3.1.1 changelog 2023-04-11 14:31:39 +02:00
098f294cac fix(GODT-2573): Crash on null update
Ensure that if we don't produce an update we don't construct an update
array with nil values.
2023-04-11 10:36:26 +02:00
a6f5cc870c fix(GODT-2500): pass handler pointer down the road. 2023-04-06 16:39:29 +02:00
7330406752 fix(GODT-2500): Recover in deferred function. 2023-04-05 09:25:24 +02:00
20 changed files with 131 additions and 86 deletions

View File

@ -2,6 +2,25 @@
Changelog [format](http://keepachangelog.com/en/1.0.0/) Changelog [format](http://keepachangelog.com/en/1.0.0/)
## [Bridge 3.1.3] Quebec
### Changed
* GODT-2616: Silence UID of order report.
* GODT-2614: Handle failed update during sync.
## [Bridge 3.1.2] Quebec
### Changed
* GODT-2582 Dedup recovered messages folder.
## [Bridge 3.1.1] Quebec
### Fixed
* GODT-2500: Fix handler passing.
## [Bridge 3.1.0] Quebec ## [Bridge 3.1.0] Quebec
### Changed ### Changed

View File

@ -11,7 +11,7 @@ ROOT_DIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
.PHONY: build build-gui build-nogui build-launcher versioner hasher .PHONY: build build-gui build-nogui build-launcher versioner hasher
# Keep version hardcoded so app build works also without Git repository. # Keep version hardcoded so app build works also without Git repository.
BRIDGE_APP_VERSION?=3.1.0+git BRIDGE_APP_VERSION?=3.1.3+git
APP_VERSION:=${BRIDGE_APP_VERSION} APP_VERSION:=${BRIDGE_APP_VERSION}
APP_FULL_NAME:=Proton Mail Bridge APP_FULL_NAME:=Proton Mail Bridge
APP_VENDOR:=Proton AG APP_VENDOR:=Proton AG
@ -325,7 +325,11 @@ run-nogui: build-nogui clean-vendor gofiles
PROTONMAIL_ENV=dev ./${LAUNCHER_EXE} ${RUN_FLAGS} -c PROTONMAIL_ENV=dev ./${LAUNCHER_EXE} ${RUN_FLAGS} -c
run-debug: run-debug:
dlv debug ./cmd/Desktop-Bridge/main.go -- -l=debug dlv debug \
--build-flags "-ldflags '-X github.com/ProtonMail/proton-bridge/v3/internal/constants.Version=3.1.0+git'" \
./cmd/Desktop-Bridge/main.go \
-- \
-n -l=trace
ifeq "${TARGET_OS}" "windows" ifeq "${TARGET_OS}" "windows"
EXE_SUFFIX=.exe EXE_SUFFIX=.exe

View File

@ -25,6 +25,7 @@ import (
"time" "time"
"github.com/Masterminds/semver/v3" "github.com/Masterminds/semver/v3"
"github.com/ProtonMail/gluon/async"
"github.com/ProtonMail/gopenpgp/v2/crypto" "github.com/ProtonMail/gopenpgp/v2/crypto"
"github.com/ProtonMail/proton-bridge/v3/internal/constants" "github.com/ProtonMail/proton-bridge/v3/internal/constants"
"github.com/ProtonMail/proton-bridge/v3/internal/crash" "github.com/ProtonMail/proton-bridge/v3/internal/crash"
@ -62,7 +63,7 @@ func main() { //nolint:funlen
reporter := sentry.NewReporter(appName, useragent.New()) reporter := sentry.NewReporter(appName, useragent.New())
crashHandler := crash.NewHandler(reporter.ReportException) crashHandler := crash.NewHandler(reporter.ReportException)
defer crashHandler.HandlePanic() defer async.HandlePanic(crashHandler)
locationsProvider, err := locations.NewDefaultProvider(filepath.Join(constants.VendorName, constants.ConfigName)) locationsProvider, err := locations.NewDefaultProvider(filepath.Join(constants.VendorName, constants.ConfigName))
if err != nil { if err != nil {

4
go.mod
View File

@ -5,9 +5,9 @@ go 1.18
require ( require (
github.com/0xAX/notificator v0.0.0-20220220101646-ee9b8921e557 github.com/0xAX/notificator v0.0.0-20220220101646-ee9b8921e557
github.com/Masterminds/semver/v3 v3.2.0 github.com/Masterminds/semver/v3 v3.2.0
github.com/ProtonMail/gluon v0.15.1-0.20230331095629-e23a7a1be2a8 github.com/ProtonMail/gluon v0.15.1-0.20230508082626-2467e0b45ed9
github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a
github.com/ProtonMail/go-proton-api v0.4.1-0.20230331115846-7ba084061eaa github.com/ProtonMail/go-proton-api v0.4.1-0.20230406143739-c7596e170799
github.com/ProtonMail/gopenpgp/v2 v2.5.2 github.com/ProtonMail/gopenpgp/v2 v2.5.2
github.com/PuerkitoBio/goquery v1.8.1 github.com/PuerkitoBio/goquery v1.8.1
github.com/abiosoft/ishell v2.0.0+incompatible github.com/abiosoft/ishell v2.0.0+incompatible

8
go.sum
View File

@ -28,8 +28,8 @@ github.com/ProtonMail/bcrypt v0.0.0-20211005172633-e235017c1baf h1:yc9daCCYUefEs
github.com/ProtonMail/bcrypt v0.0.0-20211005172633-e235017c1baf/go.mod h1:o0ESU9p83twszAU8LBeJKFAAMX14tISa0yk4Oo5TOqo= github.com/ProtonMail/bcrypt v0.0.0-20211005172633-e235017c1baf/go.mod h1:o0ESU9p83twszAU8LBeJKFAAMX14tISa0yk4Oo5TOqo=
github.com/ProtonMail/docker-credential-helpers v1.1.0 h1:+kvUIpwWcbtP3WFv5sSvkFn/XLzSqPOB5AAthuk9xPk= github.com/ProtonMail/docker-credential-helpers v1.1.0 h1:+kvUIpwWcbtP3WFv5sSvkFn/XLzSqPOB5AAthuk9xPk=
github.com/ProtonMail/docker-credential-helpers v1.1.0/go.mod h1:mK0aBveCxhnQ756AmaTfXMZDeULvheYVhF/MWMErN5g= github.com/ProtonMail/docker-credential-helpers v1.1.0/go.mod h1:mK0aBveCxhnQ756AmaTfXMZDeULvheYVhF/MWMErN5g=
github.com/ProtonMail/gluon v0.15.1-0.20230331095629-e23a7a1be2a8 h1:USMR8imbxkP4Ailch4ceV3hCZTaANMIGHhb5rpZFYn4= github.com/ProtonMail/gluon v0.15.1-0.20230508082626-2467e0b45ed9 h1:UwxjrPVOgyLLSVFhnxkpXLItowNzGGacqwVCp01wn6E=
github.com/ProtonMail/gluon v0.15.1-0.20230331095629-e23a7a1be2a8/go.mod h1:yA4hk6CJw0BMo+YL8Y3ckCYs5L20sysu9xseshwY3QI= github.com/ProtonMail/gluon v0.15.1-0.20230508082626-2467e0b45ed9/go.mod h1:yA4hk6CJw0BMo+YL8Y3ckCYs5L20sysu9xseshwY3QI=
github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a h1:D+aZah+k14Gn6kmL7eKxoo/4Dr/lK3ChBcwce2+SQP4= github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a h1:D+aZah+k14Gn6kmL7eKxoo/4Dr/lK3ChBcwce2+SQP4=
github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a/go.mod h1:oTGdE7/DlWIr23G0IKW3OXK9wZ5Hw1GGiaJFccTvZi4= github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a/go.mod h1:oTGdE7/DlWIr23G0IKW3OXK9wZ5Hw1GGiaJFccTvZi4=
github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo=
@ -40,8 +40,8 @@ github.com/ProtonMail/go-message v0.0.0-20210611055058-fabeff2ec753 h1:I8IsYA297
github.com/ProtonMail/go-message v0.0.0-20210611055058-fabeff2ec753/go.mod h1:NBAn21zgCJ/52WLDyed18YvYFm5tEoeDauubFqLokM4= github.com/ProtonMail/go-message v0.0.0-20210611055058-fabeff2ec753/go.mod h1:NBAn21zgCJ/52WLDyed18YvYFm5tEoeDauubFqLokM4=
github.com/ProtonMail/go-mime v0.0.0-20221031134845-8fd9bc37cf08 h1:dS7r5z4iGS0qCjM7UwWdsEMzQesUQbGcXdSm2/tWboA= github.com/ProtonMail/go-mime v0.0.0-20221031134845-8fd9bc37cf08 h1:dS7r5z4iGS0qCjM7UwWdsEMzQesUQbGcXdSm2/tWboA=
github.com/ProtonMail/go-mime v0.0.0-20221031134845-8fd9bc37cf08/go.mod h1:qRZgbeASl2a9OwmsV85aWwRqic0NHPh+9ewGAzb4cgM= github.com/ProtonMail/go-mime v0.0.0-20221031134845-8fd9bc37cf08/go.mod h1:qRZgbeASl2a9OwmsV85aWwRqic0NHPh+9ewGAzb4cgM=
github.com/ProtonMail/go-proton-api v0.4.1-0.20230331115846-7ba084061eaa h1:0JKWkz/gIYf+eky0dCFeBWrjEDLf59lS8HOlXtvn6Nk= github.com/ProtonMail/go-proton-api v0.4.1-0.20230406143739-c7596e170799 h1:slk4Drrkij1EVTnFOlIDyJsfjt69tnw8w2g1NMb253U=
github.com/ProtonMail/go-proton-api v0.4.1-0.20230331115846-7ba084061eaa/go.mod h1:RfpLBcTIhfjOIcBhh7f36LtAOEi0mqPd3t8gyLWmCZM= github.com/ProtonMail/go-proton-api v0.4.1-0.20230406143739-c7596e170799/go.mod h1:kis4GD6FHp1ZWnenSBepldt8ai+vYalDPeey9yGwyXk=
github.com/ProtonMail/go-srp v0.0.5 h1:xhUioxZgDbCnpo9JehyFhwwsn9JLWkUGfB0oiKXgiGg= github.com/ProtonMail/go-srp v0.0.5 h1:xhUioxZgDbCnpo9JehyFhwwsn9JLWkUGfB0oiKXgiGg=
github.com/ProtonMail/go-srp v0.0.5/go.mod h1:06iYHtLXW8vjLtccWj++x3MKy65sIT8yZd7nrJF49rs= github.com/ProtonMail/go-srp v0.0.5/go.mod h1:06iYHtLXW8vjLtccWj++x3MKy65sIT8yZd7nrJF49rs=
github.com/ProtonMail/gopenpgp/v2 v2.5.2 h1:97SjlWNAxXl9P22lgwgrZRshQdiEfAht0g3ZoiA1GCw= github.com/ProtonMail/gopenpgp/v2 v2.5.2 h1:97SjlWNAxXl9P22lgwgrZRshQdiEfAht0g3ZoiA1GCw=

View File

@ -28,6 +28,7 @@ import (
"time" "time"
"github.com/Masterminds/semver/v3" "github.com/Masterminds/semver/v3"
"github.com/ProtonMail/gluon/async"
"github.com/ProtonMail/proton-bridge/v3/internal/bridge" "github.com/ProtonMail/proton-bridge/v3/internal/bridge"
"github.com/ProtonMail/proton-bridge/v3/internal/constants" "github.com/ProtonMail/proton-bridge/v3/internal/constants"
"github.com/ProtonMail/proton-bridge/v3/internal/cookies" "github.com/ProtonMail/proton-bridge/v3/internal/cookies"
@ -379,7 +380,7 @@ func withCrashHandler(restarter *restarter.Restarter, reporter *sentry.Reporter,
defer logrus.Debug("Crash handler stopped") defer logrus.Debug("Crash handler stopped")
crashHandler := crash.NewHandler(crash.ShowErrorNotification(constants.FullAppName)) crashHandler := crash.NewHandler(crash.ShowErrorNotification(constants.FullAppName))
defer crashHandler.HandlePanic() defer async.HandlePanic(crashHandler)
// On crash, send crash report to Sentry. // On crash, send crash report to Sentry.
crashHandler.AddRecoveryAction(reporter.ReportException) crashHandler.AddRecoveryAction(reporter.ReportException)

View File

@ -46,10 +46,11 @@ func runFrontend(
switch { switch {
case c.Bool(flagCLI): case c.Bool(flagCLI):
return bridgeCLI.New(bridge, restarter, eventCh, crashHandler).Loop() return bridgeCLI.New(bridge, restarter, eventCh, crashHandler, quitCh).Loop()
case c.Bool(flagNonInteractive): case c.Bool(flagNonInteractive):
select {} <-quitCh
return nil
case c.Bool(flagGRPC): case c.Bool(flagGRPC):
service, err := grpc.NewService(crashHandler, restarter, locations, bridge, eventCh, quitCh, !c.Bool(flagNoWindow), parentPID) service, err := grpc.NewService(crashHandler, restarter, locations, bridge, eventCh, quitCh, !c.Bool(flagNoWindow), parentPID)

View File

@ -40,7 +40,7 @@ func checkSingleInstance(settingPath, lockFilePath string, curVersion *semver.Ve
return lock, nil return lock, nil
} }
logrus.Debug("Failed to create lock file; another instance is running") logrus.Warn("Failed to create lock file; another instance is running")
// We couldn't create the lock file, so another instance is probably running. // We couldn't create the lock file, so another instance is probably running.
// Check if it's an older version of the app. // Check if it's an older version of the app.

View File

@ -45,7 +45,7 @@ func NewMocks(tb testing.TB, version, minAuto *semver.Version) *Mocks {
mocks.TLSReporter.EXPECT().GetTLSIssueCh().Return(mocks.TLSIssueCh).AnyTimes() mocks.TLSReporter.EXPECT().GetTLSIssueCh().Return(mocks.TLSIssueCh).AnyTimes()
// This is called at he end of any go-routine: // This is called at he end of any go-routine:
mocks.CrashHandler.EXPECT().HandlePanic().AnyTimes() mocks.CrashHandler.EXPECT().HandlePanic(gomock.Any()).AnyTimes()
return mocks return mocks
} }

View File

@ -1,5 +1,5 @@
// Code generated by MockGen. DO NOT EDIT. // Code generated by MockGen. DO NOT EDIT.
// Source: github.com/ProtonMail/proton-bridge/v3/internal/async (interfaces: PanicHandler) // Source: github.com/ProtonMail/gluon/async (interfaces: PanicHandler)
// Package mocks is a generated GoMock package. // Package mocks is a generated GoMock package.
package mocks package mocks
@ -34,13 +34,13 @@ func (m *MockPanicHandler) EXPECT() *MockPanicHandlerMockRecorder {
} }
// HandlePanic mocks base method. // HandlePanic mocks base method.
func (m *MockPanicHandler) HandlePanic() { func (m *MockPanicHandler) HandlePanic(arg0 interface{}) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
m.ctrl.Call(m, "HandlePanic") m.ctrl.Call(m, "HandlePanic", arg0)
} }
// HandlePanic indicates an expected call of HandlePanic. // HandlePanic indicates an expected call of HandlePanic.
func (mr *MockPanicHandlerMockRecorder) HandlePanic() *gomock.Call { func (mr *MockPanicHandlerMockRecorder) HandlePanic(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HandlePanic", reflect.TypeOf((*MockPanicHandler)(nil).HandlePanic)) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HandlePanic", reflect.TypeOf((*MockPanicHandler)(nil).HandlePanic), arg0)
} }

View File

@ -38,14 +38,16 @@ func (h *Handler) AddRecoveryAction(action RecoveryAction) *Handler {
return h return h
} }
func (h *Handler) HandlePanic() { func (h *Handler) HandlePanic(r interface{}) {
sentry.SkipDuringUnwind() sentry.SkipDuringUnwind()
if r := recover(); r != nil { if r == nil {
for _, action := range h.actions { return
if err := action(r); err != nil { }
logrus.WithError(err).Error("Failed to execute recovery action")
} for _, action := range h.actions {
if err := action(r); err != nil {
logrus.WithError(err).Error("Failed to execute recovery action")
} }
} }
} }

View File

@ -21,38 +21,41 @@ import (
"fmt" "fmt"
"testing" "testing"
"github.com/ProtonMail/gluon/async"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func TestHandler(t *testing.T) { func TestHandler(t *testing.T) {
var s string assert.NotPanics(t, func() {
var s string
h := NewHandler( h := NewHandler(
func(r interface{}) error { func(r interface{}) error {
s += fmt.Sprintf("1: %v\n", r) s += fmt.Sprintf("1: %v\n", r)
return nil return nil
}, },
func(r interface{}) error { func(r interface{}) error {
s += fmt.Sprintf("2: %v\n", r) s += fmt.Sprintf("2: %v\n", r)
return nil return nil
}, },
) )
h. h.
AddRecoveryAction(func(r interface{}) error { AddRecoveryAction(func(r interface{}) error {
s += fmt.Sprintf("3: %v\n", r) s += fmt.Sprintf("3: %v\n", r)
return nil return nil
}). }).
AddRecoveryAction(func(r interface{}) error { AddRecoveryAction(func(r interface{}) error {
s += fmt.Sprintf("4: %v\n", r) s += fmt.Sprintf("4: %v\n", r)
return nil return nil
}) })
defer func() { defer func() {
assert.Equal(t, "1: thing\n2: thing\n3: thing\n4: thing\n", s) assert.Equal(t, "1: thing\n2: thing\n3: thing\n4: thing\n", s)
}() }()
defer h.HandlePanic() defer async.HandlePanic(h)
panic("thing") panic("thing")
})
} }

View File

@ -45,7 +45,13 @@ type frontendCLI struct {
} }
// New returns a new CLI frontend configured with the given options. // New returns a new CLI frontend configured with the given options.
func New(bridge *bridge.Bridge, restarter *restarter.Restarter, eventCh <-chan events.Event, panicHandler async.PanicHandler) *frontendCLI { //nolint:revive func New(
bridge *bridge.Bridge,
restarter *restarter.Restarter,
eventCh <-chan events.Event,
panicHandler async.PanicHandler,
quitCh <-chan struct{},
) *frontendCLI { //nolint:revive
fe := &frontendCLI{ fe := &frontendCLI{
Shell: ishell.New(), Shell: ishell.New(),
bridge: bridge, bridge: bridge,
@ -285,6 +291,11 @@ func New(bridge *bridge.Bridge, restarter *restarter.Restarter, eventCh <-chan e
go fe.watchEvents(eventCh) go fe.watchEvents(eventCh)
go func() {
<-quitCh
fe.Close()
}()
return fe return fe
} }

View File

@ -70,7 +70,7 @@ type Service struct { // nolint:structcheck
eventQueue []*StreamEvent eventQueue []*StreamEvent
eventQueueMutex sync.Mutex eventQueueMutex sync.Mutex
panicHandler CrashHandler panicHandler async.PanicHandler
restarter Restarter restarter Restarter
bridge *bridge.Bridge bridge *bridge.Bridge
eventCh <-chan events.Event eventCh <-chan events.Event
@ -97,7 +97,7 @@ type Service struct { // nolint:structcheck
// NewService returns a new instance of the service. // NewService returns a new instance of the service.
func NewService( func NewService(
panicHandler CrashHandler, panicHandler async.PanicHandler,
restarter Restarter, restarter Restarter,
locations service.Locator, locations service.Locator,
bridge *bridge.Bridge, bridge *bridge.Bridge,
@ -192,10 +192,6 @@ func NewService(
return s, nil return s, nil
} }
func (s *Service) handlePanic() {
async.HandlePanic(s.panicHandler)
}
func (s *Service) initAutostart() { func (s *Service) initAutostart() {
s.firstTimeAutostart.Do(func() { s.firstTimeAutostart.Do(func() {
shouldAutostartBeOn := s.bridge.GetAutostart() shouldAutostartBeOn := s.bridge.GetAutostart()
@ -213,13 +209,13 @@ func (s *Service) Loop() error {
s.log.Info("Not monitoring parent PID") s.log.Info("Not monitoring parent PID")
} else { } else {
go func() { go func() {
defer s.handlePanic() defer async.HandlePanic(s.panicHandler)
s.monitorParentPID() s.monitorParentPID()
}() }()
} }
go func() { go func() {
defer s.handlePanic() defer async.HandlePanic(s.panicHandler)
s.watchEvents() s.watchEvents()
}() }()
@ -229,7 +225,7 @@ func (s *Service) Loop() error {
defer close(doneCh) defer close(doneCh)
go func() { go func() {
defer s.handlePanic() defer async.HandlePanic(s.panicHandler)
select { select {
case <-s.quitCh: case <-s.quitCh:
@ -577,7 +573,7 @@ func (s *Service) monitorParentPID() {
s.log.Info("Parent process does not exist anymore. Initiating shutdown") s.log.Info("Parent process does not exist anymore. Initiating shutdown")
// quit will write to the parentPIDDoneCh, so we launch a goroutine. // quit will write to the parentPIDDoneCh, so we launch a goroutine.
go func() { go func() {
defer s.handlePanic() defer async.HandlePanic(s.panicHandler)
if err := s.quit(); err != nil { if err := s.quit(); err != nil {
logrus.WithError(err).Error("Error on quit") logrus.WithError(err).Error("Error on quit")

View File

@ -26,6 +26,7 @@ import (
"runtime" "runtime"
"github.com/Masterminds/semver/v3" "github.com/Masterminds/semver/v3"
"github.com/ProtonMail/gluon/async"
"github.com/ProtonMail/go-proton-api" "github.com/ProtonMail/go-proton-api"
"github.com/ProtonMail/proton-bridge/v3/internal/bridge" "github.com/ProtonMail/proton-bridge/v3/internal/bridge"
"github.com/ProtonMail/proton-bridge/v3/internal/constants" "github.com/ProtonMail/proton-bridge/v3/internal/constants"
@ -114,7 +115,7 @@ func (s *Service) Quit(ctx context.Context, empty *emptypb.Empty) (*emptypb.Empt
func (s *Service) quit() error { func (s *Service) quit() error {
// Windows is notably slow at Quitting. We do it in a goroutine to speed things up a bit. // Windows is notably slow at Quitting. We do it in a goroutine to speed things up a bit.
go func() { go func() {
defer s.handlePanic() defer async.HandlePanic(s.panicHandler)
if s.parentPID >= 0 { if s.parentPID >= 0 {
s.parentPIDDoneCh <- struct{}{} s.parentPIDDoneCh <- struct{}{}
@ -223,7 +224,7 @@ func (s *Service) TriggerReset(ctx context.Context, _ *emptypb.Empty) (*emptypb.
s.log.Debug("TriggerReset") s.log.Debug("TriggerReset")
go func() { go func() {
defer s.handlePanic() defer async.HandlePanic(s.panicHandler)
s.triggerReset() s.triggerReset()
}() }()
@ -319,7 +320,7 @@ func (s *Service) ReportBug(ctx context.Context, report *ReportBugRequest) (*emp
}).Debug("ReportBug") }).Debug("ReportBug")
go func() { go func() {
defer s.handlePanic() defer async.HandlePanic(s.panicHandler)
defer func() { _ = s.SendEvent(NewReportBugFinishedEvent()) }() defer func() { _ = s.SendEvent(NewReportBugFinishedEvent()) }()
@ -348,7 +349,7 @@ func (s *Service) ExportTLSCertificates(_ context.Context, folderPath *wrappersp
s.log.WithField("folderPath", folderPath).Info("ExportTLSCertificates") s.log.WithField("folderPath", folderPath).Info("ExportTLSCertificates")
go func() { go func() {
defer s.handlePanic() defer async.HandlePanic(s.panicHandler)
cert, key := s.bridge.GetBridgeTLSCert() cert, key := s.bridge.GetBridgeTLSCert()
@ -384,7 +385,7 @@ func (s *Service) Login(ctx context.Context, login *LoginRequest) (*emptypb.Empt
s.log.WithField("username", login.Username).Debug("Login") s.log.WithField("username", login.Username).Debug("Login")
go func() { go func() {
defer s.handlePanic() defer async.HandlePanic(s.panicHandler)
password, err := base64Decode(login.Password) password, err := base64Decode(login.Password)
if err != nil { if err != nil {
@ -440,7 +441,7 @@ func (s *Service) Login2FA(ctx context.Context, login *LoginRequest) (*emptypb.E
s.log.WithField("username", login.Username).Debug("Login2FA") s.log.WithField("username", login.Username).Debug("Login2FA")
go func() { go func() {
defer s.handlePanic() defer async.HandlePanic(s.panicHandler)
if s.auth.UID == "" || s.authClient == nil { if s.auth.UID == "" || s.authClient == nil {
s.log.Errorf("Login 2FA: authethication incomplete %s %p", s.auth.UID, s.authClient) s.log.Errorf("Login 2FA: authethication incomplete %s %p", s.auth.UID, s.authClient)
@ -485,7 +486,7 @@ func (s *Service) Login2Passwords(ctx context.Context, login *LoginRequest) (*em
s.log.WithField("username", login.Username).Debug("Login2Passwords") s.log.WithField("username", login.Username).Debug("Login2Passwords")
go func() { go func() {
defer s.handlePanic() defer async.HandlePanic(s.panicHandler)
password, err := base64Decode(login.Password) password, err := base64Decode(login.Password)
if err != nil { if err != nil {
@ -507,7 +508,7 @@ func (s *Service) LoginAbort(ctx context.Context, loginAbort *LoginAbortRequest)
s.log.WithField("username", loginAbort.Username).Debug("LoginAbort") s.log.WithField("username", loginAbort.Username).Debug("LoginAbort")
go func() { go func() {
defer s.handlePanic() defer async.HandlePanic(s.panicHandler)
s.loginAbort() s.loginAbort()
}() }()
@ -519,7 +520,7 @@ func (s *Service) CheckUpdate(context.Context, *emptypb.Empty) (*emptypb.Empty,
s.log.Debug("CheckUpdate") s.log.Debug("CheckUpdate")
go func() { go func() {
defer s.handlePanic() defer async.HandlePanic(s.panicHandler)
updateCh, done := s.bridge.GetEvents( updateCh, done := s.bridge.GetEvents(
events.UpdateAvailable{}, events.UpdateAvailable{},
@ -551,7 +552,7 @@ func (s *Service) InstallUpdate(ctx context.Context, _ *emptypb.Empty) (*emptypb
s.log.Debug("InstallUpdate") s.log.Debug("InstallUpdate")
go func() { go func() {
defer s.handlePanic() defer async.HandlePanic(s.panicHandler)
safe.RLock(func() { safe.RLock(func() {
s.bridge.InstallUpdate(s.target) s.bridge.InstallUpdate(s.target)
@ -592,7 +593,7 @@ func (s *Service) SetDiskCachePath(ctx context.Context, newPath *wrapperspb.Stri
s.log.WithField("path", newPath.Value).Debug("setDiskCachePath") s.log.WithField("path", newPath.Value).Debug("setDiskCachePath")
go func() { go func() {
defer s.handlePanic() defer async.HandlePanic(s.panicHandler)
defer func() { defer func() {
_ = s.SendEvent(NewDiskCachePathChangeFinishedEvent()) _ = s.SendEvent(NewDiskCachePathChangeFinishedEvent())
@ -659,7 +660,7 @@ func (s *Service) SetMailServerSettings(_ context.Context, settings *ImapSmtpSet
Debug("SetConnectionMode") Debug("SetConnectionMode")
go func() { go func() {
defer s.handlePanic() defer async.HandlePanic(s.panicHandler)
defer func() { _ = s.SendEvent(NewChangeMailServerSettingsFinishedEvent()) }() defer func() { _ = s.SendEvent(NewChangeMailServerSettingsFinishedEvent()) }()

View File

@ -20,6 +20,7 @@ package grpc
import ( import (
"context" "context"
"github.com/ProtonMail/gluon/async"
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"
"google.golang.org/grpc/status" "google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/emptypb" "google.golang.org/protobuf/types/known/emptypb"
@ -49,7 +50,7 @@ func (s *Service) RunEventStream(request *EventStreamRequest, server Bridge_RunE
// if events occurred before streaming started, they've been queued. Now that the stream channel is available // if events occurred before streaming started, they've been queued. Now that the stream channel is available
// we can flush the queued // we can flush the queued
go func() { go func() {
defer s.handlePanic() defer async.HandlePanic(s.panicHandler)
s.eventQueueMutex.Lock() s.eventQueueMutex.Lock()
defer s.eventQueueMutex.Unlock() defer s.eventQueueMutex.Unlock()

View File

@ -20,6 +20,7 @@ package grpc
import ( import (
"context" "context"
"github.com/ProtonMail/gluon/async"
"github.com/ProtonMail/proton-bridge/v3/internal/vault" "github.com/ProtonMail/proton-bridge/v3/internal/vault"
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"
"google.golang.org/grpc/status" "google.golang.org/grpc/status"
@ -70,7 +71,7 @@ func (s *Service) SetUserSplitMode(ctx context.Context, splitMode *UserSplitMode
} }
go func() { go func() {
defer s.handlePanic() defer async.HandlePanic(s.panicHandler)
defer func() { _ = s.SendEvent(NewUserToggleSplitModeFinishedEvent(splitMode.UserID)) }() defer func() { _ = s.SendEvent(NewUserToggleSplitModeFinishedEvent(splitMode.UserID)) }()
var targetMode vault.AddressMode var targetMode vault.AddressMode
@ -121,7 +122,7 @@ func (s *Service) LogoutUser(ctx context.Context, userID *wrapperspb.StringValue
} }
go func() { go func() {
defer s.handlePanic() defer async.HandlePanic(s.panicHandler)
if err := s.bridge.LogoutUser(context.Background(), userID.Value); err != nil { if err := s.bridge.LogoutUser(context.Background(), userID.Value); err != nil {
s.log.WithError(err).Error("Failed to log user out") s.log.WithError(err).Error("Failed to log user out")
@ -135,7 +136,7 @@ func (s *Service) RemoveUser(ctx context.Context, userID *wrapperspb.StringValue
s.log.WithField("UserID", userID.Value).Debug("RemoveUser") s.log.WithField("UserID", userID.Value).Debug("RemoveUser")
go func() { go func() {
defer s.handlePanic() defer async.HandlePanic(s.panicHandler)
// remove preferences // remove preferences
if err := s.bridge.DeleteUser(context.Background(), userID.Value); err != nil { if err := s.bridge.DeleteUser(context.Background(), userID.Value); err != nil {

View File

@ -17,10 +17,6 @@
package grpc package grpc
type CrashHandler interface {
HandlePanic()
}
type Restarter interface { type Restarter interface {
Set(restart, crash bool) Set(restart, crash bool)
AddFlags(flags ...string) AddFlags(flags ...string)

View File

@ -635,6 +635,10 @@ func (user *User) handleCreateMessageEvent(ctx context.Context, message proton.M
return nil, err return nil, err
} }
if update == nil {
return nil, nil
}
return []imap.Update{update}, nil return []imap.Update{update}, nil
}, user.apiUserLock, user.apiAddrsLock, user.apiLabelsLock, user.updateChLock) }, user.apiUserLock, user.apiAddrsLock, user.apiLabelsLock, user.updateChLock)
} }

View File

@ -370,7 +370,7 @@ func (user *User) syncMessages(
errorCh := make(chan error, maxParallelDownloads*4) errorCh := make(chan error, maxParallelDownloads*4)
// Go routine in charge of downloading message metadata // Go routine in charge of downloading message metadata
logging.GoAnnotated(ctx, user.panicHandler, func(ctx context.Context) { async.GoAnnotated(ctx, user.panicHandler, func(ctx context.Context) {
defer close(downloadCh) defer close(downloadCh)
const MetadataDataPageSize = 150 const MetadataDataPageSize = 150
@ -433,7 +433,7 @@ func (user *User) syncMessages(
}, logging.Labels{"sync-stage": "meta-data"}) }, logging.Labels{"sync-stage": "meta-data"})
// Goroutine in charge of downloading and building messages in maxBatchSize batches. // Goroutine in charge of downloading and building messages in maxBatchSize batches.
logging.GoAnnotated(ctx, user.panicHandler, func(ctx context.Context) { async.GoAnnotated(ctx, user.panicHandler, func(ctx context.Context) {
defer close(buildCh) defer close(buildCh)
defer close(errorCh) defer close(errorCh)
defer func() { defer func() {
@ -492,7 +492,7 @@ func (user *User) syncMessages(
}, logging.Labels{"sync-stage": "download"}) }, logging.Labels{"sync-stage": "download"})
// Goroutine which builds messages after they have been downloaded // Goroutine which builds messages after they have been downloaded
logging.GoAnnotated(ctx, user.panicHandler, func(ctx context.Context) { async.GoAnnotated(ctx, user.panicHandler, func(ctx context.Context) {
defer close(flushCh) defer close(flushCh)
defer func() { defer func() {
logrus.Debugf("sync builder exit") logrus.Debugf("sync builder exit")
@ -530,7 +530,7 @@ func (user *User) syncMessages(
}, logging.Labels{"sync-stage": "builder"}) }, logging.Labels{"sync-stage": "builder"})
// Goroutine which converts the messages into updates and builds a waitable structure for progress tracking. // Goroutine which converts the messages into updates and builds a waitable structure for progress tracking.
logging.GoAnnotated(ctx, user.panicHandler, func(ctx context.Context) { async.GoAnnotated(ctx, user.panicHandler, func(ctx context.Context) {
defer close(flushUpdateCh) defer close(flushUpdateCh)
defer func() { defer func() {
logrus.Debugf("sync flush exit") logrus.Debugf("sync flush exit")
@ -610,6 +610,10 @@ func (user *User) syncMessages(
}, logging.Labels{"sync-stage": "flush"}) }, logging.Labels{"sync-stage": "flush"})
for flushUpdate := range flushUpdateCh { for flushUpdate := range flushUpdateCh {
if flushUpdate.err != nil {
return flushUpdate.err
}
if err := vault.SetLastMessageID(flushUpdate.messageID); err != nil { if err := vault.SetLastMessageID(flushUpdate.messageID); err != nil {
return fmt.Errorf("failed to set last synced message ID: %w", err) return fmt.Errorf("failed to set last synced message ID: %w", err)
} }
@ -780,7 +784,7 @@ func (user *User) newAttachmentDownloader(ctx context.Context, client *proton.Cl
ctx, cancel := context.WithCancel(ctx) ctx, cancel := context.WithCancel(ctx)
for i := 0; i < workerCount; i++ { for i := 0; i < workerCount; i++ {
workerCh = make(chan attachmentJob) workerCh = make(chan attachmentJob)
logging.GoAnnotated(ctx, user.panicHandler, func(ctx context.Context) { attachmentWorker(ctx, client, workerCh) }, logging.Labels{ async.GoAnnotated(ctx, user.panicHandler, func(ctx context.Context) { attachmentWorker(ctx, client, workerCh) }, logging.Labels{
"sync": fmt.Sprintf("att-downloader %v", i), "sync": fmt.Sprintf("att-downloader %v", i),
}) })
} }