From 91529df0fecc68d5b0fdbb682529ee545884e7c5 Mon Sep 17 00:00:00 2001 From: Ben Burwell Date: Wed, 3 Jul 2019 16:10:16 -0400 Subject: Factor UI models out of the worker message package Before, the information needed to display different parts of the UI was tightly coupled to the specific messages being sent back and forth to the backend worker. Separating out a models package allows us to be more specific about exactly what a backend is able to and required to provide for the UI. --- lib/indexformat.go | 4 ++-- lib/msgstore.go | 31 ++++++++++++++++--------------- models/models.go | 32 ++++++++++++++++++++++++++++++++ widgets/account.go | 3 ++- widgets/msglist.go | 4 ++-- widgets/msgviewer.go | 18 +++++++++--------- widgets/providesmessage.go | 4 ++-- worker/imap/fetch.go | 41 ++++++++++++++++++++++++++--------------- worker/imap/worker.go | 13 ++++++++----- worker/types/messages.go | 16 ++++------------ 10 files changed, 103 insertions(+), 63 deletions(-) create mode 100644 models/models.go diff --git a/lib/indexformat.go b/lib/indexformat.go index 9e7a805..43d2ef8 100644 --- a/lib/indexformat.go +++ b/lib/indexformat.go @@ -9,11 +9,11 @@ import ( "github.com/emersion/go-imap" "git.sr.ht/~sircmpwn/aerc/config" - "git.sr.ht/~sircmpwn/aerc/worker/types" + "git.sr.ht/~sircmpwn/aerc/models" ) func ParseIndexFormat(conf *config.AercConfig, number int, - msg *types.MessageInfo) (string, []interface{}, error) { + msg *models.MessageInfo) (string, []interface{}, error) { format := conf.Ui.IndexFormat retval := make([]byte, 0, len(format)) diff --git a/lib/msgstore.go b/lib/msgstore.go index 09cf31f..19f328d 100644 --- a/lib/msgstore.go +++ b/lib/msgstore.go @@ -6,6 +6,7 @@ import ( "github.com/emersion/go-imap" + "git.sr.ht/~sircmpwn/aerc/models" "git.sr.ht/~sircmpwn/aerc/worker/types" ) @@ -13,7 +14,7 @@ import ( type MessageStore struct { Deleted map[uint32]interface{} DirInfo types.DirectoryInfo - Messages map[uint32]*types.MessageInfo + Messages map[uint32]*models.MessageInfo // Ordered list of known UIDs Uids []uint32 @@ -106,11 +107,11 @@ func (store *MessageStore) FetchBodyPart( if !ok { return } - cb(msg.Reader) + cb(msg.Part.Reader) }) } -func merge(to *types.MessageInfo, from *types.MessageInfo) { +func merge(to *models.MessageInfo, from *models.MessageInfo) { if from.BodyStructure != nil { to.BodyStructure = from.BodyStructure } @@ -135,7 +136,7 @@ func (store *MessageStore) Update(msg types.WorkerMessage) { store.worker.PostAction(&types.FetchDirectoryContents{}, nil) update = true case *types.DirectoryContents: - newMap := make(map[uint32]*types.MessageInfo) + newMap := make(map[uint32]*models.MessageInfo) for _, uid := range msg.Uids { if msg, ok := store.Messages[uid]; ok { newMap[uid] = msg @@ -147,14 +148,14 @@ func (store *MessageStore) Update(msg types.WorkerMessage) { store.Uids = msg.Uids update = true case *types.MessageInfo: - if existing, ok := store.Messages[msg.Uid]; ok && existing != nil { - merge(existing, msg) + if existing, ok := store.Messages[msg.Info.Uid]; ok && existing != nil { + merge(existing, msg.Info) } else { - store.Messages[msg.Uid] = msg + store.Messages[msg.Info.Uid] = msg.Info } - if _, ok := store.pendingHeaders[msg.Uid]; msg.Envelope != nil && ok { - delete(store.pendingHeaders, msg.Uid) - if cbs, ok := store.headerCallbacks[msg.Uid]; ok { + if _, ok := store.pendingHeaders[msg.Info.Uid]; msg.Info.Envelope != nil && ok { + delete(store.pendingHeaders, msg.Info.Uid) + if cbs, ok := store.headerCallbacks[msg.Info.Uid]; ok { for _, cb := range cbs { cb(msg) } @@ -162,11 +163,11 @@ func (store *MessageStore) Update(msg types.WorkerMessage) { } update = true case *types.FullMessage: - if _, ok := store.pendingBodies[msg.Uid]; ok { - delete(store.pendingBodies, msg.Uid) - if cbs, ok := store.bodyCallbacks[msg.Uid]; ok { + if _, ok := store.pendingBodies[msg.Content.Uid]; ok { + delete(store.pendingBodies, msg.Content.Uid) + if cbs, ok := store.bodyCallbacks[msg.Content.Uid]; ok { for _, cb := range cbs { - cb(msg.Reader) + cb(msg.Content.Reader) } } } @@ -283,7 +284,7 @@ func (store *MessageStore) Read(uids []uint32, read bool, }, cb) } -func (store *MessageStore) Selected() *types.MessageInfo { +func (store *MessageStore) Selected() *models.MessageInfo { return store.Messages[store.Uids[len(store.Uids)-store.selected-1]] } diff --git a/models/models.go b/models/models.go new file mode 100644 index 0000000..00297e9 --- /dev/null +++ b/models/models.go @@ -0,0 +1,32 @@ +package models + +import ( + "io" + "time" + + "github.com/emersion/go-imap" + "github.com/emersion/go-message/mail" +) + +// A MessageInfo holds information about the structure of a message +type MessageInfo struct { + BodyStructure *imap.BodyStructure + Envelope *imap.Envelope + Flags []string + InternalDate time.Time + RFC822Headers *mail.Header + Size uint32 + Uid uint32 +} + +// A MessageBodyPart can be displayed in the message viewer +type MessageBodyPart struct { + Reader io.Reader + Uid uint32 +} + +// A FullMessage is the entire message +type FullMessage struct { + Reader io.Reader + Uid uint32 +} diff --git a/widgets/account.go b/widgets/account.go index 824f958..ae0cf56 100644 --- a/widgets/account.go +++ b/widgets/account.go @@ -9,6 +9,7 @@ import ( "git.sr.ht/~sircmpwn/aerc/config" "git.sr.ht/~sircmpwn/aerc/lib" "git.sr.ht/~sircmpwn/aerc/lib/ui" + "git.sr.ht/~sircmpwn/aerc/models" "git.sr.ht/~sircmpwn/aerc/worker" "git.sr.ht/~sircmpwn/aerc/worker/types" ) @@ -165,7 +166,7 @@ func (acct *AccountView) Store() *lib.MessageStore { return acct.msglist.Store() } -func (acct *AccountView) SelectedMessage() *types.MessageInfo { +func (acct *AccountView) SelectedMessage() *models.MessageInfo { return acct.msglist.Selected() } diff --git a/widgets/msglist.go b/widgets/msglist.go index 211cbce..7051478 100644 --- a/widgets/msglist.go +++ b/widgets/msglist.go @@ -11,7 +11,7 @@ import ( "git.sr.ht/~sircmpwn/aerc/config" "git.sr.ht/~sircmpwn/aerc/lib" "git.sr.ht/~sircmpwn/aerc/lib/ui" - "git.sr.ht/~sircmpwn/aerc/worker/types" + "git.sr.ht/~sircmpwn/aerc/models" ) type MessageList struct { @@ -176,7 +176,7 @@ func (ml *MessageList) Empty() bool { return store == nil || len(store.Uids) == 0 } -func (ml *MessageList) Selected() *types.MessageInfo { +func (ml *MessageList) Selected() *models.MessageInfo { store := ml.Store() return store.Messages[store.Uids[len(store.Uids)-ml.store.SelectedIndex()-1]] } diff --git a/widgets/msgviewer.go b/widgets/msgviewer.go index 10c2182..49b4dd4 100644 --- a/widgets/msgviewer.go +++ b/widgets/msgviewer.go @@ -20,7 +20,7 @@ import ( "git.sr.ht/~sircmpwn/aerc/config" "git.sr.ht/~sircmpwn/aerc/lib" "git.sr.ht/~sircmpwn/aerc/lib/ui" - "git.sr.ht/~sircmpwn/aerc/worker/types" + "git.sr.ht/~sircmpwn/aerc/models" ) var ansi = regexp.MustCompile("^\x1B\\[[0-?]*[ -/]*[@-~]") @@ -31,7 +31,7 @@ type MessageViewer struct { conf *config.AercConfig err error grid *ui.Grid - msg *types.MessageInfo + msg *models.MessageInfo switcher *PartSwitcher store *lib.MessageStore } @@ -44,7 +44,7 @@ type PartSwitcher struct { } func NewMessageViewer(acct *AccountView, conf *config.AercConfig, - store *lib.MessageStore, msg *types.MessageInfo) *MessageViewer { + store *lib.MessageStore, msg *models.MessageInfo) *MessageViewer { grid := ui.NewGrid().Rows([]ui.GridSpec{ {ui.SIZE_EXACT, 4}, // TODO: Based on number of header rows @@ -112,7 +112,7 @@ handle_error: } func enumerateParts(conf *config.AercConfig, store *lib.MessageStore, - msg *types.MessageInfo, body *imap.BodyStructure, + msg *models.MessageInfo, body *imap.BodyStructure, showHeaders bool, index []int) ([]*PartViewer, error) { var parts []*PartViewer @@ -140,7 +140,7 @@ func enumerateParts(conf *config.AercConfig, store *lib.MessageStore, } func createSwitcher(switcher *PartSwitcher, conf *config.AercConfig, - store *lib.MessageStore, msg *types.MessageInfo, showHeaders bool) error { + store *lib.MessageStore, msg *models.MessageInfo, showHeaders bool) error { var err error switcher.showHeaders = showHeaders @@ -212,7 +212,7 @@ func (mv *MessageViewer) SelectedAccount() *AccountView { return mv.acct } -func (mv *MessageViewer) SelectedMessage() *types.MessageInfo { +func (mv *MessageViewer) SelectedMessage() *models.MessageInfo { return mv.msg } @@ -321,7 +321,7 @@ type PartViewer struct { fetched bool filter *exec.Cmd index []int - msg *types.MessageInfo + msg *models.MessageInfo pager *exec.Cmd pagerin io.WriteCloser part *imap.BodyStructure @@ -334,13 +334,13 @@ type PartViewer struct { type PartInfo struct { Index []int - Msg *types.MessageInfo + Msg *models.MessageInfo Part *imap.BodyStructure Store *lib.MessageStore } func NewPartViewer(conf *config.AercConfig, - store *lib.MessageStore, msg *types.MessageInfo, + store *lib.MessageStore, msg *models.MessageInfo, part *imap.BodyStructure, showHeaders bool, index []int) (*PartViewer, error) { diff --git a/widgets/providesmessage.go b/widgets/providesmessage.go index 7be8e7e..cff546b 100644 --- a/widgets/providesmessage.go +++ b/widgets/providesmessage.go @@ -3,12 +3,12 @@ package widgets import ( "git.sr.ht/~sircmpwn/aerc/lib" "git.sr.ht/~sircmpwn/aerc/lib/ui" - "git.sr.ht/~sircmpwn/aerc/worker/types" + "git.sr.ht/~sircmpwn/aerc/models" ) type ProvidesMessage interface { ui.Drawable Store() *lib.MessageStore - SelectedMessage() *types.MessageInfo + SelectedMessage() *models.MessageInfo SelectedAccount() *AccountView } diff --git a/worker/imap/fetch.go b/worker/imap/fetch.go index 7d1bfcf..d5bb9aa 100644 --- a/worker/imap/fetch.go +++ b/worker/imap/fetch.go @@ -8,6 +8,7 @@ import ( "github.com/emersion/go-message/mail" "github.com/emersion/go-message/textproto" + "git.sr.ht/~sircmpwn/aerc/models" "git.sr.ht/~sircmpwn/aerc/worker/types" ) @@ -82,39 +83,49 @@ func (imapw *IMAPWorker) handleFetchMessages( header = &mail.Header{message.Header{textprotoHeader}} } imapw.worker.PostMessage(&types.MessageInfo{ - Message: types.RespondTo(msg), - BodyStructure: _msg.BodyStructure, - Envelope: _msg.Envelope, - Flags: _msg.Flags, - InternalDate: _msg.InternalDate, - RFC822Headers: header, - Uid: _msg.Uid, + Message: types.RespondTo(msg), + Info: &models.MessageInfo{ + BodyStructure: _msg.BodyStructure, + Envelope: _msg.Envelope, + Flags: _msg.Flags, + InternalDate: _msg.InternalDate, + RFC822Headers: header, + Uid: _msg.Uid, + }, }, nil) case *types.FetchFullMessages: reader := _msg.GetBody(section) imapw.worker.PostMessage(&types.FullMessage{ Message: types.RespondTo(msg), - Reader: reader, - Uid: _msg.Uid, + Content: &models.FullMessage{ + Reader: reader, + Uid: _msg.Uid, + }, }, nil) // Update flags (to mark message as read) imapw.worker.PostMessage(&types.MessageInfo{ Message: types.RespondTo(msg), - Flags: _msg.Flags, - Uid: _msg.Uid, + Info: &models.MessageInfo{ + Flags: _msg.Flags, + Uid: _msg.Uid, + }, }, nil) case *types.FetchMessageBodyPart: reader := _msg.GetBody(section) imapw.worker.PostMessage(&types.MessageBodyPart{ Message: types.RespondTo(msg), - Reader: reader, - Uid: _msg.Uid, + Part: &models.MessageBodyPart{ + Reader: reader, + Uid: _msg.Uid, + }, }, nil) // Update flags (to mark message as read) imapw.worker.PostMessage(&types.MessageInfo{ Message: types.RespondTo(msg), - Flags: _msg.Flags, - Uid: _msg.Uid, + Info: &models.MessageInfo{ + Flags: _msg.Flags, + Uid: _msg.Uid, + }, }, nil) } } diff --git a/worker/imap/worker.go b/worker/imap/worker.go index 5005620..ff02a78 100644 --- a/worker/imap/worker.go +++ b/worker/imap/worker.go @@ -10,6 +10,7 @@ import ( idle "github.com/emersion/go-imap-idle" "github.com/emersion/go-imap/client" + "git.sr.ht/~sircmpwn/aerc/models" "git.sr.ht/~sircmpwn/aerc/worker/types" ) @@ -183,11 +184,13 @@ func (w *IMAPWorker) handleImapUpdate(update client.Update) { msg.Uid = w.seqMap[msg.SeqNum-1] } w.worker.PostMessage(&types.MessageInfo{ - BodyStructure: msg.BodyStructure, - Envelope: msg.Envelope, - Flags: msg.Flags, - InternalDate: msg.InternalDate, - Uid: msg.Uid, + Info: &models.MessageInfo{ + BodyStructure: msg.BodyStructure, + Envelope: msg.Envelope, + Flags: msg.Flags, + InternalDate: msg.InternalDate, + Uid: msg.Uid, + }, }, nil) case *client.ExpungeUpdate: i := update.SeqNum - 1 diff --git a/worker/types/messages.go b/worker/types/messages.go index d9e911f..7eac896 100644 --- a/worker/types/messages.go +++ b/worker/types/messages.go @@ -5,9 +5,9 @@ import ( "time" "github.com/emersion/go-imap" - "github.com/emersion/go-message/mail" "git.sr.ht/~sircmpwn/aerc/config" + "git.sr.ht/~sircmpwn/aerc/models" ) type WorkerMessage interface { @@ -164,25 +164,17 @@ type SearchResults struct { type MessageInfo struct { Message - BodyStructure *imap.BodyStructure - Envelope *imap.Envelope - Flags []string - InternalDate time.Time - RFC822Headers *mail.Header - Size uint32 - Uid uint32 + Info *models.MessageInfo } type FullMessage struct { Message - Reader io.Reader - Uid uint32 + Content *models.FullMessage } type MessageBodyPart struct { Message - Reader io.Reader - Uid uint32 + Part *models.MessageBodyPart } type MessagesDeleted struct { -- cgit v1.2.3