github.com/zly-app/zapp@v1.3.3/config/apollo.go (about) 1 /* 2 ------------------------------------------------- 3 Author : zlyuancn 4 date: 2020/12/18 5 Description : 6 ------------------------------------------------- 7 */ 8 9 package config 10 11 import ( 12 "errors" 13 "fmt" 14 "os" 15 "strings" 16 17 "github.com/spf13/viper" 18 "go.uber.org/zap" 19 20 "github.com/zly-app/zapp/config/apollo_sdk" 21 "github.com/zly-app/zapp/consts" 22 "github.com/zly-app/zapp/logger" 23 ) 24 25 const defApplicationDataType = "yaml" 26 27 // 默认application命名空间下哪些key数据会被解析 28 var defApplicationParseKeys = []string{"frame", "components", "plugins", "services"} 29 30 type ApolloConfig struct { 31 Address string // apollo-api地址, 多个地址用英文逗号连接 32 AppId string // 应用名 33 AccessKey string // 验证key, 优先级高于基础认证 34 AuthBasicUser string // 基础认证用户名, 可用于nginx的基础认证扩展 35 AuthBasicPassword string // 基础认证密码 36 Cluster string // 集群名, 默认default 37 AlwaysLoadFromRemote bool // 总是从远程获取, 在远程加载失败时不会从备份文件加载 38 BackupFile string // 备份文件名 39 ApplicationDataType string // application命名空间下key的值的数据类型, 支持yaml,yml,toml,json 40 ApplicationParseKeys []string // application命名空间下哪些key数据会被解析, 无论如何默认的key(frame/components/plugins/services)会被解析 41 Namespaces []string // 其他自定义命名空间 42 IgnoreNamespaceNotFound bool // 是否忽略命名空间不存在, 无论如何设置application命名空间必须存在 43 client *apollo_sdk.ApolloClient 44 } 45 46 // 从viper构建apollo配置 47 func makeApolloConfigFromViper(vi *viper.Viper) (*ApolloConfig, error) { 48 if !vi.IsSet(consts.ApolloConfigKey) { 49 return nil, errors.New("apollo配置不存在") 50 } 51 52 var conf ApolloConfig 53 v := vi.Get(consts.ApolloConfigKey) 54 if value, ok := v.(*ApolloConfig); ok { 55 conf = *value 56 if conf.client != nil { 57 return &conf, nil 58 } 59 } else { 60 err := vi.UnmarshalKey(consts.ApolloConfigKey, &conf) 61 if err != nil { 62 return nil, err 63 } 64 } 65 66 if conf.Cluster == "" { 67 conf.Cluster = os.Getenv(consts.ApolloConfigClusterFromEnvKey) 68 } 69 70 switch v := strings.ToLower(conf.ApplicationDataType); v { 71 case "": 72 conf.ApplicationDataType = defApplicationDataType 73 case "yaml", "yml", "json", "toml": 74 conf.ApplicationDataType = v 75 default: 76 return nil, fmt.Errorf("不支持的ApplicationDataType: %v", conf.ApplicationDataType) 77 } 78 79 ac := &apollo_sdk.ApolloClient{ 80 Address: conf.Address, 81 AppId: conf.AppId, 82 AccessKey: conf.AccessKey, 83 AuthBasicUser: conf.AuthBasicUser, 84 AuthBasicPassword: conf.AuthBasicPassword, 85 Cluster: conf.Cluster, 86 AlwaysLoadFromRemote: conf.AlwaysLoadFromRemote, 87 BackupFile: conf.BackupFile, 88 Namespaces: append([]string{}, conf.Namespaces...), 89 IgnoreNamespaceNotFound: conf.IgnoreNamespaceNotFound, 90 } 91 err := ac.Init() 92 if err != nil { 93 return nil, err 94 } 95 conf.client = ac 96 97 vi.Set(consts.ApolloConfigKey, &conf) 98 return &conf, nil 99 } 100 101 // 从apollo中获取配置构建viper 102 func makeViperFromApollo(conf *ApolloConfig) (*viper.Viper, error) { 103 dataList, err := conf.client.GetNamespacesData() 104 if err != nil { 105 return nil, fmt.Errorf("获取apollo配置数据失败: %s", err) 106 } 107 108 configs := make(map[string]interface{}, len(dataList)) 109 for namespace, data := range dataList { 110 err := analyseApolloConfig(configs, namespace, data.Configurations, conf) 111 if err != nil { 112 return nil, fmt.Errorf("分析apollo配置数据失败: %v", err) 113 } 114 } 115 116 // 构建viper 117 vi := viper.New() 118 if err = vi.MergeConfigMap(configs); err != nil { 119 return nil, fmt.Errorf("合并apollo配置数据失败: %s", err) 120 } 121 return vi, nil 122 } 123 124 // 分析apollo配置 125 func analyseApolloConfig(dst map[string]interface{}, namespace string, configurations map[string]string, conf *ApolloConfig) error { 126 if namespace != apollo_sdk.ApplicationNamespace { 127 dst[namespace] = configurations 128 logger.Log.Info("分析apollo配置数据", 129 zap.String("namespace", namespace), 130 zap.Any("configurations", configurations), 131 ) 132 return nil 133 } 134 135 isParseKey := func(key string) bool { 136 for _, s := range defApplicationParseKeys { 137 if key == s { 138 return true 139 } 140 } 141 for _, s := range conf.ApplicationParseKeys { 142 if key == s { 143 return true 144 } 145 } 146 return false 147 } 148 149 for k, v := range configurations { 150 if !isParseKey(k) { 151 mm, ok := dst[namespace] 152 if !ok { 153 mm = make(map[string]string) 154 dst[namespace] = mm 155 } 156 mm.(map[string]string)[k] = v 157 continue 158 } 159 160 vi := viper.New() 161 vi.SetConfigType(conf.ApplicationDataType) 162 err := vi.ReadConfig(strings.NewReader(v)) 163 if err != nil { 164 return fmt.Errorf("解析数据失败 key: %v, value: %v, err: %v", k, v, err) 165 } 166 data := vi.AllSettings() 167 dst[k] = data 168 } 169 return nil 170 } 171 172 // 获取apollo客户端 173 func GetApolloClient() (*apollo_sdk.ApolloClient, error) { 174 if Conf == nil { 175 return nil, fmt.Errorf("config未初始化") 176 } 177 vi := Conf.GetViper() 178 conf, err := makeApolloConfigFromViper(vi) 179 if err != nil { 180 return nil, err 181 } 182 return conf.client, nil 183 }