/
options.go
135 lines (121 loc) · 3.19 KB
/
options.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package config
import (
"fmt"
"regexp"
"strings"
"github.com/go-kratos/kratos/v2/encoding"
"github.com/go-kratos/kratos/v2/log"
)
// Decoder is config decoder.
type Decoder func(*KeyValue, map[string]interface{}) error
// Resolver resolve placeholder in config.
type Resolver func(map[string]interface{}) error
// Option is config option.
type Option func(*options)
type options struct {
sources []Source
decoder Decoder
resolver Resolver
logger log.Logger
}
// WithSource with config source.
func WithSource(s ...Source) Option {
return func(o *options) {
o.sources = s
}
}
// WithDecoder with config decoder.
// DefaultDecoder behavior:
// If KeyValue.Format is non-empty, then KeyValue.Value will be deserialized into map[string]interface{}
// and stored in the config cache(map[string]interface{})
// if KeyValue.Format is empty,{KeyValue.Key : KeyValue.Value} will be stored in config cache(map[string]interface{})
func WithDecoder(d Decoder) Option {
return func(o *options) {
o.decoder = d
}
}
// WithResolver with config resolver.
func WithResolver(r Resolver) Option {
return func(o *options) {
o.resolver = r
}
}
// WithLogger with config logger.
func WithLogger(l log.Logger) Option {
return func(o *options) {
o.logger = l
}
}
// defaultDecoder decode config from source KeyValue
// to target map[string]interface{} using src.Format codec.
func defaultDecoder(src *KeyValue, target map[string]interface{}) error {
if src.Format == "" {
// expand key "aaa.bbb" into map[aaa]map[bbb]interface{}
keys := strings.Split(src.Key, ".")
for i, k := range keys {
if i == len(keys)-1 {
target[k] = src.Value
} else {
sub := make(map[string]interface{})
target[k] = sub
target = sub
}
}
return nil
}
if codec := encoding.GetCodec(src.Format); codec != nil {
return codec.Unmarshal(src.Value, &target)
}
return fmt.Errorf("unsupported key: %s format: %s", src.Key, src.Format)
}
// defaultResolver resolve placeholder in map value,
// placeholder format in ${key:default}.
func defaultResolver(input map[string]interface{}) error {
mapper := func(name string) string {
args := strings.SplitN(strings.TrimSpace(name), ":", 2) //nolint:gomnd
if v, has := readValue(input, args[0]); has {
s, _ := v.String()
return s
} else if len(args) > 1 { // default value
return args[1]
}
return ""
}
var resolve func(map[string]interface{}) error
resolve = func(sub map[string]interface{}) error {
for k, v := range sub {
switch vt := v.(type) {
case string:
sub[k] = expand(vt, mapper)
case map[string]interface{}:
if err := resolve(vt); err != nil {
return err
}
case []interface{}:
for i, iface := range vt {
switch it := iface.(type) {
case string:
vt[i] = expand(it, mapper)
case map[string]interface{}:
if err := resolve(it); err != nil {
return err
}
}
}
sub[k] = vt
}
}
return nil
}
return resolve(input)
}
func expand(s string, mapping func(string) string) string {
r := regexp.MustCompile(`\${(.*?)}`)
re := r.FindAllStringSubmatch(s, -1)
for _, i := range re {
if len(i) == 2 { //nolint:gomnd
s = strings.ReplaceAll(s, i[0], mapping(i[1]))
}
}
return s
}