Skip to content

Commit

Permalink
Added support back for -o shorthand for --output and added `--out…
Browse files Browse the repository at this point in the history
…put=bytes` support
  • Loading branch information
maoueh committed Jan 21, 2025
1 parent 567c271 commit b2c6312
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 6 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ Operators, you should copy/paste content of this content straight to your projec

If you were at `firehose-core` version `1.0.0` and are bumping to `1.1.0`, you should copy the content between those 2 version to your own repository, replacing placeholder value `fire{chain}` with your chain's own binary.

## Unreleased

* Added support for `--output=bytes` mode which prints the chain's specific Protobuf block as bytes, the encoding for the bytes string printed is determined by `--bytes-encoding`, uses `hex` by default.

* Added back `-o` as shortand for `--output` in `firecore tools ...` sub-commands.

## v1.7.1

* Add back `grpc.health.v1.Health` service to `firehose` and `substreams-tier1` services (regression in 1.7.0)
Expand Down
6 changes: 5 additions & 1 deletion cmd/tools/print/printer.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,16 @@ func GetOutputPrinter(cmd *cobra.Command, chainFileDescriptor protoreflect.FileD
return NewTextOutputPrinter(bytesEncoding, registry, printTransactions), nil
}

if printer == "bytes" {
return NewBytesOutputPrinter(bytesEncoding, registry), nil
}

return nil, fmt.Errorf("unsupported output printer %q", printer)
}

//go:generate go-enum -f=$GOFILE --marshal --names --nocase

// ENUM(Text, JSON, JSONL, ProtoJSON, ProtoJSONL)
// ENUM(Text, JSON, JSONL, ProtoJSON, ProtoJSONL, Bytes)
type PrintOutputMode uint

type OutputPrinter interface {
Expand Down
108 changes: 108 additions & 0 deletions cmd/tools/print/printer_bytes.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// Copyright 2021 dfuse Platform Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package print

import (
"encoding/base64"
"encoding/hex"
"fmt"
"io"

"github.com/mr-tron/base58"
pbbstream "github.com/streamingfast/bstream/pb/sf/bstream/v1"
fcproto "github.com/streamingfast/firehose-core/proto"
pbfirehose "github.com/streamingfast/pbgo/sf/firehose/v2"
"google.golang.org/protobuf/proto"
)

var _ OutputPrinter = (*BytesOutputPrinter)(nil)

type BytesOutputPrinter struct {
bytesEncoding string
registry *fcproto.Registry
}

func NewBytesOutputPrinter(bytesEncoding string, registry *fcproto.Registry) *BytesOutputPrinter {
return &BytesOutputPrinter{
bytesEncoding: bytesEncoding,
registry: registry,
}
}

func (p *BytesOutputPrinter) PrintTo(input any, out io.Writer) error {
if pbblock, ok := input.(*pbbstream.Block); ok {
return p.printBytes(pbblock.Payload.Value, out)
}

if v, ok := input.(*pbfirehose.Response); ok {
return p.printBytes(v.Block.Value, out)
}

if v, ok := input.(*pbfirehose.SingleBlockResponse); ok {
return p.printBytes(v.Block.Value, out)
}

if v, ok := input.(proto.Message); ok {
data, err := proto.Marshal(v)
if err != nil {
return fmt.Errorf("unable to marshal proto message: %w", err)
}

return p.printBytes(data, out)
}

return fmt.Errorf("unsupported type %T", input)
}

var base64Encoding = base64.StdEncoding

func (p *BytesOutputPrinter) printBytes(data []byte, out io.Writer) error {
var err error
switch p.bytesEncoding {
case "hex":
err = p.printBytesHex(data, out)
case "base58":
err = p.printBytesBase58(data, out)
case "base64":
err = p.printBytesBase64(data, out)
default:
return fmt.Errorf("unsupported bytes encoding %q", p.bytesEncoding)
}
if err != nil {
return fmt.Errorf("unable to print bytes: %w", err)
}

return writeStringToWriter(out, "")
}

func (p *BytesOutputPrinter) printBytesHex(data []byte, out io.Writer) error {
encoder := hex.NewEncoder(out)
_, err := encoder.Write(data)
return err
}

func (p *BytesOutputPrinter) printBytesBase58(data []byte, out io.Writer) error {
return writeStringToWriter(out, base58.Encode(data))
}

func (p *BytesOutputPrinter) printBytesBase64(data []byte, out io.Writer) error {
encoder := base64.NewEncoder(base64Encoding, out)
// This flushes the base64 encoder but doesn't close the underlying writer, which is
// what we want here
defer encoder.Close()

_, err := encoder.Write(data)
return err
}
8 changes: 7 additions & 1 deletion cmd/tools/print/printer_enum.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 10 additions & 4 deletions cmd/tools/tools.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,21 +41,27 @@ func ConfigureToolsCmd[B firecore.Block](
tracer logging.Tracer,
) error {
if flags := ToolsCmd.PersistentFlags(); flags != nil {
flags.String("output", "", cli.Dedent(`
flags.StringP("output", "o", "", cli.Dedent(`
The default output printer to use to print responses and blocks across
tools sub-command.
If defined, has precedence over tools specific flags. Bytes encoding is
tried to be respected if possible, protojson and protojsonl are always
using base64 today for compatibility across Protobuf supported languages.
tried to be respected if possible. The 'protojson' and 'protojsonl' output
are always using base64 for bytes values today for compatibility across
Protobuf supported languages. The 'bytes' output is using the bytes-encoding
flag value to determine how to encode Protobuf bytes to the console.
JSON and JSONL have the caveat to print enum value using the integer value
instead of the name which would be more convenient.
ProtoJSON and ProtoJSONL being able to print only Protobuf messages, they
are refused on commands that are not returning Protobuf messages.
One of: text, json, jsonl, protojson, protojsonl
The 'bytes' output marshals the Protobuf message to bytes and prints
the bytes as a string for which the encoding is determined by the
--bytes-encoding flag value, hexadecimal by default.
One of: text, json, jsonl, protojson, protojsonl, bytes
`))

flags.String("bytes-encoding", "hex", "Encoding for bytes fields when printing in 'text', 'json' or 'jsonl' --output, either 'hex', 'base58' or 'base64'")
Expand Down

0 comments on commit b2c6312

Please sign in to comment.