Move MessageStore into its own file

This commit is contained in:
Drew DeVault 2019-03-15 21:36:06 -04:00
parent 77c76ba462
commit ef6178a12a
3 changed files with 93 additions and 86 deletions

86
lib/msgstore.go Normal file
View File

@ -0,0 +1,86 @@
package lib
import (
"github.com/emersion/go-imap"
"git.sr.ht/~sircmpwn/aerc2/worker/types"
)
type MessageStore struct {
DirInfo types.DirectoryInfo
Messages map[uint32]*types.MessageInfo
// Ordered list of known UIDs
Uids []uint32
// Map of uids we've asked the worker to fetch
onUpdate func(store *MessageStore)
pendingBodies map[uint32]interface{}
pendingHeaders map[uint32]interface{}
worker *types.Worker
}
func NewMessageStore(worker *types.Worker,
dirInfo *types.DirectoryInfo) *MessageStore {
return &MessageStore{
DirInfo: *dirInfo,
pendingBodies: make(map[uint32]interface{}),
pendingHeaders: make(map[uint32]interface{}),
worker: worker,
}
}
func (store *MessageStore) FetchHeaders(uids []uint32) {
// TODO: this could be optimized by pre-allocating toFetch and trimming it
// at the end. In practice we expect to get most messages back in one frame.
var toFetch imap.SeqSet
for _, uid := range uids {
if _, ok := store.pendingHeaders[uid]; !ok {
toFetch.AddNum(uint32(uid))
store.pendingHeaders[uid] = nil
}
}
if !toFetch.Empty() {
store.worker.PostAction(&types.FetchMessageHeaders{
Uids: toFetch,
}, nil)
}
}
func (store *MessageStore) Update(msg types.WorkerMessage) {
update := false
switch msg := msg.(type) {
case *types.DirectoryInfo:
store.DirInfo = *msg
update = true
break
case *types.DirectoryContents:
newMap := make(map[uint32]*types.MessageInfo)
for _, uid := range msg.Uids {
if msg, ok := store.Messages[uid]; ok {
newMap[uid] = msg
} else {
newMap[uid] = nil
}
}
store.Messages = newMap
store.Uids = msg.Uids
update = true
break
case *types.MessageInfo:
// TODO: merge message info into existing record, if applicable
store.Messages[msg.Uid] = msg
if _, ok := store.pendingHeaders[msg.Uid]; msg.Envelope != nil && ok {
delete(store.pendingHeaders, msg.Uid)
}
update = true
break
}
if update && store.onUpdate != nil {
store.onUpdate(store)
}
}
func (store *MessageStore) OnUpdate(fn func(store *MessageStore)) {
store.onUpdate = fn
}

View File

@ -8,6 +8,7 @@ import (
"github.com/gdamore/tcell" "github.com/gdamore/tcell"
"git.sr.ht/~sircmpwn/aerc2/config" "git.sr.ht/~sircmpwn/aerc2/config"
"git.sr.ht/~sircmpwn/aerc2/lib"
"git.sr.ht/~sircmpwn/aerc2/lib/ui" "git.sr.ht/~sircmpwn/aerc2/lib/ui"
"git.sr.ht/~sircmpwn/aerc2/worker" "git.sr.ht/~sircmpwn/aerc2/worker"
"git.sr.ht/~sircmpwn/aerc2/worker/types" "git.sr.ht/~sircmpwn/aerc2/worker/types"
@ -23,7 +24,7 @@ type AccountView struct {
onInvalidate func(d ui.Drawable) onInvalidate func(d ui.Drawable)
runCmd func(cmd string) error runCmd func(cmd string) error
msglist *MessageList msglist *MessageList
msgStores map[string]*MessageStore msgStores map[string]*lib.MessageStore
pendingKeys []config.KeyStroke pendingKeys []config.KeyStroke
statusline *StatusLine statusline *StatusLine
statusbar *ui.Stack statusbar *ui.Stack
@ -70,7 +71,7 @@ func NewAccountView(conf *config.AercConfig, acct *config.AccountConfig,
grid: grid, grid: grid,
logger: logger, logger: logger,
msglist: msglist, msglist: msglist,
msgStores: make(map[string]*MessageStore), msgStores: make(map[string]*lib.MessageStore),
runCmd: runCmd, runCmd: runCmd,
statusbar: statusbar, statusbar: statusbar,
statusline: statusline, statusline: statusline,
@ -226,7 +227,7 @@ func (acct *AccountView) onMessage(msg types.WorkerMessage) {
if store, ok := acct.msgStores[msg.Name]; ok { if store, ok := acct.msgStores[msg.Name]; ok {
store.Update(msg) store.Update(msg)
} else { } else {
acct.msgStores[msg.Name] = NewMessageStore(acct.worker, msg) acct.msgStores[msg.Name] = lib.NewMessageStore(acct.worker, msg)
} }
case *types.DirectoryContents: case *types.DirectoryContents:
store := acct.msgStores[acct.dirlist.selected] store := acct.msgStores[acct.dirlist.selected]

View File

@ -3,100 +3,20 @@ package widgets
import ( import (
"log" "log"
"github.com/emersion/go-imap"
"github.com/gdamore/tcell" "github.com/gdamore/tcell"
"git.sr.ht/~sircmpwn/aerc2/config" "git.sr.ht/~sircmpwn/aerc2/config"
"git.sr.ht/~sircmpwn/aerc2/lib"
"git.sr.ht/~sircmpwn/aerc2/lib/ui" "git.sr.ht/~sircmpwn/aerc2/lib/ui"
"git.sr.ht/~sircmpwn/aerc2/worker/types"
) )
type MessageStore struct {
DirInfo types.DirectoryInfo
Messages map[uint32]*types.MessageInfo
// Ordered list of known UIDs
Uids []uint32
// Map of uids we've asked the worker to fetch
onUpdate func(store *MessageStore)
pendingBodies map[uint32]interface{}
pendingHeaders map[uint32]interface{}
worker *types.Worker
}
func NewMessageStore(worker *types.Worker,
dirInfo *types.DirectoryInfo) *MessageStore {
return &MessageStore{
DirInfo: *dirInfo,
pendingBodies: make(map[uint32]interface{}),
pendingHeaders: make(map[uint32]interface{}),
worker: worker,
}
}
func (store *MessageStore) FetchHeaders(uids []uint32) {
// TODO: this could be optimized by pre-allocating toFetch and trimming it
// at the end. In practice we expect to get most messages back in one frame.
var toFetch imap.SeqSet
for _, uid := range uids {
if _, ok := store.pendingHeaders[uid]; !ok {
toFetch.AddNum(uint32(uid))
store.pendingHeaders[uid] = nil
}
}
if !toFetch.Empty() {
store.worker.PostAction(&types.FetchMessageHeaders{
Uids: toFetch,
}, nil)
}
}
func (store *MessageStore) Update(msg types.WorkerMessage) {
update := false
switch msg := msg.(type) {
case *types.DirectoryInfo:
store.DirInfo = *msg
update = true
break
case *types.DirectoryContents:
newMap := make(map[uint32]*types.MessageInfo)
for _, uid := range msg.Uids {
if msg, ok := store.Messages[uid]; ok {
newMap[uid] = msg
} else {
newMap[uid] = nil
}
}
store.Messages = newMap
store.Uids = msg.Uids
update = true
break
case *types.MessageInfo:
// TODO: merge message info into existing record, if applicable
store.Messages[msg.Uid] = msg
if _, ok := store.pendingHeaders[msg.Uid]; msg.Envelope != nil && ok {
delete(store.pendingHeaders, msg.Uid)
}
update = true
break
}
if update && store.onUpdate != nil {
store.onUpdate(store)
}
}
func (store *MessageStore) OnUpdate(fn func(store *MessageStore)) {
store.onUpdate = fn
}
type MessageList struct { type MessageList struct {
conf *config.AercConfig conf *config.AercConfig
logger *log.Logger logger *log.Logger
onInvalidate func(d ui.Drawable) onInvalidate func(d ui.Drawable)
selected int selected int
spinner *Spinner spinner *Spinner
store *MessageStore store *lib.MessageStore
} }
// TODO: fish in config // TODO: fish in config
@ -171,7 +91,7 @@ func (ml *MessageList) Draw(ctx *ui.Context) {
} }
} }
func (ml *MessageList) SetStore(store *MessageStore) { func (ml *MessageList) SetStore(store *lib.MessageStore) {
ml.store = store ml.store = store
if store != nil { if store != nil {
ml.spinner.Stop() ml.spinner.Stop()