nacos.go 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. package conf
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "fmt"
  6. "leafstalk/log"
  7. "strings"
  8. "github.com/nacos-group/nacos-sdk-go/v2/clients"
  9. "github.com/nacos-group/nacos-sdk-go/v2/clients/config_client"
  10. "github.com/nacos-group/nacos-sdk-go/v2/common/constant"
  11. "github.com/nacos-group/nacos-sdk-go/v2/vo"
  12. "github.com/spf13/viper"
  13. )
  14. // LocalNacosConfig 本地nacos配置
  15. type LocalNacosConfig struct {
  16. NamespaceId string `json:"namespaceId"` // 空间命名
  17. LineGroup string `json:"lineGroup"` // 线路分组
  18. PublicGroup string `json:"publicGroup"` // 线路分组
  19. UserName string `json:"userName"` //
  20. PassWord string `json:"passWord"` //
  21. Servers []*ConfigServer `json:"servers"` // 集群服务器
  22. }
  23. type ConfigServer struct {
  24. IpAddr string `json:"ipAddr"` // ip地址
  25. Port uint64 `json:"port"` // 端口
  26. }
  27. // ConfigCenterAgent 配置中心代理
  28. type ConfigCenterAgent struct {
  29. NacosClient config_client.IConfigClient // 客户端api
  30. }
  31. // 配置中心代理
  32. func NewNacosConfigCenter(cfg *LocalNacosConfig, dataDirName string) (cli *ConfigCenterAgent, err error) {
  33. // 基本配置检查
  34. if cfg == nil || len(cfg.NamespaceId) == 0 { // len(cfg.DataID) == 0 ||
  35. err = errors.New("configuration check failed")
  36. return
  37. }
  38. // nacos客户端
  39. nacosClient, err := createNacosClient(cfg, dataDirName)
  40. if err != nil {
  41. return nil, err
  42. }
  43. cli = new(ConfigCenterAgent)
  44. cli.NacosClient = nacosClient
  45. return
  46. }
  47. // createNacosClient create config client.
  48. func createNacosClient(cfg *LocalNacosConfig, dataDirName string) (iClient config_client.IConfigClient, err error) {
  49. clientConfig := *constant.NewClientConfig(
  50. constant.WithNamespaceId(cfg.NamespaceId), //When namespace is public, fill in the blank string here.
  51. constant.WithTimeoutMs(5000),
  52. constant.WithBeatInterval(1000),
  53. constant.WithNotLoadCacheAtStart(true),
  54. constant.WithLogDir(fmt.Sprintf("../nacos/%s/log", dataDirName)),
  55. constant.WithCacheDir(fmt.Sprintf("../nacos/%s/cache", dataDirName)),
  56. constant.WithLogLevel("debug"),
  57. constant.WithUsername(cfg.UserName),
  58. constant.WithPassword(cfg.PassWord),
  59. )
  60. var serverConfigs []constant.ServerConfig
  61. for _, serv := range cfg.Servers {
  62. c := constant.NewServerConfig(
  63. serv.IpAddr,
  64. serv.Port,
  65. constant.WithScheme("http"),
  66. constant.WithContextPath("/nacos"),
  67. )
  68. serverConfigs = append(serverConfigs, *c)
  69. }
  70. // Another way of create config client for dynamic configuration (recommend)
  71. return clients.NewConfigClient(
  72. vo.NacosClientParam{
  73. ClientConfig: &clientConfig,
  74. ServerConfigs: serverConfigs,
  75. },
  76. )
  77. }
  78. // GetIClient get client api
  79. func (c *ConfigCenterAgent) GetIClient() config_client.IConfigClient {
  80. return c.NacosClient
  81. }
  82. // GetConfig get config info
  83. func (c *ConfigCenterAgent) GetConfig(dataId string, group string) (string, error) {
  84. return c.NacosClient.GetConfig(vo.ConfigParam{
  85. DataId: dataId,
  86. Group: group,
  87. })
  88. }
  89. // PublishConfig publish config
  90. func (c *ConfigCenterAgent) PublishConfig(content string, dataId string, group string) (bool, error) {
  91. return c.NacosClient.PublishConfig(vo.ConfigParam{
  92. DataId: dataId,
  93. Group: group,
  94. Content: content,
  95. })
  96. }
  97. // DeleteConfig delete config
  98. func (c *ConfigCenterAgent) DeleteConfig(dataId string, group string) (bool, error) {
  99. return c.NacosClient.DeleteConfig(vo.ConfigParam{
  100. DataId: dataId,
  101. Group: group,
  102. })
  103. }
  104. // CancelListenConfig Cancel the listening of config change event
  105. func (c *ConfigCenterAgent) CancelListenConfig(dataId string, group string) error {
  106. return c.NacosClient.CancelListenConfig(vo.ConfigParam{
  107. DataId: dataId,
  108. Group: group,
  109. })
  110. }
  111. // ListenChanges Listen config change event
  112. func (c *ConfigCenterAgent) ListenChanges(dataId string, group string, onChange func(namespace, group, dataId, data string)) error {
  113. return c.NacosClient.ListenConfig(vo.ConfigParam{
  114. DataId: dataId,
  115. Group: group,
  116. OnChange: onChange,
  117. })
  118. }
  119. // LoadSysConfig 加载系统配置
  120. // 先从本地拿到nacos配置,然后到nacos中拿系统配置
  121. func LoadSysConfig(cfgFile string, appName string) (sub1 *Config, err error) {
  122. conf1 := viper.New()
  123. conf1.SetConfigFile(cfgFile) //"../conf/grave.json"
  124. if err = conf1.ReadInConfig(); err != nil {
  125. log.Warnf("LoadSysConfig ReadInConfig error %v", err)
  126. return
  127. }
  128. // 取nacos相关配置
  129. var nacosCfg *LocalNacosConfig
  130. if err = conf1.UnmarshalKey("nacos", &nacosCfg); err != nil {
  131. log.Warnf("LoadSysConfig UnmarshalKey error %v", err)
  132. return
  133. }
  134. if nacosCfg == nil {
  135. return nil, errors.New("no config")
  136. }
  137. log.Infof("LoadSysConfig nacosCfg %v", *nacosCfg)
  138. // 构成配置中心
  139. cfgCenter, err := NewNacosConfigCenter(nacosCfg, appName)
  140. if err != nil {
  141. log.Warnf("LoadSysConfig NewNacosConfigCenter error %v", err)
  142. return
  143. }
  144. // 初始化动态配置事件
  145. err = initDynamicEvent(cfgCenter, nacosCfg.PublicGroup)
  146. if err != nil {
  147. log.Warnf("LoadSysConfig initDynamicEvent error %v", err)
  148. return
  149. }
  150. // 从配置中心拿静态配置
  151. content, err := cfgCenter.GetConfig(appName, nacosCfg.LineGroup)
  152. if err != nil {
  153. log.Warnf("LoadSysConfig GetConfig %v error %v", nacosCfg.LineGroup, err)
  154. return
  155. }
  156. if err = conf1.MergeConfig(strings.NewReader(content)); err != nil {
  157. log.Warnf("LoadSysConfig MergeConfig %v error %v %v", nacosCfg.LineGroup, content, err)
  158. return
  159. }
  160. // // 共享组配置
  161. // content2, err2 := cfgCenter.GetConfig(appName, nacosCfg.PublicGroup)
  162. // if err2 != nil {
  163. // log.Warnf("LoadSysConfig GetConfig %v error %v", nacosCfg.PublicGroup, err2)
  164. // return
  165. // }
  166. // if err = conf1.MergeConfig(strings.NewReader(content2)); err != nil {
  167. // log.Warnf("LoadSysConfig MergeConfig %v error %v %v", nacosCfg.PublicGroup, content, err)
  168. // return
  169. // }
  170. // 拿各模块配置
  171. includeList := conf1.GetStringSlice("include")
  172. for _, v := range includeList {
  173. dataId := v
  174. lineGroup := nacosCfg.LineGroup
  175. ss := strings.Split(v, ".")
  176. if len(ss) == 2 {
  177. lineGroup = ss[0]
  178. dataId = ss[1]
  179. }
  180. // // 分析一条包含项, 获取到线路、数据项,选择项
  181. // lineGroup, dataId, opts, err := parseIncludeItem(dataId, lineGroup)
  182. // if err != nil {
  183. // log.Warnf("LoadSysConfig parseIncludeItem error %v", err)
  184. // return nil, err
  185. // }
  186. // 先获取数据项
  187. var subContent string
  188. if subContent, err = cfgCenter.GetConfig(dataId, lineGroup); err != nil {
  189. log.Warnf("LoadSysConfig GetConfig %v error2 %v", dataId, err)
  190. return nil, err
  191. }
  192. var data map[string]interface{}
  193. if err = json.Unmarshal([]byte(subContent), &data); err != nil {
  194. log.Warnf("LoadSysConfig Unmarshal error2 %v", err)
  195. err = fmt.Errorf("load include sub:%v, err:%+v", dataId, err)
  196. return nil, err
  197. }
  198. // // 调整可选项
  199. // data, err = adjustOpts(dataId, data, opts)
  200. // if err != nil {
  201. // return nil, err
  202. // }
  203. conf1.Set(dataId, data)
  204. }
  205. for _, key := range conf1.AllKeys() {
  206. value := conf1.Get(key)
  207. fmt.Printf("%s: %v\n", key, value)
  208. }
  209. sub1 = NewConfig(conf1)
  210. return
  211. }
  212. // ["etcd", "nats", "sharedRedis", "lines.etcd", "lines.nats.[gmSbject.line1]", "lines.redis.[line1]" ]
  213. // 从.[分割,前面是数据项;后面是可选项
  214. // 数据项单项:默认数据组做数据组 单项值做数据ID
  215. // 数据项双项:第一项是数据组,第二项是数据ID
  216. // 可选项:可以有多个可选项
  217. func parseIncludeItem(itemVal string, defaultLineGroup string) (lineGroup string, dataId string, opts []string, err error) {
  218. splitDataId := func(val string) (group string, dataId string, err error) {
  219. vals := strings.Split(val, ".")
  220. if len(vals) == 1 {
  221. return defaultLineGroup, vals[0], nil
  222. } else if len(vals) == 2 {
  223. return vals[0], vals[1], nil
  224. }
  225. return "", "", errors.New("error dataId format")
  226. }
  227. // 用.[分割字符串
  228. vals := strings.Split(itemVal, ".[")
  229. num := len(vals)
  230. if num != 1 && num != 2 {
  231. return "", "", nil, errors.New("error dataId format1")
  232. }
  233. if num == 2 {
  234. vals[1] = strings.TrimRight(vals[1], "]")
  235. }
  236. // 先分割数据项
  237. lineGroup, dataId, err = splitDataId(vals[0])
  238. if err != nil {
  239. return "", "", nil, errors.New("error dataId format2")
  240. }
  241. if num == 1 {
  242. return lineGroup, dataId, nil, nil
  243. }
  244. // 分割选项
  245. opts = strings.Split(vals[1], ",")
  246. return lineGroup, dataId, opts, nil
  247. }
  248. // "lines.redis.[line1]"; "lines.redis.[db.line1]"; "lines.redis.[db.line1, addr.line1]"
  249. // 所有非可选项 + 可选项 做数据项的值.可以有多个可选项. 针对每个子可选项:
  250. // 分割后只有一项:单项值做数据项的值;只有一项时,不能有其他可选项,例如不能lines.redis.[line1, addr.line1]
  251. // 分割后有2项:第二项的值提取出来,做第一项的值
  252. func adjustOpts(dataId string, data map[string]interface{}, opts []string) (map[string]interface{}, error) {
  253. for _, opt := range opts {
  254. path := strings.Split(opt, ".")
  255. if len(path) == 1 {
  256. // 子项做主项,只能一个,并且没有兄弟子项
  257. if len(opts) != 1 {
  258. return nil, errors.New("errors opts format1")
  259. }
  260. data[dataId] = data[opt]
  261. return data, nil
  262. } else if len(path) == 2 {
  263. // 孙子项替换子项 lines.redis.[db.line1]
  264. childKey := path[0]
  265. grandsonKey := path[1]
  266. childVal, ok := data[childKey]
  267. if !ok {
  268. return nil, errors.New("errors opts format2")
  269. }
  270. grandsons, ok := childVal.(map[string]interface{})
  271. if !ok {
  272. return nil, errors.New("errors opts format3")
  273. }
  274. data[childKey], ok = grandsons[grandsonKey]
  275. if !ok {
  276. return nil, errors.New("errors opts format4")
  277. }
  278. continue
  279. }
  280. return nil, errors.New("errors opts formatn")
  281. }
  282. return data, nil
  283. }