package initialize import ( "fmt" "os" "path/filepath" "github.com/glebarez/sqlite" "go.uber.org/zap" "gorm.io/gorm" "wails-app/internal/config" "wails-app/internal/global" "wails-app/internal/initialize/internal" ) // GormSqlite 初始化Sqlite数据库 func GormSqlite() *gorm.DB { s := global.GVA_CONFIG.Sqlite if s.Dbname == "" { return nil } // Resolve path: empty = %APPDATA%/smart-parking/ if s.Path == "" { if appData := os.Getenv("APPDATA"); appData != "" { s.Path = appData } else { // Fallback: exe directory if exePath, err := os.Executable(); err == nil { s.Path = filepath.Dir(exePath) } } s.Path = filepath.Join(s.Path, "smart-parking") } // Ensure directory exists if err := os.MkdirAll(s.Path, 0755); err != nil { panic(fmt.Errorf("failed to create SQLite db directory %s: %w", s.Path, err)) } dsn := filepath.Join(s.Path, s.Dbname+".db") fmt.Printf("SQLite database: %s\n", dsn) if global.GVA_LOG != nil { global.GVA_LOG.Info("SQLite 数据库路径", zap.String("dsn", dsn)) } if db, err := gorm.Open(sqlite.Open(dsn), internal.Gorm.Config(s.Prefix, s.Singular)); err != nil { panic(err) } else { configureSQLite(db, s) return db } } // GormSqliteByConfig 初始化Sqlite数据库用过传入配置 func GormSqliteByConfig(s config.Sqlite) *gorm.DB { if s.Dbname == "" { return nil } if db, err := gorm.Open(sqlite.Open(s.Dsn()), internal.Gorm.Config(s.Prefix, s.Singular)); err != nil { panic(err) } else { configureSQLite(db, s) return db } } // configureSQLite limits concurrent connections and enables SQLite settings // that avoid long writer starvation when device events and API requests share // the same database file. func configureSQLite(db *gorm.DB, s config.Sqlite) { sqlDB, err := db.DB() if err != nil { panic(err) } maxIdle := s.MaxIdleConns if maxIdle <= 0 { maxIdle = 1 } maxOpen := s.MaxOpenConns if maxOpen <= 0 { maxOpen = 4 } if maxOpen < maxIdle { maxOpen = maxIdle } sqlDB.SetMaxIdleConns(maxIdle) sqlDB.SetMaxOpenConns(maxOpen) // WAL allows readers to continue while a writer commits. busy_timeout // prevents transient lock contention from immediately failing a request. for _, pragma := range []string{ "PRAGMA busy_timeout = 5000", "PRAGMA journal_mode = WAL", "PRAGMA synchronous = NORMAL", } { if err := sqlDB.Ping(); err != nil { if global.GVA_LOG != nil { global.GVA_LOG.Warn("SQLite 连接检查失败", zap.Error(err)) } return } if _, err := sqlDB.Exec(pragma); err != nil && global.GVA_LOG != nil { global.GVA_LOG.Warn("SQLite PRAGMA 设置失败", zap.String("pragma", pragma), zap.Error(err)) } } }