Skip to content

Commit 03d4559

Browse files
author
Jason Yellick
committed
[FAB-8025] proto_encode/decode configtxlator opts
Currently, configtxlator only exposes its proto encoding/decoding functionality through a REST interface. Although this is generically useful for applications written in other programming languages, it makes CLI usage painfully dependant on curl. This CR simply allows configtxlator to be run in a CLI fashion without starting up the REST server. Change-Id: Ie02a690271e6e0de95e11187c59c4ab04bde7eaa Signed-off-by: Jason Yellick <jyellick@us.ibm.com>
1 parent ab837c1 commit 03d4559

File tree

1 file changed

+81
-1
lines changed

1 file changed

+81
-1
lines changed

common/tools/configtxlator/main.go

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,18 @@ package main
1818

1919
import (
2020
"fmt"
21+
"io/ioutil"
2122
"net/http"
2223
"os"
24+
"reflect"
2325

2426
"github.com/hyperledger/fabric/common/tools/configtxlator/metadata"
2527
"github.com/hyperledger/fabric/common/tools/configtxlator/rest"
28+
"github.com/hyperledger/fabric/common/tools/protolator"
29+
30+
"github.com/golang/protobuf/proto"
2631
"github.com/op/go-logging"
32+
"github.com/pkg/errors"
2733
"gopkg.in/alecthomas/kingpin.v2"
2834
)
2935

@@ -37,6 +43,16 @@ var (
3743
hostname = start.Flag("hostname", "The hostname or IP on which the REST server will listen").Default("0.0.0.0").String()
3844
port = start.Flag("port", "The port on which the REST server will listen").Default("7059").Int()
3945

46+
protoEncode = app.Command("proto_encode", "Converts a JSON document to protobuf.")
47+
protoEncodeType = protoEncode.Flag("type", "The type of protobuf structure to encode to. For example, 'common.Config'.").Required().String()
48+
protoEncodeSource = protoEncode.Flag("input", "A file containing the JSON document.").Default(os.Stdin.Name()).File()
49+
protoEncodeDest = protoEncode.Flag("output", "A file to write the output to.").Default(os.Stdout.Name()).OpenFile(os.O_RDWR|os.O_CREATE, 0600)
50+
51+
protoDecode = app.Command("proto_decode", "Converts a proto message to JSON.")
52+
protoDecodeType = protoDecode.Flag("type", "The type of protobuf structure to decode from. For example, 'common.Config'.").Required().String()
53+
protoDecodeSource = protoDecode.Flag("input", "A file containing the proto message.").Default(os.Stdin.Name()).File()
54+
protoDecodeDest = protoDecode.Flag("output", "A file to write the JSON document to.").Default(os.Stdout.Name()).OpenFile(os.O_RDWR|os.O_CREATE, 0600)
55+
4056
version = app.Command("version", "Show version information")
4157
)
4258

@@ -46,7 +62,21 @@ func main() {
4662
// "start" command
4763
case start.FullCommand():
4864
startServer(fmt.Sprintf("%s:%d", *hostname, *port))
49-
65+
// "proto_encode" command
66+
case protoEncode.FullCommand():
67+
defer (*protoEncodeSource).Close()
68+
defer (*protoEncodeDest).Close()
69+
err := encodeProto(*protoEncodeType, *protoEncodeSource, *protoEncodeDest)
70+
if err != nil {
71+
app.Fatalf("Error decoding: %s", err)
72+
}
73+
case protoDecode.FullCommand():
74+
defer (*protoDecodeSource).Close()
75+
defer (*protoDecodeDest).Close()
76+
err := decodeProto(*protoDecodeType, *protoDecodeSource, *protoDecodeDest)
77+
if err != nil {
78+
app.Fatalf("Error decoding: %s", err)
79+
}
5080
// "version" command
5181
case version.FullCommand():
5282
printVersion()
@@ -64,3 +94,53 @@ func startServer(address string) {
6494
func printVersion() {
6595
fmt.Println(metadata.GetVersionInfo())
6696
}
97+
98+
func encodeProto(msgName string, input, output *os.File) error {
99+
msgType := proto.MessageType(msgName)
100+
if msgType == nil {
101+
return errors.Errorf("message of type %s unknown", msgType)
102+
}
103+
msg := reflect.New(msgType.Elem()).Interface().(proto.Message)
104+
105+
err := protolator.DeepUnmarshalJSON(input, msg)
106+
if err != nil {
107+
return errors.Wrapf(err, "error decoding input")
108+
}
109+
110+
out, err := proto.Marshal(msg)
111+
if err != nil {
112+
return errors.Wrapf(err, "error marshaling")
113+
}
114+
115+
_, err = output.Write(out)
116+
if err != nil {
117+
return errors.Wrapf(err, "error writing output")
118+
}
119+
120+
return nil
121+
}
122+
123+
func decodeProto(msgName string, input, output *os.File) error {
124+
msgType := proto.MessageType(msgName)
125+
if msgType == nil {
126+
return errors.Errorf("message of type %s unknown", msgType)
127+
}
128+
msg := reflect.New(msgType.Elem()).Interface().(proto.Message)
129+
130+
in, err := ioutil.ReadAll(input)
131+
if err != nil {
132+
return errors.Wrapf(err, "error reading input")
133+
}
134+
135+
err = proto.Unmarshal(in, msg)
136+
if err != nil {
137+
return errors.Wrapf(err, "error unmarshaling")
138+
}
139+
140+
err = protolator.DeepMarshalJSON(output, msg)
141+
if err != nil {
142+
return errors.Wrapf(err, "error encoding output")
143+
}
144+
145+
return nil
146+
}

0 commit comments

Comments
 (0)