Skip to content

Commit

Permalink
feat(daemon): add import command to download pruned snapshots (#1424)
Browse files Browse the repository at this point in the history
  • Loading branch information
Ja7ad authored Jul 19, 2024
1 parent 6eec4f4 commit a055d0c
Show file tree
Hide file tree
Showing 11 changed files with 493 additions and 19 deletions.
40 changes: 40 additions & 0 deletions cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"syscall"
"time"

"github.com/k0kubun/go-ansi"
"github.com/manifoldco/promptui"
"github.com/pactus-project/pactus/config"
"github.com/pactus-project/pactus/crypto"
Expand All @@ -29,6 +30,7 @@ import (
"github.com/pactus-project/pactus/wallet"
"github.com/pactus-project/pactus/wallet/addresspath"
"github.com/pactus-project/pactus/wallet/vault"
"github.com/schollz/progressbar/v3"
)

const (
Expand Down Expand Up @@ -121,6 +123,20 @@ func PromptInput(label string) string {
return result
}

// PromptSelect prompts create choice menu for select by user.
func PromptSelect(label string, items []string) int {
prompt := promptui.Select{
Label: label,
Items: items,
Pointer: promptui.PipeCursor,
}

choice, _, err := prompt.Run()
FatalErrorCheck(err)

return choice
}

// PromptInputWithSuggestion prompts the user for an input string with a suggestion.
func PromptInputWithSuggestion(label, suggestion string) string {
prompt := promptui.Prompt{
Expand Down Expand Up @@ -617,3 +633,27 @@ func MakeValidatorKey(walletInstance *wallet.Wallet, valAddrsInfo []vault.Addres

return valKeys, nil
}

func TerminalProgressBar(totalSize, barWidth int, showBytes bool) *progressbar.ProgressBar {
if barWidth < 15 {
barWidth = 15
}

opts := []progressbar.Option{
progressbar.OptionSetWriter(ansi.NewAnsiStdout()),
progressbar.OptionEnableColorCodes(true),
progressbar.OptionShowBytes(showBytes),
progressbar.OptionSetWidth(barWidth),
progressbar.OptionSetElapsedTime(false),
progressbar.OptionSetPredictTime(false),
progressbar.OptionSetTheme(progressbar.Theme{
Saucer: "[green]=[reset]",
SaucerHead: "[green]>[reset]",
SaucerPadding: " ",
BarStart: "[",
BarEnd: "]",
}),
}

return progressbar.NewOptions(totalSize, opts...)
}
149 changes: 149 additions & 0 deletions cmd/daemon/import.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
package main

import (
"fmt"
"os"
"path/filepath"
"time"

"github.com/gofrs/flock"
"github.com/pactus-project/pactus/cmd"
"github.com/pactus-project/pactus/genesis"
"github.com/pactus-project/pactus/util"
"github.com/spf13/cobra"
)

func buildImportCmd(parentCmd *cobra.Command) {
importCmd := &cobra.Command{
Use: "import",
Short: "download and import pruned data",
}
parentCmd.AddCommand(importCmd)

workingDirOpt := addWorkingDirOption(importCmd)
serverAddrOpt := importCmd.Flags().String("server-addr", "https://download.pactus.org",
"import server address")

importCmd.Run = func(c *cobra.Command, _ []string) {
workingDir, err := filepath.Abs(*workingDirOpt)
cmd.FatalErrorCheck(err)

err = os.Chdir(workingDir)
cmd.FatalErrorCheck(err)

conf, gen, err := cmd.MakeConfig(workingDir)
cmd.FatalErrorCheck(err)

lockFilePath := filepath.Join(workingDir, ".pactus.lock")
fileLock := flock.New(lockFilePath)

locked, err := fileLock.TryLock()
cmd.FatalErrorCheck(err)

if !locked {
cmd.PrintWarnMsgf("Could not lock '%s', another instance is running?", lockFilePath)

return
}

storeDir, _ := filepath.Abs(conf.Store.StorePath())
if !util.IsDirNotExistsOrEmpty(storeDir) {
cmd.PrintErrorMsgf("The data directory is not empty: %s", conf.Store.StorePath())

return
}

snapshotURL := *serverAddrOpt

switch gen.ChainType() {
case genesis.Mainnet:
snapshotURL += "/mainnet/"
case genesis.Testnet:
snapshotURL += "/testnet/"
case genesis.Localnet:
cmd.PrintErrorMsgf("Unsupported chain type: %s", gen.ChainType())

return
}

metadata, err := cmd.GetSnapshotMetadata(c.Context(), snapshotURL)
if err != nil {
cmd.PrintErrorMsgf("Failed to get snapshot metadata: %s", err)

return
}

snapshots := make([]string, 0, len(metadata))

for _, m := range metadata {
item := fmt.Sprintf("snapshot %s (%s)",
parseTime(m.CreatedAt).Format("2006-01-02"),
util.FormatBytesToHumanReadable(m.TotalSize),
)

snapshots = append(snapshots, item)
}

cmd.PrintLine()

choice := cmd.PromptSelect("Please select a snapshot", snapshots)

selected := metadata[choice]
tmpDir := util.TempDirPath()
extractPath := fmt.Sprintf("%s/data", tmpDir)

err = os.MkdirAll(extractPath, 0o750)
cmd.FatalErrorCheck(err)

cmd.PrintLine()

zipFileList := cmd.DownloadManager(
c.Context(),
&selected,
snapshotURL,
tmpDir,
downloadProgressBar,
)

for _, zFile := range zipFileList {
err := cmd.ExtractAndStoreFile(zFile, extractPath)
cmd.FatalErrorCheck(err)
}

err = os.MkdirAll(filepath.Dir(conf.Store.StorePath()), 0o750)
cmd.FatalErrorCheck(err)

err = cmd.CopyAllFiles(extractPath, conf.Store.StorePath())
cmd.FatalErrorCheck(err)

err = os.RemoveAll(tmpDir)
cmd.FatalErrorCheck(err)

_ = fileLock.Unlock()

cmd.PrintLine()
cmd.PrintLine()
cmd.PrintInfoMsgf("✅ Your node successfully imported prune data.")
cmd.PrintLine()
cmd.PrintInfoMsgf("You can start the node by running this command:")
cmd.PrintInfoMsgf("./pactus-daemon start -w %v", workingDir)
}
}

func downloadProgressBar(fileName string, totalSize, downloaded int64, _ float64) {
bar := cmd.TerminalProgressBar(int(totalSize), 30, true)
bar.Describe(fileName)
err := bar.Add(int(downloaded))
cmd.FatalErrorCheck(err)
}

func parseTime(dateString string) time.Time {
const layout = "2006-01-02T15:04:05.000000"

parsedTime, err := time.Parse(layout, dateString)
if err != nil {
return time.Time{}
}

return parsedTime
}
1 change: 1 addition & 0 deletions cmd/daemon/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ func main() {
buildInitCmd(rootCmd)
buildStartCmd(rootCmd)
buildPruneCmd(rootCmd)
buildImportCmd(rootCmd)

err := rootCmd.Execute()
if err != nil {
Expand Down
16 changes: 4 additions & 12 deletions cmd/daemon/prune.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"fmt"
"os"
"path/filepath"
"strings"

"github.com/gofrs/flock"
"github.com/pactus-project/pactus/cmd"
Expand Down Expand Up @@ -115,15 +114,8 @@ func buildPruneCmd(parentCmd *cobra.Command) {
}

func pruningProgressBar(prunedCount, skippedCount, totalCount uint32) {
percentage := float64(prunedCount+skippedCount) / float64(totalCount) * 100
if percentage > 100 {
percentage = 100
}

barLength := 40
filledLength := int(float64(barLength) * percentage / 100)

bar := strings.Repeat("=", filledLength) + strings.Repeat(" ", barLength-filledLength)
fmt.Printf("\r [%s] %.0f%% Pruned: %d | Skipped: %d", //nolint
bar, percentage, prunedCount, skippedCount)
bar := cmd.TerminalProgressBar(int(totalCount), 30, false)
bar.Describe(fmt.Sprintf("Pruned: %d | Skipped: %d", prunedCount, skippedCount))
err := bar.Add(int(prunedCount + skippedCount))
cmd.FatalErrorCheck(err)
}
Loading

0 comments on commit a055d0c

Please sign in to comment.