-
Notifications
You must be signed in to change notification settings - Fork 9
/
perspective.go
128 lines (110 loc) · 3.18 KB
/
perspective.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
package config
import (
"fmt"
"github.com/safing/portbase/log"
)
// Perspective is a view on configuration data without interfering with the configuration system.
type Perspective struct {
config map[string]*perspectiveOption
}
type perspectiveOption struct {
option *Option
valueCache *valueCache
}
// NewPerspective parses the given config and returns it as a new perspective.
func NewPerspective(config map[string]interface{}) (*Perspective, error) {
// flatten config structure
config = Flatten(config)
perspective := &Perspective{
config: make(map[string]*perspectiveOption),
}
var firstErr error
var errCnt int
optionsLock.Lock()
optionsLoop:
for key, option := range options {
// get option key from config
configValue, ok := config[key]
if !ok {
continue
}
// validate value
valueCache, err := validateValue(option, configValue)
if err != nil {
errCnt++
if firstErr == nil {
firstErr = err
}
continue optionsLoop
}
// add to perspective
perspective.config[key] = &perspectiveOption{
option: option,
valueCache: valueCache,
}
}
optionsLock.Unlock()
if firstErr != nil {
if errCnt > 0 {
return perspective, fmt.Errorf("encountered %d errors, first was: %s", errCnt, firstErr)
}
return perspective, firstErr
}
return perspective, nil
}
func (p *Perspective) getPerspectiveValueCache(name string, requestedType uint8) *valueCache {
// get option
pOption, ok := p.config[name]
if !ok {
// check if option exists at all
optionsLock.RLock()
_, ok = options[name]
optionsLock.RUnlock()
if !ok {
log.Errorf("config: request for unregistered option: %s", name)
}
return nil
}
// check type
if requestedType != pOption.option.OptType {
log.Errorf("config: bad type: requested %s as %s, but is %s", name, getTypeName(requestedType), getTypeName(pOption.option.OptType))
return nil
}
// check release level
if pOption.option.ReleaseLevel > getReleaseLevel() {
return nil
}
return pOption.valueCache
}
// GetAsString returns a function that returns the wanted string with high performance.
func (p *Perspective) GetAsString(name string) (value string, ok bool) {
valueCache := p.getPerspectiveValueCache(name, OptTypeString)
if valueCache != nil {
return valueCache.stringVal, true
}
return "", false
}
// GetAsStringArray returns a function that returns the wanted string with high performance.
func (p *Perspective) GetAsStringArray(name string) (value []string, ok bool) {
valueCache := p.getPerspectiveValueCache(name, OptTypeStringArray)
if valueCache != nil {
return valueCache.stringArrayVal, true
}
return nil, false
}
// GetAsInt returns a function that returns the wanted int with high performance.
func (p *Perspective) GetAsInt(name string) (value int64, ok bool) {
valueCache := p.getPerspectiveValueCache(name, OptTypeInt)
if valueCache != nil {
return valueCache.intVal, true
}
return 0, false
}
// GetAsBool returns a function that returns the wanted int with high performance.
func (p *Perspective) GetAsBool(name string) (value bool, ok bool) {
valueCache := p.getPerspectiveValueCache(name, OptTypeBool)
if valueCache != nil {
return valueCache.boolVal, true
}
return false, false
}