/
config.go
131 lines (110 loc) · 2.42 KB
/
config.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package main
import (
"context"
"log"
"os"
"sync"
"time"
"github.com/abh/geodns/v3/targeting/geoip2"
"github.com/fsnotify/fsnotify"
gcfg "gopkg.in/gcfg.v1"
)
type AppConfig struct {
GeoIP struct {
Directory string
}
HTTP struct {
User string
Password string
}
QueryLog struct {
Path string
MaxSize int
Keep int
}
AvroLog struct {
Path string
MaxSize int // rotate files at this size
MaxTime string // rotate active files after this time, even if small
}
Health struct {
Directory string
}
Nodeping struct {
Token string
}
Pingdom struct {
Username string
Password string
AccountEmail string
AppKey string
StateMap string
}
}
var Config = new(AppConfig)
var cfgMutex sync.RWMutex
func (conf *AppConfig) GeoIPDirectory() string {
cfgMutex.RLock()
defer cfgMutex.RUnlock()
if len(conf.GeoIP.Directory) > 0 {
return conf.GeoIP.Directory
}
return geoip2.FindDB()
}
func configWatcher(ctx context.Context, fileName string) error {
watcher, err := fsnotify.NewWatcher()
if err != nil {
return err
}
if err := watcher.Add(*flagconfig); err != nil {
return err
}
for {
select {
case <-ctx.Done():
return nil
case ev := <-watcher.Events:
if ev.Name == fileName {
// Write = when the file is updated directly
// Rename = when it's updated atomicly
// Chmod = for `touch`
if ev.Has(fsnotify.Write) ||
ev.Has(fsnotify.Rename) ||
ev.Has(fsnotify.Chmod) {
time.Sleep(200 * time.Millisecond)
err := configReader(fileName)
if err != nil {
// don't quit because we'll just keep the old config at this
// stage and try again next it changes
log.Printf("error reading config file: %s", err)
}
}
}
case err := <-watcher.Errors:
log.Printf("fsnotify error: %s", err)
}
}
}
var lastReadConfig time.Time
func configReader(fileName string) error {
stat, err := os.Stat(fileName)
if err != nil {
log.Printf("Failed to find config file: %s\n", err)
return err
}
if !stat.ModTime().After(lastReadConfig) {
return err
}
lastReadConfig = time.Now()
log.Printf("Loading config: %s\n", fileName)
cfg := new(AppConfig)
err = gcfg.ReadFileInto(cfg, fileName)
if err != nil {
log.Printf("Failed to parse config data: %s\n", err)
return err
}
cfgMutex.Lock()
*Config = *cfg // shallow copy to prevent race conditions in referring to Config.foo()
cfgMutex.Unlock()
return nil
}