File: config.go

package info (click to toggle)
tendermint-go-config 0.0~git20160626.0.e64b424-1
  • links: PTS, VCS
  • area: main
  • in suites: buster, sid, stretch
  • size: 88 kB
  • ctags: 28
  • sloc: sh: 23; makefile: 2
file content (159 lines) | stat: -rw-r--r-- 3,955 bytes parent folder | download
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
package config

import (
	"strings"
	"sync"
	"time"

	"github.com/BurntSushi/toml"
	. "github.com/tendermint/go-common"
)

type Config interface {
	Get(key string) interface{}
	GetBool(key string) bool
	GetFloat64(key string) float64
	GetInt(key string) int
	GetString(key string) string
	GetStringSlice(key string) []string
	GetTime(key string) time.Time
	GetMap(key string) map[string]interface{}
	GetMapString(key string) map[string]string
	GetConfig(key string) Config
	IsSet(key string) bool
	Set(key string, value interface{})
	SetDefault(key string, value interface{})
}

type MapConfig struct {
	mtx      sync.Mutex
	required map[string]struct{} // blows up if trying to use before setting.
	data     map[string]interface{}
}

func ReadMapConfigFromFile(filePath string) (*MapConfig, error) {
	var configData = make(map[string]interface{})
	fileBytes := MustReadFile(filePath)
	err := toml.Unmarshal(fileBytes, &configData)
	if err != nil {
		return nil, err
	}
	return NewMapConfig(configData), nil
}

func NewMapConfig(data map[string]interface{}) *MapConfig {
	if data == nil {
		data = make(map[string]interface{})
	}
	return &MapConfig{
		required: make(map[string]struct{}),
		data:     data,
	}
}

func (cfg *MapConfig) Get(key string) interface{} {
	cfg.mtx.Lock()
	defer cfg.mtx.Unlock()
	if _, ok := cfg.required[key]; ok {
		PanicSanity(Fmt("config key %v is required but was not set.", key))
	}
	spl := strings.Split(key, ".")
	l := len(spl)
	if l > 1 {
		first, keyPath, keyBase := spl[0], spl[1:l-1], spl[l-1]

		f := cfg.data[first].(map[string]interface{})
		for _, k := range keyPath {
			f = f[k].(map[string]interface{})
		}
		return f[keyBase]
	}
	return cfg.data[key]
}
func (cfg *MapConfig) GetBool(key string) bool       { return cfg.Get(key).(bool) }
func (cfg *MapConfig) GetFloat64(key string) float64 { return cfg.Get(key).(float64) }
func (cfg *MapConfig) GetInt(key string) int {
	switch v := cfg.Get(key).(type) {
	case int:
		return v
	case int64:
		// when loaded from toml file, ints come as int64
		return int(v)
	}
	return cfg.Get(key).(int) // panic
}
func (cfg *MapConfig) GetString(key string) string { return cfg.Get(key).(string) }
func (cfg *MapConfig) GetMap(key string) map[string]interface{} {
	return cfg.Get(key).(map[string]interface{})
}
func (cfg *MapConfig) GetMapString(key string) map[string]string {
	return cfg.Get(key).(map[string]string)
}
func (cfg *MapConfig) GetConfig(key string) Config {
	v := cfg.Get(key)
	if v == nil {
		return NewMapConfig(nil)
	}
	return NewMapConfig(v.(map[string]interface{}))
}
func (cfg *MapConfig) GetStringSlice(key string) []string { return cfg.Get(key).([]string) }
func (cfg *MapConfig) GetTime(key string) time.Time       { return cfg.Get(key).(time.Time) }
func (cfg *MapConfig) IsSet(key string) bool {
	cfg.mtx.Lock()
	defer cfg.mtx.Unlock()
	_, ok := cfg.data[key]
	return ok
}
func (cfg *MapConfig) Set(key string, value interface{}) {
	cfg.mtx.Lock()
	defer cfg.mtx.Unlock()
	delete(cfg.required, key)
	cfg.set(key, value)
}
func (cfg *MapConfig) set(key string, value interface{}) {
	spl := strings.Split(key, ".")
	l := len(spl)
	if l > 1 {
		first, keyPath, keyBase := spl[0], spl[1:l-1], spl[l-1]

		f := assertOrNewMap(cfg.data, first)
		for _, k := range keyPath {
			f = assertOrNewMap(f, k)
		}
		f[keyBase] = value
		return
	}
	cfg.data[key] = value
}

func (cfg *MapConfig) SetDefault(key string, value interface{}) {
	cfg.mtx.Lock()
	delete(cfg.required, key)
	cfg.mtx.Unlock()

	if cfg.IsSet(key) {
		return
	}

	cfg.mtx.Lock()
	cfg.set(key, value)
	cfg.mtx.Unlock()
}

func (cfg *MapConfig) SetRequired(key string) {
	if cfg.IsSet(key) {
		return
	}
	cfg.mtx.Lock()
	cfg.required[key] = struct{}{}
	cfg.mtx.Unlock()
}

func assertOrNewMap(dataMap map[string]interface{}, key string) map[string]interface{} {
	m, ok := dataMap[key].(map[string]interface{})
	if !ok {
		m = make(map[string]interface{})
		dataMap[key] = m
	}
	return m
}