feat(migrate): support migrate data to another storage

This commit is contained in:
iyear 2023-12-18 20:00:16 +08:00
parent 6470e57ff5
commit 8d4ce974d6
6 changed files with 90 additions and 23 deletions

View File

@ -1,4 +1,4 @@
package archive package migrate
import ( import (
"context" "context"

44
app/migrate/migrate.go Normal file
View File

@ -0,0 +1,44 @@
package migrate
import (
"context"
"github.com/AlecAivazis/survey/v2"
"github.com/fatih/color"
"github.com/go-faster/errors"
"github.com/iyear/tdl/pkg/kv"
)
func Migrate(ctx context.Context, to map[string]string) error {
meta, err := kv.From(ctx).MigrateTo()
if err != nil {
return errors.Wrap(err, "read data")
}
dest, err := kv.NewWithMap(to)
if err != nil {
return errors.Wrap(err, "create dest storage")
}
var confirm bool
if err = survey.AskOne(&survey.Confirm{
Message: "It will overwrite the namespace data in the destination storage, continue?",
Default: false,
}, &confirm); err != nil {
return errors.Wrap(err, "confirm")
}
if !confirm {
return nil
}
if err = dest.MigrateFrom(meta); err != nil {
return errors.Wrap(err, "migrate from")
}
color.Green("Migrate successfully.")
for ns := range meta {
color.Green(" - %s", ns)
}
return nil
}

View File

@ -1,4 +1,4 @@
package archive package migrate
import ( import (
"bytes" "bytes"

View File

@ -2,11 +2,13 @@ package cmd
import ( import (
"fmt" "fmt"
"strings"
"time" "time"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/iyear/tdl/app/archive" "github.com/iyear/tdl/app/migrate"
"github.com/iyear/tdl/pkg/kv"
) )
func NewBackup() *cobra.Command { func NewBackup() *cobra.Command {
@ -20,7 +22,7 @@ func NewBackup() *cobra.Command {
dst = fmt.Sprintf("%s.backup.tdl", time.Now().Format("2006-01-02-15_04_05")) dst = fmt.Sprintf("%s.backup.tdl", time.Now().Format("2006-01-02-15_04_05"))
} }
return archive.Backup(cmd.Context(), dst) return migrate.Backup(cmd.Context(), dst)
}, },
} }
@ -36,7 +38,7 @@ func NewRecover() *cobra.Command {
Use: "recover", Use: "recover",
Short: "Recover your data", Short: "Recover your data",
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return archive.Recover(cmd.Context(), file) return migrate.Recover(cmd.Context(), file)
}, },
} }
@ -50,3 +52,21 @@ func NewRecover() *cobra.Command {
return cmd return cmd
} }
func NewMigrate() *cobra.Command {
var to map[string]string
cmd := &cobra.Command{
Use: "migrate",
Short: "Migrate your current data to another storage",
RunE: func(cmd *cobra.Command, args []string) error {
return migrate.Migrate(cmd.Context(), to)
},
}
cmd.Flags().StringToStringVar(&to, "to", map[string]string{},
fmt.Sprintf("destination storage options, format: type=driver,key1=value1,key2=value2. Available drivers: [%s]",
strings.Join(kv.DriverNames(), ",")))
return cmd
}

View File

@ -21,8 +21,6 @@ import (
) )
func New() *cobra.Command { func New() *cobra.Command {
driverTypeKey := "type"
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "tdl", Use: "tdl",
Short: "Telegram Downloader, but more than a downloader", Short: "Telegram Downloader, but more than a downloader",
@ -43,19 +41,7 @@ func New() *cobra.Command {
zap.String("namespace", ns)) zap.String("namespace", ns))
} }
// check storage flag storage, err := kv.NewWithMap(viper.GetStringMapString(consts.FlagStorage))
storageOpts := viper.GetStringMapString(consts.FlagStorage)
driver, err := kv.ParseDriver(storageOpts[driverTypeKey])
if err != nil {
return errors.Wrap(err, "parse driver")
}
delete(storageOpts, driverTypeKey)
opts := make(map[string]any)
for k, v := range storageOpts {
opts[k] = v
}
storage, err := kv.New(driver, opts)
if err != nil { if err != nil {
return errors.Wrap(err, "create kv storage") return errors.Wrap(err, "create kv storage")
} }
@ -72,11 +58,11 @@ func New() *cobra.Command {
} }
cmd.AddCommand(NewVersion(), NewLogin(), NewDownload(), NewForward(), cmd.AddCommand(NewVersion(), NewLogin(), NewDownload(), NewForward(),
NewChat(), NewUpload(), NewBackup(), NewRecover(), NewGen()) NewChat(), NewUpload(), NewBackup(), NewRecover(), NewMigrate(), NewGen())
cmd.PersistentFlags().StringToString(consts.FlagStorage, map[string]string{ cmd.PersistentFlags().StringToString(consts.FlagStorage, map[string]string{
driverTypeKey: kv.DriverLegacy.String(), kv.DriverTypeKey: kv.DriverLegacy.String(),
"path": consts.KVPath, "path": consts.KVPath,
}, fmt.Sprintf("storage options, format: type=driver,key1=value1,key2=value2. Available drivers: [%s]", }, fmt.Sprintf("storage options, format: type=driver,key1=value1,key2=value2. Available drivers: [%s]",
strings.Join(kv.DriverNames(), ","))) strings.Join(kv.DriverNames(), ",")))

View File

@ -13,6 +13,8 @@ import (
// ENUM(legacy, bolt, file) // ENUM(legacy, bolt, file)
type Driver string type Driver string
const DriverTypeKey = "type"
var ErrNotFound = errors.New("key not found") var ErrNotFound = errors.New("key not found")
type Meta map[string]map[string][]byte // namespace, key, value type Meta map[string]map[string][]byte // namespace, key, value
@ -46,6 +48,21 @@ func New(driver Driver, opts map[string]any) (Storage, error) {
return nil, errors.Errorf("unsupported driver: %s", driver) return nil, errors.Errorf("unsupported driver: %s", driver)
} }
func NewWithMap(o map[string]string) (Storage, error) {
driver, err := ParseDriver(o[DriverTypeKey])
if err != nil {
return nil, errors.Wrap(err, "parse driver")
}
delete(o, DriverTypeKey)
opts := make(map[string]any)
for k, v := range o {
opts[k] = v
}
return New(driver, opts)
}
type ctxKey struct{} type ctxKey struct{}
func With(ctx context.Context, kv Storage) context.Context { func With(ctx context.Context, kv Storage) context.Context {