Skip to content

Commit f411bae

Browse files
committed
Add Auto Reload Callback
1 parent 7fe8380 commit f411bae

File tree

3 files changed

+55
-18
lines changed

3 files changed

+55
-18
lines changed

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,14 @@ configor.New(&configor.Config{AutoReload: true}).Load(&Config, "config.json")
7676
configor.New(&configor.Config{AutoReload: true, AutoReloadInterval: time.Minute}).Load(&Config, "config.json")
7777
```
7878
79+
Auto Reload Callback
80+
81+
```go
82+
configor.New(&configor.Config{AutoReload: true, AutoReloadCallback: func(config interface{}) {
83+
fmt.Printf("%v changed", config)
84+
}}).Load(&Config, "config.json")
85+
```
86+
7987
# Advanced Usage
8088

8189
* Load mutiple configurations

configor.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010

1111
type Configor struct {
1212
*Config
13+
configModTimes map[string]time.Time
1314
}
1415

1516
type Config struct {
@@ -20,6 +21,7 @@ type Config struct {
2021
Silent bool
2122
AutoReload bool
2223
AutoReloadInterval time.Duration
24+
AutoReloadCallback func(config interface{})
2325

2426
// In case of json files, this field will be used only when compiled with
2527
// go 1.10 or later.
@@ -83,7 +85,7 @@ func (configor *Configor) Load(config interface{}, files ...string) (err error)
8385
if !defaultValue.CanAddr() {
8486
return fmt.Errorf("Config %v should be addressable", config)
8587
}
86-
err = configor.load(config, files...)
88+
err, _ = configor.load(config, false, files...)
8789

8890
if configor.Config.AutoReload {
8991
go func() {
@@ -92,9 +94,13 @@ func (configor *Configor) Load(config interface{}, files ...string) (err error)
9294
reflectPtr := reflect.New(reflect.ValueOf(config).Elem().Type())
9395
reflectPtr.Elem().Set(defaultValue)
9496

95-
if err = configor.load(reflectPtr.Interface(), files...); err == nil {
97+
var changed bool
98+
if err, changed = configor.load(reflectPtr.Interface(), true, files...); err == nil && changed {
9699
reflect.ValueOf(config).Elem().Set(reflectPtr.Elem())
97-
} else {
100+
if configor.Config.AutoReloadCallback != nil {
101+
configor.Config.AutoReloadCallback(config)
102+
}
103+
} else if err != nil {
98104
fmt.Printf("Failed to reload configuration from %v, got error %v\n", files, err)
99105
}
100106
timer.Reset(configor.Config.AutoReloadInterval)

utils.go

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"path"
1111
"reflect"
1212
"strings"
13+
"time"
1314

1415
"github.com/BurntSushi/toml"
1516
"gopkg.in/yaml.v2"
@@ -37,7 +38,7 @@ func (configor *Configor) getENVPrefix(config interface{}) string {
3738
return configor.Config.ENVPrefix
3839
}
3940

40-
func getConfigurationFileWithENVPrefix(file, env string) (string, error) {
41+
func getConfigurationFileWithENVPrefix(file, env string) (string, time.Time, error) {
4142
var (
4243
envFile string
4344
extname = path.Ext(file)
@@ -50,13 +51,14 @@ func getConfigurationFileWithENVPrefix(file, env string) (string, error) {
5051
}
5152

5253
if fileInfo, err := os.Stat(envFile); err == nil && fileInfo.Mode().IsRegular() {
53-
return envFile, nil
54+
return envFile, fileInfo.ModTime(), nil
5455
}
55-
return "", fmt.Errorf("failed to find file %v", file)
56+
return "", time.Now(), fmt.Errorf("failed to find file %v", file)
5657
}
5758

58-
func (configor *Configor) getConfigurationFiles(files ...string) []string {
59-
var results []string
59+
func (configor *Configor) getConfigurationFiles(files ...string) ([]string, map[string]time.Time) {
60+
var resultKeys []string
61+
var results = map[string]time.Time{}
6062

6163
if configor.Config.Debug || configor.Config.Verbose {
6264
fmt.Printf("Current environment: '%v'\n", configor.GetEnvironment())
@@ -69,28 +71,31 @@ func (configor *Configor) getConfigurationFiles(files ...string) []string {
6971
// check configuration
7072
if fileInfo, err := os.Stat(file); err == nil && fileInfo.Mode().IsRegular() {
7173
foundFile = true
72-
results = append(results, file)
74+
resultKeys = append(resultKeys, file)
75+
results[file] = fileInfo.ModTime()
7376
}
7477

7578
// check configuration with env
76-
if file, err := getConfigurationFileWithENVPrefix(file, configor.GetEnvironment()); err == nil {
79+
if file, modTime, err := getConfigurationFileWithENVPrefix(file, configor.GetEnvironment()); err == nil {
7780
foundFile = true
78-
results = append(results, file)
81+
resultKeys = append(resultKeys, file)
82+
results[file] = modTime
7983
}
8084

8185
// check example configuration
8286
if !foundFile {
83-
if example, err := getConfigurationFileWithENVPrefix(file, "example"); err == nil {
87+
if example, modTime, err := getConfigurationFileWithENVPrefix(file, "example"); err == nil {
8488
if !configor.Silent {
8589
fmt.Printf("Failed to find configuration %v, using example file %v\n", file, example)
8690
}
87-
results = append(results, example)
91+
resultKeys = append(resultKeys, file)
92+
results[example] = modTime
8893
} else if !configor.Silent {
8994
fmt.Printf("Failed to find configuration %v\n", file)
9095
}
9196
}
9297
}
93-
return results
98+
return resultKeys, results
9499
}
95100

96101
func processFile(config interface{}, file string, errorOnUnmatchedKeys bool) error {
@@ -294,7 +299,7 @@ func (configor *Configor) processTags(config interface{}, prefixes ...string) er
294299
return nil
295300
}
296301

297-
func (configor *Configor) load(config interface{}, files ...string) (err error) {
302+
func (configor *Configor) load(config interface{}, watchMode bool, files ...string) (err error, changed bool) {
298303
defer func() {
299304
if configor.Config.Debug || configor.Config.Verbose {
300305
if err != nil {
@@ -305,20 +310,38 @@ func (configor *Configor) load(config interface{}, files ...string) (err error)
305310
}
306311
}()
307312

308-
for _, file := range configor.getConfigurationFiles(files...) {
313+
configFiles, configModTimeMap := configor.getConfigurationFiles(files...)
314+
315+
if watchMode {
316+
if len(configModTimeMap) == len(configor.configModTimes) {
317+
var changed bool
318+
for f, t := range configModTimeMap {
319+
if v, ok := configor.configModTimes[f]; !ok || t.After(v) {
320+
changed = true
321+
}
322+
}
323+
324+
if !changed {
325+
return nil, false
326+
}
327+
}
328+
}
329+
330+
for _, file := range configFiles {
309331
if configor.Config.Debug || configor.Config.Verbose {
310332
fmt.Printf("Loading configurations from file '%v'...\n", file)
311333
}
312334
if err = processFile(config, file, configor.GetErrorOnUnmatchedKeys()); err != nil {
313-
return err
335+
return err, true
314336
}
315337
}
338+
configor.configModTimes = configModTimeMap
316339

317340
if prefix := configor.getENVPrefix(config); prefix == "-" {
318341
err = configor.processTags(config)
319342
} else {
320343
err = configor.processTags(config, prefix)
321344
}
322345

323-
return err
346+
return err, true
324347
}

0 commit comments

Comments
 (0)