Skip to content

Commit

Permalink
use interval poll instead of fsnotify
Browse files Browse the repository at this point in the history
  • Loading branch information
xgfone committed Oct 12, 2023
1 parent 83745a6 commit d78ac89
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 61 deletions.
3 changes: 0 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
module github.com/xgfone/gconf/v6

require (
github.com/fsnotify/fsnotify v1.6.0
github.com/xgfone/go-cast v0.8.1
github.com/xgfone/go-defaults v0.13.0
)

require golang.org/x/sys v0.0.0-20220908164124-27713097b956 // indirect

go 1.18
4 changes: 0 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/xgfone/go-cast v0.8.1 h1:x80Qu+XCUyQoFvCo2j+CFRiKiJydF11jeAJRzRtGY9U=
github.com/xgfone/go-cast v0.8.1/go.mod h1:aHO9rXhmN4IZ4d1UG35+6WEVbg5yyISynFQJCVltrsk=
github.com/xgfone/go-defaults v0.13.0 h1:aJX/RJSI8yN6Xxn1b1NlFQyClwION2DM5X1NDz3KQ0U=
github.com/xgfone/go-defaults v0.13.0/go.mod h1:4qxXP2vvK8n2csVwYmFbhbQAISq5s/2zYZE9CKYj/bw=
golang.org/x/sys v0.0.0-20220908164124-27713097b956 h1:XeJjHH1KiLpKGb6lvMiksZ9l0fVUh+AmGcm0nOMEBOY=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
72 changes: 18 additions & 54 deletions source_file.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ import (
"path/filepath"
"strings"
"time"

"github.com/fsnotify/fsnotify"
)

// ConfigFileOpt is the default option for the configuration file.
Expand All @@ -47,13 +45,14 @@ func NewFileSource(filename string, defaultFormat ...string) Source {
}

id := fmt.Sprintf("file:%s", filename)
return fileSource{id: id, filepath: filename, format: format}
return fileSource{id: id, filepath: filename, format: format, timeout: time.Second * 10}
}

type fileSource struct {
id string
format string
filepath string
timeout time.Duration
}

func (f fileSource) String() string { return f.id }
Expand Down Expand Up @@ -94,19 +93,9 @@ func (f fileSource) Watch(exit <-chan struct{}, load func(DataSet, error) bool)
}

func (f fileSource) watch(exit <-chan struct{}, load func(DataSet, error) bool) {
fw, err := fsnotify.NewWatcher()
if err != nil {
load(DataSet{Source: f.id, Format: f.format}, err)
return
}
defer fw.Close()

var add bool
if fw.Add(f.filepath) == nil {
add = true
}
lastsize, lasttime, _ := getfileinfo(f.filepath)

ticker := time.NewTicker(time.Minute)
ticker := time.NewTicker(f.timeout)
defer ticker.Stop()

for {
Expand All @@ -115,49 +104,24 @@ func (f fileSource) watch(exit <-chan struct{}, load func(DataSet, error) bool)
return

case <-ticker.C:
if _, err := os.Stat(f.filepath); err != nil {
if os.IsNotExist(err) {
if add {
if err := fw.Remove(f.filepath); err != nil {
load(DataSet{Source: f.id, Format: f.format}, err)
} else {
add = false
}
}
} else {
if size, time, err := getfileinfo(f.filepath); err != nil {
if !os.IsNotExist(err) {
load(DataSet{Source: f.id, Format: f.format}, err)
}
continue
}

if !add {
if err := fw.Add(f.filepath); err != nil {
load(DataSet{Source: f.id, Format: f.format}, err)
} else {
add = true
load(f.Read())
}
continue
}

case event, ok := <-fw.Events:
if !ok {
return
}

// BUG: it will be triggered twice continuously by fsnotify on Windows.
if event.Op&fsnotify.Write == fsnotify.Write {
} else if size != lastsize || time != lasttime {
load(f.Read())
} else if event.Op&fsnotify.Remove == fsnotify.Remove {
add = false
}

case err, ok := <-fw.Errors:
if !ok {
return
lastsize = size
lasttime = time
}

load(DataSet{Source: f.id, Format: f.format}, err)
}
}
}

func getfileinfo(filepath string) (size, time int64, err error) {
fi, err := os.Stat(filepath)
if err == nil {
time = fi.ModTime().Unix()
size = fi.Size()
}
return
}
45 changes: 45 additions & 0 deletions source_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,51 @@ func TestNewFileSource_JSON(t *testing.T) {
}
}

func TestFileSourceWatch(t *testing.T) {
// Prepare the json file
filename := "_test_file_source_watch_.json"
defer os.Remove(filename)

source := NewFileSource(filename).(fileSource)
source.timeout = time.Second * 2

exit := make(chan struct{})
go func() {
time.Sleep(time.Second)
file, err := os.OpenFile(filename, testfileflag, os.ModePerm)
if err != nil {
t.Error(err)
} else {
_, _ = file.Write([]byte(`{"opt": 1}`))
file.Close()
}
time.Sleep(time.Second * 2)
close(exit)
}()

var data string
start := time.Now()
source.Watch(exit, func(ds DataSet, err error) bool {
if err != nil {
t.Error(err)
} else if data == "" {
data = string(ds.Data)
} else {
t.Fail()
}
return true
})

if cost := time.Since(start); cost < time.Second*3 || cost > time.Second*4 {
t.Errorf("not wait for 3~4s")
}

expect := `{"opt": 1}`
if data != expect {
t.Errorf("expect '%s', but got '%s'", expect, data)
}
}

func TestNewURLSource(t *testing.T) {
first := true

Expand Down

0 comments on commit d78ac89

Please sign in to comment.