mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-04-14 11:35:50 +00:00
111 lines
2.6 KiB
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)
|
|
}
|