Skip to content

Commit

Permalink
Fix handling of unmapped configuration options
Browse files Browse the repository at this point in the history
  • Loading branch information
ppacher committed Sep 5, 2022
1 parent 866cd48 commit eb335ab
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 1 deletion.
26 changes: 26 additions & 0 deletions config/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ import (
var (
optionsLock sync.RWMutex
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
Expand Down Expand Up @@ -98,9 +104,29 @@ func Register(option *Option) error {
return fmt.Errorf("config: invalid default value: %w", vErr)
}

if err := loadUnmappedValue(option); err != nil {
return err
}

optionsLock.Lock()
defer optionsLock.Unlock()
options[option.Key] = option

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
}
14 changes: 13 additions & 1 deletion config/set.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,21 @@ func signalChanges() {
func replaceConfig(newValues map[string]interface{}) []*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
// options from the registration but rather only update the
// options value which is guarded by the option's lock itself
optionsLock.RLock()
defer optionsLock.RUnlock()

for key, option := range options {
newValue, ok := newValues[key]
newValue, ok := valuesCopy[key]

delete(valuesCopy, key)

option.Lock()
option.activeValue = nil
Expand All @@ -65,6 +72,11 @@ func replaceConfig(newValues map[string]interface{}) []*ValidationError {
option.Unlock()
}

unmappedValuesLock.Lock()
defer unmappedValuesLock.Unlock()

unmappedValues = valuesCopy

signalChanges()

return validationErrors
Expand Down

0 comments on commit eb335ab

Please sign in to comment.