From d09855765a199333e2d250db27620cbd8e22bf3a Mon Sep 17 00:00:00 2001
From: Pascal Bleser
Date: Wed, 10 Sep 2025 10:03:47 +0200
Subject: [PATCH] refactor(groupware): use a function for multi-account method
call IDs
* introduce a function 'mcid' to assemble method call IDs per account
instead of doing that inline in each function, in case the rules for
doing so change in the future
---
pkg/jmap/jmap_api_mailbox.go | 38 +++++++++++++-----------------------
pkg/jmap/jmap_tools.go | 11 +++++++++++
2 files changed, 25 insertions(+), 24 deletions(-)
diff --git a/pkg/jmap/jmap_api_mailbox.go b/pkg/jmap/jmap_api_mailbox.go
index 529a6d1ee9..633499e19f 100644
--- a/pkg/jmap/jmap_api_mailbox.go
+++ b/pkg/jmap/jmap_api_mailbox.go
@@ -26,8 +26,7 @@ func (j *Client) GetMailbox(accountIds []string, session *Session, ctx context.C
invocations := make([]Invocation, n)
for i, accountId := range uniqueAccountIds {
- baseId := accountId + ":"
- invocations[i] = invocation(CommandMailboxGet, MailboxGetCommand{AccountId: accountId, Ids: ids}, baseId+"0")
+ invocations[i] = invocation(CommandMailboxGet, MailboxGetCommand{AccountId: accountId, Ids: ids}, mcid(accountId, "0"))
}
cmd, err := j.request(session, logger, invocations...)
@@ -38,10 +37,8 @@ func (j *Client) GetMailbox(accountIds []string, session *Session, ctx context.C
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, func(body *Response) (map[string]MailboxesResponse, Error) {
resp := map[string]MailboxesResponse{}
for _, accountId := range uniqueAccountIds {
- baseId := accountId + ":"
-
var response MailboxGetResponse
- err = retrieveResponseMatchParameters(logger, body, CommandMailboxGet, baseId+"0", &response)
+ err = retrieveResponseMatchParameters(logger, body, CommandMailboxGet, mcid(accountId, "0"), &response)
if err != nil {
return map[string]MailboxesResponse{}, err
}
@@ -92,12 +89,11 @@ func (j *Client) SearchMailboxes(accountIds []string, session *Session, ctx cont
invocations := make([]Invocation, len(uniqueAccountIds)*2)
for i, accountId := range uniqueAccountIds {
- baseId := accountId + ":"
- invocations[i*2+0] = invocation(CommandMailboxQuery, MailboxQueryCommand{AccountId: accountId, Filter: filter}, baseId+"0")
+ invocations[i*2+0] = invocation(CommandMailboxQuery, MailboxQueryCommand{AccountId: accountId, Filter: filter}, mcid(accountId, "0"))
invocations[i*2+1] = invocation(CommandMailboxGet, MailboxGetRefCommand{
AccountId: accountId,
- IdRef: &ResultReference{Name: CommandMailboxQuery, Path: "/ids/*", ResultOf: baseId + "0"},
- }, baseId+"1")
+ IdRef: &ResultReference{Name: CommandMailboxQuery, Path: "/ids/*", ResultOf: mcid(accountId, "0")},
+ }, mcid(accountId, "1"))
}
cmd, err := j.request(session, logger, invocations...)
if err != nil {
@@ -107,10 +103,8 @@ func (j *Client) SearchMailboxes(accountIds []string, session *Session, ctx cont
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, func(body *Response) (map[string]Mailboxes, Error) {
resp := map[string]Mailboxes{}
for _, accountId := range uniqueAccountIds {
- baseId := accountId + ":"
-
var response MailboxGetResponse
- err = retrieveResponseMatchParameters(logger, body, CommandMailboxGet, baseId+"1", &response)
+ err = retrieveResponseMatchParameters(logger, body, CommandMailboxGet, mcid(accountId, "1"), &response)
if err != nil {
return map[string]Mailboxes{}, err
}
@@ -233,12 +227,10 @@ func (j *Client) GetMailboxChangesForMultipleAccounts(accountIds []string, sessi
changes.MaxChanges = maxChanges
}
- baseId := accountId + ":"
-
getCreated := EmailGetRefCommand{
AccountId: accountId,
FetchAllBodyValues: fetchBodies,
- IdRef: &ResultReference{Name: CommandMailboxChanges, Path: "/created", ResultOf: baseId + "0"},
+ IdRef: &ResultReference{Name: CommandMailboxChanges, Path: "/created", ResultOf: mcid(accountId, "0")},
}
if maxBodyValueBytes > 0 {
getCreated.MaxBodyValueBytes = maxBodyValueBytes
@@ -246,15 +238,15 @@ func (j *Client) GetMailboxChangesForMultipleAccounts(accountIds []string, sessi
getUpdated := EmailGetRefCommand{
AccountId: accountId,
FetchAllBodyValues: fetchBodies,
- IdRef: &ResultReference{Name: CommandMailboxChanges, Path: "/updated", ResultOf: baseId + "0"},
+ IdRef: &ResultReference{Name: CommandMailboxChanges, Path: "/updated", ResultOf: mcid(accountId, "0")},
}
if maxBodyValueBytes > 0 {
getUpdated.MaxBodyValueBytes = maxBodyValueBytes
}
- invocations[i*3+0] = invocation(CommandMailboxChanges, changes, baseId+"0")
- invocations[i*3+1] = invocation(CommandEmailGet, getCreated, baseId+"1")
- invocations[i*3+2] = invocation(CommandEmailGet, getUpdated, baseId+"2")
+ invocations[i*3+0] = invocation(CommandMailboxChanges, changes, mcid(accountId, "0"))
+ invocations[i*3+1] = invocation(CommandEmailGet, getCreated, mcid(accountId, "1"))
+ invocations[i*3+2] = invocation(CommandEmailGet, getUpdated, mcid(accountId, "2"))
}
cmd, err := j.request(session, logger, invocations...)
@@ -265,22 +257,20 @@ func (j *Client) GetMailboxChangesForMultipleAccounts(accountIds []string, sessi
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, func(body *Response) (map[string]MailboxChanges, Error) {
resp := make(map[string]MailboxChanges, n)
for _, accountId := range uniqueAccountIds {
- baseId := accountId + ":"
-
var mailboxResponse MailboxChangesResponse
- err = retrieveResponseMatchParameters(logger, body, CommandMailboxChanges, baseId+"0", &mailboxResponse)
+ err = retrieveResponseMatchParameters(logger, body, CommandMailboxChanges, mcid(accountId, "0"), &mailboxResponse)
if err != nil {
return map[string]MailboxChanges{}, err
}
var createdResponse EmailGetResponse
- err = retrieveResponseMatchParameters(logger, body, CommandEmailGet, baseId+"1", &createdResponse)
+ err = retrieveResponseMatchParameters(logger, body, CommandEmailGet, mcid(accountId, "1"), &createdResponse)
if err != nil {
return map[string]MailboxChanges{}, err
}
var updatedResponse EmailGetResponse
- err = retrieveResponseMatchParameters(logger, body, CommandEmailGet, baseId+"2", &updatedResponse)
+ err = retrieveResponseMatchParameters(logger, body, CommandEmailGet, mcid(accountId, "2"), &updatedResponse)
if err != nil {
return map[string]MailboxChanges{}, err
}
diff --git a/pkg/jmap/jmap_tools.go b/pkg/jmap/jmap_tools.go
index d7cc30521b..81feedfaa8 100644
--- a/pkg/jmap/jmap_tools.go
+++ b/pkg/jmap/jmap_tools.go
@@ -38,6 +38,17 @@ func newEventListeners[T any]() *eventListeners[T] {
}
}
+// Create an identifier to use as a method call ID, from the specified accountId and additional
+// tag, to make something unique within that API request.
+func mcid(accountId string, tag string) string {
+ // https://jmap.io/spec-core.html#the-invocation-data-type
+ // May be any string of data:
+ // An arbitrary string from the client to be echoed back with the responses emitted by that method
+ // call (a method may return 1 or more responses, as it may make implicit calls to other methods;
+ // all responses initiated by this method call get the same method call id in the response).
+ return accountId + ":" + tag
+}
+
func command[T any](api ApiClient,
logger *log.Logger,
ctx context.Context,