fixed some performance issues when pulling a large amount of messages

Signed-off-by: Michael <michael.lindman@gmail.com>
This commit is contained in:
Michael 2022-01-20 17:11:43 +00:00
parent f12e865042
commit 6d4d7e3459
3 changed files with 26 additions and 52 deletions

2
go.mod
View File

@ -5,6 +5,6 @@ go 1.16
require ( require (
github.com/emersion/go-imap v1.2.0 github.com/emersion/go-imap v1.2.0
github.com/emersion/go-sasl v0.0.0-20211008083017-0b9dcfb154ac // indirect github.com/emersion/go-sasl v0.0.0-20211008083017-0b9dcfb154ac // indirect
golang.org/x/net v0.0.0-20211209124913-491a49abca63 golang.org/x/net v0.0.0-20220114011407-0dd24b26b47d
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
) )

View File

@ -3,11 +3,11 @@ package mail
import ( import (
"errors" "errors"
"fmt" "fmt"
"io"
"io/ioutil" "io/ioutil"
"log" "log"
"os" "os"
"strconv" "strconv"
"time"
"github.com/emersion/go-imap" "github.com/emersion/go-imap"
"github.com/emersion/go-imap/client" "github.com/emersion/go-imap/client"
@ -18,19 +18,6 @@ type Mail struct {
Client *client.Client Client *client.Client
} }
type Message struct {
SeqNum uint32
Subject string
To []*imap.Address
From []*imap.Address
Date time.Time
Body imap.Literal
}
type Messages struct {
Message []Message
}
type Conn struct { type Conn struct {
Addr string Addr string
Username string Username string
@ -76,20 +63,19 @@ func Login(conn Conn) (mail *Mail, err error) {
return mail, nil return mail, nil
} }
func (mail *Mail) GetMessages(mailbox string, msgs int32) (*Messages, error) { func (mail *Mail) GetMessages(mailbox string, path string) error {
var messages Messages
mbox, err := mail.Client.Select(mailbox, true) mbox, err := mail.Client.Select(mailbox, true)
if err != nil { if err != nil {
return nil, err return err
} }
if mbox.Messages == 0 { if mbox.Messages == 0 {
return nil, errors.New("no messages in mailbox") return errors.New("no messages in mailbox")
} }
seqSet := new(imap.SeqSet) seqSet := new(imap.SeqSet)
seqSet.AddRange(1, mbox.Messages) seqSet.AddRange(1, mbox.Messages)
var section imap.BodySectionName var section imap.BodySectionName
imapMessages := make(chan *imap.Message, msgs) imapMessages := make(chan *imap.Message, mbox.Messages)
done := make(chan error, 1) done := make(chan error, 1)
go func() { go func() {
done <- mail.Client.Fetch(seqSet, []imap.FetchItem{imap.FetchEnvelope, section.FetchItem()}, imapMessages) done <- mail.Client.Fetch(seqSet, []imap.FetchItem{imap.FetchEnvelope, section.FetchItem()}, imapMessages)
@ -98,33 +84,26 @@ func (mail *Mail) GetMessages(mailbox string, msgs int32) (*Messages, error) {
for msg := range imapMessages { for msg := range imapMessages {
body := msg.GetBody(&section) body := msg.GetBody(&section)
if body == nil { if body == nil {
return nil, errors.New("server didn't returned message body") return errors.New("server didn't returned message body")
} }
message := Message{ fmt.Println(msg.Envelope.Subject)
SeqNum: msg.SeqNum, if err := Write(path, msg, body); err != nil {
Subject: msg.Envelope.Subject, return err
To: msg.Envelope.To,
From: msg.Envelope.From,
Date: msg.Envelope.Date,
Body: body,
} }
messages.Message = append(messages.Message, message)
} }
if err := <-done; err != nil { if err := <-done; err != nil {
return nil, err
}
return &messages, nil
}
func WriteMessages(path string, messages *Messages) error {
for _, msg := range messages.Message {
body, err := ioutil.ReadAll(msg.Body)
if err != nil {
return err return err
} }
if err := ioutil.WriteFile(path+"/"+strconv.Itoa(int(msg.SeqNum))+"_"+msg.Date.String()+".eml", body, 0644); err != nil { return nil
return err }
}
} func Write(path string, msg *imap.Message, literal imap.Literal) error {
body, err := io.ReadAll(literal)
if err != nil {
return err
}
if err := ioutil.WriteFile(path+"/"+strconv.Itoa(int(msg.SeqNum))+"_"+msg.Envelope.Date.String()+".eml", body, 0644); err != nil {
return err
}
return nil return nil
} }

13
main.go
View File

@ -11,7 +11,7 @@ import (
) )
func main() { func main() {
cfgFile, mailbox, msgs := ui() cfgFile, mailbox := ui()
cfg := NewConfig(*cfgFile) cfg := NewConfig(*cfgFile)
chErr, chDone := make(chan error), make(chan bool) chErr, chDone := make(chan error), make(chan bool)
for _, account := range cfg.Account { for _, account := range cfg.Account {
@ -34,17 +34,13 @@ func main() {
} }
} }
defer conn.Client.Logout() defer conn.Client.Logout()
messages, err := conn.GetMessages(*mailbox, int32(*msgs))
if err != nil {
chErr <- err
}
path := cfg.Path + username + "/" + time.Now().Format("2006-01-02-15:04:05") path := cfg.Path + username + "/" + time.Now().Format("2006-01-02-15:04:05")
for _, p := range []string{cfg.Path + username, path} { for _, p := range []string{cfg.Path + username, path} {
if _, err := os.Stat(p); os.IsNotExist(err) { if _, err := os.Stat(p); os.IsNotExist(err) {
os.Mkdir(p, 0775) os.Mkdir(p, 0775)
} }
} }
if err := mail.WriteMessages(path, messages); err != nil { if err = conn.GetMessages(*mailbox, path); err != nil {
chErr <- err chErr <- err
} }
}(account.Addr, account.Username, account.Password, chErr, chDone) }(account.Addr, account.Username, account.Password, chErr, chDone)
@ -59,7 +55,7 @@ func main() {
} }
} }
func ui() (cfgFile, mailbox *string, msgs *int) { func ui() (cfgFile, mailbox *string) {
flag.Usage = func() { flag.Usage = func() {
fmt.Printf("Usage of %s:\n", os.Args[0]) fmt.Printf("Usage of %s:\n", os.Args[0])
flag.PrintDefaults() flag.PrintDefaults()
@ -70,8 +66,7 @@ func ui() (cfgFile, mailbox *string, msgs *int) {
} }
cfgFile = flag.String("cfgFile", home+"/.config/gomail/config.yaml", "path to config file") cfgFile = flag.String("cfgFile", home+"/.config/gomail/config.yaml", "path to config file")
mailbox = flag.String("mailbox", "inbox", "mailbox to scan messages") mailbox = flag.String("mailbox", "inbox", "mailbox to scan messages")
msgs = flag.Int("msgs", 100, "Number of messages to pull")
flag.Parse() flag.Parse()
return cfgFile, mailbox, msgs return cfgFile, mailbox
} }