Wox/wox.core/setting/value.go

174 lines
3.7 KiB
Go

package setting
import (
"fmt"
"sync"
"wox/util"
)
// ValidatorFunc is a function type for validating setting values
type ValidatorFunc[T any] func(T) bool
// SettingValue is a generic type that represents a single, observable setting.
// It handles lazy loading and persisting of its value.
type SettingValue[T any] struct {
key string
value T
defaultValue T
settingStore SettingStore
validator ValidatorFunc[T]
syncable bool
isLoaded bool
mu sync.RWMutex
}
type WoxSettingValue[T any] struct {
*SettingValue[T]
}
// platform specific setting value. Don't set this value directly, use get,set instead
type PlatformValue[T any] struct {
*WoxSettingValue[struct {
MacValue T
WinValue T
LinuxValue T
}]
}
type PluginSettingValue[T any] struct {
*SettingValue[T]
pluginId string
}
func (p *PlatformValue[T]) Get() T {
if util.IsWindows() {
return p.SettingValue.Get().WinValue
} else if util.IsMacOS() {
return p.SettingValue.Get().MacValue
} else if util.IsLinux() {
return p.SettingValue.Get().LinuxValue
}
panic("unknown platform")
}
func (p *PlatformValue[T]) Set(t T) {
if util.IsWindows() {
p.value.WinValue = t
p.SettingValue.Set(p.value)
return
} else if util.IsMacOS() {
p.value.MacValue = t
p.SettingValue.Set(p.value)
return
} else if util.IsLinux() {
p.value.LinuxValue = t
p.SettingValue.Set(p.value)
return
}
panic("unknown platform")
}
func NewWoxSettingValue[T any](store *WoxSettingStore, key string, defaultValue T) *WoxSettingValue[T] {
return &WoxSettingValue[T]{
SettingValue: &SettingValue[T]{
settingStore: store,
key: key,
defaultValue: defaultValue,
},
}
}
func NewWoxSettingValueWithValidator[T any](store *WoxSettingStore, key string, defaultValue T, validator ValidatorFunc[T]) *WoxSettingValue[T] {
return &WoxSettingValue[T]{
SettingValue: &SettingValue[T]{
settingStore: store,
key: key,
defaultValue: defaultValue,
validator: validator,
},
}
}
func NewPlatformValue[T any](store *WoxSettingStore, key string, winValue T, macValue T, linuxValue T) *PlatformValue[T] {
return &PlatformValue[T]{
WoxSettingValue: NewWoxSettingValue(store, key, struct {
MacValue T
WinValue T
LinuxValue T
}{
MacValue: macValue,
WinValue: winValue,
LinuxValue: linuxValue,
}),
}
}
func NewPluginSettingValue[T any](store *PluginSettingStore, key string, defaultValue T) *PluginSettingValue[T] {
return &PluginSettingValue[T]{
SettingValue: &SettingValue[T]{
settingStore: store,
key: key,
defaultValue: defaultValue,
},
pluginId: store.pluginId,
}
}
// Get returns the value of the setting, loading it from the store if necessary.
func (v *SettingValue[T]) Get() T {
v.mu.RLock()
if v.isLoaded {
defer v.mu.RUnlock()
return v.value
}
v.mu.RUnlock()
v.mu.Lock()
defer v.mu.Unlock()
// Double-check in case another goroutine loaded it while we were waiting for the lock.
if v.isLoaded {
return v.value
}
// Load from unified store
v.value = v.defaultValue // Start with default value
if v.settingStore != nil {
if err := v.settingStore.Get(v.key, &v.value); err != nil {
// Log error and keep default value
v.value = v.defaultValue
}
}
// Apply validation if provided
if v.validator != nil && !v.validator(v.value) {
v.value = v.defaultValue
}
v.isLoaded = true
return v.value
}
// Set updates the value of the setting and persists it to the store.
func (v *SettingValue[T]) Set(newValue T) error {
v.mu.Lock()
defer v.mu.Unlock()
var err error
if v.settingStore != nil {
err = v.settingStore.Set(v.key, newValue)
} else {
return fmt.Errorf("no store available")
}
if err != nil {
return err
}
v.value = newValue
v.isLoaded = true
return nil
}