🎨 Optimize configuration service
This commit is contained in:
6
go.mod
6
go.mod
@@ -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
|
||||||
|
@@ -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)
|
||||||
|
}
|
||||||
|
@@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user