Wox/wox.core/setting/store.go

169 lines
4.2 KiB
Go

package setting
import (
"context"
"encoding/json"
"fmt"
"reflect"
"strconv"
"wox/database"
"wox/util"
"gorm.io/gorm"
)
// SettingStore defines the abstract interface for reading and writing settings
// This is the base interface that both WoxSettingStore and PluginSettingStore adapters implement
type SettingStore interface {
Get(key string, target interface{}) error
Set(key string, value interface{}) error
Delete(key string) error
}
type SynableStore interface {
LogOplog(key string, value interface{}) error
}
type WoxSettingStore struct {
db *gorm.DB
}
func NewWoxSettingStore(db *gorm.DB) *WoxSettingStore {
return &WoxSettingStore{
db: db,
}
}
func (s *WoxSettingStore) Get(key string, target interface{}) error {
var setting database.WoxSetting
if err := s.db.Where("key = ?", key).First(&setting).Error; err != nil {
util.GetLogger().Error(context.Background(), fmt.Sprintf("Failed to read wox setting %s: %v", key, err))
return err
}
return deserializeValue(setting.Value, target)
}
func (s *WoxSettingStore) Set(key string, value interface{}) error {
strValue, err := serializeValue(value)
if err != nil {
return fmt.Errorf("failed to serialize value: %w", err)
}
return s.db.Save(&database.WoxSetting{Key: key, Value: strValue}).Error
}
func (s *WoxSettingStore) Delete(key string) error {
return s.db.Delete(&database.WoxSetting{Key: key}).Error
}
func (s *WoxSettingStore) LogOplog(key string, value interface{}) error {
strValue, err := serializeValue(value)
if err != nil {
return fmt.Errorf("failed to serialize value for oplog: %w", err)
}
oplog := database.Oplog{
EntityType: "setting",
EntityID: key,
Operation: "update",
Value: strValue,
Timestamp: util.GetSystemTimestamp(),
}
return s.db.Create(&oplog).Error
}
// PluginSettingStore defines the interface for plugin settings
type PluginSettingStore struct {
db *gorm.DB
pluginId string
}
func NewPluginSettingStore(db *gorm.DB, pluginId string) *PluginSettingStore {
return &PluginSettingStore{
db: db,
pluginId: pluginId,
}
}
func (s *PluginSettingStore) Get(key string, target interface{}) error {
var setting database.PluginSetting
if err := s.db.Where("plugin_id = ? AND key = ?", s.pluginId, key).First(&setting).Error; err != nil {
util.GetLogger().Error(context.Background(), fmt.Sprintf("Failed to read plugin setting %s.%s: %v", s.pluginId, key, err))
return err
}
return deserializeValue(setting.Value, target)
}
func (s *PluginSettingStore) Set(key string, value interface{}) error {
strValue, err := serializeValue(value)
if err != nil {
return fmt.Errorf("failed to serialize plugin setting value: %w", err)
}
return s.db.Save(&database.PluginSetting{PluginID: s.pluginId, Key: key, Value: strValue}).Error
}
func (s *PluginSettingStore) Delete(key string) error {
return s.db.Delete(&database.PluginSetting{PluginID: s.pluginId, Key: key}).Error
}
func serializeValue(value interface{}) (string, error) {
if value == nil {
return "", nil
}
switch v := value.(type) {
case string:
return v, nil
case int:
return strconv.Itoa(v), nil
case bool:
return strconv.FormatBool(v), nil
default:
// For complex types, marshal to JSON
bytes, err := json.Marshal(v)
return string(bytes), err
}
}
func deserializeValue(strValue string, target interface{}) error {
rv := reflect.ValueOf(target)
if rv.Kind() != reflect.Ptr {
return fmt.Errorf("target must be a pointer")
}
elem := rv.Elem()
switch elem.Kind() {
case reflect.String:
elem.SetString(strValue)
return nil
case reflect.Int:
i, err := strconv.Atoi(strValue)
if err != nil {
return fmt.Errorf("failed to parse int: %w", err)
}
elem.SetInt(int64(i))
return nil
case reflect.Bool:
b, err := strconv.ParseBool(strValue)
if err != nil {
return fmt.Errorf("failed to parse bool: %w", err)
}
elem.SetBool(b)
return nil
default:
// For complex types, unmarshal from JSON
if elem.Type().Kind() == reflect.String {
// Custom string-based types (like LangCode)
elem.Set(reflect.ValueOf(strValue).Convert(elem.Type()))
return nil
}
// Try JSON unmarshaling for complex types
return json.Unmarshal([]byte(strValue), target)
}
}