source_file.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. package mhayaDataConfig
  2. import (
  3. "os"
  4. "regexp"
  5. "time"
  6. cerr "github.com/mhaya/error"
  7. cfile "github.com/mhaya/extend/file"
  8. clog "github.com/mhaya/logger"
  9. cprofile "github.com/mhaya/profile"
  10. "github.com/radovskyb/watcher"
  11. )
  12. type (
  13. // SourceFile 本地读取数据配置文件
  14. SourceFile struct {
  15. fileConfig
  16. watcher *watcher.Watcher
  17. changeFn ConfigChangeFn
  18. monitorPath string
  19. }
  20. fileConfig struct {
  21. FilePath string `json:"file_path"` // 配置文件路径
  22. ExtName string `json:"ext_name"` // 文件扩展名
  23. ReloadTime int64 `json:"reload_time"` // 定时重载扫描(毫秒)
  24. }
  25. )
  26. func (f *SourceFile) Name() string {
  27. return "file"
  28. }
  29. func (f *SourceFile) Init(_ IDataConfig) {
  30. err := f.unmarshalFileConfig()
  31. if err != nil {
  32. clog.Panicf("Unmarshal fileConfig fail. err = %v", err)
  33. return
  34. }
  35. f.watcher = watcher.New()
  36. f.watcher.FilterOps(watcher.Write)
  37. var regexpFilter *regexp.Regexp
  38. regexpFilter, err = regexp.Compile(`.*\` + f.ExtName + `$`)
  39. if err != nil {
  40. clog.Panicf("AddFilterHook extName fail. err = %v", err)
  41. return
  42. }
  43. f.watcher.AddFilterHook(watcher.RegexFilterHook(regexpFilter, false))
  44. f.monitorPath, err = cfile.JoinPath(cprofile.Path(), f.FilePath)
  45. if err != nil {
  46. clog.Panicf("[name = %s] join path fail. err = %v.", f.Name(), err)
  47. return
  48. }
  49. err = f.watcher.Add(f.monitorPath)
  50. if err != nil {
  51. clog.Panicf("New watcher error. path=%s, err = %v", f.monitorPath, err)
  52. return
  53. }
  54. // new watcher
  55. go f.newWatcher()
  56. }
  57. func (f *SourceFile) ReadBytes(configName string) ([]byte, error) {
  58. if configName == "" {
  59. return nil, cerr.Error("Config name is empty.")
  60. }
  61. fullPath, err := cfile.JoinPath(f.monitorPath, configName+f.ExtName)
  62. if err != nil {
  63. return nil, cerr.Errorf("Config file not found. err = %v", err)
  64. }
  65. data, err := os.ReadFile(fullPath)
  66. if err != nil {
  67. return nil, cerr.Errorf("Read file error. [path = %s, err = %v]", fullPath, err)
  68. }
  69. if len(data) < 1 {
  70. return nil, cerr.Errorf("Data is empty. [configName = %s]", configName)
  71. }
  72. return data, err
  73. }
  74. func (f *SourceFile) OnChange(fn ConfigChangeFn) {
  75. f.changeFn = fn
  76. }
  77. func (f *SourceFile) newWatcher() {
  78. go func() {
  79. for {
  80. select {
  81. case ev := <-f.watcher.Event:
  82. {
  83. if ev.IsDir() {
  84. continue
  85. }
  86. configName := cfile.GetFileName(ev.FileInfo.Name(), true)
  87. clog.Infof("Trigger file change. [name = %s]", configName)
  88. data, err := f.ReadBytes(configName)
  89. if err != nil {
  90. clog.Warn("Read data fail. [name = %s, err = %s]", configName, err)
  91. continue
  92. }
  93. if f.changeFn != nil {
  94. f.changeFn(configName, data)
  95. }
  96. }
  97. case err := <-f.watcher.Error:
  98. {
  99. clog.Error(err)
  100. continue
  101. }
  102. case <-f.watcher.Closed:
  103. return
  104. }
  105. }
  106. }()
  107. err := f.watcher.Start(time.Duration(f.ReloadTime) * time.Millisecond)
  108. if err != nil {
  109. clog.Panic(err)
  110. }
  111. }
  112. func (f *SourceFile) Stop() {
  113. if f.watcher == nil {
  114. return
  115. }
  116. err := f.watcher.Remove(f.monitorPath)
  117. clog.Infof("Remote watcher [path = %s, err = %v]", f.monitorPath, err)
  118. f.watcher.Close()
  119. }
  120. func (f *SourceFile) unmarshalFileConfig() error {
  121. //read data_config->file node
  122. dataConfig := cprofile.GetConfig("data_config").GetConfig(f.Name())
  123. err := dataConfig.Unmarshal(&f.fileConfig)
  124. if err != nil {
  125. return err
  126. }
  127. if f.ReloadTime < 1 {
  128. f.ReloadTime = 3000
  129. }
  130. if len(f.ExtName) < 1 {
  131. f.ExtName = ".json"
  132. }
  133. if len(f.FilePath) < 1 {
  134. f.FilePath = "data/"
  135. }
  136. return nil
  137. }