mirror of
https://github.com/pomerium/pomerium.git
synced 2025-04-28 18:06:34 +02:00
* refactor config loading * wip * move autocert to its own config source * refactor options updaters * fix stuttering * fix autocert validate check
103 lines
2.4 KiB
Go
103 lines
2.4 KiB
Go
package config
|
|
|
|
import (
|
|
"reflect"
|
|
"sync"
|
|
|
|
"github.com/fsnotify/fsnotify"
|
|
"github.com/mitchellh/copystructure"
|
|
"github.com/spf13/viper"
|
|
)
|
|
|
|
// Config holds pomerium configuration options.
|
|
type Config struct {
|
|
Options *Options
|
|
}
|
|
|
|
// Clone creates a deep clone of the config.
|
|
func (cfg *Config) Clone() *Config {
|
|
return copystructure.Must(copystructure.Config{
|
|
Copiers: map[reflect.Type]copystructure.CopierFunc{
|
|
reflect.TypeOf((*viper.Viper)(nil)): func(i interface{}) (interface{}, error) {
|
|
return i, nil
|
|
},
|
|
},
|
|
}.Copy(cfg)).(*Config)
|
|
}
|
|
|
|
// A ChangeListener is called when configuration changes.
|
|
type ChangeListener = func(*Config)
|
|
|
|
// A ChangeDispatcher manages listeners on config changes.
|
|
type ChangeDispatcher struct {
|
|
sync.Mutex
|
|
onConfigChangeListeners []ChangeListener
|
|
}
|
|
|
|
// Trigger triggers a change.
|
|
func (dispatcher *ChangeDispatcher) Trigger(cfg *Config) {
|
|
dispatcher.Lock()
|
|
defer dispatcher.Unlock()
|
|
|
|
for _, li := range dispatcher.onConfigChangeListeners {
|
|
li(cfg)
|
|
}
|
|
}
|
|
|
|
// OnConfigChange adds a listener.
|
|
func (dispatcher *ChangeDispatcher) OnConfigChange(li ChangeListener) {
|
|
dispatcher.Lock()
|
|
defer dispatcher.Unlock()
|
|
dispatcher.onConfigChangeListeners = append(dispatcher.onConfigChangeListeners, li)
|
|
}
|
|
|
|
// A Source gets configuration.
|
|
type Source interface {
|
|
GetConfig() *Config
|
|
OnConfigChange(ChangeListener)
|
|
}
|
|
|
|
// A FileOrEnvironmentSource retrieves config options from a file or the environment.
|
|
type FileOrEnvironmentSource struct {
|
|
configFile string
|
|
|
|
mu sync.RWMutex
|
|
config *Config
|
|
|
|
ChangeDispatcher
|
|
}
|
|
|
|
// NewFileOrEnvironmentSource creates a new FileOrEnvironmentSource.
|
|
func NewFileOrEnvironmentSource(configFile string) (*FileOrEnvironmentSource, error) {
|
|
options, err := newOptionsFromConfig(configFile)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
src := &FileOrEnvironmentSource{
|
|
configFile: configFile,
|
|
config: &Config{Options: options},
|
|
}
|
|
options.viper.OnConfigChange(src.onConfigChange)
|
|
go options.viper.WatchConfig()
|
|
|
|
return src, nil
|
|
}
|
|
|
|
func (src *FileOrEnvironmentSource) onConfigChange(evt fsnotify.Event) {
|
|
src.mu.Lock()
|
|
newOptions := handleConfigUpdate(src.configFile, src.config.Options)
|
|
cfg := &Config{Options: newOptions}
|
|
src.config = cfg
|
|
src.mu.Unlock()
|
|
|
|
src.Trigger(cfg)
|
|
}
|
|
|
|
// GetConfig gets the config.
|
|
func (src *FileOrEnvironmentSource) GetConfig() *Config {
|
|
src.mu.RLock()
|
|
defer src.mu.RUnlock()
|
|
|
|
return src.config
|
|
}
|