GODT-35: New pmapi client and manager using resty

This commit is contained in:
James Houlahan
2021-02-22 18:23:51 +01:00
committed by Jakub
parent 1d538e8540
commit 2284e9ede1
163 changed files with 3333 additions and 8124 deletions

View File

@ -18,6 +18,7 @@
package store
import (
"context"
"math/rand"
"time"
@ -80,7 +81,7 @@ func (loop *eventLoop) client() pmapi.Client {
func (loop *eventLoop) setFirstEventID() (err error) {
loop.log.Info("Setting first event ID")
event, err := loop.client().GetEvent("")
event, err := loop.client().GetEvent(context.TODO(), "")
if err != nil {
loop.log.WithError(err).Error("Could not get latest event ID")
return
@ -221,7 +222,8 @@ func (loop *eventLoop) processNextEvent() (more bool, err error) { // nolint[fun
// We only want to consider invalid tokens as real errors because all other errors might fix themselves eventually
// (e.g. no internet, ulimit reached etc.)
defer func() {
if errors.Cause(err) == pmapi.ErrAPINotReachable {
// FIXME(conman): How to handle errors of different types?
if errors.Is(err, pmapi.ErrNoConnection) {
l.Warn("Internet unavailable")
err = nil
}
@ -232,18 +234,20 @@ func (loop *eventLoop) processNextEvent() (more bool, err error) { // nolint[fun
err = nil
}
if errors.Cause(err) == pmapi.ErrUpgradeApplication {
l.Warn("Need to upgrade application")
err = nil
}
_, errUnauthorized := errors.Cause(err).(*pmapi.ErrUnauthorized)
// FIXME(conman): Handle force upgrade.
/*
if errors.Cause(err) == pmapi.ErrUpgradeApplication {
l.Warn("Need to upgrade application")
err = nil
}
*/
if err == nil {
loop.errCounter = 0
}
// All errors except Invalid Token (which is not possible to recover from) are ignored.
if err != nil && !errUnauthorized && errors.Cause(err) != pmapi.ErrInvalidToken {
// All errors except ErrUnauthorized (which is not possible to recover from) are ignored.
if !errors.Is(err, pmapi.ErrUnauthorized) {
l.WithError(err).WithField("errors", loop.errCounter).Error("Error skipped")
loop.errCounter++
if loop.errCounter == errMaxSentry {
@ -264,7 +268,7 @@ func (loop *eventLoop) processNextEvent() (more bool, err error) { // nolint[fun
loop.pollCounter++
var event *pmapi.Event
if event, err = loop.client().GetEvent(loop.currentEventID); err != nil {
if event, err = loop.client().GetEvent(context.TODO(), loop.currentEventID); err != nil {
return false, errors.Wrap(err, "failed to get event")
}
@ -461,12 +465,16 @@ func (loop *eventLoop) processMessages(eventLog *logrus.Entry, messages []*pmapi
msgLog.WithError(err).Warning("Message was not present in DB. Trying fetch...")
if msg, err = loop.client().GetMessage(message.ID); err != nil {
if _, ok := err.(*pmapi.ErrUnprocessableEntity); ok {
msgLog.WithError(err).Warn("Skipping message update because message exists neither in local DB nor on API")
err = nil
continue
}
if msg, err = loop.client().GetMessage(context.TODO(), message.ID); err != nil {
// FIXME(conman): How to handle error of this particular type?
/*
if _, ok := err.(*pmapi.ErrUnprocessableEntity); ok {
msgLog.WithError(err).Warn("Skipping message update because message exists neither in local DB nor on API")
err = nil
continue
}
*/
return errors.Wrap(err, "failed to get message from API for updating")
}

View File

@ -18,6 +18,7 @@
package store
import (
"context"
"net/mail"
"testing"
"time"
@ -39,15 +40,15 @@ func TestEventLoopProcessMoreEvents(t *testing.T) {
// Doesn't matter which IDs are used.
// This test is trying to see whether event loop will immediately process
// next event if there is `More` of them.
m.client.EXPECT().GetEvent("latestEventID").Return(&pmapi.Event{
m.client.EXPECT().GetEvent(gomock.Any(), "latestEventID").Return(&pmapi.Event{
EventID: "event50",
More: 1,
}, nil),
m.client.EXPECT().GetEvent("event50").Return(&pmapi.Event{
m.client.EXPECT().GetEvent(gomock.Any(), "event50").Return(&pmapi.Event{
EventID: "event70",
More: 0,
}, nil),
m.client.EXPECT().GetEvent("event70").Return(&pmapi.Event{
m.client.EXPECT().GetEvent(gomock.Any(), "event70").Return(&pmapi.Event{
EventID: "event71",
More: 0,
}, nil),
@ -165,7 +166,7 @@ func TestEventLoopDeletionPaused(t *testing.T) {
func testEvent(t *testing.T, m *mocksForStore, event *pmapi.Event) {
eventReceived := make(chan struct{})
m.client.EXPECT().GetEvent("latestEventID").DoAndReturn(func(eventID string) (*pmapi.Event, error) {
m.client.EXPECT().GetEvent(gomock.Any(), "latestEventID").DoAndReturn(func(_ context.Context, eventID string) (*pmapi.Event, error) {
defer close(eventReceived)
return event, nil
})

View File

@ -18,6 +18,8 @@
package store
import (
"context"
"github.com/ProtonMail/proton-bridge/pkg/pmapi"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@ -41,7 +43,7 @@ func (storeMailbox *Mailbox) GetMessage(apiID string) (*Message, error) {
// FetchMessage fetches the message with the given `apiID`, stores it in the database, and returns a new store message
// wrapping it.
func (storeMailbox *Mailbox) FetchMessage(apiID string) (*Message, error) {
msg, err := storeMailbox.client().GetMessage(apiID)
msg, err := storeMailbox.client().GetMessage(context.TODO(), apiID)
if err != nil {
return nil, err
}
@ -58,15 +60,17 @@ func (storeMailbox *Mailbox) ImportMessage(msg *pmapi.Message, body []byte, labe
}
importReqs := &pmapi.ImportMsgReq{
AddressID: msg.AddressID,
Body: body,
Unread: msg.Unread,
Flags: msg.Flags,
Time: msg.Time,
LabelIDs: labelIDs,
Metadata: &pmapi.ImportMetadata{
AddressID: msg.AddressID,
Unread: msg.Unread,
Flags: msg.Flags,
Time: msg.Time,
LabelIDs: labelIDs,
},
Message: body,
}
res, err := storeMailbox.client().Import([]*pmapi.ImportMsgReq{importReqs})
res, err := storeMailbox.client().Import(context.TODO(), pmapi.ImportMsgReqs{importReqs})
if err != nil {
return err
}
@ -95,7 +99,7 @@ func (storeMailbox *Mailbox) LabelMessages(apiIDs []string) error {
return ErrAllMailOpNotAllowed
}
defer storeMailbox.pollNow()
return storeMailbox.client().LabelMessages(apiIDs, storeMailbox.labelID)
return storeMailbox.client().LabelMessages(context.TODO(), apiIDs, storeMailbox.labelID)
}
// UnlabelMessages removes the label by calling an API.
@ -108,7 +112,7 @@ func (storeMailbox *Mailbox) UnlabelMessages(apiIDs []string) error {
return ErrAllMailOpNotAllowed
}
defer storeMailbox.pollNow()
return storeMailbox.client().UnlabelMessages(apiIDs, storeMailbox.labelID)
return storeMailbox.client().UnlabelMessages(context.TODO(), apiIDs, storeMailbox.labelID)
}
// MarkMessagesRead marks the message read by calling an API.
@ -135,7 +139,7 @@ func (storeMailbox *Mailbox) MarkMessagesRead(apiIDs []string) error {
if len(ids) == 0 {
return nil
}
return storeMailbox.client().MarkMessagesRead(ids)
return storeMailbox.client().MarkMessagesRead(context.TODO(), ids)
}
// MarkMessagesUnread marks the message unread by calling an API.
@ -147,7 +151,7 @@ func (storeMailbox *Mailbox) MarkMessagesUnread(apiIDs []string) error {
"mailbox": storeMailbox.Name,
}).Trace("Marking messages as unread")
defer storeMailbox.pollNow()
return storeMailbox.client().MarkMessagesUnread(apiIDs)
return storeMailbox.client().MarkMessagesUnread(context.TODO(), apiIDs)
}
// MarkMessagesStarred adds the Starred label by calling an API.
@ -160,7 +164,7 @@ func (storeMailbox *Mailbox) MarkMessagesStarred(apiIDs []string) error {
"mailbox": storeMailbox.Name,
}).Trace("Marking messages as starred")
defer storeMailbox.pollNow()
return storeMailbox.client().LabelMessages(apiIDs, pmapi.StarredLabel)
return storeMailbox.client().LabelMessages(context.TODO(), apiIDs, pmapi.StarredLabel)
}
// MarkMessagesUnstarred removes the Starred label by calling an API.
@ -173,7 +177,7 @@ func (storeMailbox *Mailbox) MarkMessagesUnstarred(apiIDs []string) error {
"mailbox": storeMailbox.Name,
}).Trace("Marking messages as unstarred")
defer storeMailbox.pollNow()
return storeMailbox.client().UnlabelMessages(apiIDs, pmapi.StarredLabel)
return storeMailbox.client().UnlabelMessages(context.TODO(), apiIDs, pmapi.StarredLabel)
}
// MarkMessagesDeleted adds local flag \Deleted. This is not propagated to API
@ -257,11 +261,11 @@ func (storeMailbox *Mailbox) RemoveDeleted(apiIDs []string) error {
}
case pmapi.DraftLabel:
storeMailbox.log.WithField("ids", apiIDs).Warn("Deleting drafts")
if err := storeMailbox.client().DeleteMessages(apiIDs); err != nil {
if err := storeMailbox.client().DeleteMessages(context.TODO(), apiIDs); err != nil {
return err
}
default:
if err := storeMailbox.client().UnlabelMessages(apiIDs, storeMailbox.labelID); err != nil {
if err := storeMailbox.client().UnlabelMessages(context.TODO(), apiIDs, storeMailbox.labelID); err != nil {
return err
}
}
@ -299,13 +303,13 @@ func (storeMailbox *Mailbox) deleteFromTrashOrSpam(apiIDs []string) error {
}
}
if len(messageIDsToUnlabel) > 0 {
if err := storeMailbox.client().UnlabelMessages(messageIDsToUnlabel, storeMailbox.labelID); err != nil {
if err := storeMailbox.client().UnlabelMessages(context.TODO(), messageIDsToUnlabel, storeMailbox.labelID); err != nil {
l.WithError(err).Warning("Cannot unlabel before deleting")
}
}
if len(messageIDsToDelete) > 0 {
storeMailbox.log.WithField("ids", messageIDsToDelete).Warn("Deleting messages")
if err := storeMailbox.client().DeleteMessages(messageIDsToDelete); err != nil {
if err := storeMailbox.client().DeleteMessages(context.TODO(), messageIDsToDelete); err != nil {
return err
}
}

View File

@ -1,5 +1,5 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/ProtonMail/proton-bridge/internal/store (interfaces: PanicHandler,ClientManager,BridgeUser,ChangeNotifier)
// Source: github.com/ProtonMail/proton-bridge/internal/store (interfaces: PanicHandler,BridgeUser,ChangeNotifier)
// Package mocks is a generated GoMock package.
package mocks
@ -46,43 +46,6 @@ func (mr *MockPanicHandlerMockRecorder) HandlePanic() *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HandlePanic", reflect.TypeOf((*MockPanicHandler)(nil).HandlePanic))
}
// MockClientManager is a mock of ClientManager interface
type MockClientManager struct {
ctrl *gomock.Controller
recorder *MockClientManagerMockRecorder
}
// MockClientManagerMockRecorder is the mock recorder for MockClientManager
type MockClientManagerMockRecorder struct {
mock *MockClientManager
}
// NewMockClientManager creates a new mock instance
func NewMockClientManager(ctrl *gomock.Controller) *MockClientManager {
mock := &MockClientManager{ctrl: ctrl}
mock.recorder = &MockClientManagerMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockClientManager) EXPECT() *MockClientManagerMockRecorder {
return m.recorder
}
// GetClient mocks base method
func (m *MockClientManager) GetClient(arg0 string) pmapi.Client {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetClient", arg0)
ret0, _ := ret[0].(pmapi.Client)
return ret0
}
// GetClient indicates an expected call of GetClient
func (mr *MockClientManagerMockRecorder) GetClient(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetClient", reflect.TypeOf((*MockClientManager)(nil).GetClient), arg0)
}
// MockBridgeUser is a mock of BridgeUser interface
type MockBridgeUser struct {
ctrl *gomock.Controller
@ -145,6 +108,20 @@ func (mr *MockBridgeUserMockRecorder) GetAddressID(arg0 interface{}) *gomock.Cal
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAddressID", reflect.TypeOf((*MockBridgeUser)(nil).GetAddressID), arg0)
}
// GetClient mocks base method
func (m *MockBridgeUser) GetClient() pmapi.Client {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetClient")
ret0, _ := ret[0].(pmapi.Client)
return ret0
}
// GetClient indicates an expected call of GetClient
func (mr *MockBridgeUserMockRecorder) GetClient() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetClient", reflect.TypeOf((*MockBridgeUser)(nil).GetClient))
}
// GetPrimaryAddress mocks base method
func (m *MockBridgeUser) GetPrimaryAddress() string {
m.ctrl.T.Helper()

View File

@ -19,6 +19,7 @@
package store
import (
"context"
"fmt"
"os"
"sync"
@ -106,7 +107,6 @@ type Store struct {
panicHandler PanicHandler
eventLoop *eventLoop
user BridgeUser
clientManager ClientManager
log *logrus.Entry
@ -127,13 +127,12 @@ func New( // nolint[funlen]
sentryReporter *sentry.Reporter,
panicHandler PanicHandler,
user BridgeUser,
clientManager ClientManager,
events listener.Listener,
path string,
cache *Cache,
) (store *Store, err error) {
if user == nil || clientManager == nil || events == nil || cache == nil {
return nil, fmt.Errorf("missing parameters - user: %v, api: %v, events: %v, cache: %v", user, clientManager, events, cache)
if user == nil || events == nil || cache == nil {
return nil, fmt.Errorf("missing parameters - user: %v, events: %v, cache: %v", user, events, cache)
}
l := log.WithField("user", user.ID())
@ -156,7 +155,6 @@ func New( // nolint[funlen]
store = &Store{
sentryReporter: sentryReporter,
panicHandler: panicHandler,
clientManager: clientManager,
user: user,
cache: cache,
filePath: path,
@ -274,13 +272,13 @@ func (store *Store) init(firstInit bool) (err error) {
}
func (store *Store) client() pmapi.Client {
return store.clientManager.GetClient(store.UserID())
return store.user.GetClient()
}
// initCounts initialises the counts for each label. It tries to use the API first to fetch the labels but if
// the API is unavailable for whatever reason it tries to fetch the labels locally.
func (store *Store) initCounts() (labels []*pmapi.Label, err error) {
if labels, err = store.client().ListLabels(); err != nil {
if labels, err = store.client().ListLabels(context.TODO()); err != nil {
store.log.WithError(err).Warn("Could not list API labels. Trying with local labels.")
if labels, err = store.getLabelsFromLocalStorage(); err != nil {
store.log.WithError(err).Error("Cannot list local labels")

View File

@ -18,6 +18,7 @@
package store
import (
"context"
"fmt"
"io/ioutil"
"os"
@ -133,7 +134,6 @@ type mocksForStore struct {
events *storemocks.MockListener
user *storemocks.MockBridgeUser
client *pmapimocks.MockClient
clientManager *storemocks.MockClientManager
panicHandler *storemocks.MockPanicHandler
changeNotifier *storemocks.MockChangeNotifier
store *Store
@ -150,7 +150,6 @@ func initMocks(tb testing.TB) (*mocksForStore, func()) {
events: storemocks.NewMockListener(ctrl),
user: storemocks.NewMockBridgeUser(ctrl),
client: pmapimocks.NewMockClient(ctrl),
clientManager: storemocks.NewMockClientManager(ctrl),
panicHandler: storemocks.NewMockPanicHandler(ctrl),
changeNotifier: storemocks.NewMockChangeNotifier(ctrl),
}
@ -182,30 +181,30 @@ func (mocks *mocksForStore) newStoreNoEvents(combinedMode bool, msgs ...*pmapi.M
mocks.user.EXPECT().IsConnected().Return(true)
mocks.user.EXPECT().IsCombinedAddressMode().Return(combinedMode)
mocks.clientManager.EXPECT().GetClient("userID").AnyTimes().Return(mocks.client)
mocks.user.EXPECT().GetClient().AnyTimes().Return(mocks.client)
mocks.client.EXPECT().Addresses().Return(pmapi.AddressList{
{ID: addrID1, Email: addr1, Type: pmapi.OriginalAddress, Receive: pmapi.CanReceive},
{ID: addrID2, Email: addr2, Type: pmapi.AliasAddress, Receive: pmapi.CanReceive},
})
mocks.client.EXPECT().ListLabels().AnyTimes()
mocks.client.EXPECT().CountMessages("")
mocks.client.EXPECT().ListLabels(gomock.Any()).AnyTimes()
mocks.client.EXPECT().CountMessages(gomock.Any(), "")
// Call to get latest event ID and then to process first event.
eventAfterSyncRequested := make(chan struct{})
mocks.client.EXPECT().GetEvent("").Return(&pmapi.Event{
mocks.client.EXPECT().GetEvent(gomock.Any(), "").Return(&pmapi.Event{
EventID: "firstEventID",
}, nil)
mocks.client.EXPECT().GetEvent("firstEventID").DoAndReturn(func(_ string) (*pmapi.Event, error) {
mocks.client.EXPECT().GetEvent(gomock.Any(), "firstEventID").DoAndReturn(func(_ context.Context, _ string) (*pmapi.Event, error) {
close(eventAfterSyncRequested)
return &pmapi.Event{
EventID: "latestEventID",
}, nil
})
mocks.client.EXPECT().ListMessages(gomock.Any()).Return(msgs, len(msgs), nil).AnyTimes()
mocks.client.EXPECT().ListMessages(gomock.Any(), gomock.Any()).Return(msgs, len(msgs), nil).AnyTimes()
for _, msg := range msgs {
mocks.client.EXPECT().GetMessage(msg.ID).Return(msg, nil).AnyTimes()
mocks.client.EXPECT().GetMessage(gomock.Any(), msg.ID).Return(msg, nil).AnyTimes()
}
var err error
@ -213,7 +212,6 @@ func (mocks *mocksForStore) newStoreNoEvents(combinedMode bool, msgs ...*pmapi.M
nil, // Sentry reporter is not used under unit tests.
mocks.panicHandler,
mocks.user,
mocks.clientManager,
mocks.events,
filepath.Join(mocks.tmpDir, "mailbox-test.db"),
mocks.cache,

View File

@ -18,6 +18,7 @@
package store
import (
"context"
"math"
"sync"
@ -39,10 +40,10 @@ type storeSynchronizer interface {
}
type messageLister interface {
ListMessages(*pmapi.MessagesFilter) ([]*pmapi.Message, int, error)
ListMessages(context.Context, *pmapi.MessagesFilter) ([]*pmapi.Message, int, error)
}
func syncAllMail(panicHandler PanicHandler, store storeSynchronizer, api func() messageLister, syncState *syncState) error {
func syncAllMail(panicHandler PanicHandler, store storeSynchronizer, api messageLister, syncState *syncState) error {
labelID := pmapi.AllMailLabel
// When the full sync starts (i.e. is not already in progress), we need to load
@ -53,7 +54,7 @@ func syncAllMail(panicHandler PanicHandler, store storeSynchronizer, api func()
return errors.Wrap(err, "failed to load message IDs")
}
if err := findIDRanges(labelID, api(), syncState); err != nil {
if err := findIDRanges(labelID, api, syncState); err != nil {
return errors.Wrap(err, "failed to load IDs ranges")
}
syncState.save()
@ -71,7 +72,7 @@ func syncAllMail(panicHandler PanicHandler, store storeSynchronizer, api func()
defer panicHandler.HandlePanic()
defer wg.Done()
err := syncBatch(labelID, store, api(), syncState, idRange, &shouldStop)
err := syncBatch(labelID, store, api, syncState, idRange, &shouldStop)
if err != nil {
shouldStop = 1
resultError = errors.Wrap(err, "failed to sync group")
@ -147,7 +148,7 @@ func getSplitIDAndCount(labelID string, api messageLister, page int) (string, in
Limit: 1,
}
// If the page does not exist, an empty page instead of an error is returned.
messages, total, err := api.ListMessages(filter)
messages, total, err := api.ListMessages(context.TODO(), filter)
if err != nil {
return "", 0, errors.Wrap(err, "failed to list messages")
}
@ -189,7 +190,7 @@ func syncBatch( //nolint[funlen]
log.WithField("begin", filter.BeginID).WithField("end", filter.EndID).Debug("Fetching page")
messages, _, err := api.ListMessages(filter)
messages, _, err := api.ListMessages(context.TODO(), filter)
if err != nil {
return errors.Wrap(err, "failed to list messages")
}

View File

@ -18,6 +18,7 @@
package store
import (
"context"
"sort"
"strconv"
"sync"
@ -34,7 +35,7 @@ type mockLister struct {
messageIDs []string
}
func (m *mockLister) ListMessages(filter *pmapi.MessagesFilter) (msgs []*pmapi.Message, total int, err error) {
func (m *mockLister) ListMessages(_ context.Context, filter *pmapi.MessagesFilter) (msgs []*pmapi.Message, total int, err error) {
if m.err != nil {
return nil, 0, m.err
}
@ -197,7 +198,7 @@ func TestSyncAllMail(t *testing.T) { //nolint[funlen]
syncState := newSyncState(store, 0, tc.idRanges, tc.idsToBeDeleted)
err := syncAllMail(m.panicHandler, store, func() messageLister { return api }, syncState)
err := syncAllMail(m.panicHandler, store, api, syncState)
require.Nil(t, err)
// Check all messages were created or updated.
@ -245,7 +246,7 @@ func TestSyncAllMail_FailedListing(t *testing.T) {
}
syncState := newTestSyncState(store)
err := syncAllMail(m.panicHandler, store, func() messageLister { return api }, syncState)
err := syncAllMail(m.panicHandler, store, api, syncState)
require.EqualError(t, err, "failed to sync group: failed to list messages: error")
}
@ -264,7 +265,7 @@ func TestSyncAllMail_FailedCreateOrUpdateMessage(t *testing.T) {
}
syncState := newTestSyncState(store)
err := syncAllMail(m.panicHandler, store, func() messageLister { return api }, syncState)
err := syncAllMail(m.panicHandler, store, api, syncState)
require.EqualError(t, err, "failed to sync group: failed to create or update messages: error")
}

View File

@ -23,10 +23,6 @@ type PanicHandler interface {
HandlePanic()
}
type ClientManager interface {
GetClient(userID string) pmapi.Client
}
// BridgeUser is subset of bridge.User for use by the Store.
type BridgeUser interface {
ID() string
@ -35,6 +31,7 @@ type BridgeUser interface {
IsCombinedAddressMode() bool
GetPrimaryAddress() string
GetStoreAddresses() []string
GetClient() pmapi.Client
UpdateUser() error
CloseAllConnections()
CloseConnection(string)

View File

@ -17,6 +17,8 @@
package store
import "context"
// UserID returns user ID.
func (store *Store) UserID() string {
return store.user.ID()
@ -24,7 +26,7 @@ func (store *Store) UserID() string {
// GetSpace returns used and total space in bytes.
func (store *Store) GetSpace() (usedSpace, maxSpace uint, err error) {
apiUser, err := store.client().CurrentUser()
apiUser, err := store.client().CurrentUser(context.TODO())
if err != nil {
return 0, 0, err
}
@ -33,7 +35,7 @@ func (store *Store) GetSpace() (usedSpace, maxSpace uint, err error) {
// GetMaxUpload returns max size of message + all attachments in bytes.
func (store *Store) GetMaxUpload() (int64, error) {
apiUser, err := store.client().CurrentUser()
apiUser, err := store.client().CurrentUser(context.TODO())
if err != nil {
return 0, err
}

View File

@ -18,6 +18,7 @@
package store
import (
"context"
"fmt"
"strings"
@ -55,7 +56,7 @@ func (store *Store) createMailbox(name string) error {
return nil
}
_, err := store.client().CreateLabel(&pmapi.Label{
_, err := store.client().CreateLabel(context.TODO(), &pmapi.Label{
Name: name,
Color: color,
Exclusive: exclusive,
@ -125,7 +126,7 @@ func (store *Store) leastUsedColor() string {
func (store *Store) updateMailbox(labelID, newName, color string) error {
defer store.eventLoop.pollNow()
_, err := store.client().UpdateLabel(&pmapi.Label{
_, err := store.client().UpdateLabel(context.TODO(), &pmapi.Label{
ID: labelID,
Name: newName,
Color: color,
@ -142,15 +143,15 @@ func (store *Store) deleteMailbox(labelID, addressID string) error {
var err error
switch labelID {
case pmapi.SpamLabel:
err = store.client().EmptyFolder(pmapi.SpamLabel, addressID)
err = store.client().EmptyFolder(context.TODO(), pmapi.SpamLabel, addressID)
case pmapi.TrashLabel:
err = store.client().EmptyFolder(pmapi.TrashLabel, addressID)
err = store.client().EmptyFolder(context.TODO(), pmapi.TrashLabel, addressID)
default:
err = fmt.Errorf("cannot empty mailbox %v", labelID)
}
return err
}
return store.client().DeleteLabel(labelID)
return store.client().DeleteLabel(context.TODO(), labelID)
}
func (store *Store) createLabelsIfMissing(affectedLabelIDs map[string]bool) error {
@ -165,7 +166,7 @@ func (store *Store) createLabelsIfMissing(affectedLabelIDs map[string]bool) erro
return nil
}
labels, err := store.client().ListLabels()
labels, err := store.client().ListLabels(context.TODO())
if err != nil {
return err
}

View File

@ -19,6 +19,7 @@ package store
import (
"bytes"
"context"
"encoding/json"
"io"
"io/ioutil"
@ -57,7 +58,7 @@ func (store *Store) CreateDraft(
}
draftAction := store.getDraftAction(message)
draft, err := store.client().CreateDraft(message, parentID, draftAction)
draft, err := store.client().CreateDraft(context.TODO(), message, parentID, draftAction)
if err != nil {
return nil, nil, errors.Wrap(err, "failed to create draft")
}
@ -69,7 +70,7 @@ func (store *Store) CreateDraft(
for _, att := range attachments {
att.attachment.MessageID = draft.ID
createdAttachment, err := store.client().CreateAttachment(att.attachment, att.encReader, att.sigReader)
createdAttachment, err := store.client().CreateAttachment(context.TODO(), att.attachment, att.encReader, att.sigReader)
if err != nil {
return nil, nil, errors.Wrap(err, "failed to create attachment")
}
@ -183,7 +184,7 @@ func (store *Store) getDraftAction(message *pmapi.Message) int {
// SendMessage sends the message.
func (store *Store) SendMessage(messageID string, req *pmapi.SendMessageReq) error {
defer store.eventLoop.pollNow()
_, _, err := store.client().SendMessage(messageID, req)
_, _, err := store.client().SendMessage(context.TODO(), messageID, req)
return err
}

View File

@ -127,12 +127,12 @@ func TestDeleteMessage(t *testing.T) {
checkMailboxMessageIDs(t, m, pmapi.AllMailLabel, []wantID{{"msg2", 2}})
}
func insertMessage(t *testing.T, m *mocksForStore, id, subject, sender string, unread int, labelIDs []string) { //nolint[unparam]
func insertMessage(t *testing.T, m *mocksForStore, id, subject, sender string, unread pmapi.Boolean, labelIDs []string) { //nolint[unparam]
msg := getTestMessage(id, subject, sender, unread, labelIDs)
require.Nil(t, m.store.createOrUpdateMessageEvent(msg))
}
func getTestMessage(id, subject, sender string, unread int, labelIDs []string) *pmapi.Message {
func getTestMessage(id, subject, sender string, unread pmapi.Boolean, labelIDs []string) *pmapi.Message {
address := &mail.Address{Address: sender}
return &pmapi.Message{
ID: id,

View File

@ -18,6 +18,7 @@
package store
import (
"context"
"encoding/json"
"fmt"
"strconv"
@ -34,7 +35,7 @@ const syncIDsToBeDeletedKey = "ids_to_be_deleted"
// updateCountsFromServer will download and set the counts.
func (store *Store) updateCountsFromServer() error {
counts, err := store.client().CountMessages("")
counts, err := store.client().CountMessages(context.TODO(), "")
if err != nil {
return errors.Wrap(err, "cannot update counts from server")
}
@ -152,7 +153,7 @@ func (store *Store) triggerSync() {
store.log.WithField("isIncomplete", syncState.isIncomplete()).Info("Store sync started")
err := syncAllMail(store.panicHandler, store, func() messageLister { return store.client() }, syncState)
err := syncAllMail(store.panicHandler, store, store.client(), syncState)
if err != nil {
log.WithError(err).Error("Store sync failed")
store.syncCooldown.increaseWaitTime()