mirror of
https://git.sr.ht/~ashkeel/strimertul
synced 2024-09-18 01:50:50 +00:00
112 lines
2.9 KiB
Go
112 lines
2.9 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"sort"
|
|
"time"
|
|
|
|
kv "github.com/strimertul/kilovolt/v9"
|
|
"github.com/strimertul/strimertul/utils"
|
|
"github.com/urfave/cli/v2"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
// DatabaseDriver is a driver wrapping a supported database
|
|
type DatabaseDriver interface {
|
|
Hub() *kv.Hub
|
|
Close() error
|
|
Import(map[string]string) error
|
|
Export(io.Writer) error
|
|
Restore(io.Reader) error
|
|
Backup(io.Writer) error
|
|
}
|
|
|
|
func BackupTask(driver DatabaseDriver, options BackupOptions) {
|
|
if options.BackupDir == "" {
|
|
logger.Warn("backup directory not set, database backups are disabled")
|
|
return
|
|
}
|
|
|
|
err := os.MkdirAll(options.BackupDir, 0o755)
|
|
if err != nil {
|
|
logger.Error("could not create backup directory, moving to a temporary folder", zap.Error(err))
|
|
options.BackupDir = os.TempDir()
|
|
logger.Info("using temporary directory", zap.String("backup-dir", options.BackupDir))
|
|
return
|
|
}
|
|
|
|
ticker := time.NewTicker(time.Duration(options.BackupInterval) * time.Minute)
|
|
defer ticker.Stop()
|
|
for range ticker.C {
|
|
// Run backup procedure
|
|
file, err := os.Create(fmt.Sprintf("%s/%s.db", options.BackupDir, time.Now().Format("20060102-150405")))
|
|
if err != nil {
|
|
logger.Error("could not create backup file", zap.Error(err))
|
|
continue
|
|
}
|
|
err = driver.Backup(file)
|
|
if err != nil {
|
|
logger.Error("could not backup database", zap.Error(err))
|
|
}
|
|
_ = file.Close()
|
|
logger.Info("database backed up", zap.String("backup-file", file.Name()))
|
|
// Remove old backups
|
|
files, err := os.ReadDir(options.BackupDir)
|
|
if err != nil {
|
|
logger.Error("could not read backup directory", zap.Error(err))
|
|
continue
|
|
}
|
|
// 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 {
|
|
logger.Error("could not remove backup file", zap.Error(err))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
type BackupOptions struct {
|
|
BackupDir string
|
|
BackupInterval int
|
|
MaxBackups int
|
|
}
|
|
|
|
func getDatabaseDriverName(ctx *cli.Context) string {
|
|
driver := ctx.String("driver")
|
|
if driver != "auto" {
|
|
return driver
|
|
}
|
|
|
|
dbdir := ctx.String("database-dir")
|
|
file, err := os.ReadFile(filepath.Join(dbdir, "stul-driver"))
|
|
if err != nil {
|
|
// No driver file found (or file corrupted), use default driver
|
|
return databaseDefaultDriver
|
|
}
|
|
return string(file)
|
|
}
|
|
|
|
func getDatabaseDriver(ctx *cli.Context) (DatabaseDriver, error) {
|
|
name := getDatabaseDriverName(ctx)
|
|
dbdir := ctx.String("database-dir")
|
|
|
|
switch name {
|
|
case "badger":
|
|
return nil, cli.Exit("Badger is not supported anymore as a database driver", 64)
|
|
case "pebble":
|
|
return NewPebble(dbdir)
|
|
default:
|
|
return nil, cli.Exit(fmt.Sprintf("Unknown database driver: %s", name), 64)
|
|
}
|
|
}
|