mirror of
https://git.sr.ht/~ashkeel/strimertul
synced 2024-09-30 02:40:33 +00:00
132 lines
3.2 KiB
Go
132 lines
3.2 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"log/slog"
|
|
"os"
|
|
"path/filepath"
|
|
"sort"
|
|
"time"
|
|
|
|
"git.sr.ht/~ashkeel/strimertul/log"
|
|
|
|
"git.sr.ht/~ashkeel/strimertul/database"
|
|
"git.sr.ht/~ashkeel/strimertul/utils"
|
|
)
|
|
|
|
func BackupTask(driver database.Driver, options database.BackupOptions) {
|
|
if options.BackupDir == "" {
|
|
slog.Warn("Backup directory not set, database backups are disabled")
|
|
return
|
|
}
|
|
|
|
err := os.MkdirAll(options.BackupDir, 0o755)
|
|
if err != nil {
|
|
slog.Error("Could not create backup directory, moving to a temporary folder", log.Error(err))
|
|
options.BackupDir = os.TempDir()
|
|
slog.Info("Using temporary directory", slog.String("backup-dir", options.BackupDir))
|
|
return
|
|
}
|
|
|
|
ticker := time.NewTicker(time.Duration(options.BackupInterval) * time.Minute)
|
|
defer ticker.Stop()
|
|
for range ticker.C {
|
|
performBackup(driver, options)
|
|
}
|
|
}
|
|
|
|
func performBackup(driver database.Driver, options database.BackupOptions) {
|
|
// Run backup procedure
|
|
file, err := os.Create(fmt.Sprintf("%s/%s.db", options.BackupDir, time.Now().Format("20060102-150405")))
|
|
if err != nil {
|
|
slog.Error("Could not create backup file", log.Error(err))
|
|
return
|
|
}
|
|
|
|
err = driver.Backup(file)
|
|
if err != nil {
|
|
slog.Error("Could not backup database", log.Error(err))
|
|
}
|
|
_ = file.Close()
|
|
slog.Info("Database backup created", slog.String("backup-file", file.Name()))
|
|
|
|
// Remove old backups
|
|
files, err := os.ReadDir(options.BackupDir)
|
|
if err != nil {
|
|
slog.Error("Could not read backup directory", log.Error(err))
|
|
return
|
|
}
|
|
|
|
// If maxBackups is set, remove older backups when we reach the limit
|
|
if options.MaxBackups > 0 && len(files) > options.MaxBackups {
|
|
// Sort by date
|
|
sort.Sort(utils.ByDate(files))
|
|
// Get files to remove
|
|
toRemove := files[:len(files)-options.MaxBackups]
|
|
for _, file := range toRemove {
|
|
err = os.Remove(fmt.Sprintf("%s/%s", options.BackupDir, file.Name()))
|
|
if err != nil {
|
|
slog.Error("Could not remove backup file", log.Error(err))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
type BackupInfo struct {
|
|
Filename string `json:"filename"`
|
|
Date int64 `json:"date"`
|
|
Size int64 `json:"size"`
|
|
}
|
|
|
|
func (a *App) GetBackups() (list []BackupInfo) {
|
|
files, err := os.ReadDir(a.backupOptions.BackupDir)
|
|
if err != nil {
|
|
slog.Error("Could not read backup directory", log.Error(err))
|
|
return nil
|
|
}
|
|
|
|
for _, file := range files {
|
|
if file.IsDir() {
|
|
continue
|
|
}
|
|
|
|
info, err := file.Info()
|
|
if err != nil {
|
|
slog.Error("Could not get info for backup file", log.Error(err))
|
|
continue
|
|
}
|
|
|
|
list = append(list, BackupInfo{
|
|
Filename: file.Name(),
|
|
Date: info.ModTime().UnixMilli(),
|
|
Size: info.Size(),
|
|
})
|
|
}
|
|
return
|
|
}
|
|
|
|
func (a *App) RestoreBackup(backupName string) error {
|
|
path := filepath.Join(a.backupOptions.BackupDir, backupName)
|
|
|
|
file, err := os.Open(path)
|
|
if err != nil {
|
|
return fmt.Errorf("could not open import file for reading: %w", err)
|
|
}
|
|
defer utils.Close(file)
|
|
inStream := file
|
|
|
|
if a.driver == nil {
|
|
a.driver, err = database.GetDatabaseDriver(a.cliParams)
|
|
if err != nil {
|
|
return fmt.Errorf("could not open database: %w", err)
|
|
}
|
|
}
|
|
|
|
err = a.driver.Restore(inStream)
|
|
if err != nil {
|
|
return fmt.Errorf("could not restore database: %w", err)
|
|
}
|
|
|
|
slog.Info("Restored database from backup")
|
|
return nil
|
|
}
|