82 lines
1.7 KiB
Go
82 lines
1.7 KiB
Go
package settings
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"log"
|
|
"sync"
|
|
)
|
|
|
|
type ValueMonitorParseFunc[T any] func(string) (T, error)
|
|
|
|
type ValueMonitor[T any] struct {
|
|
mutex sync.RWMutex
|
|
parent *Settings
|
|
updates <-chan string
|
|
key string
|
|
parserFunc ValueMonitorParseFunc[T]
|
|
value T
|
|
}
|
|
|
|
func (v *ValueMonitor[T]) GetValue() T {
|
|
v.mutex.RLock()
|
|
defer v.mutex.RUnlock()
|
|
return v.value
|
|
}
|
|
|
|
func (v *ValueMonitor[T]) maintenanceThread() {
|
|
ctx := v.parent.context
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
return
|
|
case s, ok := <-v.updates:
|
|
if !ok {
|
|
return
|
|
}
|
|
t, err := v.parserFunc(s)
|
|
if err != nil {
|
|
log.Printf("ValueMonitor error parsing key %q value %q from channel: %v\n", v.key, s, err)
|
|
continue
|
|
}
|
|
func() {
|
|
v.mutex.RLock()
|
|
defer v.mutex.RUnlock()
|
|
v.value = t
|
|
}()
|
|
}
|
|
}
|
|
}
|
|
|
|
func NewValueMonitor[T any](settings *Settings, key string, parserFunc ValueMonitorParseFunc[T]) (*ValueMonitor[T], error) {
|
|
monitorChannel := make(chan string, 1)
|
|
err := settings.RegisterKeyToMonitor(key, monitorChannel)
|
|
if err != nil {
|
|
close(monitorChannel)
|
|
return nil, fmt.Errorf("error registering ValueMonitor %w", err)
|
|
}
|
|
initialString, ok := <-monitorChannel
|
|
if !ok {
|
|
close(monitorChannel)
|
|
return nil, errors.New("channel closed before reading initial value")
|
|
}
|
|
parsed, err := parserFunc(initialString)
|
|
if err != nil {
|
|
close(monitorChannel)
|
|
return nil, fmt.Errorf("error parsing initial value from %q: %v", initialString, err)
|
|
}
|
|
go func() {
|
|
<-settings.context.Done()
|
|
close(monitorChannel)
|
|
}()
|
|
results := &ValueMonitor[T]{
|
|
parent: settings,
|
|
updates: monitorChannel,
|
|
key: key,
|
|
parserFunc: parserFunc,
|
|
value: parsed,
|
|
}
|
|
go results.maintenanceThread()
|
|
return results, nil
|
|
}
|