✨ Use SQLite instead of JSON storage
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
Reference in New Issue
Block a user