config.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. package config
  2. import (
  3. "context"
  4. "encoding/json"
  5. "fmt"
  6. "io/ioutil"
  7. "os"
  8. "strings"
  9. "time"
  10. "github.com/fsnotify/fsnotify"
  11. "go.etcd.io/etcd/client"
  12. )
  13. var Conf *Configure
  14. const ConfigPath = "conf/common.json"
  15. // mysql 配置
  16. type MysqlConfig struct {
  17. User string `json:"user"`
  18. Password string `json:"password"`
  19. Addr string `json:"addr"`
  20. DefaultDB string `json:"default_db"`
  21. Charset string `json:"charset"`
  22. MaxIdle json.Number `json:"max_idle"`
  23. MaxConn json.Number `json:"max_conn"`
  24. ServiceName string `json:"service_name"`
  25. ServicePort int `json:"service_port"`
  26. }
  27. // redis 配置
  28. type RedisConfig struct {
  29. Addrs string `json:"addrs"`
  30. Password string `json:"password"`
  31. DefaultDB json.Number `json:"default_db"`
  32. PoolSize json.Number `json:"pool_size"`
  33. MinIdleConns json.Number `json:"min_idle_conns"`
  34. MaxRetries json.Number `json:"max_retries"`
  35. IsCluster string `json:"is_cluster"`
  36. }
  37. type ElasticConfig struct {
  38. Addr string `json:"addr"`
  39. Sniff string `json:"sniff"`
  40. }
  41. type LogConfig struct {
  42. MaxSize json.Number `json:"max_size"`
  43. MaxBackups json.Number `json:"max_backups"`
  44. MaxAge json.Number `json:"max_age"`
  45. DisableStacktrace string `json:"disable_stacktrace"`
  46. }
  47. type RPCNode struct {
  48. Scheme string `json:"scheme"`
  49. Name string `json:"name"`
  50. UpdateInterval json.Number `json:"update_interval"`
  51. MysqlDB string `json:"mysql_db"`
  52. RedisDB json.Number `json:"redis_db"`
  53. Log LogConfig `json:"log"`
  54. ServiceName string `json:"service_name"`
  55. ServicePort json.Number `json:"service_port"`
  56. }
  57. type RPCConfig struct {
  58. BasePath string `json:"base_path"`
  59. Admin RPCNode `json:"gd_admin"`
  60. }
  61. type Configure struct {
  62. RunMode string `json:"run_mode"`
  63. AppKey string `json:"app_key"`
  64. AppSecret string `json:"app_secret"`
  65. Mysql MysqlConfig `json:"mysql"`
  66. Redis RedisConfig `json:"redis"`
  67. Elastic ElasticConfig `json:"elastic"`
  68. Rpc RPCConfig `json:"rpc"`
  69. }
  70. // key 为加密密钥
  71. func GetConfig(runmode, key string, cli client.Client) *Configure {
  72. keysAPI := client.NewKeysAPI(cli)
  73. basePath := fmt.Sprintf("/%s/config", runmode)
  74. if resp, err := keysAPI.Get(context.Background(), basePath, &client.GetOptions{
  75. Recursive: true,
  76. }); err == nil && resp != nil && resp.Node != nil {
  77. Conf = &Configure{}
  78. value := getNodeData(key, resp.Node)
  79. if jsonStr, err := json.Marshal(value); err == nil {
  80. if err := json.Unmarshal(jsonStr, &Conf); err == nil {
  81. return Conf
  82. } else {
  83. fmt.Printf("json Unmarshal failed. error:%s", err)
  84. }
  85. } else {
  86. fmt.Printf("json Marshal failed. error:%s", err)
  87. }
  88. } else {
  89. fmt.Printf("get %s failed. error:%s", basePath, err)
  90. os.Exit(1)
  91. }
  92. return nil
  93. }
  94. // 递归取出node的叶子节点值
  95. func getNodeData(key string, head *client.Node) (value interface{}) {
  96. s0 := strings.Split(head.Key, "/")
  97. len0 := len(s0)
  98. if len0 == 0 {
  99. return
  100. }
  101. if head.Dir {
  102. mapData := map[string]interface{}{}
  103. for _, node := range head.Nodes {
  104. s1 := strings.Split(node.Key, "/")
  105. len1 := len(s1)
  106. if len1 == 0 {
  107. break
  108. }
  109. mapData[s1[len1-1]] = getNodeData(key, node)
  110. }
  111. value = mapData
  112. } else {
  113. if key != "" && head.Value != "" {
  114. if bytesData, err := Base64URLDecode(head.Value); err != nil {
  115. fmt.Printf("Base64URLDecode(%s) failed. error:%s", head.Value, err)
  116. os.Exit(1)
  117. } else {
  118. if data, err := AesDecrypt(bytesData, []byte(key)); err != nil {
  119. fmt.Printf("AesDecrypt failed. error:%s", err)
  120. os.Exit(1)
  121. } else {
  122. value = string(data)
  123. }
  124. }
  125. } else {
  126. // 无加密,直接取值
  127. value = head.Value
  128. }
  129. }
  130. return
  131. }
  132. // 适配k8s 方式
  133. // 公共配置会以configmap的方式映射到容器的conf/common.json中
  134. func GetConfigForK8s() *Configure {
  135. buffer, err := ioutil.ReadFile(ConfigPath)
  136. if err != nil {
  137. fmt.Printf("get %s failed. error:%s", ConfigPath, err)
  138. return nil
  139. }
  140. Conf = &Configure{}
  141. if err := json.Unmarshal(buffer, Conf); err != nil {
  142. fmt.Printf("json Unmarshal failed. error:%s", err)
  143. return nil
  144. }
  145. go watchConfigFileForK8s()
  146. return Conf
  147. }
  148. func ReloadConfigForK8s() {
  149. buffer, err := ioutil.ReadFile(ConfigPath)
  150. if err != nil {
  151. fmt.Printf("get %s failed. error:%s", ConfigPath, err)
  152. }
  153. confTmp := &Configure{}
  154. if err := json.Unmarshal(buffer, confTmp); err != nil {
  155. fmt.Printf("json Unmarshal failed. error:%s", err)
  156. }
  157. Conf = confTmp
  158. }
  159. // 判断路径文件/文件夹是否存在
  160. func Exists(path string) bool {
  161. _, err := os.Stat(path)
  162. if err != nil {
  163. if os.IsExist(err) {
  164. return true
  165. }
  166. return false
  167. }
  168. return true
  169. }
  170. func watchConfigFileForK8s() {
  171. fileExist := true
  172. watch, err := fsnotify.NewWatcher()
  173. if err != nil {
  174. fmt.Printf("new file watcher failed\n\n")
  175. os.Exit(1)
  176. }
  177. defer watch.Close()
  178. /*err = watch.Add(ConfigPath)
  179. if err != nil {
  180. fmt.Printf("add file watcher failed\n\n")
  181. os.Exit(1)
  182. }*/
  183. for {
  184. // 判断文件是否存在
  185. if !Exists(ConfigPath) {
  186. time.Sleep(10 * time.Second)
  187. fileExist = false
  188. continue
  189. } else {
  190. watch.Remove(ConfigPath)
  191. watch.Add(ConfigPath)
  192. if !fileExist { // 文件重新创建
  193. ReloadConfigForK8s()
  194. }
  195. fileExist = true
  196. }
  197. select {
  198. case ev := <-watch.Events:
  199. {
  200. fmt.Println("op : ", ev.Op)
  201. ReloadConfigForK8s()
  202. }
  203. case err := <-watch.Errors:
  204. {
  205. fmt.Println("error : ", err)
  206. continue
  207. }
  208. }
  209. }
  210. }