mirror of
https://github.com/safing/portbase
synced 2025-09-04 19:50:18 +00:00
Fix handling of unmapped configuration options
This commit is contained in:
parent
900a654a4d
commit
34453d6989
2 changed files with 39 additions and 1 deletions
|
@ -11,6 +11,12 @@ import (
|
||||||
var (
|
var (
|
||||||
optionsLock sync.RWMutex
|
optionsLock sync.RWMutex
|
||||||
options = make(map[string]*Option)
|
options = make(map[string]*Option)
|
||||||
|
|
||||||
|
// unmappedValues holds a list of configuration values that have been
|
||||||
|
// read from the persistence layer but no option has been defined yet.
|
||||||
|
// This is mainly to support the plugin system of the Portmaster.
|
||||||
|
unmappedValuesLock sync.Mutex
|
||||||
|
unmappedValues map[string]interface{}
|
||||||
)
|
)
|
||||||
|
|
||||||
// ForEachOption calls fn for each defined option. If fn returns
|
// ForEachOption calls fn for each defined option. If fn returns
|
||||||
|
@ -98,9 +104,29 @@ func Register(option *Option) error {
|
||||||
return fmt.Errorf("config: invalid default value: %w", vErr)
|
return fmt.Errorf("config: invalid default value: %w", vErr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := loadUnmappedValue(option); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
optionsLock.Lock()
|
optionsLock.Lock()
|
||||||
defer optionsLock.Unlock()
|
defer optionsLock.Unlock()
|
||||||
options[option.Key] = option
|
options[option.Key] = option
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func loadUnmappedValue(option *Option) error {
|
||||||
|
unmappedValuesLock.Lock()
|
||||||
|
defer unmappedValuesLock.Unlock()
|
||||||
|
if value, ok := unmappedValues[option.Key]; ok {
|
||||||
|
delete(unmappedValues, option.Key)
|
||||||
|
|
||||||
|
var vErr *ValidationError
|
||||||
|
option.activeValue, vErr = validateValue(option, value)
|
||||||
|
if vErr != nil {
|
||||||
|
return fmt.Errorf("config: invalid value: %w", vErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -41,6 +41,11 @@ func signalChanges() {
|
||||||
func replaceConfig(newValues map[string]interface{}) []*ValidationError {
|
func replaceConfig(newValues map[string]interface{}) []*ValidationError {
|
||||||
var validationErrors []*ValidationError
|
var validationErrors []*ValidationError
|
||||||
|
|
||||||
|
valuesCopy := make(map[string]interface{}, len(newValues))
|
||||||
|
for key, value := range newValues {
|
||||||
|
valuesCopy[key] = value
|
||||||
|
}
|
||||||
|
|
||||||
// RLock the options because we are not adding or removing
|
// RLock the options because we are not adding or removing
|
||||||
// options from the registration but rather only update the
|
// options from the registration but rather only update the
|
||||||
// options value which is guarded by the option's lock itself
|
// options value which is guarded by the option's lock itself
|
||||||
|
@ -48,7 +53,9 @@ func replaceConfig(newValues map[string]interface{}) []*ValidationError {
|
||||||
defer optionsLock.RUnlock()
|
defer optionsLock.RUnlock()
|
||||||
|
|
||||||
for key, option := range options {
|
for key, option := range options {
|
||||||
newValue, ok := newValues[key]
|
newValue, ok := valuesCopy[key]
|
||||||
|
|
||||||
|
delete(valuesCopy, key)
|
||||||
|
|
||||||
option.Lock()
|
option.Lock()
|
||||||
option.activeValue = nil
|
option.activeValue = nil
|
||||||
|
@ -66,6 +73,11 @@ func replaceConfig(newValues map[string]interface{}) []*ValidationError {
|
||||||
option.Unlock()
|
option.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unmappedValuesLock.Lock()
|
||||||
|
defer unmappedValuesLock.Unlock()
|
||||||
|
|
||||||
|
unmappedValues = valuesCopy
|
||||||
|
|
||||||
signalChanges()
|
signalChanges()
|
||||||
|
|
||||||
return validationErrors
|
return validationErrors
|
||||||
|
|
Loading…
Add table
Reference in a new issue