3x-ui/database/manager.go

111 lines
2.6 KiB
Go

package database
import (
"errors"
"fmt"
"os"
"path/filepath"
"time"
"github.com/mhsanaei/3x-ui/v2/config"
)
func configsEqual(a, b *config.DatabaseConfig) bool {
if a == nil || b == nil {
return false
}
a = a.Clone().Normalize()
b = b.Clone().Normalize()
if a.Driver != b.Driver {
return false
}
if a.Driver == config.DatabaseDriverSQLite {
return a.SQLite.Path == b.SQLite.Path
}
return a.Postgres.Mode == b.Postgres.Mode &&
a.Postgres.Host == b.Postgres.Host &&
a.Postgres.Port == b.Postgres.Port &&
a.Postgres.DBName == b.Postgres.DBName &&
a.Postgres.User == b.Postgres.User &&
a.Postgres.Password == b.Postgres.Password &&
a.Postgres.SSLMode == b.Postgres.SSLMode &&
a.Postgres.ManagedLocally == b.Postgres.ManagedLocally
}
func loadSnapshotFromConfig(cfg *config.DatabaseConfig) (*BackupSnapshot, error) {
cfg = cfg.Clone().Normalize()
if cfg.UsesSQLite() {
if _, err := os.Stat(cfg.SQLite.Path); err != nil {
if os.IsNotExist(err) {
return newBackupSnapshot(cfg.Driver), nil
}
return nil, err
}
}
conn, err := OpenDatabase(cfg)
if err != nil {
return nil, err
}
defer CloseConnection(conn)
if err := MigrateModels(conn); err != nil {
return nil, err
}
return ExportSnapshot(conn, cfg.Driver)
}
func saveSwitchBackup(snapshot *BackupSnapshot, prefix string) error {
if snapshot == nil {
return nil
}
data, err := EncodePortableBackup(snapshot)
if err != nil {
return err
}
name := fmt.Sprintf("%s-%s.xui-backup", prefix, time.Now().UTC().Format("20060102-150405"))
return SavePortableBackup(filepath.Join(config.GetBackupFolderPath(), name), data)
}
// SwitchDatabase migrates panel data into a new backend and writes the new runtime configuration.
func SwitchDatabase(target *config.DatabaseConfig) error {
if target == nil {
return errors.New("target database configuration is nil")
}
target = target.Clone().Normalize()
currentCfg, err := config.LoadDatabaseConfig()
if err != nil {
return err
}
if configsEqual(currentCfg, target) {
return config.SaveDatabaseConfig(target)
}
sourceSnapshot, err := loadSnapshotFromConfig(currentCfg)
if err != nil {
return err
}
if err := saveSwitchBackup(sourceSnapshot, "switch"); err != nil {
return err
}
if err := TestConnection(target); err != nil {
return err
}
targetConn, err := OpenDatabase(target)
if err != nil {
return err
}
defer CloseConnection(targetConn)
if err := MigrateModels(targetConn); err != nil {
return err
}
if err := ApplySnapshot(targetConn, sourceSnapshot); err != nil {
return err
}
return config.SaveDatabaseConfig(target)
}