apollo.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. package apollo
  2. import (
  3. "bufio"
  4. "fmt"
  5. "io/ioutil"
  6. "os"
  7. "os/signal"
  8. "reflect"
  9. "sync"
  10. "time"
  11. agollo2 "git.shuncheng.lu/bigthing/gocommon/pkg/conf/remote/apollo/agollo"
  12. "git.shuncheng.lu/bigthing/gocommon/pkg/internal/util"
  13. "github.com/tidwall/gjson"
  14. )
  15. var (
  16. readLock sync.Mutex
  17. rootPath string
  18. lastConfig map[string]interface{}
  19. watchChannel = make(chan struct{})
  20. nameSpaceConfig gjson.Result
  21. regularMonitorInterval = 30 * time.Second
  22. )
  23. func Start() {
  24. rootPath = util.GetRootPath() + "/config"
  25. err := loadNameSpacesConfig(getNameSpacesConfigPath())
  26. if err != nil {
  27. panic(fmt.Sprintf("apollo:load err: %s", err.Error()))
  28. }
  29. err = agollo2.InitWithConfigFile(
  30. getApolloConfigPath(),
  31. agollo2.WithLogger(agollo2.NewLogger(agollo2.LoggerWriter(os.Stdout))), // 打印日志信息
  32. agollo2.PreloadNamespaces(getNameSpaces()...), // 预先加载的namespace列表,如果是通过配置启动,会在app.properties配置的基础上追加
  33. agollo2.AutoFetchOnCacheMiss(), // 在配置未找到时,去apollo的带缓存的获取配置接口,获取配置
  34. agollo2.FailTolerantOnBackupExists(),
  35. agollo2.BackupFile(getBackFilePath()), // 在连接apollo失败时,如果在配置的目录下存在.agollo备份配置,会读取备份在服务器无法连接的情况下
  36. )
  37. if err != nil {
  38. panic(fmt.Sprintf("apollo:init err: %s", err.Error()))
  39. }
  40. err = writeMapToFile()
  41. if err != nil {
  42. panic(fmt.Sprintf("apollo:write file err: %s", err.Error()))
  43. }
  44. go listen()
  45. }
  46. func GetConfigPath() string {
  47. return rootPath + "/apollo/env.ini"
  48. }
  49. func SetRefreshInterval(second int) {
  50. regularMonitorInterval = time.Duration(second) * time.Second
  51. }
  52. func Watch() <-chan struct{} {
  53. return watchChannel
  54. }
  55. func listen() {
  56. signals := make(chan os.Signal)
  57. signal.Notify(signals, os.Interrupt)
  58. lastConfig = deepCopy(agollo2.GetAll())
  59. for {
  60. timer := time.NewTimer(regularMonitorInterval)
  61. select {
  62. case <-timer.C:
  63. err := agollo2.Reload()
  64. if err != nil {
  65. fmt.Printf("[apollo] reload err: %s\n", err)
  66. continue
  67. }
  68. newConfig := deepCopy(agollo2.GetAll())
  69. if reflect.DeepEqual(lastConfig, newConfig) {
  70. continue
  71. }
  72. lastConfig = newConfig
  73. err = writeMapToFile()
  74. if err != nil {
  75. fmt.Printf("[apollo] write env err: %s\n", err)
  76. continue
  77. }
  78. watchChannel <- struct{}{}
  79. case <-signals:
  80. fmt.Println("[apollo] receive signal, exited")
  81. return
  82. }
  83. }
  84. select {}
  85. }
  86. func getBackFilePath() string {
  87. return rootPath + "/apollo/.agollo"
  88. }
  89. func getApolloConfigPath() string {
  90. return rootPath + "/apollo/apollo.json"
  91. }
  92. func getNameSpacesConfigPath() string {
  93. return rootPath + "/apollo/namespaces.json"
  94. }
  95. func getNameSpaces() []string {
  96. nameSpaceList := make([]string, 0)
  97. nameSpaceConfig.ForEach(func(key gjson.Result, value gjson.Result) bool {
  98. nameSpaceList = append(nameSpaceList, getNameSpace(value))
  99. return true
  100. })
  101. return nameSpaceList
  102. }
  103. func getNameSpace(nameSpace gjson.Result) string {
  104. return nameSpace.Get("namespace").String()
  105. }
  106. func getSections(sections gjson.Result) gjson.Result {
  107. return sections.Get("sections")
  108. }
  109. func getSectionName(section gjson.Result) string {
  110. return section.Get("name").String()
  111. }
  112. func getKeys(section gjson.Result) gjson.Result {
  113. return section.Get("keys")
  114. }
  115. func getKeyName(key gjson.Result) string {
  116. return key.Get("name").String()
  117. }
  118. func getKeyMapTo(key gjson.Result) string {
  119. return key.Get("mapTo").String()
  120. }
  121. func getKeysMap() map[string]map[string]map[string]string {
  122. maps := map[string]map[string]map[string]string{}
  123. nameSpaceConfig.ForEach(func(nameSpaceKey gjson.Result, value gjson.Result) bool {
  124. nameSpace := getNameSpace(value)
  125. _, ok := maps[nameSpace]
  126. if !ok {
  127. maps[nameSpace] = map[string]map[string]string{}
  128. }
  129. sections := getSections(value)
  130. sections.ForEach(func(sectionKey gjson.Result, section gjson.Result) bool {
  131. sectionName := getSectionName(section)
  132. keys := getKeys(section)
  133. keys.ForEach(func(keys gjson.Result, key gjson.Result) bool {
  134. keyName := getKeyName(key)
  135. keyMapTo := getKeyMapTo(key)
  136. _, ok := maps[nameSpace][keyName]
  137. if ok {
  138. return true
  139. }
  140. maps[nameSpace][keyName] = map[string]string{}
  141. maps[nameSpace][keyName]["section"] = sectionName
  142. keyRealName := keyMapTo
  143. if keyMapTo == "" {
  144. keyRealName = keyName
  145. }
  146. maps[nameSpace][keyName]["mapTo"] = keyRealName
  147. return true
  148. })
  149. return true
  150. })
  151. return true
  152. })
  153. return maps
  154. }
  155. func loadNameSpacesConfig(configPath string) error {
  156. file, err := os.Open(configPath)
  157. if err != nil {
  158. return err
  159. }
  160. defer file.Close()
  161. contents, err := ioutil.ReadAll(file)
  162. if err != nil {
  163. return err
  164. }
  165. nameSpaceConfig = gjson.Get(string(contents), "namespaces")
  166. return nil
  167. }
  168. //将所有的配置信息写入标准的配置文件里面
  169. func writeMapToFile() error {
  170. readLock.Lock()
  171. defer readLock.Unlock()
  172. f, err := os.Create(GetConfigPath())
  173. if err != nil {
  174. fmt.Printf("apollo:create config file err, err: %s", err.Error())
  175. return err
  176. }
  177. defer f.Close()
  178. w := bufio.NewWriter(f)
  179. keysMap := getKeysMap()
  180. for _, nameSpace := range getNameSpaces() {
  181. sections := map[string][]string{}
  182. _, ok := keysMap[nameSpace]
  183. if !ok {
  184. continue
  185. }
  186. ConfigInfo := agollo2.GetNameSpace(nameSpace)
  187. for key, val := range ConfigInfo {
  188. _, ok = keysMap[nameSpace][key]
  189. if !ok {
  190. continue
  191. }
  192. _, ok = sections[keysMap[nameSpace][key]["section"]]
  193. if !ok {
  194. sections[keysMap[nameSpace][key]["section"]] = make([]string, 0)
  195. }
  196. lineStr := fmt.Sprintf("%s=%s", keysMap[nameSpace][key]["mapTo"], val)
  197. sections[keysMap[nameSpace][key]["section"]] = append(sections[keysMap[nameSpace][key]["section"]], lineStr)
  198. }
  199. if len(sections) == 0 {
  200. continue
  201. }
  202. for section, lineStrs := range sections {
  203. lineSection := fmt.Sprintf("[%s]", section)
  204. fmt.Fprintln(w, lineSection)
  205. for _, lineStr := range lineStrs {
  206. fmt.Fprintln(w, lineStr)
  207. }
  208. }
  209. }
  210. err = w.Flush()
  211. if err == nil {
  212. return nil
  213. }
  214. return err
  215. }
  216. func deepCopy(value map[string]interface{}) map[string]interface{} {
  217. newMap := make(map[string]interface{})
  218. for k, v := range value {
  219. newMap[k] = v
  220. }
  221. return newMap
  222. }