Skip to content

Commit

Permalink
cleaned up progress
Browse files Browse the repository at this point in the history
  • Loading branch information
evmar committed Oct 28, 2011
1 parent e68e229 commit b138210
Showing 1 changed file with 55 additions and 31 deletions.
86 changes: 55 additions & 31 deletions imapsync/main.go
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -20,18 +20,23 @@ func check(err os.Error) {
} }
} }


type progressMessage struct {
cur, total int
text string
}

type UI struct { type UI struct {
statusChan chan string statusChan chan interface{}
netmon *netmonReader netmon *netmonReader
} }


func (ui *UI) status(format string, args ...interface{}) { func (ui *UI) log(format string, args ...interface{}) {
if ui.statusChan != nil { ui.statusChan <- fmt.Sprintf(format, args...)
ui.statusChan <- fmt.Sprintf(format, args...) }
} else {
fmt.Printf(format, args...) func (ui *UI) progress(cur, total int, format string, args ...interface{}) {
fmt.Printf("\n") message := &progressMessage{cur, total, fmt.Sprintf(format, args...)}
} ui.statusChan <- message
} }


func loadAuth(path string) (string, string) { func loadAuth(path string) (string, string) {
Expand Down Expand Up @@ -68,7 +73,7 @@ func readExtra(im *imap.IMAP) {
func (ui *UI) connect(useNetmon bool) *imap.IMAP { func (ui *UI) connect(useNetmon bool) *imap.IMAP {
user, pass := loadAuth("auth") user, pass := loadAuth("auth")


ui.status("connecting...") ui.log("connecting...")
conn, err := tls.Dial("tcp", "imap.gmail.com:993", nil) conn, err := tls.Dial("tcp", "imap.gmail.com:993", nil)
check(err) check(err)


Expand All @@ -85,91 +90,111 @@ func (ui *UI) connect(useNetmon bool) *imap.IMAP {


hello, err := im.Start() hello, err := im.Start()
check(err) check(err)
ui.status("server hello: %s", hello) ui.log("server hello: %s", hello)


ui.status("logging in...") ui.log("logging in...")
resp, caps, err := im.Auth(user, pass) resp, caps, err := im.Auth(user, pass)
check(err) check(err)
ui.status("%s", resp) ui.log("%s", resp)
ui.status("server capabilities: %s", caps) ui.log("server capabilities: %s", caps)


return im return im
} }


func (ui *UI) fetch(im *imap.IMAP, mailbox string) { func (ui *UI) fetch(im *imap.IMAP, mailbox string) {
ui.status("opening %s...", mailbox) ui.log("opening %s...", mailbox)
examine, err := im.Examine(mailbox) examine, err := im.Examine(mailbox)
check(err) check(err)
ui.status("mailbox status: %+v", examine) ui.log("mailbox status: %+v", examine)
readExtra(im) readExtra(im)


f, err := os.Create(mailbox + ".mbox") f, err := os.Create(mailbox + ".mbox")
check(err) check(err)
mbox := newMbox(f) mbox := newMbox(f)


query := fmt.Sprintf("1:%d", examine.Exists) query := fmt.Sprintf("1:%d", examine.Exists)
ui.status("fetching messages %s", query) ui.log("requesting messages %s", query)


ch, err := im.FetchAsync(query, []string{"RFC822"}) ch, err := im.FetchAsync(query, []string{"RFC822"})
check(err) check(err)


envelopeDate := time.LocalTime().Format(time.ANSIC) envelopeDate := time.LocalTime().Format(time.ANSIC)


i := 1 i := 0
total := examine.Exists
ui.progress(i, total, "fetching messages", i, total)
L: L:
for { for {
r := <-ch r := <-ch
switch r := r.(type) { switch r := r.(type) {
case *imap.ResponseFetch: case *imap.ResponseFetch:
mbox.writeMessage("imapsync@none", envelopeDate, r.Rfc822) mbox.writeMessage("imapsync@none", envelopeDate, r.Rfc822)
ui.status("got message %d/%d", i, examine.Exists)
i++ i++
ui.progress(i, total, "fetching messages")
case *imap.ResponseStatus: case *imap.ResponseStatus:
ui.status("complete %v\n", r) ui.log("complete %v\n", r)
break L break L
} }
} }
readExtra(im) readExtra(im)
} }


func (ui *UI) runFetch(im *imap.IMAP, mailbox string) { func (ui *UI) runFetch(mailbox string) {
ui.statusChan = make(chan string) ui.statusChan = make(chan interface{})
go func() { go func() {
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
log.Printf("paniced %s", e) ui.statusChan <- e
} }
}() }()
im := ui.connect(true)
ui.fetch(im, mailbox) ui.fetch(im, mailbox)
close(ui.statusChan) close(ui.statusChan)
}() }()


ticker := time.NewTicker(1000 * 1000 * 1000) ticker := time.NewTicker(1000 * 1000 * 1000)
overprint := false
status := "" status := ""
overprintLast := false
for ui.statusChan != nil { for ui.statusChan != nil {
overprint := true
select { select {
case s, stillOpen := <-ui.statusChan: case s, stillOpen := <-ui.statusChan:
if s != status { switch s := s.(type) {
overprint = false case string:
status = s status = s
overprint = false
case *progressMessage:
status = fmt.Sprintf("%s [%d/%d]", s.text, s.cur, s.total)
overprint = true
default:
if s != nil {
status = s.(os.Error).String()
ui.statusChan = nil
ticker.Stop()
}
} }
if !stillOpen { if !stillOpen {
ui.statusChan = nil ui.statusChan = nil
ticker.Stop() ticker.Stop()
} }
case <-ticker.C: case <-ticker.C:
ui.netmon.Tick() if ui.netmon != nil {
ui.netmon.Tick()
}
} }
if overprint {
if overprintLast {
fmt.Printf("\r\x1B[K") fmt.Printf("\r\x1B[K")
} else { } else {
fmt.Printf("\n") fmt.Printf("\n")
} }
if status != "" { overprintLast = overprint
fmt.Printf("[%.1fk/s] %s", ui.netmon.Bandwidth() / 1000.0, status) fmt.Printf("%s", status)
if overprint && ui.netmon != nil {
fmt.Printf(" [%.1fk/s]", ui.netmon.Bandwidth() / 1000.0)
} }
} }
fmt.Printf("\n")
} }


func usage() { func usage() {
Expand Down Expand Up @@ -208,8 +233,7 @@ func main() {
fmt.Printf("must specify mailbox to fetch\n") fmt.Printf("must specify mailbox to fetch\n")
os.Exit(1) os.Exit(1)
} }
im := ui.connect(true) ui.runFetch(args[0])
ui.runFetch(im, args[0])
default: default:
usage() usage()
} }
Expand Down

0 comments on commit b138210

Please sign in to comment.