mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2025-12-23 14:52:43 +00:00
Fix db.go and setting.go
This commit is contained in:
parent
82f0a5680b
commit
b5861d31ae
2 changed files with 51 additions and 43 deletions
|
|
@ -2,9 +2,7 @@ package database
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"io/fs"
|
"fmt"
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
|
|
||||||
"github.com/mhsanaei/3x-ui/v2/database/model"
|
"github.com/mhsanaei/3x-ui/v2/database/model"
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
|
@ -14,30 +12,20 @@ import (
|
||||||
|
|
||||||
var db *gorm.DB
|
var db *gorm.DB
|
||||||
|
|
||||||
// GetDB returns the global GORM database instance.
|
// InitDB открывает sqlite и выполняет миграции / начальное заполнение.
|
||||||
func GetDB() *gorm.DB { return db }
|
|
||||||
|
|
||||||
// InitDB sets up the database connection, migrates models, and runs seeders.
|
|
||||||
func InitDB(dbPath string) error {
|
func InitDB(dbPath string) error {
|
||||||
// ensure dir exists
|
|
||||||
dir := path.Dir(dbPath)
|
|
||||||
if err := os.MkdirAll(dir, fs.ModePerm); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// open SQLite (dev)
|
|
||||||
database, err := gorm.Open(sqlite.Open(dbPath), &gorm.Config{})
|
database, err := gorm.Open(sqlite.Open(dbPath), &gorm.Config{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
db = database
|
db = database
|
||||||
|
|
||||||
// migrations
|
// миграции
|
||||||
if err := AutoMigrate(); err != nil {
|
if err := AutoMigrate(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// seed admin
|
// seed admin (один раз создаём дефолтного админа при отсутствии)
|
||||||
if err := SeedAdmin(); err != nil {
|
if err := SeedAdmin(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -45,14 +33,38 @@ func InitDB(dbPath string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// AutoMigrate applies schema migrations.
|
// GetDB возвращает активное соединение GORM.
|
||||||
|
func GetDB() *gorm.DB {
|
||||||
|
return db
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsNotFound — хелпер для проверки "запись не найдена".
|
||||||
|
func IsNotFound(err error) bool {
|
||||||
|
return errors.Is(err, gorm.ErrRecordNotFound)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checkpoint — безопасный чекпоинт WAL для sqlite.
|
||||||
|
// Для других СУБД — no-op.
|
||||||
|
func Checkpoint() error {
|
||||||
|
if db == nil {
|
||||||
|
return fmt.Errorf("database is not initialized")
|
||||||
|
}
|
||||||
|
if db.Dialector.Name() != "sqlite" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// TRUNCATE обычно полезнее, чтобы подрезать WAL-файл.
|
||||||
|
return db.Exec("PRAGMA wal_checkpoint(TRUNCATE);").Error
|
||||||
|
}
|
||||||
|
|
||||||
|
// AutoMigrate применяет миграции схемы.
|
||||||
func AutoMigrate() error {
|
func AutoMigrate() error {
|
||||||
return db.AutoMigrate(
|
return db.AutoMigrate(
|
||||||
&model.User{}, // User{ Id, Username, PasswordHash, Role }
|
&model.User{},
|
||||||
|
&model.Setting{}, // таблица настроек
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SeedAdmin creates a default admin if it doesn't exist.
|
// SeedAdmin создаёт дефолтного админа, если его нет.
|
||||||
func SeedAdmin() error {
|
func SeedAdmin() error {
|
||||||
var count int64
|
var count int64
|
||||||
if err := db.Model(&model.User{}).
|
if err := db.Model(&model.User{}).
|
||||||
|
|
@ -72,27 +84,3 @@ func SeedAdmin() error {
|
||||||
}
|
}
|
||||||
return db.Create(&admin).Error
|
return db.Create(&admin).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsNotFound reports whether err is gorm's record-not-found.
|
|
||||||
func IsNotFound(err error) bool {
|
|
||||||
return errors.Is(err, gorm.ErrRecordNotFound)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsSQLiteDB reports whether current DB dialector is sqlite.
|
|
||||||
func IsSQLiteDB() bool {
|
|
||||||
if db == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return db.Dialector.Name() == "sqlite"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Checkpoint runs WAL checkpoint for SQLite to compact the WAL file.
|
|
||||||
// No-op for non-SQLite databases.
|
|
||||||
func Checkpoint() error {
|
|
||||||
if !IsSQLiteDB() {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
// FULL/TRUNCATE — в зависимости от нужной семантики.
|
|
||||||
// TRUNCATE чаще используется, чтобы обрезать WAL-файл.
|
|
||||||
return db.Exec("PRAGMA wal_checkpoint(TRUNCATE);").Error
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -110,6 +110,26 @@ var defaultValueMap = map[string]string{
|
||||||
// It handles configuration storage, retrieval, and validation for all system settings.
|
// It handles configuration storage, retrieval, and validation for all system settings.
|
||||||
type SettingService struct{}
|
type SettingService struct{}
|
||||||
|
|
||||||
|
// getValue читает ключ из БД (таблица settings). Если записи нет — вернёт дефолт.
|
||||||
|
func (s *SettingService) getValue(key string) (string, error) {
|
||||||
|
db := database.GetDB()
|
||||||
|
if db != nil {
|
||||||
|
var rec model.Setting
|
||||||
|
err := db.First(&rec, "key = ?", key).Error
|
||||||
|
if err == nil {
|
||||||
|
return rec.Value, nil
|
||||||
|
}
|
||||||
|
// если записи нет — идём в дефолты; если другая ошибка — пробрасываем
|
||||||
|
if !database.IsNotFound(err) {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if v, ok := defaultValueMap[key]; ok {
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
return "", fmt.Errorf("setting %q not found", key)
|
||||||
|
}
|
||||||
|
|
||||||
// OIDCConfig defines OpenID Connect settings for external authentication.
|
// OIDCConfig defines OpenID Connect settings for external authentication.
|
||||||
type OIDCConfig struct {
|
type OIDCConfig struct {
|
||||||
Enabled bool
|
Enabled bool
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue