aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTim Culverhouse <tim@timculverhouse.com>2024-08-16 09:14:46 -0500
committerRobin Jarry <robin@jarry.cc>2024-08-20 12:26:46 +0200
commit401bcee258713b911cd67aa6dc832e4eff25deb4 (patch)
tree8d374bd33d443200e43dafa7e19d403727b478b8
parentb896120f00d0b811a4b7e41709d8331a29c82cb0 (diff)
downloadaerc-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>
-rw-r--r--worker/jmap/fetch.go14
-rw-r--r--worker/jmap/threads.go49
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: