| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247 |
- package apollo
- import (
- "bufio"
- "fmt"
- "io/ioutil"
- "os"
- "os/signal"
- "reflect"
- "sync"
- "time"
- agollo2 "git.shuncheng.lu/bigthing/gocommon/pkg/conf/remote/apollo/agollo"
- "git.shuncheng.lu/bigthing/gocommon/pkg/internal/util"
- "github.com/tidwall/gjson"
- )
- var (
- readLock sync.Mutex
- rootPath string
- lastConfig map[string]interface{}
- watchChannel = make(chan struct{})
- nameSpaceConfig gjson.Result
- regularMonitorInterval = 30 * time.Second
- )
- func Start() {
- rootPath = util.GetRootPath() + "/config"
- err := loadNameSpacesConfig(getNameSpacesConfigPath())
- if err != nil {
- panic(fmt.Sprintf("apollo:load err: %s", err.Error()))
- }
- err = agollo2.InitWithConfigFile(
- getApolloConfigPath(),
- agollo2.WithLogger(agollo2.NewLogger(agollo2.LoggerWriter(os.Stdout))), // 打印日志信息
- agollo2.PreloadNamespaces(getNameSpaces()...), // 预先加载的namespace列表,如果是通过配置启动,会在app.properties配置的基础上追加
- agollo2.AutoFetchOnCacheMiss(), // 在配置未找到时,去apollo的带缓存的获取配置接口,获取配置
- agollo2.FailTolerantOnBackupExists(),
- agollo2.BackupFile(getBackFilePath()), // 在连接apollo失败时,如果在配置的目录下存在.agollo备份配置,会读取备份在服务器无法连接的情况下
- )
- if err != nil {
- panic(fmt.Sprintf("apollo:init err: %s", err.Error()))
- }
- err = writeMapToFile()
- if err != nil {
- panic(fmt.Sprintf("apollo:write file err: %s", err.Error()))
- }
- go listen()
- }
- func GetConfigPath() string {
- return rootPath + "/apollo/env.ini"
- }
- func SetRefreshInterval(second int) {
- regularMonitorInterval = time.Duration(second) * time.Second
- }
- func Watch() <-chan struct{} {
- return watchChannel
- }
- func listen() {
- signals := make(chan os.Signal)
- signal.Notify(signals, os.Interrupt)
- lastConfig = deepCopy(agollo2.GetAll())
- for {
- timer := time.NewTimer(regularMonitorInterval)
- select {
- case <-timer.C:
- err := agollo2.Reload()
- if err != nil {
- fmt.Printf("[apollo] reload err: %s\n", err)
- continue
- }
- newConfig := deepCopy(agollo2.GetAll())
- if reflect.DeepEqual(lastConfig, newConfig) {
- continue
- }
- lastConfig = newConfig
- err = writeMapToFile()
- if err != nil {
- fmt.Printf("[apollo] write env err: %s\n", err)
- continue
- }
- watchChannel <- struct{}{}
- case <-signals:
- fmt.Println("[apollo] receive signal, exited")
- return
- }
- }
- select {}
- }
- func getBackFilePath() string {
- return rootPath + "/apollo/.agollo"
- }
- func getApolloConfigPath() string {
- return rootPath + "/apollo/apollo.json"
- }
- func getNameSpacesConfigPath() string {
- return rootPath + "/apollo/namespaces.json"
- }
- func getNameSpaces() []string {
- nameSpaceList := make([]string, 0)
- nameSpaceConfig.ForEach(func(key gjson.Result, value gjson.Result) bool {
- nameSpaceList = append(nameSpaceList, getNameSpace(value))
- return true
- })
- return nameSpaceList
- }
- func getNameSpace(nameSpace gjson.Result) string {
- return nameSpace.Get("namespace").String()
- }
- func getSections(sections gjson.Result) gjson.Result {
- return sections.Get("sections")
- }
- func getSectionName(section gjson.Result) string {
- return section.Get("name").String()
- }
- func getKeys(section gjson.Result) gjson.Result {
- return section.Get("keys")
- }
- func getKeyName(key gjson.Result) string {
- return key.Get("name").String()
- }
- func getKeyMapTo(key gjson.Result) string {
- return key.Get("mapTo").String()
- }
- func getKeysMap() map[string]map[string]map[string]string {
- maps := map[string]map[string]map[string]string{}
- nameSpaceConfig.ForEach(func(nameSpaceKey gjson.Result, value gjson.Result) bool {
- nameSpace := getNameSpace(value)
- _, ok := maps[nameSpace]
- if !ok {
- maps[nameSpace] = map[string]map[string]string{}
- }
- sections := getSections(value)
- sections.ForEach(func(sectionKey gjson.Result, section gjson.Result) bool {
- sectionName := getSectionName(section)
- keys := getKeys(section)
- keys.ForEach(func(keys gjson.Result, key gjson.Result) bool {
- keyName := getKeyName(key)
- keyMapTo := getKeyMapTo(key)
- _, ok := maps[nameSpace][keyName]
- if ok {
- return true
- }
- maps[nameSpace][keyName] = map[string]string{}
- maps[nameSpace][keyName]["section"] = sectionName
- keyRealName := keyMapTo
- if keyMapTo == "" {
- keyRealName = keyName
- }
- maps[nameSpace][keyName]["mapTo"] = keyRealName
- return true
- })
- return true
- })
- return true
- })
- return maps
- }
- func loadNameSpacesConfig(configPath string) error {
- file, err := os.Open(configPath)
- if err != nil {
- return err
- }
- defer file.Close()
- contents, err := ioutil.ReadAll(file)
- if err != nil {
- return err
- }
- nameSpaceConfig = gjson.Get(string(contents), "namespaces")
- return nil
- }
- //将所有的配置信息写入标准的配置文件里面
- func writeMapToFile() error {
- readLock.Lock()
- defer readLock.Unlock()
- f, err := os.Create(GetConfigPath())
- if err != nil {
- fmt.Printf("apollo:create config file err, err: %s", err.Error())
- return err
- }
- defer f.Close()
- w := bufio.NewWriter(f)
- keysMap := getKeysMap()
- for _, nameSpace := range getNameSpaces() {
- sections := map[string][]string{}
- _, ok := keysMap[nameSpace]
- if !ok {
- continue
- }
- ConfigInfo := agollo2.GetNameSpace(nameSpace)
- for key, val := range ConfigInfo {
- _, ok = keysMap[nameSpace][key]
- if !ok {
- continue
- }
- _, ok = sections[keysMap[nameSpace][key]["section"]]
- if !ok {
- sections[keysMap[nameSpace][key]["section"]] = make([]string, 0)
- }
- lineStr := fmt.Sprintf("%s=%s", keysMap[nameSpace][key]["mapTo"], val)
- sections[keysMap[nameSpace][key]["section"]] = append(sections[keysMap[nameSpace][key]["section"]], lineStr)
- }
- if len(sections) == 0 {
- continue
- }
- for section, lineStrs := range sections {
- lineSection := fmt.Sprintf("[%s]", section)
- fmt.Fprintln(w, lineSection)
- for _, lineStr := range lineStrs {
- fmt.Fprintln(w, lineStr)
- }
- }
- }
- err = w.Flush()
- if err == nil {
- return nil
- }
- return err
- }
- func deepCopy(value map[string]interface{}) map[string]interface{} {
- newMap := make(map[string]interface{})
- for k, v := range value {
- newMap[k] = v
- }
- return newMap
- }
|