-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
f4847b1
commit 3dadf2c
Showing
5 changed files
with
269 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package backup | ||
|
||
import "github.com/gnolang/tx-archive/log" | ||
|
||
type Option func(s *Service) | ||
Check failure on line 5 in backup/options.go GitHub Actions / Go Linter / lint
Check failure on line 5 in backup/options.go GitHub Actions / Go Linter / lint
|
||
|
||
// WithLogger specifies the logger for the backup service | ||
func WithLogger(l log.Logger) Option { | ||
return func(s *Service) { | ||
Check failure on line 9 in backup/options.go GitHub Actions / Go Linter / lint
Check failure on line 9 in backup/options.go GitHub Actions / Go Linter / lint
|
||
s.logger = l | ||
} | ||
} |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,178 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
"flag" | ||
"fmt" | ||
"os" | ||
|
||
"github.com/gnolang/tx-archive/backup" | ||
"github.com/gnolang/tx-archive/backup/client/http" | ||
"github.com/peterbourgon/ff/v3/ffcli" | ||
Check failure on line 12 in cmd/backup.go GitHub Actions / Go Test / test-with-race
|
||
"go.uber.org/zap" | ||
Check failure on line 13 in cmd/backup.go GitHub Actions / Go Test / test-with-race
|
||
) | ||
|
||
const ( | ||
defaultOutputPath = "./backup.jsonl" | ||
defaultFromBlock = 1 | ||
defaultToBlock = -1 // no limit | ||
|
||
defaultRemoteAddress = "http://127.0.0.1:26657" | ||
) | ||
|
||
var ( | ||
errInvalidOutputLocation = errors.New("invalid output location") | ||
errOutputFileExists = errors.New("output file exists") | ||
errInvalidRemote = errors.New("invalid remote address") | ||
) | ||
|
||
// backupCfg is the backup command configuration | ||
type backupCfg struct { | ||
outputPath string | ||
remote string | ||
|
||
toBlock int64 // < 0 means there is no right bound | ||
fromBlock uint64 | ||
|
||
overwrite bool | ||
} | ||
|
||
// newBackupCmd creates the backup command | ||
func newBackupCmd() *ffcli.Command { | ||
cfg := &backupCfg{} | ||
|
||
fs := flag.NewFlagSet("backup", flag.ExitOnError) | ||
cfg.registerFlags(fs) | ||
|
||
return &ffcli.Command{ | ||
Name: "backup", | ||
ShortUsage: "backup [flags]", | ||
LongHelp: "Runs the chain backup service", | ||
FlagSet: fs, | ||
Exec: cfg.exec, | ||
} | ||
} | ||
|
||
// registerFlags registers the backup command flags | ||
func (c *backupCfg) registerFlags(fs *flag.FlagSet) { | ||
fs.StringVar( | ||
&c.outputPath, | ||
"output-path", | ||
defaultOutputPath, | ||
"the output path for the JSONL chain data", | ||
) | ||
|
||
fs.StringVar( | ||
&c.remote, | ||
"remote", | ||
defaultRemoteAddress, | ||
"the JSON-RPC URL of the chain to be backed up", | ||
) | ||
|
||
fs.Int64Var( | ||
&c.toBlock, | ||
"to-block", | ||
defaultToBlock, | ||
"the end block number for the backup (inclusive). If <0, latest chain height is used", | ||
) | ||
|
||
fs.Uint64Var( | ||
&c.fromBlock, | ||
"from-block", | ||
defaultFromBlock, | ||
"the starting block number for the backup (inclusive)", | ||
) | ||
|
||
fs.BoolVar( | ||
&c.overwrite, | ||
"overwrite", | ||
false, | ||
"flag indicating if the output file should be overwritten during backup", | ||
) | ||
} | ||
|
||
// exec executes the backup command | ||
func (c *backupCfg) exec(ctx context.Context, _ []string) error { | ||
// Make sure the remote address is set | ||
if c.remote == "" { | ||
return errInvalidRemote | ||
} | ||
|
||
// Make sure the output file path is valid | ||
if c.outputPath == "" { | ||
return errInvalidOutputLocation | ||
} | ||
|
||
// Make sure the output file can be overwritten, if it exists | ||
if _, err := os.Stat(c.outputPath); err == nil && !c.overwrite { | ||
// File already exists, and the overwrite flag is not set | ||
return errOutputFileExists | ||
} | ||
|
||
// Set up the config | ||
cfg := backup.DefaultConfig() | ||
cfg.FromBlock = c.fromBlock | ||
|
||
if c.toBlock >= 0 { | ||
to64 := uint64(c.toBlock) | ||
cfg.ToBlock = &to64 | ||
} | ||
|
||
// Set up the client | ||
client := http.NewClient(c.remote) | ||
|
||
// Set up the logger | ||
zapLogger, loggerErr := zap.NewDevelopment() | ||
if loggerErr != nil { | ||
return fmt.Errorf("unable to create logger, %w", loggerErr) | ||
} | ||
|
||
logger := newCommandLogger(zapLogger) | ||
|
||
// Set up the writer (file) | ||
// Open the file for writing | ||
outputFile, openErr := os.OpenFile( | ||
c.outputPath, | ||
os.O_RDWR|os.O_CREATE|os.O_TRUNC, | ||
0o755, | ||
) | ||
if openErr != nil { | ||
return fmt.Errorf("unable to open file %s, %w", c.outputPath, openErr) | ||
} | ||
|
||
closeFile := func() error { | ||
if err := outputFile.Close(); err != nil { | ||
logger.Error("unable to close output file", "err", err.Error()) | ||
|
||
return err | ||
} | ||
|
||
return nil | ||
} | ||
|
||
teardown := func() { | ||
if err := closeFile(); err != nil { | ||
if removeErr := os.Remove(outputFile.Name()); removeErr != nil { | ||
logger.Error("unable to remove file", "err", err.Error()) | ||
} | ||
} | ||
} | ||
|
||
// Set up the teardown | ||
defer teardown() | ||
|
||
// Create the backup service | ||
service := backup.NewService( | ||
client, | ||
outputFile, | ||
backup.WithLogger(logger), | ||
) | ||
|
||
// Run the backup service | ||
if backupErr := service.ExecuteBackup(ctx, cfg); backupErr != nil { | ||
return fmt.Errorf("unable to execute backup, %w", backupErr) | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package main | ||
|
||
import "go.uber.org/zap" | ||
|
||
type cmdLogger struct { | ||
logger *zap.Logger | ||
} | ||
|
||
func newCommandLogger(logger *zap.Logger) *cmdLogger { | ||
return &cmdLogger{ | ||
logger: logger, | ||
} | ||
} | ||
|
||
func (c *cmdLogger) Info(msg string, args ...interface{}) { | ||
if len(args) == 0 { | ||
c.logger.Info(msg) | ||
|
||
return | ||
} | ||
|
||
c.logger.Info(msg, zap.Any("args", args)) | ||
} | ||
|
||
func (c *cmdLogger) Debug(msg string, args ...interface{}) { | ||
if len(args) == 0 { | ||
c.logger.Debug(msg) | ||
|
||
return | ||
} | ||
|
||
c.logger.Debug(msg, zap.Any("args", args)) | ||
} | ||
|
||
func (c *cmdLogger) Error(msg string, args ...interface{}) { | ||
if len(args) == 0 { | ||
c.logger.Error(msg) | ||
|
||
return | ||
} | ||
|
||
c.logger.Error(msg, zap.Any("args", args)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
"flag" | ||
"fmt" | ||
"os" | ||
|
||
"github.com/peterbourgon/ff/v3/ffcli" | ||
) | ||
|
||
func main() { | ||
fs := flag.NewFlagSet("root", flag.ExitOnError) | ||
|
||
// Create the root command | ||
cmd := &ffcli.Command{ | ||
ShortUsage: "<subcommand> [flags] [<arg>...]", | ||
LongHelp: "The archive command for Gno / TM2 chains", | ||
FlagSet: fs, | ||
Exec: func(_ context.Context, _ []string) error { | ||
return flag.ErrHelp | ||
}, | ||
} | ||
|
||
// Add the subcommands | ||
cmd.Subcommands = []*ffcli.Command{ | ||
newBackupCmd(), | ||
// newRestoreCmd(), | ||
} | ||
|
||
if err := cmd.ParseAndRun(context.Background(), os.Args[1:]); err != nil { | ||
_, _ = fmt.Fprintf(os.Stderr, "%+v", err) | ||
|
||
os.Exit(1) | ||
} | ||
} |