🎨 Optimize configuration service

This commit is contained in:
2025-05-13 16:56:53 +08:00
parent 7e6e7e4e73
commit 33bd4940e9
3 changed files with 220 additions and 113 deletions

6
go.mod
View File

@@ -4,10 +4,12 @@ go 1.23.0
toolchain go1.24.2 toolchain go1.24.2
require github.com/wailsapp/wails/v3 v3.0.0-alpha.9 require (
dario.cat/mergo v1.0.2
github.com/wailsapp/wails/v3 v3.0.0-alpha.9
)
require ( require (
dario.cat/mergo v1.0.2 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/ProtonMail/go-crypto v1.2.0 // indirect github.com/ProtonMail/go-crypto v1.2.0 // indirect
github.com/adrg/xdg v0.5.3 // indirect github.com/adrg/xdg v0.5.3 // indirect

View File

@@ -1,6 +1,7 @@
package services package services
import ( import (
"errors"
"fmt" "fmt"
"github.com/wailsapp/wails/v3/pkg/services/log" "github.com/wailsapp/wails/v3/pkg/services/log"
"os" "os"
@@ -8,98 +9,200 @@ import (
"sync" "sync"
"time" "time"
"voidraft/internal/models" "voidraft/internal/models"
"dario.cat/mergo"
) )
// ConfigPath 配置路径提供接口
type ConfigPath interface {
// GetConfigPath 获取配置文件路径
GetConfigPath() string
}
// DefaultConfigPathProvider 默认配置路径提供者
type DefaultConfigPathProvider struct{}
// GetConfigPath 获取默认配置路径
func (p *DefaultConfigPathProvider) GetConfigPath() string {
// 获取用户主目录
homePath, err := os.UserHomeDir()
if err != nil {
homePath = "."
}
// 返回固定的配置路径
return filepath.Join(homePath, ".voidraft", "config", "config.json")
}
// ConfigOption 配置服务选项
type ConfigOption struct {
Logger *log.LoggerService // 日志服务
PathProvider ConfigPath // 路径提供者
AutoSaveEnabled bool // 是否启用自动保存
}
// ConfigService 提供配置管理功能 // ConfigService 提供配置管理功能
type ConfigService struct { type ConfigService struct {
store *Store[models.AppConfig] // 配置存储 store *Store[models.AppConfig] // 配置存储
path string // 配置文件路径 logger *log.LoggerService // 日志服务
logger *log.LoggerService cache *models.AppConfig // 配置缓存
cache *models.AppConfig // 配置缓存 cacheMu sync.RWMutex // 缓存
cacheMu sync.RWMutex // 缓存锁 }
// ConfigError 配置错误
type ConfigError struct {
Operation string // 操作名称
Err error // 原始错误
}
// Error 实现error接口
func (e *ConfigError) Error() string {
return fmt.Sprintf("config error during %s: %v", e.Operation, e.Err)
}
// Unwrap 获取原始错误
func (e *ConfigError) Unwrap() error {
return e.Err
}
// Is 实现错误匹配
func (e *ConfigError) Is(target error) bool {
_, ok := target.(*ConfigError)
return ok
} }
// NewConfigService 创建新的配置服务实例 // NewConfigService 创建新的配置服务实例
func NewConfigService() *ConfigService { func NewConfigService(opt ...ConfigOption) *ConfigService {
// 初始化日志服务 var option ConfigOption
logger := log.New()
// 获取用户主目录 // 使用第一个选项
homePath, err := os.UserHomeDir() if len(opt) > 0 {
if err != nil { option = opt[0]
logger.Error("Config: Failed to get user home directory", "error", err)
homePath = "."
} }
// 固定配置路径 // 设置日志服务
configPath := filepath.Join(homePath, ".voidraft", "config", "config.json") logger := option.Logger
if logger == nil {
logger = log.New()
}
// 设置路径提供者
pathProvider := option.PathProvider
if pathProvider == nil {
pathProvider = &DefaultConfigPathProvider{}
}
// 获取配置路径
configPath := pathProvider.GetConfigPath()
logger.Info("Config: Using config path", "path", configPath) logger.Info("Config: Using config path", "path", configPath)
// 创建存储 // 创建存储
store := NewStore[models.AppConfig](StoreOption{ store := NewStore[models.AppConfig](StoreOption{
FilePath: configPath, FilePath: configPath,
AutoSave: true, AutoSave: option.AutoSaveEnabled,
Logger: logger, Logger: logger,
}) })
// 构造配置服务实例 // 构造配置服务实例
service := &ConfigService{ service := &ConfigService{
store: store, store: store,
path: configPath,
logger: logger, logger: logger,
} }
// 初始化加载配置 // 初始化加载配置
service.loadInitialConfig() if err := service.initConfig(); err != nil {
service.logger.Error("Config: Failed to initialize config", "error", err)
}
return service return service
} }
// loadInitialConfig 加载初始配置 // initConfig 初始配置
func (cs *ConfigService) loadInitialConfig() { func (cs *ConfigService) initConfig() error {
// 尝试加载配置 config, err := cs.loadConfig()
config, err := cs.load()
if err != nil { if err != nil {
// 如果加载失败,使用默认配置 // 如果加载失败,使用默认配置
defaultConfig := models.NewDefaultAppConfig() defaultConfig := models.NewDefaultAppConfig()
cs.logger.Info("Config: Using default config")
// 保存默认配置 // 保存默认配置并更新缓存
if err := cs.save(*defaultConfig); err != nil { if err := cs.saveConfigWithCache(*defaultConfig); err != nil {
cs.logger.Error("Config: Failed to save default config", "error", err) return &ConfigError{Operation: "init_save_default", Err: err}
} else {
// 更新缓存
cs.cacheMu.Lock()
cs.cache = defaultConfig
cs.cacheMu.Unlock()
} }
} else {
// 更新缓存 return nil
cs.cacheMu.Lock()
cs.cache = &config
cs.cacheMu.Unlock()
} }
// 合并默认配置
if err := cs.mergeWithDefaults(&config); err != nil {
return &ConfigError{Operation: "init_merge_defaults", Err: err}
}
return nil
} }
// load 加载配置 // mergeWithDefaults 将默认配置合并到现有配置中
func (cs *ConfigService) load() (models.AppConfig, error) { func (cs *ConfigService) mergeWithDefaults(config *models.AppConfig) error {
defaultConfig := models.NewDefaultAppConfig()
// 使用mergo库合并配置
if err := mergo.Merge(config, defaultConfig, mergo.WithOverrideEmptySlice, mergo.WithOverwriteWithEmptyValue); err != nil {
return err
}
// 更新最后修改时间
config.Metadata.LastUpdated = time.Now()
// 保存合并后的配置
return cs.saveConfigWithCache(*config)
}
// loadConfig 加载配置
func (cs *ConfigService) loadConfig() (models.AppConfig, error) {
// 尝试从缓存获取
cs.cacheMu.RLock()
cachedConfig := cs.cache
cs.cacheMu.RUnlock()
if cachedConfig != nil {
return *cachedConfig, nil
}
// 从存储加载
config := cs.store.Get() config := cs.store.Get()
// 检查配置是否为空 // 检查配置是否有效
if isEmptyConfig(config) { if !isValidConfig(config) {
return models.AppConfig{}, fmt.Errorf("empty config detected") return models.AppConfig{}, errors.New("invalid or empty configuration")
} }
return config, nil return config, nil
} }
// save 保存配置 // isValidConfig 检查配置是否有效
func (cs *ConfigService) save(config models.AppConfig) error { func isValidConfig(config models.AppConfig) bool {
return cs.store.Set(config) // 检查关键字段
if config.Metadata.Version == "" ||
config.Metadata.LastUpdated.IsZero() ||
config.Paths.DataPath == "" {
return false
}
return true
} }
// isEmptyConfig 检查配置是否为空 // saveConfigWithCache 保存配置并更新缓存
func isEmptyConfig(config models.AppConfig) bool { func (cs *ConfigService) saveConfigWithCache(config models.AppConfig) error {
return config.Editor.FontSize == 0 // 更新缓存
cs.cacheMu.Lock()
cs.cache = &config
cs.cacheMu.Unlock()
// 保存到存储
if err := cs.store.Set(config); err != nil {
return err
}
return nil
} }
// GetConfig 获取完整应用配置 // GetConfig 获取完整应用配置
@@ -113,74 +216,40 @@ func (cs *ConfigService) GetConfig() (*models.AppConfig, error) {
} }
cs.cacheMu.RUnlock() cs.cacheMu.RUnlock()
// 缓存不存在,从存储加载 // 加载配置
config, err := cs.load() config, err := cs.loadConfig()
if err != nil { if err != nil {
// 加载失败,使用默认配置 // 加载失败,使用默认配置
defaultConfig := models.NewDefaultAppConfig() defaultConfig := models.NewDefaultAppConfig()
// 保存默认配置 // 保存默认配置
if saveErr := cs.save(*defaultConfig); saveErr != nil { if saveErr := cs.saveConfigWithCache(*defaultConfig); saveErr != nil {
cs.logger.Error("Config: Failed to save default config", "error", saveErr) cs.logger.Error("Config: Failed to save default config", "error", saveErr)
return nil, &ConfigError{Operation: "get_save_default", Err: saveErr}
} }
// 更新缓存
cs.cacheMu.Lock()
cs.cache = defaultConfig
cs.cacheMu.Unlock()
return defaultConfig, nil return defaultConfig, nil
} }
// 更新缓存 // 合并默认配置
cs.cacheMu.Lock() if err := cs.mergeWithDefaults(&config); err != nil {
cs.cache = &config return &config, &ConfigError{Operation: "get_merge_defaults", Err: err}
cs.cacheMu.Unlock() }
return &config, nil return &config, nil
} }
// SaveConfig 保存完整应用配置 // SaveConfig 保存完整应用配置
func (cs *ConfigService) SaveConfig(config *models.AppConfig) error { func (cs *ConfigService) SaveConfig(config *models.AppConfig) error {
if config == nil {
return errors.New("cannot save nil config")
}
// 更新配置元数据 // 更新配置元数据
config.Metadata.LastUpdated = time.Now() config.Metadata.LastUpdated = time.Now()
// 更新缓存 // 保存配置
cs.cacheMu.Lock() return cs.saveConfigWithCache(*config)
cs.cache = config
cs.cacheMu.Unlock()
// 保存到存储
return cs.save(*config)
}
// UpdatePaths 更新路径配置
func (cs *ConfigService) UpdatePaths(paths models.PathsConfig) error {
config, err := cs.GetConfig()
if err != nil {
return err
}
// 更新路径配置
config.Paths.LogPath = paths.LogPath
config.Paths.DataPath = paths.DataPath
return cs.SaveConfig(config)
}
// ResetConfig 重置为默认配置
func (cs *ConfigService) ResetConfig() error {
defaultConfig := models.NewDefaultAppConfig()
return cs.SaveConfig(defaultConfig)
}
// GetEditorConfig 获取编辑器配置
func (cs *ConfigService) GetEditorConfig() (models.EditorConfig, error) {
config, err := cs.GetConfig()
if err != nil {
return models.EditorConfig{}, err
}
return config.Editor, nil
} }
// UpdateEditorConfig 更新编辑器配置 // UpdateEditorConfig 更新编辑器配置
@@ -194,6 +263,31 @@ func (cs *ConfigService) UpdateEditorConfig(editorConfig models.EditorConfig) er
return cs.SaveConfig(config) return cs.SaveConfig(config)
} }
// GetEditorConfig 获取编辑器配置
func (cs *ConfigService) GetEditorConfig() (models.EditorConfig, error) {
config, err := cs.GetConfig()
if err != nil {
return models.EditorConfig{}, err
}
return config.Editor, nil
}
// SetLanguage 设置语言
func (cs *ConfigService) SetLanguage(language models.LanguageType) error {
// 验证语言类型有效
if language != models.LangZhCN && language != models.LangEnUS {
return errors.New("invalid language type")
}
config, err := cs.GetConfig()
if err != nil {
return err
}
config.Editor.Language = language
return cs.SaveConfig(config)
}
// GetLanguage 获取当前语言设置 // GetLanguage 获取当前语言设置
func (cs *ConfigService) GetLanguage() (models.LanguageType, error) { func (cs *ConfigService) GetLanguage() (models.LanguageType, error) {
editorConfig, err := cs.GetEditorConfig() editorConfig, err := cs.GetEditorConfig()
@@ -203,19 +297,14 @@ func (cs *ConfigService) GetLanguage() (models.LanguageType, error) {
return editorConfig.Language, nil return editorConfig.Language, nil
} }
// SetLanguage 设置语言 // UpdatePaths 更新路径配置
func (cs *ConfigService) SetLanguage(language models.LanguageType) error { func (cs *ConfigService) UpdatePaths(paths models.PathsConfig) error {
// 验证语言类型有效
if language != models.LangZhCN && language != models.LangEnUS {
return nil
}
config, err := cs.GetConfig() config, err := cs.GetConfig()
if err != nil { if err != nil {
return err return err
} }
config.Editor.Language = language config.Paths = paths
return cs.SaveConfig(config) return cs.SaveConfig(config)
} }
@@ -228,15 +317,6 @@ func (cs *ConfigService) GetPaths() (models.PathsConfig, error) {
return config.Paths, nil return config.Paths, nil
} }
// GetMetadata 获取配置元数据
func (cs *ConfigService) GetMetadata() (models.ConfigMetadata, error) {
config, err := cs.GetConfig()
if err != nil {
return models.ConfigMetadata{}, err
}
return config.Metadata, nil
}
// UpdateMetadata 更新配置元数据 // UpdateMetadata 更新配置元数据
func (cs *ConfigService) UpdateMetadata(metadata models.ConfigMetadata) error { func (cs *ConfigService) UpdateMetadata(metadata models.ConfigMetadata) error {
config, err := cs.GetConfig() config, err := cs.GetConfig()
@@ -247,3 +327,18 @@ func (cs *ConfigService) UpdateMetadata(metadata models.ConfigMetadata) error {
config.Metadata = metadata config.Metadata = metadata
return cs.SaveConfig(config) return cs.SaveConfig(config)
} }
// GetMetadata 获取配置元数据
func (cs *ConfigService) GetMetadata() (models.ConfigMetadata, error) {
config, err := cs.GetConfig()
if err != nil {
return models.ConfigMetadata{}, err
}
return config.Metadata, nil
}
// ResetConfig 重置为默认配置
func (cs *ConfigService) ResetConfig() error {
defaultConfig := models.NewDefaultAppConfig()
return cs.SaveConfig(defaultConfig)
}

View File

@@ -2,20 +2,30 @@ package services
import ( import (
"github.com/wailsapp/wails/v3/pkg/application" "github.com/wailsapp/wails/v3/pkg/application"
"github.com/wailsapp/wails/v3/pkg/services/log"
) )
// ServiceManager 服务管理器,负责协调各个服务 // ServiceManager 服务管理器,负责协调各个服务
type ServiceManager struct { type ServiceManager struct {
configService *ConfigService configService *ConfigService
logger *log.LoggerService
} }
// NewServiceManager 创建新的服务管理器实例 // NewServiceManager 创建新的服务管理器实例
func NewServiceManager() *ServiceManager { func NewServiceManager() *ServiceManager {
// 初始化日志服务
logger := log.New()
// 初始化配置服务 // 初始化配置服务
configService := NewConfigService() configService := NewConfigService(ConfigOption{
Logger: logger,
PathProvider: nil,
AutoSaveEnabled: true,
})
return &ServiceManager{ return &ServiceManager{
configService: configService, configService: configService,
logger: logger,
} }
} }