mirror of
https://github.com/ProtonMail/proton-bridge.git
synced 2025-12-10 20:56:51 +00:00
fix(GODT-2442): WIP: bad events just aborts polls, feedback processed in separete channel.
This commit is contained in:
@ -24,6 +24,7 @@ import (
|
|||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
"github.com/ProtonMail/gluon/imap"
|
"github.com/ProtonMail/gluon/imap"
|
||||||
|
"github.com/ProtonMail/gluon/reporter"
|
||||||
"github.com/ProtonMail/go-proton-api"
|
"github.com/ProtonMail/go-proton-api"
|
||||||
"github.com/ProtonMail/proton-bridge/v3/internal/async"
|
"github.com/ProtonMail/proton-bridge/v3/internal/async"
|
||||||
"github.com/ProtonMail/proton-bridge/v3/internal/events"
|
"github.com/ProtonMail/proton-bridge/v3/internal/events"
|
||||||
@ -299,17 +300,52 @@ func (bridge *Bridge) SetAddressMode(ctx context.Context, userID string, mode va
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SendBadEventUserFeedback passes the feedback to the given user.
|
// SendBadEventUserFeedback passes the feedback to the given user.
|
||||||
func (bridge *Bridge) SendBadEventUserFeedback(ctx context.Context, userID string, doResync bool) error {
|
func (bridge *Bridge) SendBadEventUserFeedback(_ context.Context, userID string, doResync bool) error {
|
||||||
logrus.WithField("userID", userID).WithField("doResycn", doResync).Info("Passing bad event feedback to user")
|
logrus.WithField("userID", userID).WithField("doResync", doResync).Info("Passing bad event feedback to user")
|
||||||
|
|
||||||
user, ok := bridge.users[userID]
|
return safe.LockRet(func() error {
|
||||||
if !ok {
|
ctx := context.Background()
|
||||||
return ErrNoSuchUser
|
|
||||||
}
|
|
||||||
|
|
||||||
user.SendBadEventFeedback(doResync)
|
user, ok := bridge.users[userID]
|
||||||
|
if !ok {
|
||||||
|
if rerr := bridge.reporter.ReportMessageWithContext(
|
||||||
|
"Failed to handle event: feedback failed: no such user",
|
||||||
|
reporter.Context{"user_id": userID},
|
||||||
|
); rerr != nil {
|
||||||
|
logrus.WithError(rerr).Error("Failed to report feedback failure")
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
// Cannot recover from this
|
||||||
|
panic(ErrNoSuchUser)
|
||||||
|
}
|
||||||
|
|
||||||
|
if doResync {
|
||||||
|
if rerr := bridge.reporter.ReportMessageWithContext(
|
||||||
|
"Failed to handle event: feedback resync",
|
||||||
|
reporter.Context{"user_id": userID},
|
||||||
|
); rerr != nil {
|
||||||
|
logrus.WithError(rerr).Error("Failed to report feedback failure")
|
||||||
|
}
|
||||||
|
|
||||||
|
user.BadEventFeedbackResync(ctx)
|
||||||
|
|
||||||
|
if err := bridge.addIMAPUser(ctx, user); err != nil {
|
||||||
|
return fmt.Errorf("failed to add IMAP user: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if rerr := bridge.reporter.ReportMessageWithContext(
|
||||||
|
"Failed to handle event: feedback logout",
|
||||||
|
reporter.Context{"user_id": userID},
|
||||||
|
); rerr != nil {
|
||||||
|
logrus.WithError(rerr).Error("Failed to report feedback failure")
|
||||||
|
}
|
||||||
|
|
||||||
|
bridge.logoutUser(ctx, user, true, false)
|
||||||
|
return nil
|
||||||
|
}, bridge.usersLock)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bridge *Bridge) loginUser(ctx context.Context, client *proton.Client, authUID, authRef string, keyPass []byte) (string, error) {
|
func (bridge *Bridge) loginUser(ctx context.Context, client *proton.Client, authUID, authRef string, keyPass []byte) (string, error) {
|
||||||
|
|||||||
@ -140,57 +140,28 @@ func (bridge *Bridge) handleUserDeauth(ctx context.Context, user *user.User) {
|
|||||||
}, bridge.usersLock)
|
}, bridge.usersLock)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bridge *Bridge) handleUserBadEvent(ctx context.Context, user *user.User, event events.UserBadEvent) {
|
func (bridge *Bridge) handleUserBadEvent(_ context.Context, user *user.User, event events.UserBadEvent) {
|
||||||
go safe.Lock(func() {
|
safe.Lock(func() {
|
||||||
reportContext := reporter.Context{
|
if rerr := bridge.reporter.ReportMessageWithContext("Failed to handle event", reporter.Context{
|
||||||
"user_id": user.ID(),
|
"user_id": user.ID(),
|
||||||
"old_event_id": event.OldEventID,
|
"old_event_id": event.OldEventID,
|
||||||
"new_event_id": event.NewEventID,
|
"new_event_id": event.NewEventID,
|
||||||
"event_info": event.EventInfo,
|
"event_info": event.EventInfo,
|
||||||
"error": event.Error,
|
"error": event.Error,
|
||||||
"error_type": fmt.Sprintf("%T", internal.ErrCause(event.Error)),
|
"error_type": fmt.Sprintf("%T", internal.ErrCause(event.Error)),
|
||||||
|
}); rerr != nil {
|
||||||
|
logrus.WithError(rerr).Error("Failed to report failed event handling")
|
||||||
}
|
}
|
||||||
|
|
||||||
// blockEventsIMAPandSMTP()
|
user.BadEventAbort()
|
||||||
|
|
||||||
if doResyc, err := bridge.getBadEventUserFeedback(user.ID()); err != nil || !doResyc {
|
// Disable IMAP user
|
||||||
if rerr := bridge.reporter.ReportMessageWithContext("Failed to handle event: logout", reportContext); rerr != nil {
|
if err := bridge.removeIMAPUser(context.Background(), user, false); err != nil {
|
||||||
logrus.WithError(rerr).Error("Failed to report failed event handling")
|
logrus.WithError(err).Error("Failed to remove IMAP user")
|
||||||
}
|
|
||||||
|
|
||||||
bridge.logoutUser(ctx, user, true, false)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if rerr := bridge.reporter.ReportMessageWithContext("Failed to handle event: repair", reportContext); rerr != nil {
|
|
||||||
logrus.WithError(rerr).Error("Failed to report event handling failure")
|
|
||||||
}
|
|
||||||
|
|
||||||
if syncErr := user.SyncEvent(ctx); syncErr != nil {
|
|
||||||
reportContext["error"] = syncErr
|
|
||||||
reportContext["error_type"] = fmt.Sprintf("%T", internal.ErrCause(syncErr))
|
|
||||||
if rerr := bridge.reporter.ReportMessageWithContext("Failed to handle event: repair failed: logging out", reportContext); rerr != nil {
|
|
||||||
logrus.WithError(rerr).Error("Failed to report repair failure")
|
|
||||||
}
|
|
||||||
|
|
||||||
bridge.logoutUser(ctx, user, true, false)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}, bridge.usersLock)
|
}, bridge.usersLock)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bridge *Bridge) getBadEventUserFeedback(userID string) (doResyc bool, err error) {
|
|
||||||
user, ok := bridge.users[userID]
|
|
||||||
if !ok {
|
|
||||||
return false, ErrNoSuchUser
|
|
||||||
}
|
|
||||||
|
|
||||||
user.LockEvents()
|
|
||||||
defer user.UnlockEvents()
|
|
||||||
|
|
||||||
return user.GetBadEventFeedback(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bridge *Bridge) handleUncategorizedErrorEvent(event events.UncategorizedEventError) {
|
func (bridge *Bridge) handleUncategorizedErrorEvent(event events.UncategorizedEventError) {
|
||||||
if rerr := bridge.reporter.ReportMessageWithContext("Failed to handle due to uncategorized error", reporter.Context{
|
if rerr := bridge.reporter.ReportMessageWithContext("Failed to handle due to uncategorized error", reporter.Context{
|
||||||
"error_type": fmt.Sprintf("%T", internal.ErrCause(event.Error)),
|
"error_type": fmt.Sprintf("%T", internal.ErrCause(event.Error)),
|
||||||
|
|||||||
@ -86,16 +86,16 @@ func (user *User) handleRefreshEvent(ctx context.Context, refresh proton.Refresh
|
|||||||
l.WithError(err).Error("Failed to report refresh to sentry")
|
l.WithError(err).Error("Failed to report refresh to sentry")
|
||||||
}
|
}
|
||||||
|
|
||||||
return user.SyncEvent(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (user *User) SyncEvent(ctx context.Context) error {
|
|
||||||
// Abort the event stream
|
// Abort the event stream
|
||||||
defer user.pollAbort.Abort()
|
defer user.pollAbort.Abort()
|
||||||
|
|
||||||
// Re-sync messages after the user, address and label refresh.
|
// Re-sync messages after the user, address and label refresh.
|
||||||
defer user.goSync()
|
defer user.goSync()
|
||||||
|
|
||||||
|
return user.syncUserAddressesAndLabels(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (user *User) syncUserAddressesAndLabels(ctx context.Context) error {
|
||||||
return safe.LockRet(func() error {
|
return safe.LockRet(func() error {
|
||||||
// Fetch latest user info.
|
// Fetch latest user info.
|
||||||
apiUser, err := user.client.GetUser(ctx)
|
apiUser, err := user.client.GetUser(ctx)
|
||||||
|
|||||||
@ -90,9 +90,6 @@ type User struct {
|
|||||||
|
|
||||||
syncWorkers int
|
syncWorkers int
|
||||||
showAllMail uint32
|
showAllMail uint32
|
||||||
|
|
||||||
// doResyncFeedback must be non-blocking for first attempt (i.e. buffered)
|
|
||||||
doResyncFeedback chan bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns a new user.
|
// New returns a new user.
|
||||||
@ -151,8 +148,6 @@ func New(
|
|||||||
|
|
||||||
syncWorkers: syncWorkers,
|
syncWorkers: syncWorkers,
|
||||||
showAllMail: b32(showAllMail),
|
showAllMail: b32(showAllMail),
|
||||||
|
|
||||||
doResyncFeedback: make(chan bool, 1),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the user's update channels for its current address mode.
|
// Initialize the user's update channels for its current address mode.
|
||||||
@ -304,14 +299,17 @@ func (user *User) SetAddressMode(_ context.Context, mode vault.AddressMode) erro
|
|||||||
}, user.eventLock, user.apiAddrsLock, user.updateChLock)
|
}, user.eventLock, user.apiAddrsLock, user.updateChLock)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SendBadEventFeedback sends user feedback whether should do message re-sync.
|
// BadEventAbort stops user to communicate. The resolution is either logout or resync.
|
||||||
func (user *User) SendBadEventFeedback(doResync bool) {
|
func (user *User) BadEventAbort() {
|
||||||
user.doResyncFeedback <- doResync
|
user.syncAbort.Abort()
|
||||||
|
user.pollAbort.Abort()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBadEventFeedback read the user feedback whether should do message re-sync.
|
// BadEventFeedbackResync sends user feedback whether should do message re-sync.
|
||||||
func (user *User) GetBadEventFeedback() bool {
|
func (user *User) BadEventFeedbackResync(ctx context.Context) {
|
||||||
return <-user.doResyncFeedback
|
if err := user.syncUserAddressesAndLabels(ctx); err != nil {
|
||||||
|
user.log.WithError(err).Error("Bad event resync failed")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetShowAllMail sets whether to show the All Mail mailbox.
|
// SetShowAllMail sets whether to show the All Mail mailbox.
|
||||||
|
|||||||
Reference in New Issue
Block a user