Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
kardolus
GitHub Repository: kardolus/chatgpt-cli
Path: blob/main/vendor/github.com/spf13/viper/remote.go
2875 views
1
package viper
2
3
import (
4
"bytes"
5
"fmt"
6
"io"
7
"reflect"
8
"slices"
9
)
10
11
// SupportedRemoteProviders are universally supported remote providers.
12
var SupportedRemoteProviders = []string{"etcd", "etcd3", "consul", "firestore", "nats"}
13
14
func resetRemote() {
15
SupportedRemoteProviders = []string{"etcd", "etcd3", "consul", "firestore", "nats"}
16
}
17
18
type remoteConfigFactory interface {
19
Get(rp RemoteProvider) (io.Reader, error)
20
Watch(rp RemoteProvider) (io.Reader, error)
21
WatchChannel(rp RemoteProvider) (<-chan *RemoteResponse, chan bool)
22
}
23
24
type RemoteResponse struct {
25
Value []byte
26
Error error
27
}
28
29
// RemoteConfig is optional, see the remote package.
30
var RemoteConfig remoteConfigFactory
31
32
// UnsupportedRemoteProviderError denotes encountering an unsupported remote
33
// provider. Currently only etcd and Consul are supported.
34
type UnsupportedRemoteProviderError string
35
36
// Error returns the formatted remote provider error.
37
func (str UnsupportedRemoteProviderError) Error() string {
38
return fmt.Sprintf("Unsupported Remote Provider Type %q", string(str))
39
}
40
41
// RemoteConfigError denotes encountering an error while trying to
42
// pull the configuration from the remote provider.
43
type RemoteConfigError string
44
45
// Error returns the formatted remote provider error.
46
func (rce RemoteConfigError) Error() string {
47
return fmt.Sprintf("Remote Configurations Error: %s", string(rce))
48
}
49
50
type defaultRemoteProvider struct {
51
provider string
52
endpoint string
53
path string
54
secretKeyring string
55
}
56
57
func (rp defaultRemoteProvider) Provider() string {
58
return rp.provider
59
}
60
61
func (rp defaultRemoteProvider) Endpoint() string {
62
return rp.endpoint
63
}
64
65
func (rp defaultRemoteProvider) Path() string {
66
return rp.path
67
}
68
69
func (rp defaultRemoteProvider) SecretKeyring() string {
70
return rp.secretKeyring
71
}
72
73
// RemoteProvider stores the configuration necessary
74
// to connect to a remote key/value store.
75
// Optional secretKeyring to unencrypt encrypted values
76
// can be provided.
77
type RemoteProvider interface {
78
Provider() string
79
Endpoint() string
80
Path() string
81
SecretKeyring() string
82
}
83
84
// AddRemoteProvider adds a remote configuration source.
85
// Remote Providers are searched in the order they are added.
86
// provider is a string value: "etcd", "etcd3", "consul", "firestore" or "nats" are currently supported.
87
// endpoint is the url. etcd requires http://ip:port, consul requires ip:port, nats requires nats://ip:port
88
// path is the path in the k/v store to retrieve configuration
89
// To retrieve a config file called myapp.json from /configs/myapp.json
90
// you should set path to /configs and set config name (SetConfigName()) to
91
// "myapp".
92
func AddRemoteProvider(provider, endpoint, path string) error {
93
return v.AddRemoteProvider(provider, endpoint, path)
94
}
95
96
func (v *Viper) AddRemoteProvider(provider, endpoint, path string) error {
97
if !slices.Contains(SupportedRemoteProviders, provider) {
98
return UnsupportedRemoteProviderError(provider)
99
}
100
if provider != "" && endpoint != "" {
101
v.logger.Info("adding remote provider", "provider", provider, "endpoint", endpoint)
102
103
rp := &defaultRemoteProvider{
104
endpoint: endpoint,
105
provider: provider,
106
path: path,
107
}
108
if !v.providerPathExists(rp) {
109
v.remoteProviders = append(v.remoteProviders, rp)
110
}
111
}
112
return nil
113
}
114
115
// AddSecureRemoteProvider adds a remote configuration source.
116
// Secure Remote Providers are searched in the order they are added.
117
// provider is a string value: "etcd", "etcd3", "consul", "firestore" or "nats" are currently supported.
118
// endpoint is the url. etcd requires http://ip:port consul requires ip:port
119
// secretkeyring is the filepath to your openpgp secret keyring. e.g. /etc/secrets/myring.gpg
120
// path is the path in the k/v store to retrieve configuration
121
// To retrieve a config file called myapp.json from /configs/myapp.json
122
// you should set path to /configs and set config name (SetConfigName()) to
123
// "myapp".
124
// Secure Remote Providers are implemented with github.com/sagikazarmark/crypt.
125
func AddSecureRemoteProvider(provider, endpoint, path, secretkeyring string) error {
126
return v.AddSecureRemoteProvider(provider, endpoint, path, secretkeyring)
127
}
128
129
func (v *Viper) AddSecureRemoteProvider(provider, endpoint, path, secretkeyring string) error {
130
if !slices.Contains(SupportedRemoteProviders, provider) {
131
return UnsupportedRemoteProviderError(provider)
132
}
133
if provider != "" && endpoint != "" {
134
v.logger.Info("adding remote provider", "provider", provider, "endpoint", endpoint)
135
136
rp := &defaultRemoteProvider{
137
endpoint: endpoint,
138
provider: provider,
139
path: path,
140
secretKeyring: secretkeyring,
141
}
142
if !v.providerPathExists(rp) {
143
v.remoteProviders = append(v.remoteProviders, rp)
144
}
145
}
146
return nil
147
}
148
149
func (v *Viper) providerPathExists(p *defaultRemoteProvider) bool {
150
for _, y := range v.remoteProviders {
151
if reflect.DeepEqual(y, p) {
152
return true
153
}
154
}
155
return false
156
}
157
158
// ReadRemoteConfig attempts to get configuration from a remote source
159
// and read it in the remote configuration registry.
160
func ReadRemoteConfig() error { return v.ReadRemoteConfig() }
161
162
func (v *Viper) ReadRemoteConfig() error {
163
return v.getKeyValueConfig()
164
}
165
166
func WatchRemoteConfig() error { return v.WatchRemoteConfig() }
167
func (v *Viper) WatchRemoteConfig() error {
168
return v.watchKeyValueConfig()
169
}
170
171
func (v *Viper) WatchRemoteConfigOnChannel() error {
172
return v.watchKeyValueConfigOnChannel()
173
}
174
175
// Retrieve the first found remote configuration.
176
func (v *Viper) getKeyValueConfig() error {
177
if RemoteConfig == nil {
178
return RemoteConfigError("Enable the remote features by doing a blank import of the viper/remote package: '_ github.com/spf13/viper/remote'")
179
}
180
181
if len(v.remoteProviders) == 0 {
182
return RemoteConfigError("No Remote Providers")
183
}
184
185
for _, rp := range v.remoteProviders {
186
val, err := v.getRemoteConfig(rp)
187
if err != nil {
188
v.logger.Error(fmt.Errorf("get remote config: %w", err).Error())
189
190
continue
191
}
192
193
v.kvstore = val
194
195
return nil
196
}
197
return RemoteConfigError("No Files Found")
198
}
199
200
func (v *Viper) getRemoteConfig(provider RemoteProvider) (map[string]any, error) {
201
reader, err := RemoteConfig.Get(provider)
202
if err != nil {
203
return nil, err
204
}
205
err = v.unmarshalReader(reader, v.kvstore)
206
return v.kvstore, err
207
}
208
209
// Retrieve the first found remote configuration.
210
func (v *Viper) watchKeyValueConfigOnChannel() error {
211
if len(v.remoteProviders) == 0 {
212
return RemoteConfigError("No Remote Providers")
213
}
214
215
for _, rp := range v.remoteProviders {
216
respc, _ := RemoteConfig.WatchChannel(rp)
217
// Todo: Add quit channel
218
go func(rc <-chan *RemoteResponse) {
219
for {
220
b := <-rc
221
reader := bytes.NewReader(b.Value)
222
err := v.unmarshalReader(reader, v.kvstore)
223
if err != nil {
224
v.logger.Error(fmt.Errorf("failed to unmarshal remote config: %w", err).Error())
225
}
226
}
227
}(respc)
228
return nil
229
}
230
return RemoteConfigError("No Files Found")
231
}
232
233
// Retrieve the first found remote configuration.
234
func (v *Viper) watchKeyValueConfig() error {
235
if len(v.remoteProviders) == 0 {
236
return RemoteConfigError("No Remote Providers")
237
}
238
239
for _, rp := range v.remoteProviders {
240
val, err := v.watchRemoteConfig(rp)
241
if err != nil {
242
v.logger.Error(fmt.Errorf("watch remote config: %w", err).Error())
243
244
continue
245
}
246
v.kvstore = val
247
return nil
248
}
249
return RemoteConfigError("No Files Found")
250
}
251
252
func (v *Viper) watchRemoteConfig(provider RemoteProvider) (map[string]any, error) {
253
reader, err := RemoteConfig.Watch(provider)
254
if err != nil {
255
return nil, err
256
}
257
err = v.unmarshalReader(reader, v.kvstore)
258
return v.kvstore, err
259
}
260
261