Move MessageStore into its own file
This commit is contained in:
parent
77c76ba462
commit
ef6178a12a
3 changed files with 93 additions and 86 deletions
86
lib/msgstore.go
Normal file
86
lib/msgstore.go
Normal 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
|
||||||
|
}
|
|
@ -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]
|
||||||
|
|
|
@ -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()
|
||||||
|
|
Loading…
Reference in a new issue