cache: fetch flags from UI
When cached headers are fetched, an action is posted back to the Worker to immediately fetch the flags for the message from the server (we can't know the flags state, therefore it's not cached). When scrolling, a lag occurs when loading cached headers because the n+1 message has to wait for the flag request to return before the cached headers are retrieved. Collect the message UIDs in the UI that need flags, and fetch them based off a debounce timer in a single request. Post the action from the UI to eliminate an (ugly) go routine in the worker. Signed-off-by: Tim Culverhouse <tim@timculverhouse.com> Acked-by: Robin Jarry <robin@jarry.cc>
This commit is contained in:
parent
a91009edf7
commit
9fdc7acf5b
3 changed files with 29 additions and 11 deletions
|
@ -48,6 +48,10 @@ type MessageStore struct {
|
|||
pendingHeaders map[uint32]interface{}
|
||||
worker *types.Worker
|
||||
|
||||
needsFlags []uint32
|
||||
fetchFlagsDebounce *time.Timer
|
||||
fetchFlagsDelay time.Duration
|
||||
|
||||
triggerNewEmail func(*models.MessageInfo)
|
||||
triggerDirectoryChange func()
|
||||
|
||||
|
@ -91,6 +95,9 @@ func NewMessageStore(worker *types.Worker,
|
|||
pendingHeaders: make(map[uint32]interface{}),
|
||||
worker: worker,
|
||||
|
||||
needsFlags: []uint32{},
|
||||
fetchFlagsDelay: 50 * time.Millisecond,
|
||||
|
||||
triggerNewEmail: triggerNewEmail,
|
||||
triggerDirectoryChange: triggerDirectoryChange,
|
||||
|
||||
|
@ -251,6 +258,10 @@ func (store *MessageStore) Update(msg types.WorkerMessage) {
|
|||
} else if msg.Info.Envelope != nil {
|
||||
store.Messages[msg.Info.Uid] = msg.Info
|
||||
}
|
||||
if msg.NeedsFlags {
|
||||
store.needsFlags = append(store.needsFlags, msg.Info.Uid)
|
||||
store.fetchFlags()
|
||||
}
|
||||
seen := false
|
||||
recent := false
|
||||
for _, flag := range msg.Info.Flags {
|
||||
|
@ -752,3 +763,15 @@ func (store *MessageStore) Capabilities() *models.Capabilities {
|
|||
func (store *MessageStore) SelectedIndex() int {
|
||||
return store.FindIndexByUid(store.selectedUid)
|
||||
}
|
||||
|
||||
func (store *MessageStore) fetchFlags() {
|
||||
if store.fetchFlagsDebounce != nil {
|
||||
store.fetchFlagsDebounce.Stop()
|
||||
}
|
||||
store.fetchFlagsDebounce = time.AfterFunc(store.fetchFlagsDelay, func() {
|
||||
store.worker.PostAction(&types.FetchMessageFlags{
|
||||
Uids: store.needsFlags,
|
||||
}, nil)
|
||||
store.needsFlags = []uint32{}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -85,7 +85,7 @@ func (w *IMAPWorker) cacheHeader(mi *models.MessageInfo) {
|
|||
|
||||
func (w *IMAPWorker) getCachedHeaders(msg *types.FetchMessageHeaders) []uint32 {
|
||||
logging.Debugf("Retrieving headers from cache: %v", msg.Uids)
|
||||
var need, found []uint32
|
||||
var need []uint32
|
||||
uv := fmt.Sprintf("%d", w.selected.UidValidity)
|
||||
for _, uid := range msg.Uids {
|
||||
u := fmt.Sprintf("%d", uid)
|
||||
|
@ -118,17 +118,11 @@ func (w *IMAPWorker) getCachedHeaders(msg *types.FetchMessageHeaders) []uint32 {
|
|||
Uid: ch.Uid,
|
||||
RFC822Headers: hdr,
|
||||
}
|
||||
found = append(found, uid)
|
||||
logging.Debugf("located cached header %s.%s", uv, u)
|
||||
w.worker.PostMessage(&types.MessageInfo{
|
||||
Message: types.RespondTo(msg),
|
||||
Info: mi,
|
||||
}, nil)
|
||||
}
|
||||
if len(found) > 0 {
|
||||
// Post in a separate goroutine to prevent deadlocking
|
||||
go w.worker.PostAction(&types.FetchMessageFlags{
|
||||
Uids: found,
|
||||
NeedsFlags: true,
|
||||
}, nil)
|
||||
}
|
||||
return need
|
||||
|
|
|
@ -213,6 +213,7 @@ type SearchResults struct {
|
|||
type MessageInfo struct {
|
||||
Message
|
||||
Info *models.MessageInfo
|
||||
NeedsFlags bool
|
||||
}
|
||||
|
||||
type FullMessage struct {
|
||||
|
|
Loading…
Reference in a new issue