mirror of https://github.com/spf13/viper.git
refactor: move remote code to separate file
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
This commit is contained in:
parent
7162e9244e
commit
272344e426
|
@ -0,0 +1,255 @@
|
||||||
|
package viper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SupportedRemoteProviders are universally supported remote providers.
|
||||||
|
var SupportedRemoteProviders = []string{"etcd", "etcd3", "consul", "firestore", "nats"}
|
||||||
|
|
||||||
|
func resetRemote() {
|
||||||
|
SupportedRemoteProviders = []string{"etcd", "etcd3", "consul", "firestore", "nats"}
|
||||||
|
}
|
||||||
|
|
||||||
|
type remoteConfigFactory interface {
|
||||||
|
Get(rp RemoteProvider) (io.Reader, error)
|
||||||
|
Watch(rp RemoteProvider) (io.Reader, error)
|
||||||
|
WatchChannel(rp RemoteProvider) (<-chan *RemoteResponse, chan bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
type RemoteResponse struct {
|
||||||
|
Value []byte
|
||||||
|
Error error
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoteConfig is optional, see the remote package.
|
||||||
|
var RemoteConfig remoteConfigFactory
|
||||||
|
|
||||||
|
// UnsupportedRemoteProviderError denotes encountering an unsupported remote
|
||||||
|
// provider. Currently only etcd and Consul are supported.
|
||||||
|
type UnsupportedRemoteProviderError string
|
||||||
|
|
||||||
|
// Error returns the formatted remote provider error.
|
||||||
|
func (str UnsupportedRemoteProviderError) Error() string {
|
||||||
|
return fmt.Sprintf("Unsupported Remote Provider Type %q", string(str))
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoteConfigError denotes encountering an error while trying to
|
||||||
|
// pull the configuration from the remote provider.
|
||||||
|
type RemoteConfigError string
|
||||||
|
|
||||||
|
// Error returns the formatted remote provider error.
|
||||||
|
func (rce RemoteConfigError) Error() string {
|
||||||
|
return fmt.Sprintf("Remote Configurations Error: %s", string(rce))
|
||||||
|
}
|
||||||
|
|
||||||
|
type defaultRemoteProvider struct {
|
||||||
|
provider string
|
||||||
|
endpoint string
|
||||||
|
path string
|
||||||
|
secretKeyring string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rp defaultRemoteProvider) Provider() string {
|
||||||
|
return rp.provider
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rp defaultRemoteProvider) Endpoint() string {
|
||||||
|
return rp.endpoint
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rp defaultRemoteProvider) Path() string {
|
||||||
|
return rp.path
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rp defaultRemoteProvider) SecretKeyring() string {
|
||||||
|
return rp.secretKeyring
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoteProvider stores the configuration necessary
|
||||||
|
// to connect to a remote key/value store.
|
||||||
|
// Optional secretKeyring to unencrypt encrypted values
|
||||||
|
// can be provided.
|
||||||
|
type RemoteProvider interface {
|
||||||
|
Provider() string
|
||||||
|
Endpoint() string
|
||||||
|
Path() string
|
||||||
|
SecretKeyring() string
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddRemoteProvider adds a remote configuration source.
|
||||||
|
// Remote Providers are searched in the order they are added.
|
||||||
|
// provider is a string value: "etcd", "etcd3", "consul", "firestore" or "nats" are currently supported.
|
||||||
|
// endpoint is the url. etcd requires http://ip:port, consul requires ip:port, nats requires nats://ip:port
|
||||||
|
// path is the path in the k/v store to retrieve configuration
|
||||||
|
// To retrieve a config file called myapp.json from /configs/myapp.json
|
||||||
|
// you should set path to /configs and set config name (SetConfigName()) to
|
||||||
|
// "myapp".
|
||||||
|
func AddRemoteProvider(provider, endpoint, path string) error {
|
||||||
|
return v.AddRemoteProvider(provider, endpoint, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Viper) AddRemoteProvider(provider, endpoint, path string) error {
|
||||||
|
if !stringInSlice(provider, SupportedRemoteProviders) {
|
||||||
|
return UnsupportedRemoteProviderError(provider)
|
||||||
|
}
|
||||||
|
if provider != "" && endpoint != "" {
|
||||||
|
v.logger.Info("adding remote provider", "provider", provider, "endpoint", endpoint)
|
||||||
|
|
||||||
|
rp := &defaultRemoteProvider{
|
||||||
|
endpoint: endpoint,
|
||||||
|
provider: provider,
|
||||||
|
path: path,
|
||||||
|
}
|
||||||
|
if !v.providerPathExists(rp) {
|
||||||
|
v.remoteProviders = append(v.remoteProviders, rp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddSecureRemoteProvider adds a remote configuration source.
|
||||||
|
// Secure Remote Providers are searched in the order they are added.
|
||||||
|
// provider is a string value: "etcd", "etcd3", "consul", "firestore" or "nats" are currently supported.
|
||||||
|
// endpoint is the url. etcd requires http://ip:port consul requires ip:port
|
||||||
|
// secretkeyring is the filepath to your openpgp secret keyring. e.g. /etc/secrets/myring.gpg
|
||||||
|
// path is the path in the k/v store to retrieve configuration
|
||||||
|
// To retrieve a config file called myapp.json from /configs/myapp.json
|
||||||
|
// you should set path to /configs and set config name (SetConfigName()) to
|
||||||
|
// "myapp".
|
||||||
|
// Secure Remote Providers are implemented with github.com/sagikazarmark/crypt.
|
||||||
|
func AddSecureRemoteProvider(provider, endpoint, path, secretkeyring string) error {
|
||||||
|
return v.AddSecureRemoteProvider(provider, endpoint, path, secretkeyring)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Viper) AddSecureRemoteProvider(provider, endpoint, path, secretkeyring string) error {
|
||||||
|
if !stringInSlice(provider, SupportedRemoteProviders) {
|
||||||
|
return UnsupportedRemoteProviderError(provider)
|
||||||
|
}
|
||||||
|
if provider != "" && endpoint != "" {
|
||||||
|
v.logger.Info("adding remote provider", "provider", provider, "endpoint", endpoint)
|
||||||
|
|
||||||
|
rp := &defaultRemoteProvider{
|
||||||
|
endpoint: endpoint,
|
||||||
|
provider: provider,
|
||||||
|
path: path,
|
||||||
|
secretKeyring: secretkeyring,
|
||||||
|
}
|
||||||
|
if !v.providerPathExists(rp) {
|
||||||
|
v.remoteProviders = append(v.remoteProviders, rp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Viper) providerPathExists(p *defaultRemoteProvider) bool {
|
||||||
|
for _, y := range v.remoteProviders {
|
||||||
|
if reflect.DeepEqual(y, p) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadRemoteConfig attempts to get configuration from a remote source
|
||||||
|
// and read it in the remote configuration registry.
|
||||||
|
func ReadRemoteConfig() error { return v.ReadRemoteConfig() }
|
||||||
|
|
||||||
|
func (v *Viper) ReadRemoteConfig() error {
|
||||||
|
return v.getKeyValueConfig()
|
||||||
|
}
|
||||||
|
|
||||||
|
func WatchRemoteConfig() error { return v.WatchRemoteConfig() }
|
||||||
|
func (v *Viper) WatchRemoteConfig() error {
|
||||||
|
return v.watchKeyValueConfig()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Viper) WatchRemoteConfigOnChannel() error {
|
||||||
|
return v.watchKeyValueConfigOnChannel()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve the first found remote configuration.
|
||||||
|
func (v *Viper) getKeyValueConfig() error {
|
||||||
|
if RemoteConfig == nil {
|
||||||
|
return RemoteConfigError("Enable the remote features by doing a blank import of the viper/remote package: '_ github.com/spf13/viper/remote'")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(v.remoteProviders) == 0 {
|
||||||
|
return RemoteConfigError("No Remote Providers")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, rp := range v.remoteProviders {
|
||||||
|
val, err := v.getRemoteConfig(rp)
|
||||||
|
if err != nil {
|
||||||
|
v.logger.Error(fmt.Errorf("get remote config: %w", err).Error())
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
v.kvstore = val
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return RemoteConfigError("No Files Found")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Viper) getRemoteConfig(provider RemoteProvider) (map[string]any, error) {
|
||||||
|
reader, err := RemoteConfig.Get(provider)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = v.unmarshalReader(reader, v.kvstore)
|
||||||
|
return v.kvstore, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve the first found remote configuration.
|
||||||
|
func (v *Viper) watchKeyValueConfigOnChannel() error {
|
||||||
|
if len(v.remoteProviders) == 0 {
|
||||||
|
return RemoteConfigError("No Remote Providers")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, rp := range v.remoteProviders {
|
||||||
|
respc, _ := RemoteConfig.WatchChannel(rp)
|
||||||
|
// Todo: Add quit channel
|
||||||
|
go func(rc <-chan *RemoteResponse) {
|
||||||
|
for {
|
||||||
|
b := <-rc
|
||||||
|
reader := bytes.NewReader(b.Value)
|
||||||
|
v.unmarshalReader(reader, v.kvstore)
|
||||||
|
}
|
||||||
|
}(respc)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return RemoteConfigError("No Files Found")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve the first found remote configuration.
|
||||||
|
func (v *Viper) watchKeyValueConfig() error {
|
||||||
|
if len(v.remoteProviders) == 0 {
|
||||||
|
return RemoteConfigError("No Remote Providers")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, rp := range v.remoteProviders {
|
||||||
|
val, err := v.watchRemoteConfig(rp)
|
||||||
|
if err != nil {
|
||||||
|
v.logger.Error(fmt.Errorf("watch remote config: %w", err).Error())
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
v.kvstore = val
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return RemoteConfigError("No Files Found")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Viper) watchRemoteConfig(provider RemoteProvider) (map[string]any, error) {
|
||||||
|
reader, err := RemoteConfig.Watch(provider)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = v.unmarshalReader(reader, v.kvstore)
|
||||||
|
return v.kvstore, err
|
||||||
|
}
|
246
viper.go
246
viper.go
|
@ -63,24 +63,10 @@ func (e ConfigMarshalError) Error() string {
|
||||||
|
|
||||||
var v *Viper
|
var v *Viper
|
||||||
|
|
||||||
type RemoteResponse struct {
|
|
||||||
Value []byte
|
|
||||||
Error error
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
v = New()
|
v = New()
|
||||||
}
|
}
|
||||||
|
|
||||||
type remoteConfigFactory interface {
|
|
||||||
Get(rp RemoteProvider) (io.Reader, error)
|
|
||||||
Watch(rp RemoteProvider) (io.Reader, error)
|
|
||||||
WatchChannel(rp RemoteProvider) (<-chan *RemoteResponse, chan bool)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoteConfig is optional, see the remote package.
|
|
||||||
var RemoteConfig remoteConfigFactory
|
|
||||||
|
|
||||||
// UnsupportedConfigError denotes encountering an unsupported
|
// UnsupportedConfigError denotes encountering an unsupported
|
||||||
// configuration filetype.
|
// configuration filetype.
|
||||||
type UnsupportedConfigError string
|
type UnsupportedConfigError string
|
||||||
|
@ -90,24 +76,6 @@ func (str UnsupportedConfigError) Error() string {
|
||||||
return fmt.Sprintf("Unsupported Config Type %q", string(str))
|
return fmt.Sprintf("Unsupported Config Type %q", string(str))
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnsupportedRemoteProviderError denotes encountering an unsupported remote
|
|
||||||
// provider. Currently only etcd and Consul are supported.
|
|
||||||
type UnsupportedRemoteProviderError string
|
|
||||||
|
|
||||||
// Error returns the formatted remote provider error.
|
|
||||||
func (str UnsupportedRemoteProviderError) Error() string {
|
|
||||||
return fmt.Sprintf("Unsupported Remote Provider Type %q", string(str))
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoteConfigError denotes encountering an error while trying to
|
|
||||||
// pull the configuration from the remote provider.
|
|
||||||
type RemoteConfigError string
|
|
||||||
|
|
||||||
// Error returns the formatted remote provider error.
|
|
||||||
func (rce RemoteConfigError) Error() string {
|
|
||||||
return fmt.Sprintf("Remote Configurations Error: %s", string(rce))
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConfigFileNotFoundError denotes failing to find configuration file.
|
// ConfigFileNotFoundError denotes failing to find configuration file.
|
||||||
type ConfigFileNotFoundError struct {
|
type ConfigFileNotFoundError struct {
|
||||||
name, locations string
|
name, locations string
|
||||||
|
@ -303,7 +271,8 @@ func NewWithOptions(opts ...Option) *Viper {
|
||||||
func Reset() {
|
func Reset() {
|
||||||
v = New()
|
v = New()
|
||||||
SupportedExts = []string{"json", "toml", "yaml", "yml", "properties", "props", "prop", "hcl", "tfvars", "dotenv", "env", "ini"}
|
SupportedExts = []string{"json", "toml", "yaml", "yml", "properties", "props", "prop", "hcl", "tfvars", "dotenv", "env", "ini"}
|
||||||
SupportedRemoteProviders = []string{"etcd", "etcd3", "consul", "firestore", "nats"}
|
|
||||||
|
resetRemote()
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: make this lazy initialization instead.
|
// TODO: make this lazy initialization instead.
|
||||||
|
@ -384,46 +353,9 @@ func (v *Viper) resetEncoding() {
|
||||||
v.decoderRegistry = decoderRegistry
|
v.decoderRegistry = decoderRegistry
|
||||||
}
|
}
|
||||||
|
|
||||||
type defaultRemoteProvider struct {
|
|
||||||
provider string
|
|
||||||
endpoint string
|
|
||||||
path string
|
|
||||||
secretKeyring string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rp defaultRemoteProvider) Provider() string {
|
|
||||||
return rp.provider
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rp defaultRemoteProvider) Endpoint() string {
|
|
||||||
return rp.endpoint
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rp defaultRemoteProvider) Path() string {
|
|
||||||
return rp.path
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rp defaultRemoteProvider) SecretKeyring() string {
|
|
||||||
return rp.secretKeyring
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoteProvider stores the configuration necessary
|
|
||||||
// to connect to a remote key/value store.
|
|
||||||
// Optional secretKeyring to unencrypt encrypted values
|
|
||||||
// can be provided.
|
|
||||||
type RemoteProvider interface {
|
|
||||||
Provider() string
|
|
||||||
Endpoint() string
|
|
||||||
Path() string
|
|
||||||
SecretKeyring() string
|
|
||||||
}
|
|
||||||
|
|
||||||
// SupportedExts are universally supported extensions.
|
// SupportedExts are universally supported extensions.
|
||||||
var SupportedExts = []string{"json", "toml", "yaml", "yml", "properties", "props", "prop", "hcl", "tfvars", "dotenv", "env", "ini"}
|
var SupportedExts = []string{"json", "toml", "yaml", "yml", "properties", "props", "prop", "hcl", "tfvars", "dotenv", "env", "ini"}
|
||||||
|
|
||||||
// SupportedRemoteProviders are universally supported remote providers.
|
|
||||||
var SupportedRemoteProviders = []string{"etcd", "etcd3", "consul", "firestore", "nats"}
|
|
||||||
|
|
||||||
// OnConfigChange sets the event handler that is called when a config file changes.
|
// OnConfigChange sets the event handler that is called when a config file changes.
|
||||||
func OnConfigChange(run func(in fsnotify.Event)) { v.OnConfigChange(run) }
|
func OnConfigChange(run func(in fsnotify.Event)) { v.OnConfigChange(run) }
|
||||||
|
|
||||||
|
@ -584,80 +516,6 @@ func (v *Viper) AddConfigPath(in string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddRemoteProvider adds a remote configuration source.
|
|
||||||
// Remote Providers are searched in the order they are added.
|
|
||||||
// provider is a string value: "etcd", "etcd3", "consul", "firestore" or "nats" are currently supported.
|
|
||||||
// endpoint is the url. etcd requires http://ip:port, consul requires ip:port, nats requires nats://ip:port
|
|
||||||
// path is the path in the k/v store to retrieve configuration
|
|
||||||
// To retrieve a config file called myapp.json from /configs/myapp.json
|
|
||||||
// you should set path to /configs and set config name (SetConfigName()) to
|
|
||||||
// "myapp".
|
|
||||||
func AddRemoteProvider(provider, endpoint, path string) error {
|
|
||||||
return v.AddRemoteProvider(provider, endpoint, path)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Viper) AddRemoteProvider(provider, endpoint, path string) error {
|
|
||||||
if !stringInSlice(provider, SupportedRemoteProviders) {
|
|
||||||
return UnsupportedRemoteProviderError(provider)
|
|
||||||
}
|
|
||||||
if provider != "" && endpoint != "" {
|
|
||||||
v.logger.Info("adding remote provider", "provider", provider, "endpoint", endpoint)
|
|
||||||
|
|
||||||
rp := &defaultRemoteProvider{
|
|
||||||
endpoint: endpoint,
|
|
||||||
provider: provider,
|
|
||||||
path: path,
|
|
||||||
}
|
|
||||||
if !v.providerPathExists(rp) {
|
|
||||||
v.remoteProviders = append(v.remoteProviders, rp)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddSecureRemoteProvider adds a remote configuration source.
|
|
||||||
// Secure Remote Providers are searched in the order they are added.
|
|
||||||
// provider is a string value: "etcd", "etcd3", "consul", "firestore" or "nats" are currently supported.
|
|
||||||
// endpoint is the url. etcd requires http://ip:port consul requires ip:port
|
|
||||||
// secretkeyring is the filepath to your openpgp secret keyring. e.g. /etc/secrets/myring.gpg
|
|
||||||
// path is the path in the k/v store to retrieve configuration
|
|
||||||
// To retrieve a config file called myapp.json from /configs/myapp.json
|
|
||||||
// you should set path to /configs and set config name (SetConfigName()) to
|
|
||||||
// "myapp".
|
|
||||||
// Secure Remote Providers are implemented with github.com/sagikazarmark/crypt.
|
|
||||||
func AddSecureRemoteProvider(provider, endpoint, path, secretkeyring string) error {
|
|
||||||
return v.AddSecureRemoteProvider(provider, endpoint, path, secretkeyring)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Viper) AddSecureRemoteProvider(provider, endpoint, path, secretkeyring string) error {
|
|
||||||
if !stringInSlice(provider, SupportedRemoteProviders) {
|
|
||||||
return UnsupportedRemoteProviderError(provider)
|
|
||||||
}
|
|
||||||
if provider != "" && endpoint != "" {
|
|
||||||
v.logger.Info("adding remote provider", "provider", provider, "endpoint", endpoint)
|
|
||||||
|
|
||||||
rp := &defaultRemoteProvider{
|
|
||||||
endpoint: endpoint,
|
|
||||||
provider: provider,
|
|
||||||
path: path,
|
|
||||||
secretKeyring: secretkeyring,
|
|
||||||
}
|
|
||||||
if !v.providerPathExists(rp) {
|
|
||||||
v.remoteProviders = append(v.remoteProviders, rp)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Viper) providerPathExists(p *defaultRemoteProvider) bool {
|
|
||||||
for _, y := range v.remoteProviders {
|
|
||||||
if reflect.DeepEqual(y, p) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// searchMap recursively searches for a value for path in source map.
|
// searchMap recursively searches for a value for path in source map.
|
||||||
// Returns nil if not found.
|
// Returns nil if not found.
|
||||||
// Note: This assumes that the path entries and map keys are lower cased.
|
// Note: This assumes that the path entries and map keys are lower cased.
|
||||||
|
@ -1976,106 +1834,6 @@ func mergeMaps(src, tgt map[string]any, itgt map[any]any) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadRemoteConfig attempts to get configuration from a remote source
|
|
||||||
// and read it in the remote configuration registry.
|
|
||||||
func ReadRemoteConfig() error { return v.ReadRemoteConfig() }
|
|
||||||
|
|
||||||
func (v *Viper) ReadRemoteConfig() error {
|
|
||||||
return v.getKeyValueConfig()
|
|
||||||
}
|
|
||||||
|
|
||||||
func WatchRemoteConfig() error { return v.WatchRemoteConfig() }
|
|
||||||
func (v *Viper) WatchRemoteConfig() error {
|
|
||||||
return v.watchKeyValueConfig()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Viper) WatchRemoteConfigOnChannel() error {
|
|
||||||
return v.watchKeyValueConfigOnChannel()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve the first found remote configuration.
|
|
||||||
func (v *Viper) getKeyValueConfig() error {
|
|
||||||
if RemoteConfig == nil {
|
|
||||||
return RemoteConfigError("Enable the remote features by doing a blank import of the viper/remote package: '_ github.com/spf13/viper/remote'")
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(v.remoteProviders) == 0 {
|
|
||||||
return RemoteConfigError("No Remote Providers")
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, rp := range v.remoteProviders {
|
|
||||||
val, err := v.getRemoteConfig(rp)
|
|
||||||
if err != nil {
|
|
||||||
v.logger.Error(fmt.Errorf("get remote config: %w", err).Error())
|
|
||||||
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
v.kvstore = val
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return RemoteConfigError("No Files Found")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Viper) getRemoteConfig(provider RemoteProvider) (map[string]any, error) {
|
|
||||||
reader, err := RemoteConfig.Get(provider)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
err = v.unmarshalReader(reader, v.kvstore)
|
|
||||||
return v.kvstore, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve the first found remote configuration.
|
|
||||||
func (v *Viper) watchKeyValueConfigOnChannel() error {
|
|
||||||
if len(v.remoteProviders) == 0 {
|
|
||||||
return RemoteConfigError("No Remote Providers")
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, rp := range v.remoteProviders {
|
|
||||||
respc, _ := RemoteConfig.WatchChannel(rp)
|
|
||||||
// Todo: Add quit channel
|
|
||||||
go func(rc <-chan *RemoteResponse) {
|
|
||||||
for {
|
|
||||||
b := <-rc
|
|
||||||
reader := bytes.NewReader(b.Value)
|
|
||||||
v.unmarshalReader(reader, v.kvstore)
|
|
||||||
}
|
|
||||||
}(respc)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return RemoteConfigError("No Files Found")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve the first found remote configuration.
|
|
||||||
func (v *Viper) watchKeyValueConfig() error {
|
|
||||||
if len(v.remoteProviders) == 0 {
|
|
||||||
return RemoteConfigError("No Remote Providers")
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, rp := range v.remoteProviders {
|
|
||||||
val, err := v.watchRemoteConfig(rp)
|
|
||||||
if err != nil {
|
|
||||||
v.logger.Error(fmt.Errorf("watch remote config: %w", err).Error())
|
|
||||||
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
v.kvstore = val
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return RemoteConfigError("No Files Found")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Viper) watchRemoteConfig(provider RemoteProvider) (map[string]any, error) {
|
|
||||||
reader, err := RemoteConfig.Watch(provider)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
err = v.unmarshalReader(reader, v.kvstore)
|
|
||||||
return v.kvstore, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// AllKeys returns all keys holding a value, regardless of where they are set.
|
// AllKeys returns all keys holding a value, regardless of where they are set.
|
||||||
// Nested keys are returned with a v.keyDelim separator.
|
// Nested keys are returned with a v.keyDelim separator.
|
||||||
func AllKeys() []string { return v.AllKeys() }
|
func AllKeys() []string { return v.AllKeys() }
|
||||||
|
|
Loading…
Reference in New Issue