feat(GODT-2822): Integrate and activate all service

The bridge now runs on the new architecture.
This commit is contained in:
Leander Beernaert
2023-07-28 14:59:12 +02:00
parent a187747c7c
commit 823ca4d207
22 changed files with 558 additions and 3794 deletions

View File

@ -408,11 +408,6 @@ func (bridge *Bridge) GetErrors() []error {
func (bridge *Bridge) Close(ctx context.Context) {
logrus.Info("Closing bridge")
// Close the servers
if err := bridge.serverManager.CloseServers(ctx); err != nil {
logrus.WithError(err).Error("Failed to close servers")
}
// Close all users.
safe.Lock(func() {
for _, user := range bridge.users {
@ -420,6 +415,11 @@ func (bridge *Bridge) Close(ctx context.Context) {
}
}, bridge.usersLock)
// Close the servers
if err := bridge.serverManager.CloseServers(ctx); err != nil {
logrus.WithError(err).Error("Failed to close servers")
}
// Stop all ongoing tasks.
bridge.tasks.CancelAndWait()

View File

@ -54,6 +54,7 @@ import (
"github.com/emersion/go-sasl"
"github.com/emersion/go-smtp"
"github.com/stretchr/testify/require"
"go.uber.org/goleak"
)
var (
@ -621,6 +622,10 @@ func TestBridge_AddressWithoutKeys(t *testing.T) {
defer m.Close()
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, vaultKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
// Watch for sync finished event.
syncCh, done := chToType[events.Event, events.SyncFinished](bridge.GetEvents(events.SyncFinished{}))
defer done()
// Create a user which will have an address without keys.
userID, _, err := s.CreateUser("nokeys", []byte("password"))
require.NoError(t, err)
@ -641,10 +646,6 @@ func TestBridge_AddressWithoutKeys(t *testing.T) {
// Remove the address keys.
require.NoError(t, s.RemoveAddressKey(userID, aliasAddrID, aliasAddr.Keys[0].ID))
// Watch for sync finished event.
syncCh, done := chToType[events.Event, events.SyncFinished](bridge.GetEvents(events.SyncFinished{}))
defer done()
// We should be able to log the user in.
require.NoError(t, getErr(bridge.LoginFull(context.Background(), "nokeys", []byte("password"), nil, nil)))
require.NoError(t, err)
@ -873,6 +874,9 @@ func TestBridge_ChangeAddressOrder(t *testing.T) {
// withEnv creates the full test environment and runs the tests.
func withEnv(t *testing.T, tests func(context.Context, *server.Server, *proton.NetCtl, bridge.Locator, []byte), opts ...server.Option) {
opt := goleak.IgnoreCurrent()
defer goleak.VerifyNone(t, opt)
server := server.New(opts...)
defer server.Close()

View File

@ -79,7 +79,7 @@ func (bridge *Bridge) CheckClientState(ctx context.Context, checkFlags bool, pro
}
log.Debug("Building state")
state, err := meta.BuildMailboxToMessageMap(usr)
state, err := meta.BuildMailboxToMessageMap(ctx, usr)
if err != nil {
log.WithError(err).Error("Failed to build state")
return result, err

View File

@ -36,7 +36,6 @@ import (
"github.com/ProtonMail/proton-bridge/v3/internal/constants"
"github.com/ProtonMail/proton-bridge/v3/internal/events"
"github.com/ProtonMail/proton-bridge/v3/internal/logging"
"github.com/ProtonMail/proton-bridge/v3/internal/user"
"github.com/ProtonMail/proton-bridge/v3/internal/useragent"
"github.com/sirupsen/logrus"
)
@ -45,16 +44,6 @@ func (bridge *Bridge) restartIMAP(ctx context.Context) error {
return bridge.serverManager.RestartIMAP(ctx)
}
// addIMAPUser connects the given user to gluon.
func (bridge *Bridge) addIMAPUser(ctx context.Context, user *user.User) error {
return bridge.serverManager.AddIMAPUser(ctx, user)
}
// removeIMAPUser disconnects the given user from gluon, optionally also removing its files.
func (bridge *Bridge) removeIMAPUser(ctx context.Context, user *user.User, withData bool) error {
return bridge.serverManager.RemoveIMAPUser(ctx, user, withData)
}
func (bridge *Bridge) handleIMAPEvent(event imapEvents.Event) {
switch event := event.(type) {
case imapEvents.UserAdded:

View File

@ -28,8 +28,8 @@ import (
"github.com/ProtonMail/gluon/logging"
"github.com/ProtonMail/proton-bridge/v3/internal/events"
"github.com/ProtonMail/proton-bridge/v3/internal/safe"
"github.com/ProtonMail/proton-bridge/v3/internal/services/imapservice"
bridgesmtp "github.com/ProtonMail/proton-bridge/v3/internal/services/smtp"
"github.com/ProtonMail/proton-bridge/v3/internal/user"
"github.com/ProtonMail/proton-bridge/v3/pkg/cpc"
"github.com/emersion/go-smtp"
"github.com/sirupsen/logrus"
@ -97,16 +97,18 @@ func (sm *ServerManager) RestartSMTP(ctx context.Context) error {
return err
}
func (sm *ServerManager) AddIMAPUser(ctx context.Context, user *user.User) error {
_, err := sm.requests.Send(ctx, &smRequestAddIMAPUser{user: user})
return err
}
func (sm *ServerManager) RemoveIMAPUser(ctx context.Context, user *user.User, withData bool) error {
_, err := sm.requests.Send(ctx, &smRequestRemoveIMAPUser{
user: user,
withData: withData,
func (sm *ServerManager) AddIMAPUser(
ctx context.Context,
connector connector.Connector,
addrID string,
idProvider imapservice.GluonIDProvider,
syncStateProvider imapservice.SyncStateProvider,
) error {
_, err := sm.requests.Send(ctx, &smRequestAddIMAPUser{
connector: connector,
addrID: addrID,
idProvider: idProvider,
syncStateProvider: syncStateProvider,
})
return err
@ -120,18 +122,11 @@ func (sm *ServerManager) SetGluonDir(ctx context.Context, gluonDir string) error
return err
}
func (sm *ServerManager) AddGluonUser(ctx context.Context, conn connector.Connector, passphrase []byte) (string, error) {
reply, err := cpc.SendTyped[string](ctx, sm.requests, &smRequestAddGluonUser{
conn: conn,
passphrase: passphrase,
})
return reply, err
}
func (sm *ServerManager) RemoveGluonUser(ctx context.Context, gluonID string) error {
_, err := sm.requests.Send(ctx, &smRequestRemoveGluonUser{
userID: gluonID,
func (sm *ServerManager) RemoveIMAPUser(ctx context.Context, deleteData bool, provider imapservice.GluonIDProvider, addrID ...string) error {
_, err := sm.requests.Send(ctx, &smRequestRemoveIMAPUser{
withData: deleteData,
addrID: addrID,
idProvider: provider,
})
return err
@ -195,18 +190,16 @@ func (sm *ServerManager) run(ctx context.Context, bridge *Bridge) {
request.Reply(ctx, nil, err)
case *smRequestAddIMAPUser:
err := sm.handleAddIMAPUser(ctx, r.user)
err := sm.handleAddIMAPUser(ctx, r.connector, r.addrID, r.idProvider, r.syncStateProvider)
request.Reply(ctx, nil, err)
if err == nil {
sm.loadedUserCount++
sm.handleLoadedUserCountChange(ctx, bridge)
}
case *smRequestRemoveIMAPUser:
err := sm.handleRemoveIMAPUser(ctx, r.user, r.withData)
err := sm.handleRemoveIMAPUser(ctx, r.withData, r.idProvider, r.addrID...)
request.Reply(ctx, nil, err)
if err == nil {
sm.loadedUserCount--
sm.handleLoadedUserCountChange(ctx, bridge)
}
@ -214,14 +207,6 @@ func (sm *ServerManager) run(ctx context.Context, bridge *Bridge) {
err := sm.handleSetGluonDir(ctx, bridge, r.dir)
request.Reply(ctx, nil, err)
case *smRequestAddGluonUser:
id, err := sm.handleAddGluonUser(ctx, r.conn, r.passphrase)
request.Reply(ctx, id, err)
case *smRequestRemoveGluonUser:
err := sm.handleRemoveGluonUser(ctx, r.userID)
request.Reply(ctx, nil, err)
case *smRequestAddSMTPAccount:
logrus.WithField("user", r.account.UserID()).Debug("Adding SMTP Account")
sm.smtpAccounts.AddAccount(r.account)
@ -277,114 +262,133 @@ func (sm *ServerManager) handleClose(ctx context.Context, bridge *Bridge) {
}
}
func (sm *ServerManager) handleAddIMAPUser(ctx context.Context, user *user.User) error {
func (sm *ServerManager) handleAddIMAPUser(ctx context.Context,
connector connector.Connector,
addrID string,
idProvider imapservice.GluonIDProvider,
syncStateProvider imapservice.SyncStateProvider,
) error {
// Due to the many different error exits, performer user count change at this stage rather we split the incrementing
// of users from the logic.
err := sm.handleAddIMAPUserImpl(ctx, connector, addrID, idProvider, syncStateProvider)
if err == nil {
sm.loadedUserCount++
}
return err
}
func (sm *ServerManager) handleAddIMAPUserImpl(ctx context.Context,
connector connector.Connector,
addrID string,
idProvider imapservice.GluonIDProvider,
syncStateProvider imapservice.SyncStateProvider,
) error {
if sm.imapServer == nil {
return fmt.Errorf("no imap server instance running")
}
imapConn, err := user.NewIMAPConnectors()
if err != nil {
return fmt.Errorf("failed to create IMAP connectors: %w", err)
}
log := logrus.WithFields(logrus.Fields{
"addrID": addrID,
})
log.Info("Adding user to imap server")
for addrID, imapConn := range imapConn {
log := logrus.WithFields(logrus.Fields{
"userID": user.ID(),
"addrID": addrID,
})
if gluonID, ok := idProvider.GetGluonID(addrID); ok {
log.WithField("gluonID", gluonID).Info("Loading existing IMAP user")
if gluonID, ok := user.GetGluonID(addrID); ok {
log.WithField("gluonID", gluonID).Info("Loading existing IMAP user")
// Load the user, checking whether the DB was newly created.
isNew, err := sm.imapServer.LoadUser(ctx, connector, gluonID, idProvider.GluonKey())
if err != nil {
return fmt.Errorf("failed to load IMAP user: %w", err)
}
// Load the user, checking whether the DB was newly created.
isNew, err := sm.imapServer.LoadUser(ctx, imapConn, gluonID, user.GluonKey())
if err != nil {
return fmt.Errorf("failed to load IMAP user: %w", err)
if isNew {
// If the DB was newly created, clear the sync status; gluon's DB was not found.
logrus.Warn("IMAP user DB was newly created, clearing sync status")
// Remove the user from IMAP so we can clear the sync status.
if err := sm.imapServer.RemoveUser(ctx, gluonID, false); err != nil {
return fmt.Errorf("failed to remove IMAP user: %w", err)
}
if isNew {
// If the DB was newly created, clear the sync status; gluon's DB was not found.
logrus.Warn("IMAP user DB was newly created, clearing sync status")
// Remove the user from IMAP so we can clear the sync status.
if err := sm.imapServer.RemoveUser(ctx, gluonID, false); err != nil {
return fmt.Errorf("failed to remove IMAP user: %w", err)
}
// Clear the sync status -- we need to resync all messages.
if err := user.ClearSyncStatus(); err != nil {
return fmt.Errorf("failed to clear sync status: %w", err)
}
// Add the user back to the IMAP server.
if isNew, err := sm.imapServer.LoadUser(ctx, imapConn, gluonID, user.GluonKey()); err != nil {
return fmt.Errorf("failed to add IMAP user: %w", err)
} else if isNew {
panic("IMAP user should already have a database")
}
} else if status := user.GetSyncStatus(); !status.HasLabels {
// Otherwise, the DB already exists -- if the labels are not yet synced, we need to re-create the DB.
if err := sm.imapServer.RemoveUser(ctx, gluonID, true); err != nil {
return fmt.Errorf("failed to remove old IMAP user: %w", err)
}
if err := user.RemoveGluonID(addrID, gluonID); err != nil {
return fmt.Errorf("failed to remove old IMAP user ID: %w", err)
}
gluonID, err := sm.imapServer.AddUser(ctx, imapConn, user.GluonKey())
if err != nil {
return fmt.Errorf("failed to add IMAP user: %w", err)
}
if err := user.SetGluonID(addrID, gluonID); err != nil {
return fmt.Errorf("failed to set IMAP user ID: %w", err)
}
log.WithField("gluonID", gluonID).Info("Re-created IMAP user")
// Clear the sync status -- we need to resync all messages.
if err := syncStateProvider.ClearSyncStatus(); err != nil {
return fmt.Errorf("failed to clear sync status: %w", err)
}
} else {
log.Info("Creating new IMAP user")
gluonID, err := sm.imapServer.AddUser(ctx, imapConn, user.GluonKey())
// Add the user back to the IMAP server.
if isNew, err := sm.imapServer.LoadUser(ctx, connector, gluonID, idProvider.GluonKey()); err != nil {
return fmt.Errorf("failed to add IMAP user: %w", err)
} else if isNew {
panic("IMAP user should already have a database")
}
} else if status := syncStateProvider.GetSyncStatus(); !status.HasLabels {
// Otherwise, the DB already exists -- if the labels are not yet synced, we need to re-create the DB.
if err := sm.imapServer.RemoveUser(ctx, gluonID, true); err != nil {
return fmt.Errorf("failed to remove old IMAP user: %w", err)
}
if err := idProvider.RemoveGluonID(addrID, gluonID); err != nil {
return fmt.Errorf("failed to remove old IMAP user ID: %w", err)
}
gluonID, err := sm.imapServer.AddUser(ctx, connector, idProvider.GluonKey())
if err != nil {
return fmt.Errorf("failed to add IMAP user: %w", err)
}
if err := user.SetGluonID(addrID, gluonID); err != nil {
if err := idProvider.SetGluonID(addrID, gluonID); err != nil {
return fmt.Errorf("failed to set IMAP user ID: %w", err)
}
log.WithField("gluonID", gluonID).Info("Created new IMAP user")
log.WithField("gluonID", gluonID).Info("Re-created IMAP user")
}
}
} else {
log.Info("Creating new IMAP user")
// Trigger a sync for the user, if needed.
user.TriggerSync()
gluonID, err := sm.imapServer.AddUser(ctx, connector, idProvider.GluonKey())
if err != nil {
return fmt.Errorf("failed to add IMAP user: %w", err)
}
if err := idProvider.SetGluonID(addrID, gluonID); err != nil {
return fmt.Errorf("failed to set IMAP user ID: %w", err)
}
log.WithField("gluonID", gluonID).Info("Created new IMAP user")
}
return nil
}
func (sm *ServerManager) handleRemoveIMAPUser(ctx context.Context, user *user.User, withData bool) error {
func (sm *ServerManager) handleRemoveIMAPUser(ctx context.Context, withData bool, idProvider imapservice.GluonIDProvider, addrIDs ...string) error {
if sm.imapServer == nil {
return fmt.Errorf("no imap server instance running")
}
logrus.WithFields(logrus.Fields{
"userID": user.ID(),
"withData": withData,
"withData": withData,
"addresses": addrIDs,
}).Debug("Removing IMAP user")
for addrID, gluonID := range user.GetGluonIDs() {
for _, addrID := range addrIDs {
gluonID, ok := idProvider.GetGluonID(addrID)
if !ok {
logrus.Warnf("Could not find Gluon ID for addrID %v", addrID)
continue
}
if err := sm.imapServer.RemoveUser(ctx, gluonID, withData); err != nil {
return fmt.Errorf("failed to remove IMAP user: %w", err)
}
if withData {
if err := user.RemoveGluonID(addrID, gluonID); err != nil {
if err := idProvider.RemoveGluonID(addrID, gluonID); err != nil {
return fmt.Errorf("failed to remove IMAP user ID: %w", err)
}
}
sm.loadedUserCount--
}
return nil
@ -396,7 +400,7 @@ func createIMAPServer(bridge *Bridge) (*gluon.Server, error) {
return nil, fmt.Errorf("failed to get Gluon Database directory: %w", err)
}
return newIMAPServer(
server, err := newIMAPServer(
bridge.vault.GetGluonCacheDir(),
gluonDataDir,
bridge.curVersion,
@ -409,6 +413,11 @@ func createIMAPServer(bridge *Bridge) (*gluon.Server, error) {
bridge.uidValidityGenerator,
bridge.panicHandler,
)
if err == nil {
bridge.publish(events.IMAPServerCreated{})
}
return server, err
}
func createSMTPServer(bridge *Bridge, accounts *bridgesmtp.Accounts) *smtp.Server {
@ -464,6 +473,8 @@ func (sm *ServerManager) closeIMAPServer(ctx context.Context, bridge *Bridge) er
}
sm.imapServer = nil
bridge.publish(events.IMAPServerClosed{})
}
return nil
@ -632,35 +643,12 @@ func (sm *ServerManager) handleSetGluonDir(ctx context.Context, bridge *Bridge,
bridge.heartbeat.SetCacheLocation(newGluonDir)
gluonDataDir, err := bridge.GetGluonDataDir()
if err != nil {
return fmt.Errorf("failed to get Gluon Database directory: %w", err)
}
imapServer, err := newIMAPServer(
bridge.vault.GetGluonCacheDir(),
gluonDataDir,
bridge.curVersion,
bridge.tlsConfig,
bridge.reporter,
bridge.logIMAPClient,
bridge.logIMAPServer,
bridge.imapEventCh,
bridge.tasks,
bridge.uidValidityGenerator,
bridge.panicHandler,
)
imapServer, err := createIMAPServer(bridge)
if err != nil {
return fmt.Errorf("failed to create new IMAP server: %w", err)
}
sm.imapServer = imapServer
for _, bridgeUser := range bridge.users {
if err := sm.handleAddIMAPUser(ctx, bridgeUser); err != nil {
return fmt.Errorf("failed to add users to new IMAP server: %w", err)
}
sm.loadedUserCount++
}
if sm.shouldStartServers() {
if err := sm.serveIMAP(ctx, bridge); err != nil {
@ -672,22 +660,6 @@ func (sm *ServerManager) handleSetGluonDir(ctx context.Context, bridge *Bridge,
}, bridge.usersLock)
}
func (sm *ServerManager) handleAddGluonUser(ctx context.Context, conn connector.Connector, passphrase []byte) (string, error) {
if sm.imapServer == nil {
return "", fmt.Errorf("no imap server instance running")
}
return sm.imapServer.AddUser(ctx, conn, passphrase)
}
func (sm *ServerManager) handleRemoveGluonUser(ctx context.Context, userID string) error {
if sm.imapServer == nil {
return fmt.Errorf("no imap server instance running")
}
return sm.imapServer.RemoveUser(ctx, userID, true)
}
func (sm *ServerManager) shouldStartServers() bool {
return sm.loadedUserCount >= 1
}
@ -699,27 +671,22 @@ type smRequestRestartIMAP struct{}
type smRequestRestartSMTP struct{}
type smRequestAddIMAPUser struct {
user *user.User
connector connector.Connector
addrID string
idProvider imapservice.GluonIDProvider
syncStateProvider imapservice.SyncStateProvider
}
type smRequestRemoveIMAPUser struct {
user *user.User
withData bool
withData bool
addrID []string
idProvider imapservice.GluonIDProvider
}
type smRequestSetGluonDir struct {
dir string
}
type smRequestAddGluonUser struct {
conn connector.Connector
passphrase []byte
}
type smRequestRemoveGluonUser struct {
userID string
}
type smRequestAddSMTPAccount struct {
account *bridgesmtp.Service
}

View File

@ -278,18 +278,10 @@ func (bridge *Bridge) SetAddressMode(ctx context.Context, userID string, mode va
return fmt.Errorf("address mode is already %q", mode)
}
if err := bridge.removeIMAPUser(ctx, user, true); err != nil {
return fmt.Errorf("failed to remove IMAP user: %w", err)
}
if err := user.SetAddressMode(ctx, mode); err != nil {
return fmt.Errorf("failed to set address mode: %w", err)
}
if err := bridge.addIMAPUser(ctx, user); err != nil {
return fmt.Errorf("failed to add IMAP user: %w", err)
}
bridge.publish(events.AddressModeChanged{
UserID: userID,
AddressMode: mode,
@ -335,13 +327,7 @@ func (bridge *Bridge) SendBadEventUserFeedback(_ context.Context, userID string,
logrus.WithError(rerr).Error("Failed to report feedback failure")
}
if err := bridge.addIMAPUser(ctx, user); err != nil {
return fmt.Errorf("failed to add IMAP user: %w", err)
}
user.BadEventFeedbackResync(ctx)
return nil
return user.BadEventFeedbackResync(ctx)
}
if rerr := bridge.reporter.ReportMessageWithContext(
@ -535,16 +521,13 @@ func (bridge *Bridge) addUserWithVault(
bridge.vault.GetMaxSyncMemory(),
statsPath,
bridge,
bridge.serverManager,
&bridgeEventSubscription{b: bridge},
)
if err != nil {
return fmt.Errorf("failed to create user: %w", err)
}
// Connect the user's address(es) to gluon.
if err := bridge.addIMAPUser(ctx, user); err != nil {
return fmt.Errorf("failed to add IMAP user: %w", err)
}
if err := bridge.addSMTPUser(ctx, user); err != nil {
return fmt.Errorf("failed to add SMTP user: %w", err)
}
@ -558,11 +541,8 @@ func (bridge *Bridge) addUserWithVault(
"event": event,
}).Debug("Received user event")
if err := bridge.handleUserEvent(ctx, user, event); err != nil {
logrus.WithError(err).Error("Failed to handle user event")
} else {
bridge.publish(event)
}
bridge.handleUserEvent(ctx, user, event)
bridge.publish(event)
})
})
@ -613,10 +593,6 @@ func (bridge *Bridge) logoutUser(ctx context.Context, user *user.User, withAPI,
"withData": withData,
}).Debug("Logging out user")
if err := bridge.removeIMAPUser(ctx, user, withData); err != nil {
logrus.WithError(err).Error("Failed to remove IMAP user")
}
if err := bridge.removeSMTPUser(ctx, user); err != nil {
logrus.WithError(err).Error("Failed to remove SMTP user")
}

View File

@ -19,44 +19,17 @@ package bridge
import (
"context"
"fmt"
"github.com/ProtonMail/gluon/reporter"
"github.com/ProtonMail/proton-bridge/v3/internal"
"github.com/ProtonMail/proton-bridge/v3/internal/events"
"github.com/ProtonMail/proton-bridge/v3/internal/safe"
"github.com/ProtonMail/proton-bridge/v3/internal/user"
"github.com/ProtonMail/proton-bridge/v3/internal/vault"
"github.com/sirupsen/logrus"
)
func (bridge *Bridge) handleUserEvent(ctx context.Context, user *user.User, event events.Event) error {
func (bridge *Bridge) handleUserEvent(ctx context.Context, user *user.User, event events.Event) {
switch event := event.(type) {
case events.UserAddressCreated:
if err := bridge.handleUserAddressCreated(ctx, user, event); err != nil {
return fmt.Errorf("failed to handle user address created event: %w", err)
}
case events.UserAddressEnabled:
if err := bridge.handleUserAddressEnabled(ctx, user, event); err != nil {
return fmt.Errorf("failed to handle user address enabled event: %w", err)
}
case events.UserAddressDisabled:
if err := bridge.handleUserAddressDisabled(ctx, user, event); err != nil {
return fmt.Errorf("failed to handle user address disabled event: %w", err)
}
case events.UserAddressDeleted:
if err := bridge.handleUserAddressDeleted(ctx, user, event); err != nil {
return fmt.Errorf("failed to handle user address deleted event: %w", err)
}
case events.UserRefreshed:
if err := bridge.handleUserRefreshed(ctx, user, event); err != nil {
return fmt.Errorf("failed to handle user refreshed event: %w", err)
}
case events.UserDeauth:
bridge.handleUserDeauth(ctx, user)
@ -66,102 +39,6 @@ func (bridge *Bridge) handleUserEvent(ctx context.Context, user *user.User, even
case events.UncategorizedEventError:
bridge.handleUncategorizedErrorEvent(event)
}
return nil
}
func (bridge *Bridge) handleUserAddressCreated(ctx context.Context, user *user.User, event events.UserAddressCreated) error {
if user.GetAddressMode() == vault.CombinedMode {
return nil
}
gluonID, err := bridge.serverManager.AddGluonUser(ctx, user.NewIMAPConnector(event.AddressID), user.GluonKey())
if err != nil {
return fmt.Errorf("failed to add user to IMAP server: %w", err)
}
if err := user.SetGluonID(event.AddressID, gluonID); err != nil {
return fmt.Errorf("failed to set gluon ID: %w", err)
}
return nil
}
func (bridge *Bridge) handleUserAddressEnabled(ctx context.Context, user *user.User, event events.UserAddressEnabled) error {
if user.GetAddressMode() == vault.CombinedMode {
return nil
}
gluonID, err := bridge.serverManager.AddGluonUser(ctx, user.NewIMAPConnector(event.AddressID), user.GluonKey())
if err != nil {
return fmt.Errorf("failed to add user to IMAP server: %w", err)
}
if err := user.SetGluonID(event.AddressID, gluonID); err != nil {
return fmt.Errorf("failed to set gluon ID: %w", err)
}
return nil
}
func (bridge *Bridge) handleUserAddressDisabled(ctx context.Context, user *user.User, event events.UserAddressDisabled) error {
if user.GetAddressMode() == vault.CombinedMode {
return nil
}
gluonID, ok := user.GetGluonID(event.AddressID)
if !ok {
return fmt.Errorf("gluon ID not found for address %s", event.AddressID)
}
if err := bridge.serverManager.RemoveGluonUser(ctx, gluonID); err != nil {
return fmt.Errorf("failed to remove user from IMAP server: %w", err)
}
if err := user.RemoveGluonID(event.AddressID, gluonID); err != nil {
return fmt.Errorf("failed to remove gluon ID for address: %w", err)
}
return nil
}
func (bridge *Bridge) handleUserAddressDeleted(ctx context.Context, user *user.User, event events.UserAddressDeleted) error {
if user.GetAddressMode() == vault.CombinedMode {
return nil
}
gluonID, ok := user.GetGluonID(event.AddressID)
if !ok {
return fmt.Errorf("gluon ID not found for address %s", event.AddressID)
}
if err := bridge.serverManager.handleRemoveGluonUser(ctx, gluonID); err != nil {
return fmt.Errorf("failed to remove user from IMAP server: %w", err)
}
if err := user.RemoveGluonID(event.AddressID, gluonID); err != nil {
return fmt.Errorf("failed to remove gluon ID for address: %w", err)
}
return nil
}
func (bridge *Bridge) handleUserRefreshed(ctx context.Context, user *user.User, event events.UserRefreshed) error {
return safe.RLockRet(func() error {
if event.CancelEventPool {
user.CancelSyncAndEventPoll()
}
if err := bridge.removeIMAPUser(ctx, user, true); err != nil {
return fmt.Errorf("failed to remove IMAP user: %w", err)
}
if err := bridge.addIMAPUser(ctx, user); err != nil {
return fmt.Errorf("failed to add IMAP user: %w", err)
}
return nil
}, bridge.usersLock)
}
func (bridge *Bridge) handleUserDeauth(ctx context.Context, user *user.User) {
@ -171,7 +48,7 @@ func (bridge *Bridge) handleUserDeauth(ctx context.Context, user *user.User) {
}, bridge.usersLock)
}
func (bridge *Bridge) handleUserBadEvent(_ context.Context, user *user.User, event events.UserBadEvent) {
func (bridge *Bridge) handleUserBadEvent(ctx context.Context, user *user.User, event events.UserBadEvent) {
safe.Lock(func() {
if rerr := bridge.reporter.ReportMessageWithContext("Failed to handle event", reporter.Context{
"user_id": user.ID(),
@ -184,12 +61,7 @@ func (bridge *Bridge) handleUserBadEvent(_ context.Context, user *user.User, eve
logrus.WithError(rerr).Error("Failed to report failed event handling")
}
user.CancelSyncAndEventPoll()
// Disable IMAP user
if err := bridge.removeIMAPUser(context.Background(), user, false); err != nil {
logrus.WithError(err).Error("Failed to remove IMAP user")
}
user.OnBadEvent(ctx)
}, bridge.usersLock)
}