⬆️ Upgrade wails v3 from Alpha 9 to Alpha 10

This commit is contained in:
2025-07-10 10:01:52 +08:00
parent b52e067d50
commit 4d62da912a
42 changed files with 1220 additions and 511 deletions

View File

@@ -38,7 +38,7 @@ type Migratable interface {
// ConfigMigrationService 配置迁移服务
type ConfigMigrationService[T Migratable] struct {
logger *log.LoggerService
logger *log.Service
configDir string
configName string
targetVersion string
@@ -54,7 +54,7 @@ type MigrationResult struct {
// NewConfigMigrationService 创建配置迁移服务
func NewConfigMigrationService[T Migratable](
logger *log.LoggerService,
logger *log.Service,
configDir string,
configName, targetVersion, configPath string,
) *ConfigMigrationService[T] {
@@ -312,7 +312,7 @@ func chainLoad(k *koanf.Koanf, loaders ...func() error) error {
}
// 工厂函数
func NewAppConfigMigrationService(logger *log.LoggerService, configDir, settingsPath string) *ConfigMigrationService[*models.AppConfig] {
func NewAppConfigMigrationService(logger *log.Service, configDir, settingsPath string) *ConfigMigrationService[*models.AppConfig] {
return NewConfigMigrationService[*models.AppConfig](
logger, configDir, "settings", CurrentAppConfigVersion, settingsPath)
}

View File

@@ -49,7 +49,7 @@ type ConfigListener struct {
type ConfigNotificationService struct {
listeners map[ConfigChangeType][]*ConfigListener // 支持多监听器的map
mu sync.RWMutex // 监听器map的读写锁
logger *log.LoggerService // 日志服务
logger *log.Service // 日志服务
koanf *koanf.Koanf // koanf实例
ctx context.Context
cancel context.CancelFunc
@@ -57,7 +57,7 @@ type ConfigNotificationService struct {
}
// NewConfigNotificationService 创建配置通知服务
func NewConfigNotificationService(k *koanf.Koanf, logger *log.LoggerService) *ConfigNotificationService {
func NewConfigNotificationService(k *koanf.Koanf, logger *log.Service) *ConfigNotificationService {
ctx, cancel := context.WithCancel(context.Background())
return &ConfigNotificationService{
listeners: make(map[ConfigChangeType][]*ConfigListener),
@@ -445,8 +445,8 @@ func CreateDataPathListener(name string, callback func() error) *ConfigListener
}
}
// OnShutdown 关闭服务
func (cns *ConfigNotificationService) OnShutdown() error {
// ServiceShutdown 关闭服务
func (cns *ConfigNotificationService) ServiceShutdown() error {
cns.Cleanup()
return nil
}

View File

@@ -18,12 +18,12 @@ import (
// ConfigService 应用配置服务
type ConfigService struct {
koanf *koanf.Koanf // koanf 实例
logger *log.LoggerService // 日志服务
configDir string // 配置目录
settingsPath string // 设置文件路径
mu sync.RWMutex // 读写锁
fileProvider *file.File // 文件提供器,用于监听
koanf *koanf.Koanf // koanf 实例
logger *log.Service // 日志服务
configDir string // 配置目录
settingsPath string // 设置文件路径
mu sync.RWMutex // 读写锁
fileProvider *file.File // 文件提供器,用于监听
// 配置通知服务
notificationService *ConfigNotificationService
@@ -55,7 +55,7 @@ func (e *ConfigError) Is(target error) bool {
}
// NewConfigService 创建新的配置服务实例
func NewConfigService(logger *log.LoggerService) *ConfigService {
func NewConfigService(logger *log.Service) *ConfigService {
// 获取用户主目录
homeDir, err := os.UserHomeDir()
if err != nil {
@@ -298,8 +298,8 @@ func (cs *ConfigService) SetDataPathChangeCallback(callback func() error) error
return cs.notificationService.RegisterListener(dataPathListener)
}
// OnShutdown 关闭服务
func (cs *ConfigService) OnShutdown() error {
// ServiceShutdown 关闭服务
func (cs *ConfigService) ServiceShutdown() error {
cs.stopWatching()
if cs.notificationService != nil {
cs.notificationService.Cleanup()

View File

@@ -2,7 +2,6 @@ package services
import (
"context"
"database/sql"
"fmt"
"os"
"path/filepath"
@@ -10,7 +9,7 @@ import (
"github.com/wailsapp/wails/v3/pkg/application"
"github.com/wailsapp/wails/v3/pkg/services/log"
_ "modernc.org/sqlite" // SQLite driver
"github.com/wailsapp/wails/v3/pkg/services/sqlite"
)
const (
@@ -64,14 +63,14 @@ CREATE TABLE IF NOT EXISTS key_bindings (
// DatabaseService provides shared database functionality
type DatabaseService struct {
configService *ConfigService
logger *log.LoggerService
db *sql.DB
logger *log.Service
SQLite *sqlite.Service
mu sync.RWMutex
ctx context.Context
}
// NewDatabaseService creates a new database service
func NewDatabaseService(configService *ConfigService, logger *log.LoggerService) *DatabaseService {
func NewDatabaseService(configService *ConfigService, logger *log.Service) *DatabaseService {
if logger == nil {
logger = log.New()
}
@@ -79,11 +78,12 @@ func NewDatabaseService(configService *ConfigService, logger *log.LoggerService)
return &DatabaseService{
configService: configService,
logger: logger,
SQLite: sqlite.New(),
}
}
// OnStartup initializes the service when the application starts
func (ds *DatabaseService) OnStartup(ctx context.Context, _ application.ServiceOptions) error {
// ServiceStartup initializes the service when the application starts
func (ds *DatabaseService) ServiceStartup(ctx context.Context, options application.ServiceOptions) error {
ds.ctx = ctx
return ds.initDatabase()
}
@@ -111,24 +111,26 @@ func (ds *DatabaseService) initDatabase() error {
file.Close()
}
db, err := sql.Open("sqlite", dbPath)
if err != nil {
// 配置SQLite服务
ds.SQLite.Configure(&sqlite.Config{
DBSource: dbPath,
})
// 打开数据库连接
if err := ds.SQLite.Open(); err != nil {
return fmt.Errorf("failed to open database: %w", err)
}
ds.db = db
// Apply optimization settings
if _, err := db.Exec(sqlOptimizationSettings); err != nil {
// 应用性能优化设置
if err := ds.SQLite.Execute(sqlOptimizationSettings); err != nil {
return fmt.Errorf("failed to apply optimization settings: %w", err)
}
// Create all tables
// 创建表和索引
if err := ds.createTables(); err != nil {
return fmt.Errorf("failed to create tables: %w", err)
}
// Create indexes
if err := ds.createIndexes(); err != nil {
return fmt.Errorf("failed to create indexes: %w", err)
}
@@ -154,7 +156,7 @@ func (ds *DatabaseService) createTables() error {
}
for _, table := range tables {
if _, err := ds.db.Exec(table); err != nil {
if err := ds.SQLite.Execute(table); err != nil {
return err
}
}
@@ -177,35 +179,25 @@ func (ds *DatabaseService) createIndexes() error {
}
for _, index := range indexes {
if _, err := ds.db.Exec(index); err != nil {
if err := ds.SQLite.Execute(index); err != nil {
return err
}
}
return nil
}
// GetDB returns the database connection
func (ds *DatabaseService) GetDB() *sql.DB {
ds.mu.RLock()
defer ds.mu.RUnlock()
return ds.db
}
// OnShutdown shuts down the service when the application closes
func (ds *DatabaseService) OnShutdown() error {
if ds.db != nil {
return ds.db.Close()
}
return nil
// ServiceShutdown shuts down the service when the application closes
func (ds *DatabaseService) ServiceShutdown() error {
return ds.SQLite.Close()
}
// OnDataPathChanged handles data path changes
func (ds *DatabaseService) OnDataPathChanged() error {
// Close existing database
if ds.db != nil {
ds.db.Close()
// 关闭当前连接
if err := ds.SQLite.Close(); err != nil {
return err
}
// Reinitialize with new path
// 用新路径重新初始化
return ds.initDatabase()
}

View File

@@ -7,12 +7,12 @@ import (
// DialogService 对话框服务,处理文件选择等对话框操作
type DialogService struct {
logger *log.LoggerService
logger *log.Service
window *application.WebviewWindow // 绑定的窗口
}
// NewDialogService 创建新的对话框服务实例
func NewDialogService(logger *log.LoggerService) *DialogService {
func NewDialogService(logger *log.Service) *DialogService {
if logger == nil {
logger = log.New()
}
@@ -30,7 +30,8 @@ func (ds *DialogService) SetWindow(window *application.WebviewWindow) {
// SelectDirectory 打开目录选择对话框
func (ds *DialogService) SelectDirectory() (string, error) {
dialog := application.OpenFileDialogWithOptions(&application.OpenFileDialogOptions{
dialog := application.OpenFileDialog()
dialog.SetOptions(&application.OpenFileDialogOptions{
// 目录选择配置
CanChooseDirectories: true, // 允许选择目录
CanChooseFiles: false, // 不允许选择文件

View File

@@ -11,7 +11,6 @@ import (
"github.com/wailsapp/wails/v3/pkg/application"
"github.com/wailsapp/wails/v3/pkg/services/log"
_ "modernc.org/sqlite" // SQLite driver
)
// SQL constants for document operations
@@ -70,13 +69,13 @@ SELECT id FROM documents WHERE is_deleted = 0 ORDER BY id LIMIT 1`
// DocumentService provides document management functionality
type DocumentService struct {
databaseService *DatabaseService
logger *log.LoggerService
logger *log.Service
mu sync.RWMutex
ctx context.Context
}
// NewDocumentService creates a new document service
func NewDocumentService(databaseService *DatabaseService, logger *log.LoggerService) *DocumentService {
func NewDocumentService(databaseService *DatabaseService, logger *log.Service) *DocumentService {
if logger == nil {
logger = log.New()
}
@@ -87,8 +86,8 @@ func NewDocumentService(databaseService *DatabaseService, logger *log.LoggerServ
}
}
// OnStartup initializes the service when the application starts
func (ds *DocumentService) OnStartup(ctx context.Context, _ application.ServiceOptions) error {
// ServiceStartup initializes the service when the application starts
func (ds *DocumentService) ServiceStartup(ctx context.Context, options application.ServiceOptions) error {
ds.ctx = ctx
// Ensure default document exists
if err := ds.ensureDefaultDocument(); err != nil {
@@ -100,13 +99,20 @@ func (ds *DocumentService) OnStartup(ctx context.Context, _ application.ServiceO
// ensureDefaultDocument ensures a default document exists
func (ds *DocumentService) ensureDefaultDocument() error {
// Check if any document exists
var count int
db := ds.databaseService.GetDB()
err := db.QueryRow(sqlCountDocuments).Scan(&count)
rows, err := ds.databaseService.SQLite.Query(sqlCountDocuments)
if err != nil {
return err
}
if len(rows) == 0 {
return fmt.Errorf("failed to query document count")
}
count, ok := rows[0]["COUNT(*)"].(int64)
if !ok {
return fmt.Errorf("failed to convert count to int64")
}
// If no documents exist, create default document
if count == 0 {
defaultDoc := models.NewDefaultDocument()
@@ -121,20 +127,50 @@ func (ds *DocumentService) GetDocumentByID(id int64) (*models.Document, error) {
ds.mu.RLock()
defer ds.mu.RUnlock()
var doc models.Document
var isDeletedInt int
db := ds.databaseService.GetDB()
row := db.QueryRow(sqlGetDocumentByID, id)
err := row.Scan(&doc.ID, &doc.Title, &doc.Content, &doc.CreatedAt, &doc.UpdatedAt, &isDeletedInt)
rows, err := ds.databaseService.SQLite.Query(sqlGetDocumentByID, id)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, nil
}
return nil, fmt.Errorf("failed to get document by ID: %w", err)
}
doc.IsDeleted = isDeletedInt == 1
return &doc, nil
if len(rows) == 0 {
return nil, nil
}
row := rows[0]
doc := &models.Document{}
// 从Row中提取数据
if idVal, ok := row["id"].(int64); ok {
doc.ID = idVal
}
if title, ok := row["title"].(string); ok {
doc.Title = title
}
if content, ok := row["content"].(string); ok {
doc.Content = content
}
if createdAt, ok := row["created_at"].(string); ok {
t, err := time.Parse("2006-01-02 15:04:05", createdAt)
if err == nil {
doc.CreatedAt = t
}
}
if updatedAt, ok := row["updated_at"].(string); ok {
t, err := time.Parse("2006-01-02 15:04:05", updatedAt)
if err == nil {
doc.UpdatedAt = t
}
}
if isDeletedInt, ok := row["is_deleted"].(int64); ok {
doc.IsDeleted = isDeletedInt == 1
}
return doc, nil
}
// CreateDocument creates a new document and returns the created document with ID
@@ -152,20 +188,30 @@ func (ds *DocumentService) CreateDocument(title string) (*models.Document, error
IsDeleted: false,
}
db := ds.databaseService.GetDB()
result, err := db.Exec(sqlInsertDocument, doc.Title, doc.Content, doc.CreatedAt, doc.UpdatedAt)
if err != nil {
// 执行插入操作
if err := ds.databaseService.SQLite.Execute(sqlInsertDocument,
doc.Title, doc.Content, doc.CreatedAt, doc.UpdatedAt); err != nil {
return nil, fmt.Errorf("failed to create document: %w", err)
}
// Get the auto-generated ID
id, err := result.LastInsertId()
// 获取自增ID
lastIDRows, err := ds.databaseService.SQLite.Query("SELECT last_insert_rowid()")
if err != nil {
return nil, fmt.Errorf("failed to get last insert ID: %w", err)
}
// Return the created document with ID
doc.ID = id
if len(lastIDRows) == 0 {
return nil, fmt.Errorf("no rows returned for last insert ID query")
}
// 从结果中提取ID
lastID, ok := lastIDRows[0]["last_insert_rowid()"].(int64)
if !ok {
return nil, fmt.Errorf("failed to convert last insert ID to int64")
}
// 返回带ID的文档
doc.ID = lastID
return doc, nil
}
@@ -174,8 +220,7 @@ func (ds *DocumentService) UpdateDocumentContent(id int64, content string) error
ds.mu.Lock()
defer ds.mu.Unlock()
db := ds.databaseService.GetDB()
_, err := db.Exec(sqlUpdateDocumentContent, content, time.Now(), id)
err := ds.databaseService.SQLite.Execute(sqlUpdateDocumentContent, content, time.Now(), id)
if err != nil {
return fmt.Errorf("failed to update document content: %w", err)
}
@@ -187,8 +232,7 @@ func (ds *DocumentService) UpdateDocumentTitle(id int64, title string) error {
ds.mu.Lock()
defer ds.mu.Unlock()
db := ds.databaseService.GetDB()
_, err := db.Exec(sqlUpdateDocumentTitle, title, time.Now(), id)
err := ds.databaseService.SQLite.Execute(sqlUpdateDocumentTitle, title, time.Now(), id)
if err != nil {
return fmt.Errorf("failed to update document title: %w", err)
}
@@ -205,8 +249,7 @@ func (ds *DocumentService) DeleteDocument(id int64) error {
return fmt.Errorf("cannot delete the default document")
}
db := ds.databaseService.GetDB()
_, err := db.Exec(sqlMarkDocumentAsDeleted, time.Now(), id)
err := ds.databaseService.SQLite.Execute(sqlMarkDocumentAsDeleted, time.Now(), id)
if err != nil {
return fmt.Errorf("failed to mark document as deleted: %w", err)
}
@@ -218,8 +261,7 @@ func (ds *DocumentService) RestoreDocument(id int64) error {
ds.mu.Lock()
defer ds.mu.Unlock()
db := ds.databaseService.GetDB()
_, err := db.Exec(sqlRestoreDocument, time.Now(), id)
err := ds.databaseService.SQLite.Execute(sqlRestoreDocument, time.Now(), id)
if err != nil {
return fmt.Errorf("failed to restore document: %w", err)
}
@@ -231,22 +273,38 @@ func (ds *DocumentService) ListAllDocumentsMeta() ([]*models.Document, error) {
ds.mu.RLock()
defer ds.mu.RUnlock()
db := ds.databaseService.GetDB()
rows, err := db.Query(sqlListAllDocumentsMeta)
rows, err := ds.databaseService.SQLite.Query(sqlListAllDocumentsMeta)
if err != nil {
return nil, fmt.Errorf("failed to list document meta: %w", err)
}
defer rows.Close()
var documents []*models.Document
for rows.Next() {
var doc models.Document
err := rows.Scan(&doc.ID, &doc.Title, &doc.CreatedAt, &doc.UpdatedAt)
if err != nil {
return nil, fmt.Errorf("failed to scan document meta: %w", err)
for _, row := range rows {
doc := &models.Document{IsDeleted: false}
if id, ok := row["id"].(int64); ok {
doc.ID = id
}
doc.IsDeleted = false
documents = append(documents, &doc)
if title, ok := row["title"].(string); ok {
doc.Title = title
}
if createdAt, ok := row["created_at"].(string); ok {
t, err := time.Parse("2006-01-02 15:04:05", createdAt)
if err == nil {
doc.CreatedAt = t
}
}
if updatedAt, ok := row["updated_at"].(string); ok {
t, err := time.Parse("2006-01-02 15:04:05", updatedAt)
if err == nil {
doc.UpdatedAt = t
}
}
documents = append(documents, doc)
}
return documents, nil
@@ -257,22 +315,38 @@ func (ds *DocumentService) ListDeletedDocumentsMeta() ([]*models.Document, error
ds.mu.RLock()
defer ds.mu.RUnlock()
db := ds.databaseService.GetDB()
rows, err := db.Query(sqlListDeletedDocumentsMeta)
rows, err := ds.databaseService.SQLite.Query(sqlListDeletedDocumentsMeta)
if err != nil {
return nil, fmt.Errorf("failed to list deleted document meta: %w", err)
}
defer rows.Close()
var documents []*models.Document
for rows.Next() {
var doc models.Document
err := rows.Scan(&doc.ID, &doc.Title, &doc.CreatedAt, &doc.UpdatedAt)
if err != nil {
return nil, fmt.Errorf("failed to scan deleted document meta: %w", err)
for _, row := range rows {
doc := &models.Document{IsDeleted: true}
if id, ok := row["id"].(int64); ok {
doc.ID = id
}
doc.IsDeleted = true
documents = append(documents, &doc)
if title, ok := row["title"].(string); ok {
doc.Title = title
}
if createdAt, ok := row["created_at"].(string); ok {
t, err := time.Parse("2006-01-02 15:04:05", createdAt)
if err == nil {
doc.CreatedAt = t
}
}
if updatedAt, ok := row["updated_at"].(string); ok {
t, err := time.Parse("2006-01-02 15:04:05", updatedAt)
if err == nil {
doc.UpdatedAt = t
}
}
documents = append(documents, doc)
}
return documents, nil
@@ -283,14 +357,22 @@ func (ds *DocumentService) GetFirstDocumentID() (int64, error) {
ds.mu.RLock()
defer ds.mu.RUnlock()
db := ds.databaseService.GetDB()
var id int64
err := db.QueryRow(sqlGetFirstDocumentID).Scan(&id)
rows, err := ds.databaseService.SQLite.Query(sqlGetFirstDocumentID)
if err != nil {
if err == sql.ErrNoRows {
if errors.Is(err, sql.ErrNoRows) {
return 0, nil // No documents exist
}
return 0, fmt.Errorf("failed to get first document ID: %w", err)
}
if len(rows) == 0 {
return 0, nil
}
id, ok := rows[0]["id"].(int64)
if !ok {
return 0, fmt.Errorf("failed to convert ID to int64")
}
return id, nil
}

View File

@@ -41,7 +41,7 @@ WHERE id = ?`
// ExtensionService 扩展管理服务
type ExtensionService struct {
databaseService *DatabaseService
logger *log.LoggerService
logger *log.Service
mu sync.RWMutex
ctx context.Context
@@ -73,7 +73,7 @@ func (e *ExtensionError) Is(target error) bool {
}
// NewExtensionService 创建扩展服务实例
func NewExtensionService(databaseService *DatabaseService, logger *log.LoggerService) *ExtensionService {
func NewExtensionService(databaseService *DatabaseService, logger *log.Service) *ExtensionService {
if logger == nil {
logger = log.New()
}
@@ -105,29 +105,26 @@ func (es *ExtensionService) initDatabase() error {
defer es.mu.Unlock()
// 检查是否已有扩展数据
db := es.databaseService.GetDB()
if db == nil {
return &ExtensionError{"get_database", "", fmt.Errorf("database connection is nil")}
}
var count int
err := db.QueryRow("SELECT COUNT(*) FROM extensions").Scan(&count)
rows, err := es.databaseService.SQLite.Query("SELECT COUNT(*) FROM extensions")
if err != nil {
return &ExtensionError{"check_extensions_count", "", err}
}
es.logger.Info("Extension database check", "existing_count", count)
if len(rows) == 0 {
return &ExtensionError{"check_extensions_count", "", fmt.Errorf("no rows returned")}
}
count, ok := rows[0]["COUNT(*)"].(int64)
if !ok {
return &ExtensionError{"convert_count", "", fmt.Errorf("failed to convert count to int64")}
}
// 如果没有数据,插入默认配置
if count == 0 {
es.logger.Info("No extensions found, inserting default extensions...")
if err := es.insertDefaultExtensions(); err != nil {
es.logger.Error("Failed to insert default extensions", "error", err)
return err
}
es.logger.Info("Default extensions inserted successfully")
} else {
es.logger.Info("Extensions already exist, skipping default insertion")
}
return nil
@@ -136,21 +133,16 @@ func (es *ExtensionService) initDatabase() error {
// insertDefaultExtensions 插入默认扩展配置
func (es *ExtensionService) insertDefaultExtensions() error {
defaultSettings := models.NewDefaultExtensionSettings()
db := es.databaseService.GetDB()
now := time.Now()
es.logger.Info("Starting to insert default extensions", "count", len(defaultSettings.Extensions))
for i, ext := range defaultSettings.Extensions {
es.logger.Info("Inserting extension", "index", i+1, "id", ext.ID, "enabled", ext.Enabled)
for _, ext := range defaultSettings.Extensions {
configJSON, err := json.Marshal(ext.Config)
if err != nil {
es.logger.Error("Failed to marshal config", "extension", ext.ID, "error", err)
return &ExtensionError{"marshal_config", string(ext.ID), err}
}
_, err = db.Exec(sqlInsertExtension,
err = es.databaseService.SQLite.Execute(sqlInsertExtension,
string(ext.ID),
ext.Enabled,
ext.IsDefault,
@@ -159,31 +151,24 @@ func (es *ExtensionService) insertDefaultExtensions() error {
now,
)
if err != nil {
es.logger.Error("Failed to insert extension", "extension", ext.ID, "error", err)
return &ExtensionError{"insert_extension", string(ext.ID), err}
}
es.logger.Info("Successfully inserted extension", "id", ext.ID)
}
es.logger.Info("Completed inserting all default extensions")
return nil
}
// OnStartup 启动时调用
func (es *ExtensionService) OnStartup(ctx context.Context, _ application.ServiceOptions) error {
// ServiceStartup 启动时调用
func (es *ExtensionService) ServiceStartup(ctx context.Context, options application.ServiceOptions) error {
es.ctx = ctx
es.logger.Info("Extension service starting up")
// 初始化数据库
var initErr error
es.initOnce.Do(func() {
es.logger.Info("Initializing extension database...")
if err := es.initDatabase(); err != nil {
es.logger.Error("failed to initialize extension database", "error", err)
initErr = err
} else {
es.logger.Info("Extension database initialized successfully")
}
})
return initErr
@@ -194,28 +179,36 @@ func (es *ExtensionService) GetAllExtensions() ([]models.Extension, error) {
es.mu.RLock()
defer es.mu.RUnlock()
db := es.databaseService.GetDB()
rows, err := db.Query(sqlGetAllExtensions)
rows, err := es.databaseService.SQLite.Query(sqlGetAllExtensions)
if err != nil {
return nil, &ExtensionError{"query_extensions", "", err}
}
defer rows.Close()
var extensions []models.Extension
for rows.Next() {
for _, row := range rows {
var ext models.Extension
var configJSON string
if err := rows.Scan(&ext.ID, &ext.Enabled, &ext.IsDefault, &configJSON); err != nil {
return nil, &ExtensionError{"scan_extension", "", err}
}
if err := json.Unmarshal([]byte(configJSON), &ext.Config); err != nil {
return nil, &ExtensionError{"unmarshal_config", string(ext.ID), err}
}
extensions = append(extensions, ext)
}
if err := rows.Err(); err != nil {
return nil, &ExtensionError{"rows_error", "", err}
if id, ok := row["id"].(string); ok {
ext.ID = models.ExtensionID(id)
}
if enabled, ok := row["enabled"].(int64); ok {
ext.Enabled = enabled == 1
}
if isDefault, ok := row["is_default"].(int64); ok {
ext.IsDefault = isDefault == 1
}
if configJSON, ok := row["config"].(string); ok {
var config models.ExtensionConfig
if err := json.Unmarshal([]byte(configJSON), &config); err != nil {
return nil, &ExtensionError{"unmarshal_config", string(ext.ID), err}
}
ext.Config = config
}
extensions = append(extensions, ext)
}
return extensions, nil
@@ -231,7 +224,6 @@ func (es *ExtensionService) UpdateExtensionState(id models.ExtensionID, enabled
es.mu.Lock()
defer es.mu.Unlock()
db := es.databaseService.GetDB()
var configJSON []byte
var err error
@@ -242,20 +234,28 @@ func (es *ExtensionService) UpdateExtensionState(id models.ExtensionID, enabled
}
} else {
// 如果没有提供配置,保持原有配置
var currentConfigJSON string
err = db.QueryRow("SELECT config FROM extensions WHERE id = ?", string(id)).Scan(&currentConfigJSON)
rows, err := es.databaseService.SQLite.Query("SELECT config FROM extensions WHERE id = ?", string(id))
if err != nil {
return &ExtensionError{"query_current_config", string(id), err}
}
if len(rows) == 0 {
return &ExtensionError{"query_current_config", string(id), fmt.Errorf("extension not found")}
}
currentConfigJSON, ok := rows[0]["config"].(string)
if !ok {
return &ExtensionError{"convert_config", string(id), fmt.Errorf("failed to get current config")}
}
configJSON = []byte(currentConfigJSON)
}
_, err = db.Exec(sqlUpdateExtension, enabled, string(configJSON), time.Now(), string(id))
err = es.databaseService.SQLite.Execute(sqlUpdateExtension, enabled, string(configJSON), time.Now(), string(id))
if err != nil {
return &ExtensionError{"update_extension", string(id), err}
}
es.logger.Info("extension state updated", "id", id, "enabled", enabled)
return nil
}
@@ -277,8 +277,7 @@ func (es *ExtensionService) ResetAllExtensionsToDefault() error {
defer es.mu.Unlock()
// 删除所有现有扩展
db := es.databaseService.GetDB()
_, err := db.Exec(sqlDeleteAllExtensions)
err := es.databaseService.SQLite.Execute(sqlDeleteAllExtensions)
if err != nil {
return &ExtensionError{"delete_all_extensions", "", err}
}
@@ -288,6 +287,5 @@ func (es *ExtensionService) ResetAllExtensionsToDefault() error {
return err
}
es.logger.Info("all extensions reset to default")
return nil
}

View File

@@ -24,7 +24,7 @@ import (
// HotkeyService Windows全局热键服务
type HotkeyService struct {
logger *log.LoggerService
logger *log.Service
configService *ConfigService
app *application.App
@@ -52,7 +52,7 @@ func (e *HotkeyError) Unwrap() error {
}
// NewHotkeyService 创建热键服务实例
func NewHotkeyService(configService *ConfigService, logger *log.LoggerService) *HotkeyService {
func NewHotkeyService(configService *ConfigService, logger *log.Service) *HotkeyService {
if logger == nil {
logger = log.New()
}
@@ -202,7 +202,7 @@ func cBool(b bool) C.int {
// toggleWindow 切换窗口
func (hs *HotkeyService) toggleWindow() {
if hs.app != nil {
hs.app.EmitEvent("hotkey:toggle-window", nil)
hs.app.Event.Emit("hotkey:toggle-window", nil)
}
}
@@ -259,7 +259,7 @@ func (hs *HotkeyService) IsRegistered() bool {
return hs.isRegistered.Load()
}
// OnShutdown 关闭服务
// ServiceShutdown 关闭服务
func (hs *HotkeyService) ServiceShutdown() error {
hs.cancel()
hs.wg.Wait()

View File

@@ -80,7 +80,7 @@ var globalHotkeyService *HotkeyService
// HotkeyService macOS全局热键服务
type HotkeyService struct {
logger *log.LoggerService
logger *log.Service
configService *ConfigService
app *application.App
mu sync.RWMutex
@@ -105,7 +105,7 @@ func (e *HotkeyError) Unwrap() error {
}
// NewHotkeyService 创建新的热键服务实例
func NewHotkeyService(configService *ConfigService, logger *log.LoggerService) *HotkeyService {
func NewHotkeyService(configService *ConfigService, logger *log.Service) *HotkeyService {
if logger == nil {
logger = log.New()
}
@@ -290,8 +290,8 @@ func (hs *HotkeyService) ToggleWindow() {
}
}
// OnShutdown 关闭热键服务
func (hs *HotkeyService) OnShutdown() error {
// ServiceShutdown 关闭热键服务
func (hs *HotkeyService) ServiceShutdown() error {
return hs.UnregisterHotkey()
}

View File

@@ -141,7 +141,7 @@ import (
// HotkeyService Linux全局热键服务
type HotkeyService struct {
logger *log.LoggerService
logger *log.Service
configService *ConfigService
app *application.App
@@ -170,7 +170,7 @@ func (e *HotkeyError) Unwrap() error {
}
// NewHotkeyService 创建热键服务实例
func NewHotkeyService(configService *ConfigService, logger *log.LoggerService) *HotkeyService {
func NewHotkeyService(configService *ConfigService, logger *log.Service) *HotkeyService {
if logger == nil {
logger = log.New()
}
@@ -384,8 +384,8 @@ func (hs *HotkeyService) IsRegistered() bool {
return hs.isRegistered.Load()
}
// OnShutdown 关闭服务
func (hs *HotkeyService) OnShutdown() error {
// ServiceShutdown 关闭服务
func (hs *HotkeyService) ServiceShutdown() error {
hs.cancel()
hs.wg.Wait()
C.closeX11Display()

View File

@@ -51,7 +51,7 @@ const (
// KeyBindingService 快捷键管理服务
type KeyBindingService struct {
databaseService *DatabaseService
logger *log.LoggerService
logger *log.Service
mu sync.RWMutex
ctx context.Context
@@ -83,7 +83,7 @@ func (e *KeyBindingError) Is(target error) bool {
}
// NewKeyBindingService 创建快捷键服务实例
func NewKeyBindingService(databaseService *DatabaseService, logger *log.LoggerService) *KeyBindingService {
func NewKeyBindingService(databaseService *DatabaseService, logger *log.Service) *KeyBindingService {
if logger == nil {
logger = log.New()
}
@@ -106,29 +106,26 @@ func (kbs *KeyBindingService) initDatabase() error {
defer kbs.mu.Unlock()
// 检查是否已有快捷键数据
db := kbs.databaseService.GetDB()
if db == nil {
return &KeyBindingError{"get_database", "", fmt.Errorf("database connection is nil")}
}
var count int
err := db.QueryRow("SELECT COUNT(*) FROM key_bindings").Scan(&count)
rows, err := kbs.databaseService.SQLite.Query("SELECT COUNT(*) FROM key_bindings")
if err != nil {
return &KeyBindingError{"check_keybindings_count", "", err}
}
kbs.logger.Info("KeyBinding database check", "existing_count", count)
if len(rows) == 0 {
return &KeyBindingError{"check_keybindings_count", "", fmt.Errorf("no rows returned")}
}
count, ok := rows[0]["COUNT(*)"].(int64)
if !ok {
return &KeyBindingError{"convert_count", "", fmt.Errorf("failed to convert count to int64")}
}
// 如果没有数据,插入默认配置
if count == 0 {
kbs.logger.Info("No key bindings found, inserting default key bindings...")
if err := kbs.insertDefaultKeyBindings(); err != nil {
kbs.logger.Error("Failed to insert default key bindings", "error", err)
return err
}
kbs.logger.Info("Default key bindings inserted successfully")
} else {
kbs.logger.Info("Key bindings already exist, skipping default insertion")
}
return nil
@@ -137,17 +134,13 @@ func (kbs *KeyBindingService) initDatabase() error {
// insertDefaultKeyBindings 插入默认快捷键配置
func (kbs *KeyBindingService) insertDefaultKeyBindings() error {
defaultConfig := models.NewDefaultKeyBindingConfig()
db := kbs.databaseService.GetDB()
now := time.Now()
kbs.logger.Info("Starting to insert default key bindings", "count", len(defaultConfig.KeyBindings))
for _, kb := range defaultConfig.KeyBindings {
for i, kb := range defaultConfig.KeyBindings {
kbs.logger.Info("Inserting key binding", "index", i+1, "command", kb.Command, "key", kb.Key, "extension", kb.Extension)
_, err := db.Exec(sqlInsertKeyBinding,
kb.Command,
kb.Extension,
err := kbs.databaseService.SQLite.Execute(sqlInsertKeyBinding,
string(kb.Command), // 转换为字符串存储
string(kb.Extension), // 转换为字符串存储
kb.Key,
kb.Enabled,
kb.IsDefault,
@@ -155,72 +148,63 @@ func (kbs *KeyBindingService) insertDefaultKeyBindings() error {
now,
)
if err != nil {
kbs.logger.Error("Failed to insert key binding", "command", kb.Command, "error", err)
return &KeyBindingError{"insert_keybinding", string(kb.Command), err}
}
kbs.logger.Info("Successfully inserted key binding", "command", kb.Command)
}
kbs.logger.Info("Completed inserting all default key bindings")
return nil
}
// GetKeyBindingConfig 获取完整快捷键配置
func (kbs *KeyBindingService) GetKeyBindingConfig() (*models.KeyBindingConfig, error) {
keyBindings, err := kbs.GetAllKeyBindings()
if err != nil {
return nil, err
}
config := &models.KeyBindingConfig{
KeyBindings: keyBindings,
}
return config, nil
}
// GetAllKeyBindings 获取所有快捷键配置
func (kbs *KeyBindingService) GetAllKeyBindings() ([]models.KeyBinding, error) {
kbs.mu.RLock()
defer kbs.mu.RUnlock()
db := kbs.databaseService.GetDB()
rows, err := db.Query(sqlGetAllKeyBindings)
rows, err := kbs.databaseService.SQLite.Query(sqlGetAllKeyBindings)
if err != nil {
return nil, &KeyBindingError{"query_keybindings", "", err}
}
defer rows.Close()
var keyBindings []models.KeyBinding
for rows.Next() {
for _, row := range rows {
var kb models.KeyBinding
if err := rows.Scan(&kb.Command, &kb.Extension, &kb.Key, &kb.Enabled, &kb.IsDefault); err != nil {
return nil, &KeyBindingError{"scan_keybinding", "", err}
}
keyBindings = append(keyBindings, kb)
}
if err := rows.Err(); err != nil {
return nil, &KeyBindingError{"rows_error", "", err}
if command, ok := row["command"].(string); ok {
kb.Command = models.KeyBindingCommand(command)
}
if extension, ok := row["extension"].(string); ok {
kb.Extension = models.ExtensionID(extension)
}
if key, ok := row["key"].(string); ok {
kb.Key = key
}
if enabled, ok := row["enabled"].(int64); ok {
kb.Enabled = enabled == 1
}
if isDefault, ok := row["is_default"].(int64); ok {
kb.IsDefault = isDefault == 1
}
keyBindings = append(keyBindings, kb)
}
return keyBindings, nil
}
// OnStartup 启动时调用
func (kbs *KeyBindingService) OnStartup(ctx context.Context, _ application.ServiceOptions) error {
// ServiceStartup 启动时调用
func (kbs *KeyBindingService) ServiceStartup(ctx context.Context, options application.ServiceOptions) error {
kbs.ctx = ctx
kbs.logger.Info("KeyBinding service starting up")
// 初始化数据库
var initErr error
kbs.initOnce.Do(func() {
kbs.logger.Info("Initializing keybinding database...")
if err := kbs.initDatabase(); err != nil {
kbs.logger.Error("failed to initialize keybinding database", "error", err)
initErr = err
} else {
kbs.logger.Info("KeyBinding database initialized successfully")
}
})
return initErr

View File

@@ -33,7 +33,7 @@ type MigrationProgress struct {
// MigrationService 迁移服务
type MigrationService struct {
logger *log.LoggerService
logger *log.Service
mu sync.RWMutex
progress atomic.Value // stores MigrationProgress
@@ -42,7 +42,7 @@ type MigrationService struct {
}
// NewMigrationService 创建迁移服务
func NewMigrationService(logger *log.LoggerService) *MigrationService {
func NewMigrationService(logger *log.Service) *MigrationService {
if logger == nil {
logger = log.New()
}
@@ -417,8 +417,8 @@ func (ms *MigrationService) CancelMigration() error {
return fmt.Errorf("no active migration to cancel")
}
// OnShutdown 服务关闭
func (ms *MigrationService) OnShutdown() error {
// ServiceShutdown 服务关闭
func (ms *MigrationService) ServiceShutdown() error {
ms.CancelMigration()
return nil
}

View File

@@ -26,7 +26,7 @@ type SelfUpdateResult struct {
// SelfUpdateService 自我更新服务
type SelfUpdateService struct {
logger *log.LoggerService
logger *log.Service
configService *ConfigService
config *models.AppConfig
@@ -35,7 +35,7 @@ type SelfUpdateService struct {
}
// NewSelfUpdateService 创建自我更新服务实例
func NewSelfUpdateService(configService *ConfigService, logger *log.LoggerService) (*SelfUpdateService, error) {
func NewSelfUpdateService(configService *ConfigService, logger *log.Service) (*SelfUpdateService, error) {
// 获取配置
appConfig, err := configService.GetConfig()
if err != nil {

View File

@@ -5,12 +5,14 @@ import (
"github.com/wailsapp/wails/v3/pkg/application"
"github.com/wailsapp/wails/v3/pkg/services/log"
"github.com/wailsapp/wails/v3/pkg/services/sqlite"
)
// ServiceManager 服务管理器,负责协调各个服务
type ServiceManager struct {
configService *ConfigService
databaseService *DatabaseService
sqliteService *sqlite.Service
documentService *DocumentService
migrationService *MigrationService
systemService *SystemService
@@ -22,7 +24,7 @@ type ServiceManager struct {
startupService *StartupService
selfUpdateService *SelfUpdateService
translationService *TranslationService
logger *log.LoggerService
logger *log.Service
}
// NewServiceManager 创建新的服务管理器实例
@@ -33,6 +35,9 @@ func NewServiceManager() *ServiceManager {
// 初始化配置服务
configService := NewConfigService(logger)
// 初始化SQLite服务
sqliteService := sqlite.New()
// 初始化数据库服务
databaseService := NewDatabaseService(configService, logger)
@@ -91,6 +96,7 @@ func NewServiceManager() *ServiceManager {
return &ServiceManager{
configService: configService,
databaseService: databaseService,
sqliteService: sqliteService,
documentService: documentService,
migrationService: migrationService,
systemService: systemService,
@@ -111,7 +117,8 @@ func NewServiceManager() *ServiceManager {
func (sm *ServiceManager) GetServices() []application.Service {
services := []application.Service{
application.NewService(sm.configService),
application.NewService(sm.databaseService),
application.NewService(sm.sqliteService), // SQLite服务必须在数据库服务之前初始化
application.NewService(sm.databaseService), // 数据库服务必须在依赖它的服务之前初始化
application.NewService(sm.documentService),
application.NewService(sm.keyBindingService),
application.NewService(sm.extensionService),
@@ -138,7 +145,7 @@ func (sm *ServiceManager) GetDialogService() *DialogService {
}
// GetLogger 获取日志服务实例
func (sm *ServiceManager) GetLogger() *log.LoggerService {
func (sm *ServiceManager) GetLogger() *log.Service {
return sm.logger
}
@@ -181,3 +188,8 @@ func (sm *ServiceManager) GetTranslationService() *TranslationService {
func (sm *ServiceManager) GetDatabaseService() *DatabaseService {
return sm.databaseService
}
// GetSQLiteService 获取SQLite服务实例
func (sm *ServiceManager) GetSQLiteService() *sqlite.Service {
return sm.sqliteService
}

View File

@@ -15,14 +15,14 @@ import (
// DarwinStartupImpl macOS 平台开机启动实现
type DarwinStartupImpl struct {
logger *log.LoggerService
logger *log.Service
disabled bool
appPath string
appName string
}
// newStartupImplementation 创建平台特定的开机启动实现
func newStartupImplementation(logger *log.LoggerService) StartupImplementation {
func newStartupImplementation(logger *log.Service) StartupImplementation {
return &DarwinStartupImpl{
logger: logger,
}

View File

@@ -13,7 +13,7 @@ import (
// LinuxStartupImpl Linux 平台开机启动实现
type LinuxStartupImpl struct {
logger *log.LoggerService
logger *log.Service
autostartDir string
execPath string
appName string
@@ -37,7 +37,7 @@ X-GNOME-Autostart-enabled=true
`
// newStartupImplementation 创建平台特定的开机启动实现
func newStartupImplementation(logger *log.LoggerService) StartupImplementation {
func newStartupImplementation(logger *log.Service) StartupImplementation {
return &LinuxStartupImpl{
logger: logger,
}

View File

@@ -7,7 +7,7 @@ import (
// StartupService 开机启动服务
type StartupService struct {
configService *ConfigService
logger *log.LoggerService
logger *log.Service
impl StartupImplementation
initError error
}
@@ -19,7 +19,7 @@ type StartupImplementation interface {
}
// NewStartupService 创建开机启动服务实例
func NewStartupService(configService *ConfigService, logger *log.LoggerService) *StartupService {
func NewStartupService(configService *ConfigService, logger *log.Service) *StartupService {
service := &StartupService{
configService: configService,
logger: logger,

View File

@@ -15,7 +15,7 @@ import (
// WindowsStartupImpl Windows 平台开机启动实现
type WindowsStartupImpl struct {
logger *log.LoggerService
logger *log.Service
registryKey string
execPath string
workingDir string
@@ -23,7 +23,7 @@ type WindowsStartupImpl struct {
}
// newStartupImplementation 创建平台特定的开机启动实现
func newStartupImplementation(logger *log.LoggerService) StartupImplementation {
func newStartupImplementation(logger *log.Service) StartupImplementation {
return &WindowsStartupImpl{
logger: logger,
}

View File

@@ -15,7 +15,7 @@ import (
type StoreOption struct {
FilePath string
AutoSave bool
Logger *log.LoggerService
Logger *log.Service
}
// Store 泛型存储服务
@@ -25,7 +25,7 @@ type Store[T any] struct {
dataMap sync.Map // thread-safe map
unsaved atomic.Bool
initOnce sync.Once
logger *log.LoggerService
logger *log.Service
}
// NewStore 存储服务

View File

@@ -9,7 +9,7 @@ import (
// SystemService 系统监控服务
type SystemService struct {
logger *log.LoggerService
logger *log.Service
}
// MemoryStats 内存统计信息
@@ -29,7 +29,7 @@ type MemoryStats struct {
}
// NewSystemService 创建新的系统服务实例
func NewSystemService(logger *log.LoggerService) *SystemService {
func NewSystemService(logger *log.Service) *SystemService {
return &SystemService{
logger: logger,
}

View File

@@ -10,7 +10,7 @@ import (
// TranslationService 翻译服务
type TranslationService struct {
logger *log.LoggerService
logger *log.Service
factory *translator.TranslatorFactory
defaultTimeout time.Duration
translators map[translator.TranslatorType]translator.Translator
@@ -18,7 +18,7 @@ type TranslationService struct {
}
// NewTranslationService 创建翻译服务实例
func NewTranslationService(logger *log.LoggerService) *TranslationService {
func NewTranslationService(logger *log.Service) *TranslationService {
service := &TranslationService{
logger: logger,
factory: translator.NewTranslatorFactory(),

View File

@@ -7,14 +7,14 @@ import (
// TrayService 系统托盘服务
type TrayService struct {
logger *log.LoggerService
logger *log.Service
configService *ConfigService
app *application.App
mainWindow *application.WebviewWindow
}
// NewTrayService 创建新的系统托盘服务实例
func NewTrayService(logger *log.LoggerService, configService *ConfigService) *TrayService {
func NewTrayService(logger *log.Service, configService *ConfigService) *TrayService {
return &TrayService{
logger: logger,
configService: configService,
@@ -42,7 +42,7 @@ func (ts *TrayService) HandleWindowClose() {
if ts.ShouldMinimizeToTray() {
// 隐藏到托盘
ts.mainWindow.Hide()
ts.app.EmitEvent("window:hidden", nil)
ts.app.Event.Emit("window:hidden", nil)
} else {
// 直接退出应用
ts.app.Quit()
@@ -54,7 +54,7 @@ func (ts *TrayService) HandleWindowMinimize() {
if ts.ShouldMinimizeToTray() {
// 隐藏到托盘
ts.mainWindow.Hide()
ts.app.EmitEvent("window:hidden", nil)
ts.app.Event.Emit("window:hidden", nil)
}
}
@@ -65,7 +65,7 @@ func (ts *TrayService) ShowWindow() {
ts.mainWindow.Restore()
ts.mainWindow.Focus()
if ts.app != nil {
ts.app.EmitEvent("window:shown", nil)
ts.app.Event.Emit("window:shown", nil)
}
}
}

View File

@@ -10,7 +10,7 @@ import (
// SetupSystemTray 设置系统托盘及其功能
func SetupSystemTray(app *application.App, mainWindow *application.WebviewWindow, assets embed.FS, trayService *services.TrayService) {
// 创建系统托盘
systray := app.NewSystemTray()
systray := app.SystemTray.New()
// 设置图标
iconBytes, _ := assets.ReadFile("appicon.png")