config.go 2.4 KB

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