mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-11-03 18:12:25 -06:00 
			
		
		
		
	- codeberg.org/gruf/go-ffmpreg: v0.6.10 -> v0.6.11 - github.com/spf13/cast: v1.9.2 -> v1.10.0 - github.com/spf13/viper: v1.20.1 -> v1.21.0 - golang.org/x/crypto: v0.41.0 -> v0.42.0 - golang.org/x/image: v0.30.0 -> v0.31.0 Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4423 Co-authored-by: kim <grufwub@gmail.com> Co-committed-by: kim <grufwub@gmail.com>
		
			
				
	
	
		
			259 lines
		
	
	
	
		
			7.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			259 lines
		
	
	
	
		
			7.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package viper
 | 
						|
 | 
						|
import (
 | 
						|
	"bytes"
 | 
						|
	"fmt"
 | 
						|
	"io"
 | 
						|
	"reflect"
 | 
						|
	"slices"
 | 
						|
)
 | 
						|
 | 
						|
// 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 !slices.Contains(SupportedRemoteProviders, provider) {
 | 
						|
		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 !slices.Contains(SupportedRemoteProviders, provider) {
 | 
						|
		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)
 | 
						|
				err := v.unmarshalReader(reader, v.kvstore)
 | 
						|
				if err != nil {
 | 
						|
					v.logger.Error(fmt.Errorf("failed to unmarshal remote config: %w", err).Error())
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}(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
 | 
						|
}
 |