diff options
author | Tim Culverhouse <tim@timculverhouse.com> | 2024-08-16 09:14:46 -0500 |
---|---|---|
committer | Robin Jarry <robin@jarry.cc> | 2024-08-20 12:26:46 +0200 |
commit | 401bcee258713b911cd67aa6dc832e4eff25deb4 (patch) | |
tree | 8d374bd33d443200e43dafa7e19d403727b478b8 /worker | |
parent | b896120f00d0b811a4b7e41709d8331a29c82cb0 (diff) | |
download | aerc-401bcee258713b911cd67aa6dc832e4eff25deb4.tar.gz |
jmap: refactor thread fetching
Refactor JMAP thread fetching to occur in a single request. We use a
result reference method call on Email/get to fetch the message info for
each message in a thread.
Previously, we checked the cache and only fetched information for
messages we didn't already have. This results in two requests and is
typically slower for most contexts. Also, in most cases if we are
fetching an email we don't already have it's because we also need to
fetch the entire thread. The only case this wouldn't happen is if we get
a new email in a thread. We can optimize this by fetching message info
for created messages in the push method at a later time.
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
Diffstat (limited to 'worker')
-rw-r--r-- | worker/jmap/fetch.go | 14 | ||||
-rw-r--r-- | worker/jmap/threads.go | 49 |
2 files changed, 23 insertions, 40 deletions
diff --git a/worker/jmap/fetch.go b/worker/jmap/fetch.go index bbef1bb5..07579b99 100644 --- a/worker/jmap/fetch.go +++ b/worker/jmap/fetch.go @@ -44,14 +44,20 @@ func (w *JMAPWorker) handleFetchMessageHeaders(msg *types.FetchMessageHeaders) e } jid := jmap.ID(id) m, err := w.cache.GetEmail(jid) - if err == nil { - currentEmails = append(currentEmails, m) - } else { + if err != nil { + // Message wasn't in cache; fetch it emailIdsToFetch = append(emailIdsToFetch, jid) + continue } + currentEmails = append(currentEmails, m) + // Get the UI updated immediately + w.w.PostMessage(&types.MessageInfo{ + Message: types.RespondTo(msg), + Info: w.translateMsgInfo(m), + }, nil) } - if len(emailIdsToFetch) != 0 { + if len(emailIdsToFetch) > 0 { var req jmap.Request req.Invoke(&email.Get{ diff --git a/worker/jmap/threads.go b/worker/jmap/threads.go index b967e8cd..ee4b70a9 100644 --- a/worker/jmap/threads.go +++ b/worker/jmap/threads.go @@ -18,54 +18,31 @@ func (w *JMAPWorker) fetchEntireThreads(emailIds []*email.Email) ([]*email.Email threadsToFetch = append(threadsToFetch, m.ThreadID) } - req.Invoke(&thread.Get{ + threadGetId := req.Invoke(&thread.Get{ Account: w.AccountId(), IDs: threadsToFetch, }) - resp, err := w.Do(&req) - if err != nil { - return nil, err - } - - emailsToFetch := make([]jmap.ID, 0) - emailsToReturn := make([]*email.Email, 0) - for _, inv := range resp.Responses { - switch r := inv.Args.(type) { - case *thread.GetResponse: - for _, t := range r.List { - for _, emailId := range t.EmailIDs { - m, err := w.cache.GetEmail(emailId) - if err == nil || m == nil { - emailsToFetch = append(emailsToFetch, emailId) - } else { - emailsToReturn = append(emailsToReturn, m) - } - } - } - if err = w.cache.PutThreadState(r.State); err != nil { - w.w.Warnf("PutThreadState: %s", err) - } - case *jmap.MethodError: - return nil, wrapMethodError(r) - } - } - - if len(emailsToFetch) == 0 { - return emailsToReturn, nil - } - + // Opportunistically fetch all emails in this thread. We could wait for + // the result, check which ones we don't have, then fetch only those. + // However we can do this all in a single request which ends up being + // faster than two requests for most contexts req.Invoke(&email.Get{ - Account: w.AccountId(), - IDs: emailsToFetch, + Account: w.AccountId(), + ReferenceIDs: &jmap.ResultReference{ + ResultOf: threadGetId, + Name: "Thread/get", + Path: "/list/*/emailIds", + }, Properties: headersProperties, }) - resp, err = w.Do(&req) + resp, err := w.Do(&req) if err != nil { return nil, err } + emailsToReturn := make([]*email.Email, 0) for _, inv := range resp.Responses { switch r := inv.Args.(type) { case *email.GetResponse: |