fix: apollo unable to get and watch to the properties file

fix/apollo
baozhecheng 2 years ago
parent 0aa9719e3a
commit c423dc3494
  1. 89
      contrib/config/apollo/apollo.go
  2. 2
      contrib/config/apollo/parser.go
  3. 34
      contrib/config/apollo/watcher.go

@ -4,6 +4,7 @@ import (
"strings"
"github.com/go-kratos/kratos/v2/config"
"github.com/go-kratos/kratos/v2/encoding"
"github.com/go-kratos/kratos/v2/log"
"github.com/apolloconfig/agollo/v4"
@ -108,10 +109,9 @@ func NewSource(opts ...Option) config.Source {
func format(ns string) string {
arr := strings.Split(ns, ".")
if len(arr) <= 1 {
if len(arr) <= 1 || arr[len(arr)-1] == "properties" {
return "json"
}
return arr[len(arr)-1]
}
@ -120,18 +120,40 @@ func (e *apollo) load() []*config.KeyValue {
namespaces := strings.Split(e.opt.namespace, ",")
for _, ns := range namespaces {
value, err := e.client.GetConfigCache(ns).Get("content")
if strings.Contains(ns, ".") && !strings.Contains(ns, "properties") &&
(format(ns) == "yaml" || format(ns) == "yaml" || format(ns) == "json") {
value, err := e.client.GetConfigCache(ns).Get("content")
if err != nil {
log.Errorf("apollo get config failed,err:%v", err)
continue
}
// serialize the namespace content KeyValue into bytes.
kv = append(kv, &config.KeyValue{
Key: ns,
Value: []byte(value.(string)),
Format: format(ns),
})
continue
}
next := map[string]interface{}{}
e.client.GetConfigCache(ns).Range(func(key, value interface{}) bool {
// all values are out properties format
resolve(genKey(ns, key.(string)), value, next)
return true
})
f := format(ns)
codec := encoding.GetCodec(f)
val, err := codec.Marshal(next)
if err != nil {
log.Warnw("apollo get config failed", "err", err)
log.Warnf("apollo could not handle namespace %s: %v", ns, err)
continue
}
// serialize the namespace content KeyValue into bytes.
kv = append(kv, &config.KeyValue{
Key: ns,
Value: []byte(value.(string)),
Format: format(ns),
Value: val,
Format: f,
})
}
return kv
}
@ -146,3 +168,54 @@ func (e *apollo) Watch() (config.Watcher, error) {
}
return w, nil
}
// resolve convert kv pair into one map[string]interface{} by split key into different
// map level. such as: app.name = "application" => map[app][name] = "application"
func resolve(key string, value interface{}, target map[string]interface{}) {
// expand key "aaa.bbb" into map[aaa]map[bbb]interface{}
keys := strings.Split(key, ".")
last := len(keys) - 1
cursor := target
for i, k := range keys {
if i == last {
cursor[k] = value
break
}
// not the last key, be deeper
v, ok := cursor[k]
if !ok {
// create a new map
deeper := make(map[string]interface{})
cursor[k] = deeper
cursor = deeper
continue
}
// current exists, then check existing value type, if it's not map
// that means duplicate keys, and at least one is not map instance.
if cursor, ok = v.(map[string]interface{}); !ok {
log.Warnf("duplicate key: %v\n", strings.Join(keys[:i+1], "."))
break
}
}
}
// genKey got the key of config.KeyValue pair.
// eg: namespace.ext with subKey got namespace.subKey
func genKey(ns, sub string) string {
arr := strings.Split(ns, ".")
if len(arr) < 1 {
return sub
}
if len(arr) == 1 {
if ns == "" {
return sub
}
return ns + "." + sub
}
return strings.Join(arr[:len(arr)-1], ".") + "." + sub
}

@ -13,7 +13,7 @@ func (parser jsonExtParser) Parse(configContent interface{}) (map[string]interfa
type yamlExtParser struct{}
func (parser yamlExtParser) Parse(configContent interface{}) (out map[string]interface{}, err error) {
func (parser yamlExtParser) Parse(configContent interface{}) (map[string]interface{}, error) {
return map[string]interface{}{"content": configContent}, nil
}

@ -2,6 +2,8 @@ package apollo
import (
"context"
"github.com/go-kratos/kratos/v2/encoding"
"strings"
"github.com/go-kratos/kratos/v2/config"
"github.com/go-kratos/kratos/v2/log"
@ -23,14 +25,38 @@ type customChangeListener struct {
func (c *customChangeListener) onChange(namespace string, changes map[string]*storage.ConfigChange) []*config.KeyValue {
kv := make([]*config.KeyValue, 0, 2)
value, err := c.apollo.client.GetConfigCache(namespace).Get("content")
if strings.Contains(namespace, ".") && !strings.Contains(namespace, "properties") &&
(format(namespace) == "yaml" || format(namespace) == "yaml" || format(namespace) == "json") {
value, err := c.apollo.client.GetConfigCache(namespace).Get("content")
if err != nil {
log.Warnw("apollo get config failed", "err", err)
}
kv = append(kv, &config.KeyValue{
Key: namespace,
Value: []byte(value.(string)),
Format: format(namespace),
})
return kv
}
next := make(map[string]interface{})
for key, change := range changes {
resolve(genKey(namespace, key), change.NewValue, next)
}
f := format(namespace)
codec := encoding.GetCodec(f)
val, err := codec.Marshal(next)
if err != nil {
log.Warnw("apollo get config failed", "err", err)
log.Warnf("apollo could not handle namespace %s: %v", namespace, err)
return nil
}
kv = append(kv, &config.KeyValue{
Key: namespace,
Value: []byte(value.(string)),
Format: format(namespace),
Value: val,
Format: f,
})
return kv

Loading…
Cancel
Save