🎨 Optimize code

This commit is contained in:
2025-06-22 15:08:38 +08:00
parent 35c89e086e
commit eb9b037f8e
22 changed files with 937 additions and 1906 deletions

View File

@@ -1,10 +1,10 @@
package services
import (
"context"
"crypto/sha256"
"encoding/json"
"fmt"
"reflect"
"sync"
"time"
"voidraft/internal/models"
@@ -24,106 +24,76 @@ const (
)
// ConfigChangeCallback 配置变更回调函数类型
type ConfigChangeCallback func(changeType ConfigChangeType, oldConfig, newConfig interface{}) error
type ConfigChangeCallback func(changeType ConfigChangeType, oldConfig, newConfig *models.AppConfig) error
// ConfigListener 配置监听器
type ConfigListener struct {
Name string // 监听器名称
ChangeType ConfigChangeType // 监听的配置变更类型
Callback ConfigChangeCallback // 回调函数(现在包含新旧配置)
DebounceDelay time.Duration // 防抖延迟时间
GetConfigFunc func(*viper.Viper) interface{} // 获取相关配置的函数
Name string // 监听器名称
ChangeType ConfigChangeType // 监听的配置变更类型
Callback ConfigChangeCallback // 回调函数(现在包含新旧配置)
DebounceDelay time.Duration // 防抖延迟时间
GetConfigFunc func(*viper.Viper) *models.AppConfig // 获取相关配置的函数
// 内部状态
mu sync.RWMutex // 监听器状态锁
timer *time.Timer // 防抖定时器
lastConfigHash string // 上次配置的哈希值,用于变更检测
lastConfig interface{} // 上次的配置副本
stopChan chan struct{} // 停止通道用于停止异步goroutine
mu sync.RWMutex // 监听器状态锁
timer *time.Timer // 防抖定时器
lastConfigHash string // 上次配置的哈希值,用于变更检测
lastConfig *models.AppConfig // 上次的配置副本
ctx context.Context
cancel context.CancelFunc
}
// ConfigNotificationService 配置通知服务
type ConfigNotificationService struct {
listeners map[ConfigChangeType]*ConfigListener // 监听器映射
mu sync.RWMutex // 读写锁
logger *log.LoggerService // 日志服务
viper *viper.Viper // Viper实例
listeners sync.Map // 使用sync.Map替代普通map+锁
logger *log.LoggerService // 日志服务
viper *viper.Viper // Viper实例
ctx context.Context
cancel context.CancelFunc
wg sync.WaitGroup
}
// NewConfigNotificationService 创建配置通知服务
func NewConfigNotificationService(viper *viper.Viper, logger *log.LoggerService) *ConfigNotificationService {
ctx, cancel := context.WithCancel(context.Background())
return &ConfigNotificationService{
listeners: make(map[ConfigChangeType]*ConfigListener),
logger: logger,
viper: viper,
logger: logger,
viper: viper,
ctx: ctx,
cancel: cancel,
}
}
// RegisterListener 注册配置监听器
func (cns *ConfigNotificationService) RegisterListener(listener *ConfigListener) error {
cns.mu.Lock()
defer cns.mu.Unlock()
// 检查是否已存在同类型监听器
if existingListener, exists := cns.listeners[listener.ChangeType]; exists {
cns.logger.Warning("ConfigNotification: Listener already exists, will be replaced",
"existing_name", existingListener.Name,
"new_name", listener.Name,
"type", string(listener.ChangeType))
// 清理旧监听器
cns.cleanupListener(existingListener)
// 清理已存在的监听器
if existingValue, loaded := cns.listeners.LoadAndDelete(listener.ChangeType); loaded {
if existing, ok := existingValue.(interface{ cancel() }); ok {
existing.cancel()
}
}
// 初始化新监听器
listener.stopChan = make(chan struct{})
// 初始化监听器的配置状态
listener.ctx, listener.cancel = context.WithCancel(cns.ctx)
if err := cns.initializeListenerState(listener); err != nil {
cns.logger.Error("ConfigNotification: Failed to initialize listener state",
"listener", listener.Name,
"error", err)
listener.cancel()
return fmt.Errorf("failed to initialize listener state: %w", err)
}
cns.listeners[listener.ChangeType] = listener
cns.logger.Info("ConfigNotification: Registered listener",
"name", listener.Name,
"type", string(listener.ChangeType))
cns.listeners.Store(listener.ChangeType, listener)
return nil
}
// cleanupListener 清理监听器资源
func (cns *ConfigNotificationService) cleanupListener(listener *ConfigListener) {
listener.mu.Lock()
defer listener.mu.Unlock()
// 停止防抖定时器
if listener.timer != nil {
listener.timer.Stop()
listener.timer = nil
}
// 关闭停止通道通知goroutine退出
if listener.stopChan != nil {
close(listener.stopChan)
listener.stopChan = nil
}
}
// initializeListenerState 初始化监听器状态
func (cns *ConfigNotificationService) initializeListenerState(listener *ConfigListener) error {
if listener.GetConfigFunc == nil {
return fmt.Errorf("GetConfigFunc is required")
}
// 获取初始配置
config := listener.GetConfigFunc(cns.viper)
if config != nil {
if config := listener.GetConfigFunc(cns.viper); config != nil {
listener.mu.Lock()
listener.lastConfig = cns.deepCopy(config)
listener.lastConfigHash = cns.computeConfigHash(config)
listener.lastConfig = deepCopyConfig(config)
listener.lastConfigHash = computeConfigHash(config)
listener.mu.Unlock()
}
@@ -132,205 +102,92 @@ func (cns *ConfigNotificationService) initializeListenerState(listener *ConfigLi
// UnregisterListener 注销配置监听器
func (cns *ConfigNotificationService) UnregisterListener(changeType ConfigChangeType) {
cns.mu.Lock()
defer cns.mu.Unlock()
if listener, exists := cns.listeners[changeType]; exists {
cns.cleanupListener(listener)
delete(cns.listeners, changeType)
cns.logger.Info("ConfigNotification: Unregistered listener", "type", string(changeType))
if value, loaded := cns.listeners.LoadAndDelete(changeType); loaded {
if listener, ok := value.(*ConfigListener); ok {
listener.cancel()
}
}
}
// CheckConfigChanges 检查配置变更并通知相关监听器
func (cns *ConfigNotificationService) CheckConfigChanges() {
cns.mu.RLock()
listeners := make([]*ConfigListener, 0, len(cns.listeners))
for _, listener := range cns.listeners {
listeners = append(listeners, listener)
}
cns.mu.RUnlock()
// 检查每个监听器的配置变更
for _, listener := range listeners {
if hasChanges, oldConfig, newConfig := cns.checkListenerConfigChanges(listener); hasChanges {
cns.logger.Debug("ConfigNotification: Actual config change detected",
"type", string(listener.ChangeType),
"listener", listener.Name)
// 触发防抖通知,传递新旧配置
cns.debounceNotifyWithChanges(listener, oldConfig, newConfig)
cns.listeners.Range(func(key, value interface{}) bool {
if listener, ok := value.(*ConfigListener); ok {
cns.checkAndNotify(listener)
}
}
return true
})
}
// checkListenerConfigChanges 检查单个监听器的配置变更
func (cns *ConfigNotificationService) checkListenerConfigChanges(listener *ConfigListener) (bool, interface{}, interface{}) {
// checkAndNotify 检查配置变更并通知
func (cns *ConfigNotificationService) checkAndNotify(listener *ConfigListener) {
if listener.GetConfigFunc == nil {
return false, nil, nil
return
}
// 获取当前配置
currentConfig := listener.GetConfigFunc(cns.viper)
// 读取监听器状态
listener.mu.RLock()
lastHash := listener.lastConfigHash
lastConfig := listener.lastConfig
listener.mu.RUnlock()
if currentConfig == nil {
// 配置不存在或获取失败
if lastConfig != nil {
// 配置被删除,更新状态
listener.mu.Lock()
listener.lastConfig = nil
listener.lastConfigHash = ""
listener.mu.Unlock()
return true, lastConfig, nil
}
return false, nil, nil
var hasChanges bool
var currentHash string
if currentConfig != nil {
currentHash = computeConfigHash(currentConfig)
hasChanges = currentHash != lastHash
} else {
hasChanges = lastConfig != nil
}
// 计算当前配置的哈希
currentHash := cns.computeConfigHash(currentConfig)
// 检查是否有变更
if currentHash != lastHash {
// 更新监听器状态
if hasChanges {
listener.mu.Lock()
listener.lastConfig = cns.deepCopy(currentConfig)
listener.lastConfig = deepCopyConfig(currentConfig)
listener.lastConfigHash = currentHash
listener.mu.Unlock()
return true, lastConfig, currentConfig
cns.debounceNotify(listener, lastConfig, currentConfig)
}
return false, nil, nil
}
// computeConfigHash 计算配置的哈希值 - 安全稳定版本
func (cns *ConfigNotificationService) computeConfigHash(config interface{}) string {
// computeConfigHash 计算配置的哈希值
func computeConfigHash(config *models.AppConfig) string {
if config == nil {
return ""
}
// 使用JSON序列化确保稳定性和准确性
jsonBytes, err := json.Marshal(config)
if err != nil {
// 如果JSON序列化失败回退到字符串表示
cns.logger.Warning("ConfigNotification: JSON marshal failed, using string representation",
"error", err)
configStr := fmt.Sprintf("%+v", config)
jsonBytes = []byte(configStr)
return fmt.Sprintf("%p", config)
}
hash := sha256.Sum256(jsonBytes)
return fmt.Sprintf("%x", hash)
}
// deepCopy 深拷贝配置对象 - 完整实现
func (cns *ConfigNotificationService) deepCopy(src interface{}) interface{} {
// deepCopyConfig 深拷贝配置对象
func deepCopyConfig(src *models.AppConfig) *models.AppConfig {
if src == nil {
return nil
}
// 首先尝试JSON序列化方式深拷贝适用于大多数配置对象
jsonBytes, err := json.Marshal(src)
if err != nil {
cns.logger.Warning("ConfigNotification: JSON marshal for deep copy failed, using reflection",
"error", err)
return cns.reflectDeepCopy(src)
}
// 创建同类型的新对象
srcType := reflect.TypeOf(src)
var dst interface{}
if srcType.Kind() == reflect.Ptr {
// 对于指针类型,创建指向新对象的指针
elemType := srcType.Elem()
newObj := reflect.New(elemType)
dst = newObj.Interface()
} else {
// 对于值类型,创建零值
newObj := reflect.New(srcType)
dst = newObj.Interface()
}
// 反序列化到新对象
err = json.Unmarshal(jsonBytes, dst)
if err != nil {
cns.logger.Warning("ConfigNotification: JSON unmarshal for deep copy failed, using reflection",
"error", err)
return cns.reflectDeepCopy(src)
}
// 如果原对象不是指针类型,返回值而不是指针
if srcType.Kind() != reflect.Ptr {
return reflect.ValueOf(dst).Elem().Interface()
}
return dst
}
// reflectDeepCopy 使用反射进行深拷贝的备用方法
func (cns *ConfigNotificationService) reflectDeepCopy(src interface{}) interface{} {
srcValue := reflect.ValueOf(src)
return cns.reflectDeepCopyValue(srcValue).Interface()
}
// reflectDeepCopyValue 递归深拷贝reflect.Value
func (cns *ConfigNotificationService) reflectDeepCopyValue(src reflect.Value) reflect.Value {
if !src.IsValid() {
return reflect.Value{}
}
switch src.Kind() {
case reflect.Ptr:
if src.IsNil() {
return reflect.New(src.Type()).Elem()
}
dst := reflect.New(src.Type().Elem())
dst.Elem().Set(cns.reflectDeepCopyValue(src.Elem()))
return dst
case reflect.Struct:
dst := reflect.New(src.Type()).Elem()
for i := 0; i < src.NumField(); i++ {
if dst.Field(i).CanSet() {
dst.Field(i).Set(cns.reflectDeepCopyValue(src.Field(i)))
}
}
return dst
case reflect.Slice:
if src.IsNil() {
return reflect.Zero(src.Type())
}
dst := reflect.MakeSlice(src.Type(), src.Len(), src.Cap())
for i := 0; i < src.Len(); i++ {
dst.Index(i).Set(cns.reflectDeepCopyValue(src.Index(i)))
}
return dst
case reflect.Map:
if src.IsNil() {
return reflect.Zero(src.Type())
}
dst := reflect.MakeMap(src.Type())
for _, key := range src.MapKeys() {
dst.SetMapIndex(key, cns.reflectDeepCopyValue(src.MapIndex(key)))
}
return dst
default:
return src
}
var dst models.AppConfig
if err := json.Unmarshal(jsonBytes, &dst); err != nil {
return src
}
return &dst
}
// debounceNotifyWithChanges 防抖通知(带变更信息)- 修复内存泄漏
func (cns *ConfigNotificationService) debounceNotifyWithChanges(listener *ConfigListener, oldConfig, newConfig interface{}) {
// debounceNotify 防抖通知
func (cns *ConfigNotificationService) debounceNotify(listener *ConfigListener, oldConfig, newConfig *models.AppConfig) {
listener.mu.Lock()
defer listener.mu.Unlock()
@@ -340,87 +197,61 @@ func (cns *ConfigNotificationService) debounceNotifyWithChanges(listener *Config
}
// 创建配置副本,避免在闭包中持有原始引用
oldConfigCopy := cns.deepCopy(oldConfig)
newConfigCopy := cns.deepCopy(newConfig)
oldConfigCopy := deepCopyConfig(oldConfig)
newConfigCopy := deepCopyConfig(newConfig)
// 获取监听器信息的副本
listenerName := listener.Name
changeType := listener.ChangeType
stopChan := listener.stopChan
// 设置新的防抖定时器
listener.timer = time.AfterFunc(listener.DebounceDelay, func() {
cns.logger.Debug("ConfigNotification: Executing callback after debounce",
"listener", listenerName,
"type", string(changeType))
cns.executeCallback(listener.ctx, changeType, listener.Callback, oldConfigCopy, newConfigCopy)
})
}
// 启动独立的goroutine处理回调带有超时和停止信号检查
go func() {
defer func() {
if r := recover(); r != nil {
cns.logger.Error("ConfigNotification: Callback panic recovered",
"listener", listenerName,
"type", string(changeType),
"panic", r)
}
}()
// 检查是否收到停止信号
select {
case <-stopChan:
cns.logger.Debug("ConfigNotification: Callback cancelled due to stop signal",
"listener", listenerName)
return
default:
}
// 执行回调,设置超时
callbackDone := make(chan error, 1)
go func() {
callbackDone <- listener.Callback(changeType, oldConfigCopy, newConfigCopy)
}()
select {
case <-stopChan:
cns.logger.Debug("ConfigNotification: Callback interrupted by stop signal",
"listener", listenerName)
return
case err := <-callbackDone:
if err != nil {
cns.logger.Error("ConfigNotification: Callback execution failed",
"listener", listenerName,
"type", string(changeType),
"error", err)
} else {
cns.logger.Debug("ConfigNotification: Callback executed successfully",
"listener", listenerName,
"type", string(changeType))
}
case <-time.After(30 * time.Second): // 30秒超时
cns.logger.Error("ConfigNotification: Callback execution timeout",
"listener", listenerName,
"type", string(changeType),
"timeout", "30s")
// executeCallback 执行回调函数
func (cns *ConfigNotificationService) executeCallback(
ctx context.Context,
changeType ConfigChangeType,
callback ConfigChangeCallback,
oldConfig, newConfig *models.AppConfig,
) {
cns.wg.Add(1)
go func() {
defer cns.wg.Done()
defer func() {
if r := recover(); r != nil {
cns.logger.Error("config callback panic", "error", r)
}
}()
})
cns.logger.Debug("ConfigNotification: Debounce timer scheduled",
"listener", listenerName,
"delay", listener.DebounceDelay)
callbackCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
done := make(chan error, 1)
go func() {
done <- callback(changeType, oldConfig, newConfig)
}()
select {
case <-callbackCtx.Done():
cns.logger.Error("config callback timeout")
case err := <-done:
if err != nil {
cns.logger.Error("config callback error", "error", err)
}
}
}()
}
// Cleanup 清理所有监听器
func (cns *ConfigNotificationService) Cleanup() {
cns.mu.Lock()
defer cns.mu.Unlock()
cns.cancel() // 取消所有context
for changeType, listener := range cns.listeners {
cns.cleanupListener(listener)
delete(cns.listeners, changeType)
}
cns.listeners.Range(func(key, value interface{}) bool {
cns.listeners.Delete(key)
return true
})
cns.logger.Info("ConfigNotification: All listeners cleaned up")
cns.wg.Wait() // 等待所有协程完成
}
// CreateHotkeyListener 创建热键配置监听器
@@ -428,20 +259,16 @@ func CreateHotkeyListener(callback func(enable bool, hotkey *models.HotkeyCombo)
return &ConfigListener{
Name: "HotkeyListener",
ChangeType: ConfigChangeTypeHotkey,
Callback: func(changeType ConfigChangeType, oldConfig, newConfig interface{}) error {
// 处理新配置
if newAppConfig, ok := newConfig.(*models.AppConfig); ok {
return callback(newAppConfig.General.EnableGlobalHotkey, &newAppConfig.General.GlobalHotkey)
Callback: func(changeType ConfigChangeType, oldConfig, newConfig *models.AppConfig) error {
if newConfig != nil {
return callback(newConfig.General.EnableGlobalHotkey, &newConfig.General.GlobalHotkey)
}
// 如果新配置为空,说明配置被删除,使用默认
if newConfig == nil {
defaultConfig := models.NewDefaultAppConfig()
return callback(defaultConfig.General.EnableGlobalHotkey, &defaultConfig.General.GlobalHotkey)
}
return nil
// 使用默认配置
defaultConfig := models.NewDefaultAppConfig()
return callback(defaultConfig.General.EnableGlobalHotkey, &defaultConfig.General.GlobalHotkey)
},
DebounceDelay: 200 * time.Millisecond,
GetConfigFunc: func(v *viper.Viper) interface{} {
GetConfigFunc: func(v *viper.Viper) *models.AppConfig {
var config models.AppConfig
if err := v.Unmarshal(&config); err != nil {
return nil
@@ -456,31 +283,27 @@ func CreateDataPathListener(callback func(oldPath, newPath string) error) *Confi
return &ConfigListener{
Name: "DataPathListener",
ChangeType: ConfigChangeTypeDataPath,
Callback: func(changeType ConfigChangeType, oldConfig, newConfig interface{}) error {
Callback: func(changeType ConfigChangeType, oldConfig, newConfig *models.AppConfig) error {
var oldPath, newPath string
// 处理旧配置
if oldAppConfig, ok := oldConfig.(*models.AppConfig); ok {
oldPath = oldAppConfig.General.DataPath
if oldConfig != nil {
oldPath = oldConfig.General.DataPath
}
// 处理新配置
if newAppConfig, ok := newConfig.(*models.AppConfig); ok {
newPath = newAppConfig.General.DataPath
} else if newConfig == nil {
// 如果新配置为空,说明配置被删除,使用默认值
if newConfig != nil {
newPath = newConfig.General.DataPath
} else {
defaultConfig := models.NewDefaultAppConfig()
newPath = defaultConfig.General.DataPath
}
// 只有路径真正改变时才调用回调
if oldPath != newPath {
return callback(oldPath, newPath)
}
return nil
},
DebounceDelay: 100 * time.Millisecond, // 较短的防抖延迟,因为数据路径变更需要快速响应
GetConfigFunc: func(v *viper.Viper) interface{} {
DebounceDelay: 100 * time.Millisecond,
GetConfigFunc: func(v *viper.Viper) *models.AppConfig {
var config models.AppConfig
if err := v.Unmarshal(&config); err != nil {
return nil