fix: Restore from .db file fails (#2988)
Some checks failed
Release 3X-UI / build (386) (push) Has been cancelled
Release 3X-UI / build (amd64) (push) Has been cancelled
Release 3X-UI / build (arm64) (push) Has been cancelled
Release 3X-UI / build (armv5) (push) Has been cancelled
Release 3X-UI / build (armv6) (push) Has been cancelled
Release 3X-UI / build (armv7) (push) Has been cancelled
Release 3X-UI / build (s390x) (push) Has been cancelled

* fix: issue 2953. Restore from .db file fails because

* Update server.go
This commit is contained in:
Columbiysky 2025-05-14 18:35:53 +03:00 committed by GitHub
parent 7a5a833af3
commit 3666d1193f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -302,25 +302,22 @@ func (s *ServerService) GetXrayVersions() ([]string, error) {
return versions, nil return versions, nil
} }
func (s *ServerService) StopXrayService() (string error) { func (s *ServerService) StopXrayService() error {
err := s.xrayService.StopXray() err := s.xrayService.StopXray()
if err != nil { if err != nil {
logger.Error("stop xray failed:", err) logger.Error("stop xray failed:", err)
return err return err
} }
return nil return nil
} }
func (s *ServerService) RestartXrayService() (string error) { func (s *ServerService) RestartXrayService() error {
s.xrayService.StopXray() s.xrayService.StopXray()
defer func() { err := s.xrayService.RestartXray(true)
err := s.xrayService.RestartXray(true) if err != nil {
if err != nil { logger.Error("start xray failed:", err)
logger.Error("start xray failed:", err) return err
} }
}()
return nil return nil
} }
@ -507,35 +504,43 @@ func (s *ServerService) ImportDB(file multipart.File) error {
return common.NewErrorf("Error resetting file reader: %v", err) return common.NewErrorf("Error resetting file reader: %v", err)
} }
// Save the file as temporary file // Save the file as a temporary file
tempPath := fmt.Sprintf("%s.temp", config.GetDBPath()) tempPath := fmt.Sprintf("%s.temp", config.GetDBPath())
// Remove the existing fallback file (if any) before creating one
_, err = os.Stat(tempPath) // Remove the existing temporary file (if any)
if err == nil { if _, err := os.Stat(tempPath); err == nil {
errRemove := os.Remove(tempPath) if errRemove := os.Remove(tempPath); errRemove != nil {
if errRemove != nil {
return common.NewErrorf("Error removing existing temporary db file: %v", errRemove) return common.NewErrorf("Error removing existing temporary db file: %v", errRemove)
} }
} }
// Create the temporary file // Create the temporary file
tempFile, err := os.Create(tempPath) tempFile, err := os.Create(tempPath)
if err != nil { if err != nil {
return common.NewErrorf("Error creating temporary db file: %v", err) return common.NewErrorf("Error creating temporary db file: %v", err)
} }
defer tempFile.Close()
// Remove temp file before returning // Robust deferred cleanup for the temporary file
defer os.Remove(tempPath) defer func() {
if tempFile != nil {
if cerr := tempFile.Close(); cerr != nil {
logger.Warningf("Warning: failed to close temp file: %v", cerr)
}
}
if _, err := os.Stat(tempPath); err == nil {
if rerr := os.Remove(tempPath); rerr != nil {
logger.Warningf("Warning: failed to remove temp file: %v", rerr)
}
}
}()
// Save uploaded file to temporary file // Save uploaded file to temporary file
_, err = io.Copy(tempFile, file) if _, err = io.Copy(tempFile, file); err != nil {
if err != nil {
return common.NewErrorf("Error saving db: %v", err) return common.NewErrorf("Error saving db: %v", err)
} }
// Check if we can init db or not // Check if we can init the db or not
err = database.InitDB(tempPath) if err = database.InitDB(tempPath); err != nil {
if err != nil {
return common.NewErrorf("Error checking db: %v", err) return common.NewErrorf("Error checking db: %v", err)
} }
@ -544,111 +549,113 @@ func (s *ServerService) ImportDB(file multipart.File) error {
// Backup the current database for fallback // Backup the current database for fallback
fallbackPath := fmt.Sprintf("%s.backup", config.GetDBPath()) fallbackPath := fmt.Sprintf("%s.backup", config.GetDBPath())
// Remove the existing fallback file (if any) // Remove the existing fallback file (if any)
_, err = os.Stat(fallbackPath) if _, err := os.Stat(fallbackPath); err == nil {
if err == nil { if errRemove := os.Remove(fallbackPath); errRemove != nil {
errRemove := os.Remove(fallbackPath)
if errRemove != nil {
return common.NewErrorf("Error removing existing fallback db file: %v", errRemove) return common.NewErrorf("Error removing existing fallback db file: %v", errRemove)
} }
} }
// Move the current database to the fallback location // Move the current database to the fallback location
err = os.Rename(config.GetDBPath(), fallbackPath) if err = os.Rename(config.GetDBPath(), fallbackPath); err != nil {
if err != nil { return common.NewErrorf("Error backing up current db file: %v", err)
return common.NewErrorf("Error backing up temporary db file: %v", err)
} }
// Remove the temporary file before returning // Defer fallback cleanup ONLY if everything goes well
defer os.Remove(fallbackPath) defer func() {
if _, err := os.Stat(fallbackPath); err == nil {
if rerr := os.Remove(fallbackPath); rerr != nil {
logger.Warningf("Warning: failed to remove fallback file: %v", rerr)
}
}
}()
// Move temp to DB path // Move temp to DB path
err = os.Rename(tempPath, config.GetDBPath()) if err = os.Rename(tempPath, config.GetDBPath()); err != nil {
if err != nil { // Restore from fallback
errRename := os.Rename(fallbackPath, config.GetDBPath()) if errRename := os.Rename(fallbackPath, config.GetDBPath()); errRename != nil {
if errRename != nil {
return common.NewErrorf("Error moving db file and restoring fallback: %v", errRename) return common.NewErrorf("Error moving db file and restoring fallback: %v", errRename)
} }
return common.NewErrorf("Error moving db file: %v", err) return common.NewErrorf("Error moving db file: %v", err)
} }
// Migrate DB // Migrate DB
err = database.InitDB(config.GetDBPath()) if err = database.InitDB(config.GetDBPath()); err != nil {
if err != nil { if errRename := os.Rename(fallbackPath, config.GetDBPath()); errRename != nil {
errRename := os.Rename(fallbackPath, config.GetDBPath())
if errRename != nil {
return common.NewErrorf("Error migrating db and restoring fallback: %v", errRename) return common.NewErrorf("Error migrating db and restoring fallback: %v", errRename)
} }
return common.NewErrorf("Error migrating db: %v", err) return common.NewErrorf("Error migrating db: %v", err)
} }
s.inboundService.MigrateDB() s.inboundService.MigrateDB()
// Start Xray // Start Xray
err = s.RestartXrayService() if err = s.RestartXrayService(); err != nil {
if err != nil { return common.NewErrorf("Imported DB but failed to start Xray: %v", err)
return common.NewErrorf("Imported DB but Failed to start Xray: %v", err)
} }
return nil return nil
} }
func (s *ServerService) UpdateGeofile(fileName string) error { func (s *ServerService) UpdateGeofile(fileName string) error {
files := []struct { files := []struct {
URL string URL string
FileName string FileName string
}{ }{
{"https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat", "geoip.dat"}, {"https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat", "geoip.dat"},
{"https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat", "geosite.dat"}, {"https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat", "geosite.dat"},
{"https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geoip.dat", "geoip_IR.dat"}, {"https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geoip.dat", "geoip_IR.dat"},
{"https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geosite.dat", "geosite_IR.dat"}, {"https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geosite.dat", "geosite_IR.dat"},
{"https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/geoip.dat", "geoip_RU.dat"}, {"https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/geoip.dat", "geoip_RU.dat"},
{"https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/geosite.dat", "geosite_RU.dat"}, {"https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/geosite.dat", "geosite_RU.dat"},
} }
downloadFile := func(url, destPath string) error { downloadFile := func(url, destPath string) error {
resp, err := http.Get(url) resp, err := http.Get(url)
if err != nil { if err != nil {
return common.NewErrorf("Failed to download Geofile from %s: %v", url, err) return common.NewErrorf("Failed to download Geofile from %s: %v", url, err)
} }
defer resp.Body.Close() defer resp.Body.Close()
file, err := os.Create(destPath) file, err := os.Create(destPath)
if err != nil { if err != nil {
return common.NewErrorf("Failed to create Geofile %s: %v", destPath, err) return common.NewErrorf("Failed to create Geofile %s: %v", destPath, err)
} }
defer file.Close() defer file.Close()
_, err = io.Copy(file, resp.Body) _, err = io.Copy(file, resp.Body)
if err != nil { if err != nil {
return common.NewErrorf("Failed to save Geofile %s: %v", destPath, err) return common.NewErrorf("Failed to save Geofile %s: %v", destPath, err)
} }
return nil return nil
} }
var fileURL string var fileURL string
for _, file := range files { for _, file := range files {
if file.FileName == fileName { if file.FileName == fileName {
fileURL = file.URL fileURL = file.URL
break break
} }
} }
if fileURL == "" { if fileURL == "" {
return common.NewErrorf("File '%s' not found in the list of Geofiles", fileName) return common.NewErrorf("File '%s' not found in the list of Geofiles", fileName)
} }
destPath := fmt.Sprintf("%s/%s", config.GetBinFolderPath(), fileName) destPath := fmt.Sprintf("%s/%s", config.GetBinFolderPath(), fileName)
if err := downloadFile(fileURL, destPath); err != nil { if err := downloadFile(fileURL, destPath); err != nil {
return common.NewErrorf("Error downloading Geofile '%s': %v", fileName, err) return common.NewErrorf("Error downloading Geofile '%s': %v", fileName, err)
} }
err := s.RestartXrayService() err := s.RestartXrayService()
if err != nil { if err != nil {
return common.NewErrorf("Updated Geofile '%s' but Failed to start Xray: %v", fileName, err) return common.NewErrorf("Updated Geofile '%s' but Failed to start Xray: %v", fileName, err)
} }
return nil return nil
} }
func (s *ServerService) GetNewX25519Cert() (any, error) { func (s *ServerService) GetNewX25519Cert() (any, error) {