mirror of
https://github.com/iyear/tdl
synced 2025-01-09 04:17:35 +08:00
feat(migrate): support migrate data to another storage
This commit is contained in:
parent
6470e57ff5
commit
8d4ce974d6
@ -1,4 +1,4 @@
|
|||||||
package archive
|
package migrate
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
44
app/migrate/migrate.go
Normal file
44
app/migrate/migrate.go
Normal 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
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package archive
|
package migrate
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
@ -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
|
||||||
|
}
|
22
cmd/root.go
22
cmd/root.go
@ -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(), ",")))
|
||||||
|
|
||||||
|
17
pkg/kv/kv.go
17
pkg/kv/kv.go
@ -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 {
|
||||||
|
Loading…
Reference in New Issue
Block a user