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{}
|
pendingHeaders map[uint32]interface{}
|
||||||
worker *types.Worker
|
worker *types.Worker
|
||||||
|
|
||||||
|
needsFlags []uint32
|
||||||
|
fetchFlagsDebounce *time.Timer
|
||||||
|
fetchFlagsDelay time.Duration
|
||||||
|
|
||||||
triggerNewEmail func(*models.MessageInfo)
|
triggerNewEmail func(*models.MessageInfo)
|
||||||
triggerDirectoryChange func()
|
triggerDirectoryChange func()
|
||||||
|
|
||||||
|
@ -91,6 +95,9 @@ func NewMessageStore(worker *types.Worker,
|
||||||
pendingHeaders: make(map[uint32]interface{}),
|
pendingHeaders: make(map[uint32]interface{}),
|
||||||
worker: worker,
|
worker: worker,
|
||||||
|
|
||||||
|
needsFlags: []uint32{},
|
||||||
|
fetchFlagsDelay: 50 * time.Millisecond,
|
||||||
|
|
||||||
triggerNewEmail: triggerNewEmail,
|
triggerNewEmail: triggerNewEmail,
|
||||||
triggerDirectoryChange: triggerDirectoryChange,
|
triggerDirectoryChange: triggerDirectoryChange,
|
||||||
|
|
||||||
|
@ -251,6 +258,10 @@ func (store *MessageStore) Update(msg types.WorkerMessage) {
|
||||||
} else if msg.Info.Envelope != nil {
|
} else if msg.Info.Envelope != nil {
|
||||||
store.Messages[msg.Info.Uid] = msg.Info
|
store.Messages[msg.Info.Uid] = msg.Info
|
||||||
}
|
}
|
||||||
|
if msg.NeedsFlags {
|
||||||
|
store.needsFlags = append(store.needsFlags, msg.Info.Uid)
|
||||||
|
store.fetchFlags()
|
||||||
|
}
|
||||||
seen := false
|
seen := false
|
||||||
recent := false
|
recent := false
|
||||||
for _, flag := range msg.Info.Flags {
|
for _, flag := range msg.Info.Flags {
|
||||||
|
@ -752,3 +763,15 @@ func (store *MessageStore) Capabilities() *models.Capabilities {
|
||||||
func (store *MessageStore) SelectedIndex() int {
|
func (store *MessageStore) SelectedIndex() int {
|
||||||
return store.FindIndexByUid(store.selectedUid)
|
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 {
|
func (w *IMAPWorker) getCachedHeaders(msg *types.FetchMessageHeaders) []uint32 {
|
||||||
logging.Debugf("Retrieving headers from cache: %v", msg.Uids)
|
logging.Debugf("Retrieving headers from cache: %v", msg.Uids)
|
||||||
var need, found []uint32
|
var need []uint32
|
||||||
uv := fmt.Sprintf("%d", w.selected.UidValidity)
|
uv := fmt.Sprintf("%d", w.selected.UidValidity)
|
||||||
for _, uid := range msg.Uids {
|
for _, uid := range msg.Uids {
|
||||||
u := fmt.Sprintf("%d", uid)
|
u := fmt.Sprintf("%d", uid)
|
||||||
|
@ -118,17 +118,11 @@ func (w *IMAPWorker) getCachedHeaders(msg *types.FetchMessageHeaders) []uint32 {
|
||||||
Uid: ch.Uid,
|
Uid: ch.Uid,
|
||||||
RFC822Headers: hdr,
|
RFC822Headers: hdr,
|
||||||
}
|
}
|
||||||
found = append(found, uid)
|
|
||||||
logging.Debugf("located cached header %s.%s", uv, u)
|
logging.Debugf("located cached header %s.%s", uv, u)
|
||||||
w.worker.PostMessage(&types.MessageInfo{
|
w.worker.PostMessage(&types.MessageInfo{
|
||||||
Message: types.RespondTo(msg),
|
Message: types.RespondTo(msg),
|
||||||
Info: mi,
|
Info: mi,
|
||||||
}, nil)
|
NeedsFlags: true,
|
||||||
}
|
|
||||||
if len(found) > 0 {
|
|
||||||
// Post in a separate goroutine to prevent deadlocking
|
|
||||||
go w.worker.PostAction(&types.FetchMessageFlags{
|
|
||||||
Uids: found,
|
|
||||||
}, nil)
|
}, nil)
|
||||||
}
|
}
|
||||||
return need
|
return need
|
||||||
|
|
|
@ -212,7 +212,8 @@ type SearchResults struct {
|
||||||
|
|
||||||
type MessageInfo struct {
|
type MessageInfo struct {
|
||||||
Message
|
Message
|
||||||
Info *models.MessageInfo
|
Info *models.MessageInfo
|
||||||
|
NeedsFlags bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type FullMessage struct {
|
type FullMessage struct {
|
||||||
|
|
Loading…
Reference in a new issue