Skip to content

Commit

Permalink
feat: add multibase commands (#342)
Browse files Browse the repository at this point in the history
  • Loading branch information
Shawn-Huang-Tron authored Aug 16, 2023
1 parent a791ada commit 0b4e596
Show file tree
Hide file tree
Showing 3 changed files with 177 additions and 0 deletions.
5 changes: 5 additions & 0 deletions core/commands/commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,11 @@ func TestCommands(t *testing.T) {
"/bittorrent/scrape",
"/bittorrent/metainfo",
"/bittorrent/bencode",
"/multibase",
"/multibase/encode",
"/multibase/decode",
"/multibase/transcode",
"/multibase/list",
}

cmdSet := make(map[string]struct{})
Expand Down
171 changes: 171 additions & 0 deletions core/commands/multibase.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
package commands

import (
"bytes"
"fmt"
"io"
"strings"

cmds "github.com/bittorrent/go-btfs-cmds"
cmdenv "github.com/bittorrent/go-btfs/core/commands/cmdenv"
mbase "github.com/multiformats/go-multibase"
)

var MbaseCmd = &cmds.Command{
Helptext: cmds.HelpText{
Tagline: "Encode and decode files or stdin with multibase format",
},
Subcommands: map[string]*cmds.Command{
"encode": mbaseEncodeCmd,
"decode": mbaseDecodeCmd,
"transcode": mbaseTranscodeCmd,
"list": basesCmd,
},
Extra: CreateCmdExtras(SetDoesNotUseRepo(true)),
}

const (
mbaseOptionName = "b"
)

var mbaseEncodeCmd = &cmds.Command{
Helptext: cmds.HelpText{
Tagline: "Encode data into multibase string",
LongDescription: `
This command expects a file name or data provided via stdin.
By default it will use URL-safe base64url encoding,
but one can customize used base with -b:
> echo hello | btfs multibase encode -b base16 > output_file
> cat output_file
f68656c6c6f0a
> echo hello > input_file
> btfs multibase encode -b base16 input_file
f68656c6c6f0a
`,
},
Arguments: []cmds.Argument{
cmds.FileArg("file", true, false, "data to encode").EnableStdin(),
},
Options: []cmds.Option{
cmds.StringOption(mbaseOptionName, "multibase encoding").WithDefault("base64url"),
},
Run: func(req *cmds.Request, resp cmds.ResponseEmitter, env cmds.Environment) error {
if err := req.ParseBodyArgs(); err != nil {
return err
}
encoderName, _ := req.Options[mbaseOptionName].(string)
encoder, err := mbase.EncoderByName(encoderName)
if err != nil {
return err
}
files := req.Files.Entries()
file, err := cmdenv.GetFileArg(files)
if err != nil {
return fmt.Errorf("failed to access file: %w", err)
}
buf, err := io.ReadAll(file)
if err != nil {
return fmt.Errorf("failed to read file contents: %w", err)
}
encoded := encoder.Encode(buf)
reader := strings.NewReader(encoded)
return resp.Emit(reader)
},
}

var mbaseDecodeCmd = &cmds.Command{
Helptext: cmds.HelpText{
Tagline: "Decode multibase string",
LongDescription: `
This command expects multibase inside of a file or via stdin:
> echo -n hello | btfs multibase encode -b base16 > file
> cat file
f68656c6c6f
> btfs multibase decode file
hello
> cat file | btfs multibase decode
hello
`,
},
Arguments: []cmds.Argument{
cmds.FileArg("encoded_file", true, false, "encoded data to decode").EnableStdin(),
},
Run: func(req *cmds.Request, resp cmds.ResponseEmitter, env cmds.Environment) error {
if err := req.ParseBodyArgs(); err != nil {
return err
}
files := req.Files.Entries()
file, err := cmdenv.GetFileArg(files)
if err != nil {
return fmt.Errorf("failed to access file: %w", err)
}
encodedData, err := io.ReadAll(file)
if err != nil {
return fmt.Errorf("failed to read file contents: %w", err)
}
_, data, err := mbase.Decode(string(encodedData))
if err != nil {
return fmt.Errorf("failed to decode multibase: %w", err)
}
reader := bytes.NewReader(data)
return resp.Emit(reader)
},
}

var mbaseTranscodeCmd = &cmds.Command{
Helptext: cmds.HelpText{
Tagline: "Transcode multibase string between bases",
LongDescription: `
This command expects multibase inside of a file or via stdin.
By default it will use URL-safe base64url encoding,
but one can customize used base with -b:
> echo -n hello | btfs multibase encode > file
> cat file
uaGVsbG8
> btfs multibase transcode file -b base16 > transcoded_file
> cat transcoded_file
f68656c6c6f
`,
},
Arguments: []cmds.Argument{
cmds.FileArg("encoded_file", true, false, "encoded data to decode").EnableStdin(),
},
Options: []cmds.Option{
cmds.StringOption(mbaseOptionName, "multibase encoding").WithDefault("base64url"),
},
Run: func(req *cmds.Request, resp cmds.ResponseEmitter, env cmds.Environment) error {
if err := req.ParseBodyArgs(); err != nil {
return err
}
encoderName, _ := req.Options[mbaseOptionName].(string)
encoder, err := mbase.EncoderByName(encoderName)
if err != nil {
return err
}
files := req.Files.Entries()
file, err := cmdenv.GetFileArg(files)
if err != nil {
return fmt.Errorf("failed to access file: %w", err)
}
encodedData, err := io.ReadAll(file)
if err != nil {
return fmt.Errorf("failed to read file contents: %w", err)
}
_, data, err := mbase.Decode(string(encodedData))
if err != nil {
return fmt.Errorf("failed to decode multibase: %w", err)
}
encoded := encoder.Encode(data)
reader := strings.NewReader(encoded)
return resp.Emit(reader)
},
}
1 change: 1 addition & 0 deletions core/commands/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ var rootSubcommands = map[string]*cmds.Command{
"network": NetworkCmd,
"statuscontract": StatusContractCmd,
"bittorrent": bittorrentCmd,
"multibase": MbaseCmd,
}

// RootRO is the readonly version of Root
Expand Down

0 comments on commit 0b4e596

Please sign in to comment.