123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328 |
- package conf
- import (
- "encoding/json"
- "errors"
- "fmt"
- "leafstalk/log"
- "strings"
- "github.com/nacos-group/nacos-sdk-go/v2/clients"
- "github.com/nacos-group/nacos-sdk-go/v2/clients/config_client"
- "github.com/nacos-group/nacos-sdk-go/v2/common/constant"
- "github.com/nacos-group/nacos-sdk-go/v2/vo"
- "github.com/spf13/viper"
- )
- // LocalNacosConfig 本地nacos配置
- type LocalNacosConfig struct {
- NamespaceId string `json:"namespaceId"` // 空间命名
- LineGroup string `json:"lineGroup"` // 线路分组
- PublicGroup string `json:"publicGroup"` // 线路分组
- UserName string `json:"userName"` //
- PassWord string `json:"passWord"` //
- Servers []*ConfigServer `json:"servers"` // 集群服务器
- }
- type ConfigServer struct {
- IpAddr string `json:"ipAddr"` // ip地址
- Port uint64 `json:"port"` // 端口
- }
- // ConfigCenterAgent 配置中心代理
- type ConfigCenterAgent struct {
- NacosClient config_client.IConfigClient // 客户端api
- }
- // 配置中心代理
- func NewNacosConfigCenter(cfg *LocalNacosConfig, dataDirName string) (cli *ConfigCenterAgent, err error) {
- // 基本配置检查
- if cfg == nil || len(cfg.NamespaceId) == 0 { // len(cfg.DataID) == 0 ||
- err = errors.New("configuration check failed")
- return
- }
- // nacos客户端
- nacosClient, err := createNacosClient(cfg, dataDirName)
- if err != nil {
- return nil, err
- }
- cli = new(ConfigCenterAgent)
- cli.NacosClient = nacosClient
- return
- }
- // createNacosClient create config client.
- func createNacosClient(cfg *LocalNacosConfig, dataDirName string) (iClient config_client.IConfigClient, err error) {
- clientConfig := *constant.NewClientConfig(
- constant.WithNamespaceId(cfg.NamespaceId), //When namespace is public, fill in the blank string here.
- constant.WithTimeoutMs(5000),
- constant.WithBeatInterval(1000),
- constant.WithNotLoadCacheAtStart(true),
- constant.WithLogDir(fmt.Sprintf("../nacos/%s/log", dataDirName)),
- constant.WithCacheDir(fmt.Sprintf("../nacos/%s/cache", dataDirName)),
- constant.WithLogLevel("debug"),
- constant.WithUsername(cfg.UserName),
- constant.WithPassword(cfg.PassWord),
- )
- var serverConfigs []constant.ServerConfig
- for _, serv := range cfg.Servers {
- c := constant.NewServerConfig(
- serv.IpAddr,
- serv.Port,
- constant.WithScheme("http"),
- constant.WithContextPath("/nacos"),
- )
- serverConfigs = append(serverConfigs, *c)
- }
- // Another way of create config client for dynamic configuration (recommend)
- return clients.NewConfigClient(
- vo.NacosClientParam{
- ClientConfig: &clientConfig,
- ServerConfigs: serverConfigs,
- },
- )
- }
- // GetIClient get client api
- func (c *ConfigCenterAgent) GetIClient() config_client.IConfigClient {
- return c.NacosClient
- }
- // GetConfig get config info
- func (c *ConfigCenterAgent) GetConfig(dataId string, group string) (string, error) {
- return c.NacosClient.GetConfig(vo.ConfigParam{
- DataId: dataId,
- Group: group,
- })
- }
- // PublishConfig publish config
- func (c *ConfigCenterAgent) PublishConfig(content string, dataId string, group string) (bool, error) {
- return c.NacosClient.PublishConfig(vo.ConfigParam{
- DataId: dataId,
- Group: group,
- Content: content,
- })
- }
- // DeleteConfig delete config
- func (c *ConfigCenterAgent) DeleteConfig(dataId string, group string) (bool, error) {
- return c.NacosClient.DeleteConfig(vo.ConfigParam{
- DataId: dataId,
- Group: group,
- })
- }
- // CancelListenConfig Cancel the listening of config change event
- func (c *ConfigCenterAgent) CancelListenConfig(dataId string, group string) error {
- return c.NacosClient.CancelListenConfig(vo.ConfigParam{
- DataId: dataId,
- Group: group,
- })
- }
- // ListenChanges Listen config change event
- func (c *ConfigCenterAgent) ListenChanges(dataId string, group string, onChange func(namespace, group, dataId, data string)) error {
- return c.NacosClient.ListenConfig(vo.ConfigParam{
- DataId: dataId,
- Group: group,
- OnChange: onChange,
- })
- }
- // LoadSysConfig 加载系统配置
- // 先从本地拿到nacos配置,然后到nacos中拿系统配置
- func LoadSysConfig(cfgFile string, appName string) (sub1 *Config, err error) {
- conf1 := viper.New()
- conf1.SetConfigFile(cfgFile) //"../conf/grave.json"
- if err = conf1.ReadInConfig(); err != nil {
- log.Warnf("LoadSysConfig ReadInConfig error %v", err)
- return
- }
- // 取nacos相关配置
- var nacosCfg *LocalNacosConfig
- if err = conf1.UnmarshalKey("nacos", &nacosCfg); err != nil {
- log.Warnf("LoadSysConfig UnmarshalKey error %v", err)
- return
- }
- if nacosCfg == nil {
- return nil, errors.New("no config")
- }
- log.Infof("LoadSysConfig nacosCfg %v", *nacosCfg)
- // 构成配置中心
- cfgCenter, err := NewNacosConfigCenter(nacosCfg, appName)
- if err != nil {
- log.Warnf("LoadSysConfig NewNacosConfigCenter error %v", err)
- return
- }
- // 初始化动态配置事件
- err = initDynamicEvent(cfgCenter, nacosCfg.PublicGroup)
- if err != nil {
- log.Warnf("LoadSysConfig initDynamicEvent error %v", err)
- return
- }
- // 从配置中心拿静态配置
- content, err := cfgCenter.GetConfig(appName, nacosCfg.LineGroup)
- if err != nil {
- log.Warnf("LoadSysConfig GetConfig %v error %v", nacosCfg.LineGroup, err)
- return
- }
- if err = conf1.MergeConfig(strings.NewReader(content)); err != nil {
- log.Warnf("LoadSysConfig MergeConfig %v error %v %v", nacosCfg.LineGroup, content, err)
- return
- }
- // // 共享组配置
- // content2, err2 := cfgCenter.GetConfig(appName, nacosCfg.PublicGroup)
- // if err2 != nil {
- // log.Warnf("LoadSysConfig GetConfig %v error %v", nacosCfg.PublicGroup, err2)
- // return
- // }
- // if err = conf1.MergeConfig(strings.NewReader(content2)); err != nil {
- // log.Warnf("LoadSysConfig MergeConfig %v error %v %v", nacosCfg.PublicGroup, content, err)
- // return
- // }
- // 拿各模块配置
- includeList := conf1.GetStringSlice("include")
- for _, v := range includeList {
- dataId := v
- lineGroup := nacosCfg.LineGroup
- ss := strings.Split(v, ".")
- if len(ss) == 2 {
- lineGroup = ss[0]
- dataId = ss[1]
- }
- // // 分析一条包含项, 获取到线路、数据项,选择项
- // lineGroup, dataId, opts, err := parseIncludeItem(dataId, lineGroup)
- // if err != nil {
- // log.Warnf("LoadSysConfig parseIncludeItem error %v", err)
- // return nil, err
- // }
- // 先获取数据项
- var subContent string
- if subContent, err = cfgCenter.GetConfig(dataId, lineGroup); err != nil {
- log.Warnf("LoadSysConfig GetConfig %v error2 %v", dataId, err)
- return nil, err
- }
- var data map[string]interface{}
- if err = json.Unmarshal([]byte(subContent), &data); err != nil {
- log.Warnf("LoadSysConfig Unmarshal error2 %v", err)
- err = fmt.Errorf("load include sub:%v, err:%+v", dataId, err)
- return nil, err
- }
- // // 调整可选项
- // data, err = adjustOpts(dataId, data, opts)
- // if err != nil {
- // return nil, err
- // }
- conf1.Set(dataId, data)
- }
- for _, key := range conf1.AllKeys() {
- value := conf1.Get(key)
- fmt.Printf("%s: %v\n", key, value)
- }
- sub1 = NewConfig(conf1)
- return
- }
- // ["etcd", "nats", "sharedRedis", "lines.etcd", "lines.nats.[gmSbject.line1]", "lines.redis.[line1]" ]
- // 从.[分割,前面是数据项;后面是可选项
- // 数据项单项:默认数据组做数据组 单项值做数据ID
- // 数据项双项:第一项是数据组,第二项是数据ID
- // 可选项:可以有多个可选项
- func parseIncludeItem(itemVal string, defaultLineGroup string) (lineGroup string, dataId string, opts []string, err error) {
- splitDataId := func(val string) (group string, dataId string, err error) {
- vals := strings.Split(val, ".")
- if len(vals) == 1 {
- return defaultLineGroup, vals[0], nil
- } else if len(vals) == 2 {
- return vals[0], vals[1], nil
- }
- return "", "", errors.New("error dataId format")
- }
- // 用.[分割字符串
- vals := strings.Split(itemVal, ".[")
- num := len(vals)
- if num != 1 && num != 2 {
- return "", "", nil, errors.New("error dataId format1")
- }
- if num == 2 {
- vals[1] = strings.TrimRight(vals[1], "]")
- }
- // 先分割数据项
- lineGroup, dataId, err = splitDataId(vals[0])
- if err != nil {
- return "", "", nil, errors.New("error dataId format2")
- }
- if num == 1 {
- return lineGroup, dataId, nil, nil
- }
- // 分割选项
- opts = strings.Split(vals[1], ",")
- return lineGroup, dataId, opts, nil
- }
- // "lines.redis.[line1]"; "lines.redis.[db.line1]"; "lines.redis.[db.line1, addr.line1]"
- // 所有非可选项 + 可选项 做数据项的值.可以有多个可选项. 针对每个子可选项:
- // 分割后只有一项:单项值做数据项的值;只有一项时,不能有其他可选项,例如不能lines.redis.[line1, addr.line1]
- // 分割后有2项:第二项的值提取出来,做第一项的值
- func adjustOpts(dataId string, data map[string]interface{}, opts []string) (map[string]interface{}, error) {
- for _, opt := range opts {
- path := strings.Split(opt, ".")
- if len(path) == 1 {
- // 子项做主项,只能一个,并且没有兄弟子项
- if len(opts) != 1 {
- return nil, errors.New("errors opts format1")
- }
- data[dataId] = data[opt]
- return data, nil
- } else if len(path) == 2 {
- // 孙子项替换子项 lines.redis.[db.line1]
- childKey := path[0]
- grandsonKey := path[1]
- childVal, ok := data[childKey]
- if !ok {
- return nil, errors.New("errors opts format2")
- }
- grandsons, ok := childVal.(map[string]interface{})
- if !ok {
- return nil, errors.New("errors opts format3")
- }
- data[childKey], ok = grandsons[grandsonKey]
- if !ok {
- return nil, errors.New("errors opts format4")
- }
- continue
- }
- return nil, errors.New("errors opts formatn")
- }
- return data, nil
- }
|