config.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  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 CGINode struct {
  48. Log LogConfig `json:"log"`
  49. }
  50. type Gateway struct {
  51. AccountLockTimestamp json.Number `json:"account_lock_timestamp"`
  52. AccountLockErrors json.Number `json:"account_lock_errors"`
  53. TokenExpired json.Number `json:"token_expired"`
  54. Log LogConfig `json:"log"`
  55. ServiceName string `json:"service_name"`
  56. ServicePort json.Number `json:"service_port"`
  57. Name string `json:"name"`
  58. }
  59. type CGIConfig struct {
  60. Gateway Gateway `json:"gd_management_gateway"`
  61. }
  62. type RPCNode struct {
  63. Scheme string `json:"scheme"`
  64. Name string `json:"name"`
  65. UpdateInterval json.Number `json:"update_interval"`
  66. Log LogConfig `json:"log"`
  67. ServiceName string `json:"service_name"`
  68. ServicePort json.Number `json:"service_port"`
  69. }
  70. type RPCConfig struct {
  71. BasePath string `json:"base_path"`
  72. Service RPCNode `json:"gd_service"`
  73. Vehicle RPCNode `json:"gd_vehicle"`
  74. Management RPCNode `json:"gd_management"`
  75. Admin RPCNode `json:"gd_admin"`
  76. Statistics RPCNode `json:"gd_statistics"`
  77. Crontab RPCNode `json:"gd_crontab"`
  78. }
  79. type OssConfig struct {
  80. Endpoint string `json:"endpoint"`
  81. Id string `json:"id"`
  82. Secret string `json:"secret"`
  83. Bucket string `json:"bucket"`
  84. }
  85. type Configure struct {
  86. RunMode string `json:"run_mode"`
  87. AppKey string `json:"app_key"`
  88. AppSecret string `json:"app_secret"`
  89. Mysql MysqlConfig `json:"mysql"`
  90. Redis RedisConfig `json:"redis"`
  91. Elastic ElasticConfig `json:"elastic"`
  92. Cgi CGIConfig `json:"cgi"`
  93. Rpc RPCConfig `json:"rpc"`
  94. Oss OssConfig `json:"oss"`
  95. }
  96. // key 为加密密钥
  97. func GetConfig(runmode, key string, cli client.Client) *Configure {
  98. keysAPI := client.NewKeysAPI(cli)
  99. basePath := fmt.Sprintf("/%s/config", runmode)
  100. if resp, err := keysAPI.Get(context.Background(), basePath, &client.GetOptions{
  101. Recursive: true,
  102. }); err == nil && resp != nil && resp.Node != nil {
  103. Conf = &Configure{}
  104. value := getNodeData(key, resp.Node)
  105. if jsonStr, err := json.Marshal(value); err == nil {
  106. if err := json.Unmarshal(jsonStr, &Conf); err == nil {
  107. return Conf
  108. } else {
  109. fmt.Printf("json Unmarshal failed. error:%s", err)
  110. }
  111. } else {
  112. fmt.Printf("json Marshal failed. error:%s", err)
  113. }
  114. } else {
  115. fmt.Printf("get %s failed. error:%s", basePath, err)
  116. os.Exit(1)
  117. }
  118. return nil
  119. }
  120. // 递归取出node的叶子节点值
  121. func getNodeData(key string, head *client.Node) (value interface{}) {
  122. s0 := strings.Split(head.Key, "/")
  123. len0 := len(s0)
  124. if len0 == 0 {
  125. return
  126. }
  127. if head.Dir {
  128. mapData := map[string]interface{}{}
  129. for _, node := range head.Nodes {
  130. s1 := strings.Split(node.Key, "/")
  131. len1 := len(s1)
  132. if len1 == 0 {
  133. break
  134. }
  135. mapData[s1[len1-1]] = getNodeData(key, node)
  136. }
  137. value = mapData
  138. } else {
  139. if key != "" && head.Value != "" {
  140. if bytesData, err := Base64URLDecode(head.Value); err != nil {
  141. fmt.Printf("Base64URLDecode(%s) failed. error:%s", head.Value, err)
  142. os.Exit(1)
  143. } else {
  144. if data, err := AesDecrypt(bytesData, []byte(key)); err != nil {
  145. fmt.Printf("AesDecrypt failed. error:%s", err)
  146. os.Exit(1)
  147. } else {
  148. value = string(data)
  149. }
  150. }
  151. } else {
  152. // 无加密,直接取值
  153. value = head.Value
  154. }
  155. }
  156. return
  157. }
  158. func GetConfigForK8s() *Configure {
  159. buffer, err := ioutil.ReadFile(ConfigPath)
  160. if err != nil {
  161. fmt.Printf("get %s failed. error:%s", ConfigPath, err)
  162. return nil
  163. }
  164. Conf = &Configure{}
  165. if err := json.Unmarshal(buffer, Conf); err != nil {
  166. fmt.Printf("json Unmarshal failed. error:%s", err)
  167. return nil
  168. }
  169. go watchConfigFileForK8s()
  170. return Conf
  171. }
  172. func ReloadConfigForK8s() {
  173. buffer, err := ioutil.ReadFile(ConfigPath)
  174. if err != nil {
  175. fmt.Printf("get %s failed. error:%s", ConfigPath, err)
  176. }
  177. confTmp := &Configure{}
  178. if err := json.Unmarshal(buffer, confTmp); err != nil {
  179. fmt.Printf("json Unmarshal failed. error:%s", err)
  180. }
  181. Conf = confTmp
  182. }
  183. // 判断路径文件/文件夹是否存在
  184. func Exists(path string) bool {
  185. _, err := os.Stat(path)
  186. if err != nil {
  187. if os.IsExist(err) {
  188. return true
  189. }
  190. return false
  191. }
  192. return true
  193. }
  194. func watchConfigFileForK8s() {
  195. fileExist := true
  196. watch, err := fsnotify.NewWatcher()
  197. if err != nil {
  198. fmt.Printf("new file watcher failed\n\n")
  199. os.Exit(1)
  200. }
  201. defer watch.Close()
  202. for {
  203. // 判断文件是否存在
  204. if !Exists(ConfigPath) {
  205. time.Sleep(10 * time.Second)
  206. fileExist = false
  207. continue
  208. } else {
  209. watch.Remove(ConfigPath)
  210. watch.Add(ConfigPath)
  211. if !fileExist { // 文件重新创建
  212. ReloadConfigForK8s()
  213. }
  214. fileExist = true
  215. }
  216. select {
  217. case ev := <-watch.Events:
  218. {
  219. fmt.Println("op : ", ev.Op)
  220. ReloadConfigForK8s()
  221. }
  222. case err := <-watch.Errors:
  223. {
  224. fmt.Println("error : ", err)
  225. continue
  226. }
  227. }
  228. }
  229. }