diff --git a/go.mod b/go.mod index 51cbfaf..592ab29 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.15 require ( github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect + github.com/fsnotify/fsnotify v1.7.0 github.com/google/go-cmp v0.6.0 github.com/jmoiron/sqlx v1.3.5 github.com/kr/pretty v0.1.0 // indirect diff --git a/go.sum b/go.sum index 3026df0..e38eeb8 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,8 @@ github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbi github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= @@ -24,6 +26,8 @@ github.com/urfave/cli/v2 v2.27.1 h1:8xSQ6szndafKVRmfyeUMxkNUJQMjL1F2zmsZ+qHpfho= github.com/urfave/cli/v2 v2.27.1/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= +golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18= +golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/timefor b/timefor index d1acd58..186a532 100755 --- a/timefor +++ b/timefor @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:049af1dc748aa588344eb66b6faf62f57aeabc16965064e696b2f263a2f9b4b4 -size 9434672 +oid sha256:11d3a45f9450ece64f77602eaf3a18f5cf14b92ca9ad350aa9aa3055c74ebb97 +size 9551664 diff --git a/timefor.go b/timefor.go index bc64f41..8675bf1 100644 --- a/timefor.go +++ b/timefor.go @@ -16,6 +16,7 @@ import ( "text/template" "time" + "github.com/fsnotify/fsnotify" "github.com/jmoiron/sqlx" _ "github.com/mattn/go-sqlite3" "github.com/urfave/cli/v2" @@ -249,6 +250,7 @@ func newCmd(db *sqlx.DB) error { intervalToShowBreakReminder := cCtx.Duration("break-interval") intervalToRepeatBreakReminder := cCtx.Duration("repeat-interval") hook := cCtx.String("hook") + err := Daemon(db, intervalToUpdateDb, intervalToShowBreakReminder, intervalToRepeatBreakReminder, hook) if err != nil { return err @@ -493,6 +495,10 @@ func Daemon( ) error { var notified time.Time var lastHook string + change := make(chan ChangeEvent) + + go watchDbFile(change) + for { activity, err := Latest(db) if err != nil { @@ -512,17 +518,12 @@ func Daemon( } } } - if activity.Active() && time.Since(activity.Updated()) > intervalToUpdateDb { - fmt.Printf("updating time for %s\n", activity.Name) - _, err := UpdateIfExists(db, "", false) - if err != nil { - return err - } + if activity.Active() { duration, err := activeDuration(db) if err != nil { return err } - if activity.Active() && duration > intervalToShowBreakReminder && time.Since(notified) > intervalToRepeatBreakReminder { + if duration > intervalToShowBreakReminder && time.Since(notified) > intervalToRepeatBreakReminder { args := []string{ "Take a break!", fmt.Sprintf("Active for %v already", formatDuration(duration)), @@ -540,10 +541,64 @@ func Daemon( notified = time.Now() } } - time.Sleep(1 * time.Second) + + nextUpdate := activity.TimeSince().Truncate(time.Minute) + time.Minute - activity.TimeSince() + log.Printf("next update in %s\n", nextUpdate) + + select { + case c := <-change: + log.Println("change", c) + + case <-time.After(nextUpdate): + if activity.Active() && time.Since(activity.Updated()) > intervalToUpdateDb { + fmt.Printf("updating time for %s\n", activity.Name) + _, err := UpdateIfExists(db, "", false) + if err != nil { + return err + } + } + } } } +type ChangeEvent struct { + Event fsnotify.Event + Error error +} + +func watchDbFile(change chan ChangeEvent) error { + watcher, err := fsnotify.NewWatcher() + if err != nil { + return err + } + defer watcher.Close() + + go func() { + for { + select { + case event, ok := <-watcher.Events: + if !ok { + return + } + change <- ChangeEvent{Event: event} + + case err, ok := <-watcher.Errors: + if !ok { + return + } + change <- ChangeEvent{Error: err} + } + } + }() + + if err := watcher.Add(dbFile); err != nil { + return err + } + + <-make(chan struct{}) + return nil +} + func activeDuration(db *sqlx.DB) (time.Duration, error) { rows, err := db.Queryx(`SELECT * FROM log ORDER BY started DESC LIMIT 100`) if err != nil {