Stream source mailbox migration
This commit is contained in:
parent
f5f0ff1b8c
commit
a52963c380
4 changed files with 179 additions and 33 deletions
|
|
@ -1552,14 +1552,26 @@ func fetchSourceFolderMessages(account Account, folder string) ([]RawMessage, er
|
|||
return nil, err
|
||||
}
|
||||
defer src.Close()
|
||||
return src.Fetch(folder)
|
||||
return collectSourceMessages(src, folder)
|
||||
}
|
||||
src, err := OpenIMAPSource(account)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer src.Close()
|
||||
return src.Fetch(folder)
|
||||
return collectSourceMessages(src, folder)
|
||||
}
|
||||
|
||||
func collectSourceMessages(src SourceMailbox, folder string) ([]RawMessage, error) {
|
||||
var messages []RawMessage
|
||||
err := src.Fetch(folder, func(m RawMessage) error {
|
||||
messages = append(messages, m)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return messages, err
|
||||
}
|
||||
return messages, nil
|
||||
}
|
||||
|
||||
func renderInitialSourceMailboxList(account Account) string {
|
||||
|
|
|
|||
|
|
@ -36,8 +36,8 @@ type Folder struct {
|
|||
// SourceMailbox abstrahiert Quelle (IMAP primaer, POP3 Fallback), damit
|
||||
// 07-migrate.go gegen ein Interface arbeitet.
|
||||
type SourceMailbox interface {
|
||||
Folders() ([]Folder, error) // rekursiver Ordnerbaum
|
||||
Fetch(folder string) ([]RawMessage, error) // BODY[] FLAGS INTERNALDATE
|
||||
Folders() ([]Folder, error) // rekursiver Ordnerbaum
|
||||
Fetch(folder string, fn func(RawMessage) error) error // BODY[] FLAGS INTERNALDATE
|
||||
Close() error
|
||||
}
|
||||
|
||||
|
|
@ -75,8 +75,8 @@ func (s *imapSource) Folders() ([]Folder, error) {
|
|||
return folders, nil
|
||||
}
|
||||
|
||||
func (s *imapSource) Fetch(folder string) ([]RawMessage, error) {
|
||||
return s.mailbox.fetchAll(folder)
|
||||
func (s *imapSource) Fetch(folder string, fn func(RawMessage) error) error {
|
||||
return s.mailbox.fetchEach(folder, fn)
|
||||
}
|
||||
|
||||
func (s *imapSource) Close() error {
|
||||
|
|
@ -136,13 +136,13 @@ func (m *imapClientMailbox) listMailboxes() ([]imapListMailbox, error) {
|
|||
return out, nil
|
||||
}
|
||||
|
||||
func (m *imapClientMailbox) fetchAll(folder string) ([]RawMessage, error) {
|
||||
func (m *imapClientMailbox) fetchEach(folder string, fn func(RawMessage) error) error {
|
||||
selected, err := m.c.Select(folder, &imap.SelectOptions{ReadOnly: true}).Wait()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
if selected.NumMessages == 0 {
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
section := &imap.FetchItemBodySection{Peek: true}
|
||||
|
|
@ -154,9 +154,7 @@ func (m *imapClientMailbox) fetchAll(folder string) ([]RawMessage, error) {
|
|||
InternalDate: true,
|
||||
BodySection: []*imap.FetchItemBodySection{section},
|
||||
})
|
||||
defer cmd.Close()
|
||||
|
||||
var out []RawMessage
|
||||
for {
|
||||
data := cmd.Next()
|
||||
if data == nil {
|
||||
|
|
@ -164,20 +162,33 @@ func (m *imapClientMailbox) fetchAll(folder string) ([]RawMessage, error) {
|
|||
}
|
||||
buf, err := data.Collect()
|
||||
if err != nil {
|
||||
return out, err
|
||||
_ = cmd.Close()
|
||||
return err
|
||||
}
|
||||
body := buf.FindBodySection(section)
|
||||
if body == nil {
|
||||
body = []byte{}
|
||||
}
|
||||
out = append(out, RawMessage{
|
||||
if err := fn(RawMessage{
|
||||
MessageID: messageIDFromFetch(buf, body),
|
||||
Body: body,
|
||||
Flags: flagsToStrings(sanitizeIMAPFlags(buf.Flags)),
|
||||
InternalDate: buf.InternalDate,
|
||||
})
|
||||
}); err != nil {
|
||||
_ = cmd.Close()
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := cmd.Close(); err != nil {
|
||||
return cmd.Close()
|
||||
}
|
||||
|
||||
func (m *imapClientMailbox) fetchAll(folder string) ([]RawMessage, error) {
|
||||
var out []RawMessage
|
||||
err := m.fetchEach(folder, func(m RawMessage) error {
|
||||
out = append(out, m)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return out, err
|
||||
}
|
||||
return out, nil
|
||||
|
|
|
|||
|
|
@ -123,52 +123,53 @@ func migrateAccount(a Account, selectedFolders map[string]bool) error {
|
|||
if dstFolder == "" {
|
||||
dstFolder = folder.Name
|
||||
}
|
||||
msgs, err := src.Fetch(folder.Name)
|
||||
if err != nil {
|
||||
errs++
|
||||
log.Printf("%s %s fetch error: %v", a.Name, folder.Name, err)
|
||||
continue
|
||||
}
|
||||
total += len(msgs)
|
||||
if err := dst.EnsureFolder(dstFolder); err != nil {
|
||||
errs++
|
||||
log.Printf("%s %s ensure target %s error: %v", a.Name, folder.Name, dstFolder, err)
|
||||
continue
|
||||
}
|
||||
folderDone, folderErrs := 0, 0
|
||||
for _, m := range msgs {
|
||||
folderTotal := 0
|
||||
if err := src.Fetch(folder.Name, func(m RawMessage) error {
|
||||
total++
|
||||
folderTotal++
|
||||
already, err := AlreadyCopied(a.ID, folder.Name, m.MessageID)
|
||||
if err != nil {
|
||||
errs++
|
||||
folderErrs++
|
||||
log.Printf("%s %s dedup error %s: %v", a.Name, folder.Name, m.MessageID, err)
|
||||
continue
|
||||
return nil
|
||||
}
|
||||
if already {
|
||||
continue
|
||||
return nil
|
||||
}
|
||||
if err := dst.Append(dstFolder, m); err != nil {
|
||||
errs++
|
||||
folderErrs++
|
||||
log.Printf("%s %s append to %s error %s: %v", a.Name, folder.Name, dstFolder, m.MessageID, err)
|
||||
continue
|
||||
return nil
|
||||
}
|
||||
if err := mbox.Append(folder.Name, m); err != nil {
|
||||
errs++
|
||||
folderErrs++
|
||||
log.Printf("%s %s mbox error %s: %v", a.Name, folder.Name, m.MessageID, err)
|
||||
continue
|
||||
return nil
|
||||
}
|
||||
if err := MarkCopied(a.ID, folder.Name, m.MessageID); err != nil {
|
||||
errs++
|
||||
folderErrs++
|
||||
log.Printf("%s %s mark error %s: %v", a.Name, folder.Name, m.MessageID, err)
|
||||
continue
|
||||
return nil
|
||||
}
|
||||
done++
|
||||
folderDone++
|
||||
return nil
|
||||
}); err != nil {
|
||||
errs++
|
||||
folderErrs++
|
||||
log.Printf("%s %s fetch error: %v", a.Name, folder.Name, err)
|
||||
}
|
||||
log.Printf("migration %s %s -> %s: total=%d copied=%d errors=%d", a.Name, folder.Name, dstFolder, len(msgs), folderDone, folderErrs)
|
||||
log.Printf("migration %s %s -> %s: total=%d copied=%d errors=%d", a.Name, folder.Name, dstFolder, folderTotal, folderDone, folderErrs)
|
||||
}
|
||||
state := "success"
|
||||
if errs > 0 {
|
||||
|
|
@ -209,12 +210,15 @@ func CheckAccount(name string) error {
|
|||
}
|
||||
total := 0
|
||||
for _, folder := range folders {
|
||||
msgs, err := src.Fetch(folder.Name)
|
||||
if err != nil {
|
||||
folderTotal := 0
|
||||
if err := src.Fetch(folder.Name, func(m RawMessage) error {
|
||||
folderTotal++
|
||||
return nil
|
||||
}); err != nil {
|
||||
return fmt.Errorf("fetch source %s %s: %w", a.Name, folder.Name, err)
|
||||
}
|
||||
log.Printf("account %s source folder %s messages=%d", a.Name, folder.Name, len(msgs))
|
||||
total += len(msgs)
|
||||
log.Printf("account %s source folder %s messages=%d", a.Name, folder.Name, folderTotal)
|
||||
total += folderTotal
|
||||
}
|
||||
dst, err := OpenIMAPTarget(a)
|
||||
if err != nil {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue