From b64f9ee012ffce9478c6c4c9f5203b13f157cacc Mon Sep 17 00:00:00 2001 From: Bill Thiede Date: Sun, 1 Sep 2013 20:06:25 -0700 Subject: [PATCH] Functioning unread counts through JSON. --- watch/{watcher.go => unread.go} | 142 +++++++++++++++------- watch/{watcher_test.go => unread_test.go} | 0 2 files changed, 98 insertions(+), 44 deletions(-) rename watch/{watcher.go => unread.go} (64%) rename watch/{watcher_test.go => unread_test.go} (100%) diff --git a/watch/watcher.go b/watch/unread.go similarity index 64% rename from watch/watcher.go rename to watch/unread.go index e66507c..4d7c0bf 100644 --- a/watch/watcher.go +++ b/watch/unread.go @@ -1,8 +1,10 @@ package main import ( + "encoding/json" "flag" "log" + "net/http" "os" "path/filepath" "sort" @@ -75,29 +77,41 @@ func isNewEmail(path string) bool { } type mailCounter struct { - lastrun time.Time - counts map[string]int + lastrun time.Time + counts map[string]int + needUpdate []string + root string +} + +func newMailCounter() *mailCounter { + return &mailCounter{ + counts: map[string]int{}, + } +} + +func (mc *mailCounter) ServeHTTP(w http.ResponseWriter, r *http.Request) { + c := map[string]int{} + for k, v := range mc.counts { + if v != 0 { + c[k] = v + } + } + enc := json.NewEncoder(w) + err := enc.Encode(c) + if err != nil { + log.Println("Error printing JSON:", err) + } } func (mc *mailCounter) walk(path string, info os.FileInfo, err error) error { if err != nil { return err } + if info.IsDir() { - log.Println("path:", path) - if info.ModTime().Before(mc.lastrun) { - // Don't descend subdirectories older than our last run. - return filepath.SkipDir - } - if isMailDirParent(path) { - // This is a parent directory, or not a proper mail dir. Set the - // counts to zero in either case. - folder := folderFromPath(path) - log.Println("Setting folder to 0", folder) - mc.counts[folder] = 0 - } return nil } + dn := filepath.Dir(path) if isMailDir(dn) { if isNewEmail(path) { @@ -108,6 +122,69 @@ func (mc *mailCounter) walk(path string, info os.FileInfo, err error) error { return nil } +func skip(path string) bool { + switch filepath.Base(path) { + case "cur", "new", "tmp": + return true + } + return false +} + +func (mc *mailCounter) fillNeedUpdate() error { + mc.needUpdate = mc.needUpdate[:0] + // log.Println("BEGIN fillNeedUpdate", mc.needUpdate) + // defer func() { + // log.Println("END fillNeedUpdate", mc.needUpdate) + // }() + return filepath.Walk(mc.root, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + if info.IsDir() { + if info.ModTime().After(mc.lastrun) && isMailDir(path) { + mc.needUpdate = append(mc.needUpdate, path) + } + if skip(path) { + return filepath.SkipDir + } + } + return nil + }) +} + +func (mc *mailCounter) watch(root string, poll time.Duration) error { + mc.root = root + for { + thisrun := time.Now() + if err := mc.fillNeedUpdate(); err != nil { + return err + } + if len(mc.needUpdate) > 0 { + update := map[string]struct{}{} + for _, dir := range mc.needUpdate { + // Store parent directory, which is the IMAP folder + update[filepath.Dir(dir)] = struct{}{} + } + for u := range update { + folder := folderFromPath(u) + mc.counts[folder] = 0 + } + for u := range update { + if err := filepath.Walk(filepath.Join(u, "cur"), mc.walk); err != nil { + return err + } + if err := filepath.Walk(filepath.Join(u, "new"), mc.walk); err != nil { + return err + } + } + } + mc.lastrun = thisrun + time.Sleep(poll) + } + return nil +} + type countList []count type count struct { @@ -147,40 +224,17 @@ func printCounts(counts map[string]int) { } } -func (mc *mailCounter) watch(root string, poll time.Duration) error { - for { - fi, err := os.Stat(root) - if err != nil { - return err - } - if fi.ModTime().After(mc.lastrun) { - thisrun := time.Now() - log.Println("Mod detected", fi.ModTime(), ">", mc.lastrun) - err = filepath.Walk(root, mc.walk) - if err != nil { - return err - } - printCounts(mc.counts) - - mc.lastrun = thisrun - } else { - log.Println("No change detected") - } - time.Sleep(poll) - } - return nil -} - -func newMailCounter() *mailCounter { - return &mailCounter{ - counts: map[string]int{}, - } -} - func main() { flag.Parse() mc := newMailCounter() + go func() { + err := http.ListenAndServe(":8080", mc) + if err != nil { + log.Fatal(err) + } + }() + err := mc.watch(*root, *poll) if err != nil { log.Fatal(err) diff --git a/watch/watcher_test.go b/watch/unread_test.go similarity index 100% rename from watch/watcher_test.go rename to watch/unread_test.go