1
0

Other(refactor): Use normal value + mutex for user.apiAddrs

This commit is contained in:
James Houlahan
2022-10-26 23:48:18 +02:00
parent 83339da26c
commit 0bc99dbd4f
8 changed files with 311 additions and 306 deletions

View File

@ -99,77 +99,87 @@ func (user *User) handleAddressEvents(ctx context.Context, addressEvents []litea
}
func (user *User) handleCreateAddressEvent(ctx context.Context, event liteapi.AddressEvent) error {
if had := user.apiAddrs.Set(event.Address.ID, event.Address); had {
return fmt.Errorf("address %q already exists", event.Address.ID)
}
return safe.LockRet(func() error {
if _, ok := user.apiAddrs[event.Address.ID]; ok {
return fmt.Errorf("address %q already exists", event.ID)
}
switch user.vault.AddressMode() {
case vault.CombinedMode:
user.apiAddrs.Index(0, func(addrID string, _ liteapi.Address) {
user.updateCh.SetFrom(event.Address.ID, addrID)
user.apiAddrs[event.Address.ID] = event.Address
switch user.vault.AddressMode() {
case vault.CombinedMode:
primAddr, err := getAddrIdx(user.apiAddrs, 0)
if err != nil {
return fmt.Errorf("failed to get primary address: %w", err)
}
user.updateCh.SetFrom(event.Address.ID, primAddr.ID)
case vault.SplitMode:
user.updateCh.Set(event.Address.ID, queue.NewQueuedChannel[imap.Update](0, 0))
}
user.eventCh.Enqueue(events.UserAddressCreated{
UserID: user.ID(),
AddressID: event.Address.ID,
Email: event.Address.Email,
})
case vault.SplitMode:
user.updateCh.Set(event.Address.ID, queue.NewQueuedChannel[imap.Update](0, 0))
}
user.eventCh.Enqueue(events.UserAddressCreated{
UserID: user.ID(),
AddressID: event.Address.ID,
Email: event.Address.Email,
})
if user.vault.AddressMode() == vault.SplitMode {
if ok, err := user.updateCh.GetErr(event.Address.ID, func(updateCh *queue.QueuedChannel[imap.Update]) error {
return syncLabels(ctx, user.client, updateCh)
}); !ok {
return fmt.Errorf("no such address %q", event.Address.ID)
} else if err != nil {
return fmt.Errorf("failed to sync labels to new address: %w", err)
if user.vault.AddressMode() == vault.SplitMode {
if ok, err := user.updateCh.GetErr(event.Address.ID, func(updateCh *queue.QueuedChannel[imap.Update]) error {
return syncLabels(ctx, user.client, updateCh)
}); !ok {
return fmt.Errorf("no such address %q", event.Address.ID)
} else if err != nil {
return fmt.Errorf("failed to sync labels to new address: %w", err)
}
}
}
return nil
return nil
}, &user.apiAddrsLock)
}
func (user *User) handleUpdateAddressEvent(_ context.Context, event liteapi.AddressEvent) error { //nolint:unparam
if had := user.apiAddrs.Set(event.Address.ID, event.Address); !had {
return fmt.Errorf("address %q does not exist", event.Address.ID)
}
return safe.LockRet(func() error {
if _, ok := user.apiAddrs[event.Address.ID]; ok {
return fmt.Errorf("address %q already exists", event.ID)
}
user.eventCh.Enqueue(events.UserAddressUpdated{
UserID: user.ID(),
AddressID: event.Address.ID,
Email: event.Address.Email,
user.apiAddrs[event.Address.ID] = event.Address
user.eventCh.Enqueue(events.UserAddressUpdated{
UserID: user.ID(),
AddressID: event.Address.ID,
Email: event.Address.Email,
})
return nil
})
return nil
}
func (user *User) handleDeleteAddressEvent(_ context.Context, event liteapi.AddressEvent) error {
var email string
if ok := user.apiAddrs.GetDelete(event.ID, func(apiAddr liteapi.Address) {
email = apiAddr.Email
}); !ok {
return fmt.Errorf("no such address %q", event.ID)
}
if ok := user.updateCh.GetDelete(event.ID, func(updateCh *queue.QueuedChannel[imap.Update]) {
if user.vault.AddressMode() == vault.SplitMode {
updateCh.CloseAndDiscardQueued()
return safe.LockRet(func() error {
addr, ok := user.apiAddrs[event.ID]
if !ok {
return fmt.Errorf("address %q does not exist", event.ID)
}
}); !ok {
return fmt.Errorf("no such address %q", event.ID)
}
user.eventCh.Enqueue(events.UserAddressDeleted{
UserID: user.ID(),
AddressID: event.ID,
Email: email,
if ok := user.updateCh.GetDelete(event.ID, func(updateCh *queue.QueuedChannel[imap.Update]) {
if user.vault.AddressMode() == vault.SplitMode {
updateCh.CloseAndDiscardQueued()
}
}); !ok {
return fmt.Errorf("no such address %q", event.ID)
}
user.eventCh.Enqueue(events.UserAddressDeleted{
UserID: user.ID(),
AddressID: event.ID,
Email: addr.Email,
})
return nil
})
return nil
}
// handleLabelEvents handles the given label events.
@ -254,18 +264,20 @@ func (user *User) handleCreateMessageEvent(ctx context.Context, event liteapi.Me
return fmt.Errorf("failed to get full message: %w", err)
}
return user.withAddrKR(event.Message.AddressID, func(_, addrKR *crypto.KeyRing) error {
buildRes, err := buildRFC822(full, addrKR)
if err != nil {
return fmt.Errorf("failed to build RFC822 message: %w", err)
}
return safe.RLockRet(func() error {
return withAddrKR(user.apiUser, user.apiAddrs[event.Message.AddressID], user.vault.KeyPass(), func(_, addrKR *crypto.KeyRing) error {
buildRes, err := buildRFC822(full, addrKR)
if err != nil {
return fmt.Errorf("failed to build RFC822 message: %w", err)
}
user.updateCh.Get(full.AddressID, func(updateCh *queue.QueuedChannel[imap.Update]) {
updateCh.Enqueue(imap.NewMessagesCreated(buildRes.update))
user.updateCh.Get(full.AddressID, func(updateCh *queue.QueuedChannel[imap.Update]) {
updateCh.Enqueue(imap.NewMessagesCreated(buildRes.update))
})
return nil
})
return nil
})
}, &user.apiUserLock, &user.apiAddrsLock)
}
func (user *User) handleUpdateMessageEvent(_ context.Context, event liteapi.MessageEvent) error { //nolint:unparam