jmap: invalidate cache if mailbox state is not consistent

We weren't checking if the cached state was the same as the remote state
before reading it. This led to aerc not knowing about new mailboxes on
the remote.

Signed-off-by: Tristan Partin <tristan@partin.io>
Acked-by: Robin Jarry <robin@jarry.cc>
This commit is contained in:
Tristan Partin
2024-05-11 14:15:04 -05:00
committed by Robin Jarry
parent 36457f82f2
commit f9113810cc
2 changed files with 57 additions and 11 deletions

View File

@@ -21,21 +21,38 @@ func (w *JMAPWorker) handleListDirectories(msg *types.ListDirectories) error {
mboxes = make(map[jmap.ID]*mailbox.Mailbox)
mboxIds, err := w.cache.GetMailboxList()
if err == nil {
for _, id := range mboxIds {
mbox, err := w.cache.GetMailbox(id)
if err != nil {
w.w.Warnf("GetMailbox: %s", err)
missing = append(missing, id)
continue
currentMailboxState, err := w.getMailboxState()
if err != nil {
return err
}
// If we can't get the cached mailbox state, at worst, we will just
// query information we might already know
cachedMailboxState, err := w.cache.GetMailboxState()
if err != nil {
w.w.Warnf("PutMailboxState: %s", err)
}
consistentMailboxState := currentMailboxState == cachedMailboxState
// If we have a consistent state, check the cache
if consistentMailboxState {
mboxIds, err := w.cache.GetMailboxList()
if err == nil {
for _, id := range mboxIds {
mbox, err := w.cache.GetMailbox(id)
if err != nil {
w.w.Warnf("GetMailbox: %s", err)
missing = append(missing, id)
continue
}
mboxes[id] = mbox
ids = append(ids, id)
}
mboxes[id] = mbox
ids = append(ids, id)
}
}
if err != nil || len(missing) > 0 {
if !consistentMailboxState || len(missing) > 0 {
var req jmap.Request
req.Invoke(&mailbox.Get{Account: w.accountId})

29
worker/jmap/state.go Normal file
View File

@@ -0,0 +1,29 @@
package jmap
import (
"git.sr.ht/~rockorager/go-jmap"
"git.sr.ht/~rockorager/go-jmap/mail/mailbox"
)
func (w *JMAPWorker) getMailboxState() (string, error) {
var req jmap.Request
req.Invoke(&mailbox.Get{Account: w.accountId, IDs: make([]jmap.ID, 0)})
resp, err := w.Do(&req)
if err != nil {
return "", err
}
for _, inv := range resp.Responses {
switch r := inv.Args.(type) {
case *mailbox.GetResponse:
return r.State, nil
case *jmap.MethodError:
return "", wrapMethodError(r)
}
}
// This should be an impossibility
return "", nil
}