Use SQLite instead of JSON storage

This commit is contained in:
2025-06-29 23:41:34 +08:00
parent 6f8775472d
commit 70d88dabba
25 changed files with 807 additions and 636 deletions

View File

@@ -5,6 +5,7 @@ import (
"crypto/sha256"
"encoding/json"
"fmt"
"reflect"
"sync"
"time"
"voidraft/internal/models"
@@ -28,6 +29,7 @@ type ConfigChangeCallback func(changeType ConfigChangeType, oldConfig, newConfig
// ConfigListener 配置监听器
type ConfigListener struct {
ID string // 监听器唯一ID
Name string // 监听器名称
ChangeType ConfigChangeType // 监听的配置变更类型
Callback ConfigChangeCallback // 回调函数(现在包含新旧配置)
@@ -45,9 +47,10 @@ type ConfigListener struct {
// ConfigNotificationService 配置通知服务
type ConfigNotificationService struct {
listeners sync.Map // 使用sync.Map替代普通map+锁
logger *log.LoggerService // 日志服务
koanf *koanf.Koanf // koanf实例
listeners map[ConfigChangeType][]*ConfigListener // 支持多监听器的map
mu sync.RWMutex // 监听器map的读写锁
logger *log.LoggerService // 日志服务
koanf *koanf.Koanf // koanf实例
ctx context.Context
cancel context.CancelFunc
wg sync.WaitGroup
@@ -57,20 +60,19 @@ type ConfigNotificationService struct {
func NewConfigNotificationService(k *koanf.Koanf, logger *log.LoggerService) *ConfigNotificationService {
ctx, cancel := context.WithCancel(context.Background())
return &ConfigNotificationService{
logger: logger,
koanf: k,
ctx: ctx,
cancel: cancel,
listeners: make(map[ConfigChangeType][]*ConfigListener),
logger: logger,
koanf: k,
ctx: ctx,
cancel: cancel,
}
}
// RegisterListener 注册配置监听器
func (cns *ConfigNotificationService) RegisterListener(listener *ConfigListener) error {
// 清理已存在的监听器
if existingValue, loaded := cns.listeners.LoadAndDelete(listener.ChangeType); loaded {
if existing, ok := existingValue.(interface{ cancel() }); ok {
existing.cancel()
}
// 生成唯一ID如果没有提供
if listener.ID == "" {
listener.ID = fmt.Sprintf("%s_%d", listener.Name, time.Now().UnixNano())
}
// 初始化新监听器
@@ -80,7 +82,11 @@ func (cns *ConfigNotificationService) RegisterListener(listener *ConfigListener)
return fmt.Errorf("failed to initialize listener state: %w", err)
}
cns.listeners.Store(listener.ChangeType, listener)
// 添加到监听器列表
cns.mu.Lock()
cns.listeners[listener.ChangeType] = append(cns.listeners[listener.ChangeType], listener)
cns.mu.Unlock()
return nil
}
@@ -92,7 +98,7 @@ func (cns *ConfigNotificationService) initializeListenerState(listener *ConfigLi
if config := listener.GetConfigFunc(cns.koanf); config != nil {
listener.mu.Lock()
listener.lastConfig = deepCopyConfig(config)
listener.lastConfig = deepCopyConfigReflect(config)
listener.lastConfigHash = computeConfigHash(config)
listener.mu.Unlock()
}
@@ -100,23 +106,59 @@ func (cns *ConfigNotificationService) initializeListenerState(listener *ConfigLi
return nil
}
// UnregisterListener 注销配置监听器
func (cns *ConfigNotificationService) UnregisterListener(changeType ConfigChangeType) {
if value, loaded := cns.listeners.LoadAndDelete(changeType); loaded {
if listener, ok := value.(*ConfigListener); ok {
// UnregisterListener 注销指定ID的配置监听器
func (cns *ConfigNotificationService) UnregisterListener(changeType ConfigChangeType, listenerID string) {
cns.mu.Lock()
defer cns.mu.Unlock()
listeners := cns.listeners[changeType]
for i, listener := range listeners {
if listener.ID == listenerID {
// 取消监听器
listener.cancel()
// 从切片中移除
cns.listeners[changeType] = append(listeners[:i], listeners[i+1:]...)
break
}
}
// 如果该类型没有监听器了,删除整个条目
if len(cns.listeners[changeType]) == 0 {
delete(cns.listeners, changeType)
}
}
// UnregisterAllListeners 注销指定类型的所有监听器
func (cns *ConfigNotificationService) UnregisterAllListeners(changeType ConfigChangeType) {
cns.mu.Lock()
defer cns.mu.Unlock()
if listeners, exists := cns.listeners[changeType]; exists {
for _, listener := range listeners {
listener.cancel()
}
delete(cns.listeners, changeType)
}
}
// CheckConfigChanges 检查配置变更并通知相关监听器
func (cns *ConfigNotificationService) CheckConfigChanges() {
cns.listeners.Range(func(key, value interface{}) bool {
if listener, ok := value.(*ConfigListener); ok {
cns.mu.RLock()
allListeners := make(map[ConfigChangeType][]*ConfigListener)
for changeType, listeners := range cns.listeners {
// 创建监听器切片的副本以避免并发访问问题
listenersCopy := make([]*ConfigListener, len(listeners))
copy(listenersCopy, listeners)
allListeners[changeType] = listenersCopy
}
cns.mu.RUnlock()
// 检查所有监听器
for _, listeners := range allListeners {
for _, listener := range listeners {
cns.checkAndNotify(listener)
}
return true
})
}
}
// checkAndNotify 检查配置变更并通知
@@ -144,7 +186,7 @@ func (cns *ConfigNotificationService) checkAndNotify(listener *ConfigListener) {
if hasChanges {
listener.mu.Lock()
listener.lastConfig = deepCopyConfig(currentConfig)
listener.lastConfig = deepCopyConfigReflect(currentConfig)
listener.lastConfigHash = currentHash
listener.mu.Unlock()
@@ -167,7 +209,82 @@ func computeConfigHash(config *models.AppConfig) string {
return fmt.Sprintf("%x", hash)
}
// deepCopyConfig 深拷贝配置对象
// deepCopyConfigReflect 使用反射实现高效深拷贝
func deepCopyConfigReflect(src *models.AppConfig) *models.AppConfig {
if src == nil {
return nil
}
// 使用反射进行深拷贝
srcValue := reflect.ValueOf(src).Elem()
dstValue := reflect.New(srcValue.Type()).Elem()
deepCopyValue(srcValue, dstValue)
return dstValue.Addr().Interface().(*models.AppConfig)
}
// deepCopyValue 递归深拷贝reflect.Value
func deepCopyValue(src, dst reflect.Value) {
switch src.Kind() {
case reflect.Ptr:
if src.IsNil() {
return
}
dst.Set(reflect.New(src.Elem().Type()))
deepCopyValue(src.Elem(), dst.Elem())
case reflect.Struct:
for i := 0; i < src.NumField(); i++ {
if dst.Field(i).CanSet() {
deepCopyValue(src.Field(i), dst.Field(i))
}
}
case reflect.Slice:
if src.IsNil() {
return
}
dst.Set(reflect.MakeSlice(src.Type(), src.Len(), src.Cap()))
for i := 0; i < src.Len(); i++ {
deepCopyValue(src.Index(i), dst.Index(i))
}
case reflect.Map:
if src.IsNil() {
return
}
dst.Set(reflect.MakeMap(src.Type()))
for _, key := range src.MapKeys() {
srcValue := src.MapIndex(key)
dstValue := reflect.New(srcValue.Type()).Elem()
deepCopyValue(srcValue, dstValue)
dst.SetMapIndex(key, dstValue)
}
case reflect.Interface:
if src.IsNil() {
return
}
srcValue := src.Elem()
dstValue := reflect.New(srcValue.Type()).Elem()
deepCopyValue(srcValue, dstValue)
dst.Set(dstValue)
case reflect.Array:
for i := 0; i < src.Len(); i++ {
deepCopyValue(src.Index(i), dst.Index(i))
}
default:
// 对于基本类型和string直接赋值
if dst.CanSet() {
dst.Set(src)
}
}
}
// deepCopyConfig 保留原有的JSON深拷贝方法作为备用
func deepCopyConfig(src *models.AppConfig) *models.AppConfig {
if src == nil {
return nil
@@ -197,8 +314,8 @@ func (cns *ConfigNotificationService) debounceNotify(listener *ConfigListener, o
}
// 创建配置副本,避免在闭包中持有原始引用
oldConfigCopy := deepCopyConfig(oldConfig)
newConfigCopy := deepCopyConfig(newConfig)
oldConfigCopy := deepCopyConfigReflect(oldConfig)
newConfigCopy := deepCopyConfigReflect(newConfig)
changeType := listener.ChangeType
@@ -246,18 +363,33 @@ func (cns *ConfigNotificationService) executeCallback(
func (cns *ConfigNotificationService) Cleanup() {
cns.cancel() // 取消所有context
cns.listeners.Range(func(key, value interface{}) bool {
cns.listeners.Delete(key)
return true
})
cns.mu.Lock()
for changeType, listeners := range cns.listeners {
for _, listener := range listeners {
listener.cancel()
}
delete(cns.listeners, changeType)
}
cns.mu.Unlock()
cns.wg.Wait() // 等待所有协程完成
}
// GetListeners 获取指定类型的所有监听器
func (cns *ConfigNotificationService) GetListeners(changeType ConfigChangeType) []*ConfigListener {
cns.mu.RLock()
defer cns.mu.RUnlock()
listeners := cns.listeners[changeType]
result := make([]*ConfigListener, len(listeners))
copy(result, listeners)
return result
}
// CreateHotkeyListener 创建热键配置监听器
func CreateHotkeyListener(callback func(enable bool, hotkey *models.HotkeyCombo) error) *ConfigListener {
func CreateHotkeyListener(name string, callback func(enable bool, hotkey *models.HotkeyCombo) error) *ConfigListener {
return &ConfigListener{
Name: "HotkeyListener",
Name: name,
ChangeType: ConfigChangeTypeHotkey,
Callback: func(changeType ConfigChangeType, oldConfig, newConfig *models.AppConfig) error {
if newConfig != nil {
@@ -279,9 +411,9 @@ func CreateHotkeyListener(callback func(enable bool, hotkey *models.HotkeyCombo)
}
// CreateDataPathListener 创建数据路径配置监听器
func CreateDataPathListener(callback func(oldPath, newPath string) error) *ConfigListener {
func CreateDataPathListener(name string, callback func() error) *ConfigListener {
return &ConfigListener{
Name: "DataPathListener",
Name: name,
ChangeType: ConfigChangeTypeDataPath,
Callback: func(changeType ConfigChangeType, oldConfig, newConfig *models.AppConfig) error {
var oldPath, newPath string
@@ -298,7 +430,7 @@ func CreateDataPathListener(callback func(oldPath, newPath string) error) *Confi
}
if oldPath != newPath {
return callback(oldPath, newPath)
return callback()
}
return nil
},
@@ -313,8 +445,8 @@ func CreateDataPathListener(callback func(oldPath, newPath string) error) *Confi
}
}
// ServiceShutdown 关闭服务
func (cns *ConfigNotificationService) ServiceShutdown() error {
// OnShutdown 关闭服务
func (cns *ConfigNotificationService) OnShutdown() error {
cns.Cleanup()
return nil
}