refactor: refactor eiblog

This commit is contained in:
henry.chen
2025-07-16 19:45:50 +08:00
parent 0a410f09f3
commit 8fcabd5e15
67 changed files with 1282 additions and 1330 deletions

View File

@@ -0,0 +1,138 @@
package qiniu
import (
"context"
"errors"
"fmt"
"net/url"
"os"
"os/exec"
"path/filepath"
"time"
"github.com/eiblog/eiblog/cmd/backup/config"
"github.com/eiblog/eiblog/cmd/backup/handler/internal"
"github.com/eiblog/eiblog/pkg/connector/db"
"github.com/eiblog/eiblog/pkg/third/qiniu"
)
// BackupRestorer qiniu backup restorer
type BackupRestorer struct{}
// Backup implements timer.BackupRestorer
func (s BackupRestorer) Backup(now time.Time) error {
switch config.Conf.Database.Driver {
case "mongodb":
return backupFromMongoDB(now)
default:
return errors.New("unsupported source backup to qiniu: " +
config.Conf.Database.Driver)
}
}
// Restore implements timer.BackupRestorer
func (s BackupRestorer) Restore() error {
switch config.Conf.Database.Driver {
case "mongodb":
return restoreToMongoDB()
default:
return errors.New("unsupported source restore from qiniu: " +
config.Conf.Database.Driver)
}
}
func backupFromMongoDB(now time.Time) error {
ctx, cancel := context.WithTimeout(context.Background(), time.Minute*20)
defer cancel()
// dump
u, err := url.Parse(config.Conf.Database.Source)
if err != nil {
return err
}
arg := fmt.Sprintf("mongodump -h %s -d eiblog -o /tmp", u.Host)
cmd := exec.CommandContext(ctx, "sh", "-c", arg)
err = cmd.Run()
if err != nil {
return err
}
// tar
name := fmt.Sprintf("eiblog-%s.tar.gz", now.Format("2006-01-02"))
arg = fmt.Sprintf("tar czf /tmp/%s -C /tmp eiblog", name)
cmd = exec.CommandContext(ctx, "sh", "-c", arg)
err = cmd.Run()
if err != nil {
return err
}
// upload file
f, err := os.Open("/tmp/" + name)
if err != nil {
return err
}
s, err := f.Stat()
if err != nil {
return err
}
uploadParams := qiniu.UploadParams{
Name: filepath.Join("blog", name), // blog/eiblog-xx.tar.gz
Size: s.Size(),
Data: f,
NoCompletePath: true,
}
_, err = internal.QiniuClient.Upload(uploadParams)
if err != nil {
return err
}
// after days delete
deleteParams := qiniu.DeleteParams{
Name: filepath.Join("blog", name), // blog/eiblog-xx.tar.gz
Days: config.Conf.Validity,
NoCompletePath: true,
}
return internal.QiniuClient.Delete(deleteParams)
}
func restoreToMongoDB() error {
// backup file
params := qiniu.ContentParams{
Prefix: "blog/",
}
raw, err := internal.QiniuClient.Content(params)
if err != nil {
return err
}
f, err := os.OpenFile("/tmp/eiblog.tar.gz", os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
return err
}
_, _ = f.Write(raw)
defer f.Close()
ctx, cancel := context.WithTimeout(context.Background(), time.Minute*20)
defer cancel()
// drop database
mdb, err := db.NewMDB(config.Conf.Database)
if err != nil {
return err
}
err = mdb.Drop(ctx)
if err != nil {
return err
}
// unarchive
arg := "tar xzf /tmp/eiblog.tar.gz -C /tmp"
cmd := exec.CommandContext(ctx, "sh", "-c", arg)
err = cmd.Run()
if err != nil {
return err
}
// restore
u, err := url.Parse(config.Conf.Database.Source)
if err != nil {
return err
}
arg = fmt.Sprintf("mongorestore -h %s -d eiblog /tmp/eiblog", u.Host)
cmd = exec.CommandContext(ctx, "sh", "-c", arg)
return cmd.Run()
}

View File

@@ -0,0 +1,73 @@
package timer
import (
"errors"
"strconv"
"time"
"github.com/eiblog/eiblog/cmd/backup/config"
"github.com/eiblog/eiblog/cmd/backup/handler/timer/qiniu"
"github.com/sirupsen/logrus"
)
// BackupRestorer 备份恢复器
type BackupRestorer interface {
Backup(now time.Time) error
Restore() error
}
// Start to backup with ticker
func Start(restore bool) (err error) {
var storage BackupRestorer
// backup instance
switch config.Conf.BackupTo {
case "qiniu":
storage = qiniu.BackupRestorer{}
default:
return errors.New("timer: unknown backup to driver: " +
config.Conf.BackupTo)
}
if restore {
err = storage.Restore()
if err != nil {
return err
}
logrus.Info("timer: Restore success")
}
// parse duration
interval, err := ParseDuration(config.Conf.Interval)
if err != nil {
return err
}
t := time.NewTicker(interval)
for now := range t.C {
err = storage.Backup(now)
if err != nil {
logrus.Error("timer: Start.Backup: ", now.Format(time.RFC3339), err)
}
}
return nil
}
// ParseDuration parse string to duration
func ParseDuration(d string) (time.Duration, error) {
if len(d) == 0 {
return 0, errors.New("timer: incorrect duration input")
}
length := len(d)
switch d[length-1] {
case 's', 'm', 'h':
return time.ParseDuration(d)
case 'd':
di, err := strconv.Atoi(d[:length-1])
if err != nil {
return 0, err
}
return time.Duration(di) * time.Hour * 24, nil
}
return 0, errors.New("timer: unsupported duration:" + d)
}