proto: convert grpc to twirp

This commit is contained in:
Cadey Ratio 2018-01-21 07:22:13 -08:00
parent d0695adfb6
commit d2cb12201e
29 changed files with 6105 additions and 487 deletions

14
Gopkg.lock generated
View File

@ -206,10 +206,12 @@
branch = "master"
name = "github.com/golang/protobuf"
packages = [
"jsonpb",
"proto",
"ptypes",
"ptypes/any",
"ptypes/duration",
"ptypes/struct",
"ptypes/timestamp"
]
revision = "1e59b77b52bf8e4b449a57e6f79f21226d571845"
@ -589,6 +591,16 @@
revision = "98aa888b79d8de04afe0fccf45ed10594efc858b"
version = "v1.1"
[[projects]]
name = "github.com/twitchtv/twirp"
packages = [
".",
"ctxsetters",
"internal/contextkeys"
]
revision = "db96cdf354e8dc053e5ee5fe890bb0a7f18123ab"
version = "v5.0.0"
[[projects]]
name = "github.com/ulikunitz/xz"
packages = [
@ -753,6 +765,6 @@
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "97c8282ef9b3abed71907d17ccf38379134714596610880b02d5ca03be634678"
inputs-digest = "51866d1bd0089290b4562a563c65db61b4973e66be0e14297f0680059dbdf138"
solver-name = "gps-cdcl"
solver-version = 1

View File

@ -164,8 +164,7 @@ func Tools(ctx context.Context) {
tools := []string{
"github.com/golang/dep/cmd/dep",
"github.com/golang/protobuf/protoc-gen-go",
// "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway",
// "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger",
"github.com/twitchtv/twirp/protoc-gen-twirp",
}
for _, t := range tools {

View File

@ -1 +0,0 @@
package routeclient

View File

@ -1,2 +0,0 @@
// Package routeclient is a higer level convenience wrapper around the RPC layer for route.
package routeclient

View File

@ -1,7 +1,6 @@
#!/bin/bash
protoc -I/usr/local/include -I. \
-I$GOPATH/src \
-I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \
--go_out=Mgoogle/api/annotations.proto=github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis/google/api,plugins=grpc:. \
protoc -I. \
--go_out=:. \
--twirp_out=. \
route.proto

View File

@ -26,11 +26,6 @@ import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import (
context "golang.org/x/net/context"
grpc "google.golang.org/grpc"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
@ -352,478 +347,6 @@ func init() {
proto.RegisterType((*BackendID)(nil), "route.BackendID")
}
// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConn
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion4
// Client API for Routes service
type RoutesClient interface {
// Get fetches a single route based on the Host or ID.
Get(ctx context.Context, in *GetRouteRequest, opts ...grpc.CallOption) (*Route, error)
// GetAll fetches all of the routes that the user owns.
GetAll(ctx context.Context, in *Nil, opts ...grpc.CallOption) (*GetAllRoutesResponse, error)
// Put creates a new route based on user-supplied details.
Put(ctx context.Context, in *Route, opts ...grpc.CallOption) (*Route, error)
// Delete removes a route.
Delete(ctx context.Context, in *Route, opts ...grpc.CallOption) (*Nil, error)
}
type routesClient struct {
cc *grpc.ClientConn
}
func NewRoutesClient(cc *grpc.ClientConn) RoutesClient {
return &routesClient{cc}
}
func (c *routesClient) Get(ctx context.Context, in *GetRouteRequest, opts ...grpc.CallOption) (*Route, error) {
out := new(Route)
err := grpc.Invoke(ctx, "/route.Routes/Get", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *routesClient) GetAll(ctx context.Context, in *Nil, opts ...grpc.CallOption) (*GetAllRoutesResponse, error) {
out := new(GetAllRoutesResponse)
err := grpc.Invoke(ctx, "/route.Routes/GetAll", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *routesClient) Put(ctx context.Context, in *Route, opts ...grpc.CallOption) (*Route, error) {
out := new(Route)
err := grpc.Invoke(ctx, "/route.Routes/Put", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *routesClient) Delete(ctx context.Context, in *Route, opts ...grpc.CallOption) (*Nil, error) {
out := new(Nil)
err := grpc.Invoke(ctx, "/route.Routes/Delete", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// Server API for Routes service
type RoutesServer interface {
// Get fetches a single route based on the Host or ID.
Get(context.Context, *GetRouteRequest) (*Route, error)
// GetAll fetches all of the routes that the user owns.
GetAll(context.Context, *Nil) (*GetAllRoutesResponse, error)
// Put creates a new route based on user-supplied details.
Put(context.Context, *Route) (*Route, error)
// Delete removes a route.
Delete(context.Context, *Route) (*Nil, error)
}
func RegisterRoutesServer(s *grpc.Server, srv RoutesServer) {
s.RegisterService(&_Routes_serviceDesc, srv)
}
func _Routes_Get_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetRouteRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(RoutesServer).Get(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/route.Routes/Get",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(RoutesServer).Get(ctx, req.(*GetRouteRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Routes_GetAll_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(Nil)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(RoutesServer).GetAll(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/route.Routes/GetAll",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(RoutesServer).GetAll(ctx, req.(*Nil))
}
return interceptor(ctx, in, info, handler)
}
func _Routes_Put_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(Route)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(RoutesServer).Put(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/route.Routes/Put",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(RoutesServer).Put(ctx, req.(*Route))
}
return interceptor(ctx, in, info, handler)
}
func _Routes_Delete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(Route)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(RoutesServer).Delete(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/route.Routes/Delete",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(RoutesServer).Delete(ctx, req.(*Route))
}
return interceptor(ctx, in, info, handler)
}
var _Routes_serviceDesc = grpc.ServiceDesc{
ServiceName: "route.Routes",
HandlerType: (*RoutesServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "Get",
Handler: _Routes_Get_Handler,
},
{
MethodName: "GetAll",
Handler: _Routes_GetAll_Handler,
},
{
MethodName: "Put",
Handler: _Routes_Put_Handler,
},
{
MethodName: "Delete",
Handler: _Routes_Delete_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "route.proto",
}
// Client API for Tokens service
type TokensClient interface {
Get(ctx context.Context, in *GetTokenRequest, opts ...grpc.CallOption) (*Token, error)
GetAll(ctx context.Context, in *Nil, opts ...grpc.CallOption) (*TokenSet, error)
Put(ctx context.Context, in *Token, opts ...grpc.CallOption) (*Token, error)
Delete(ctx context.Context, in *Token, opts ...grpc.CallOption) (*Nil, error)
Deactivate(ctx context.Context, in *Token, opts ...grpc.CallOption) (*Nil, error)
}
type tokensClient struct {
cc *grpc.ClientConn
}
func NewTokensClient(cc *grpc.ClientConn) TokensClient {
return &tokensClient{cc}
}
func (c *tokensClient) Get(ctx context.Context, in *GetTokenRequest, opts ...grpc.CallOption) (*Token, error) {
out := new(Token)
err := grpc.Invoke(ctx, "/route.Tokens/Get", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *tokensClient) GetAll(ctx context.Context, in *Nil, opts ...grpc.CallOption) (*TokenSet, error) {
out := new(TokenSet)
err := grpc.Invoke(ctx, "/route.Tokens/GetAll", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *tokensClient) Put(ctx context.Context, in *Token, opts ...grpc.CallOption) (*Token, error) {
out := new(Token)
err := grpc.Invoke(ctx, "/route.Tokens/Put", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *tokensClient) Delete(ctx context.Context, in *Token, opts ...grpc.CallOption) (*Nil, error) {
out := new(Nil)
err := grpc.Invoke(ctx, "/route.Tokens/Delete", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *tokensClient) Deactivate(ctx context.Context, in *Token, opts ...grpc.CallOption) (*Nil, error) {
out := new(Nil)
err := grpc.Invoke(ctx, "/route.Tokens/Deactivate", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// Server API for Tokens service
type TokensServer interface {
Get(context.Context, *GetTokenRequest) (*Token, error)
GetAll(context.Context, *Nil) (*TokenSet, error)
Put(context.Context, *Token) (*Token, error)
Delete(context.Context, *Token) (*Nil, error)
Deactivate(context.Context, *Token) (*Nil, error)
}
func RegisterTokensServer(s *grpc.Server, srv TokensServer) {
s.RegisterService(&_Tokens_serviceDesc, srv)
}
func _Tokens_Get_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetTokenRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(TokensServer).Get(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/route.Tokens/Get",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(TokensServer).Get(ctx, req.(*GetTokenRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Tokens_GetAll_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(Nil)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(TokensServer).GetAll(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/route.Tokens/GetAll",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(TokensServer).GetAll(ctx, req.(*Nil))
}
return interceptor(ctx, in, info, handler)
}
func _Tokens_Put_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(Token)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(TokensServer).Put(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/route.Tokens/Put",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(TokensServer).Put(ctx, req.(*Token))
}
return interceptor(ctx, in, info, handler)
}
func _Tokens_Delete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(Token)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(TokensServer).Delete(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/route.Tokens/Delete",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(TokensServer).Delete(ctx, req.(*Token))
}
return interceptor(ctx, in, info, handler)
}
func _Tokens_Deactivate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(Token)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(TokensServer).Deactivate(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/route.Tokens/Deactivate",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(TokensServer).Deactivate(ctx, req.(*Token))
}
return interceptor(ctx, in, info, handler)
}
var _Tokens_serviceDesc = grpc.ServiceDesc{
ServiceName: "route.Tokens",
HandlerType: (*TokensServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "Get",
Handler: _Tokens_Get_Handler,
},
{
MethodName: "GetAll",
Handler: _Tokens_GetAll_Handler,
},
{
MethodName: "Put",
Handler: _Tokens_Put_Handler,
},
{
MethodName: "Delete",
Handler: _Tokens_Delete_Handler,
},
{
MethodName: "Deactivate",
Handler: _Tokens_Deactivate_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "route.proto",
}
// Client API for Backends service
type BackendsClient interface {
List(ctx context.Context, in *BackendSelector, opts ...grpc.CallOption) (*BackendList, error)
Kill(ctx context.Context, in *BackendID, opts ...grpc.CallOption) (*Nil, error)
}
type backendsClient struct {
cc *grpc.ClientConn
}
func NewBackendsClient(cc *grpc.ClientConn) BackendsClient {
return &backendsClient{cc}
}
func (c *backendsClient) List(ctx context.Context, in *BackendSelector, opts ...grpc.CallOption) (*BackendList, error) {
out := new(BackendList)
err := grpc.Invoke(ctx, "/route.Backends/List", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *backendsClient) Kill(ctx context.Context, in *BackendID, opts ...grpc.CallOption) (*Nil, error) {
out := new(Nil)
err := grpc.Invoke(ctx, "/route.Backends/Kill", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// Server API for Backends service
type BackendsServer interface {
List(context.Context, *BackendSelector) (*BackendList, error)
Kill(context.Context, *BackendID) (*Nil, error)
}
func RegisterBackendsServer(s *grpc.Server, srv BackendsServer) {
s.RegisterService(&_Backends_serviceDesc, srv)
}
func _Backends_List_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(BackendSelector)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(BackendsServer).List(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/route.Backends/List",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(BackendsServer).List(ctx, req.(*BackendSelector))
}
return interceptor(ctx, in, info, handler)
}
func _Backends_Kill_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(BackendID)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(BackendsServer).Kill(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/route.Backends/Kill",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(BackendsServer).Kill(ctx, req.(*BackendID))
}
return interceptor(ctx, in, info, handler)
}
var _Backends_serviceDesc = grpc.ServiceDesc{
ServiceName: "route.Backends",
HandlerType: (*BackendsServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "List",
Handler: _Backends_List_Handler,
},
{
MethodName: "Kill",
Handler: _Backends_Kill_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "route.proto",
}
func init() { proto.RegisterFile("route.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{

2486
proto/route.twirp.go Normal file

File diff suppressed because it is too large Load Diff

1082
vendor/github.com/golang/protobuf/jsonpb/jsonpb.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

897
vendor/github.com/golang/protobuf/jsonpb/jsonpb_test.go generated vendored Normal file
View File

@ -0,0 +1,897 @@
// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2015 The Go Authors. All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package jsonpb
import (
"bytes"
"encoding/json"
"io"
"math"
"reflect"
"strings"
"testing"
"github.com/golang/protobuf/proto"
pb "github.com/golang/protobuf/jsonpb/jsonpb_test_proto"
proto3pb "github.com/golang/protobuf/proto/proto3_proto"
"github.com/golang/protobuf/ptypes"
anypb "github.com/golang/protobuf/ptypes/any"
durpb "github.com/golang/protobuf/ptypes/duration"
stpb "github.com/golang/protobuf/ptypes/struct"
tspb "github.com/golang/protobuf/ptypes/timestamp"
wpb "github.com/golang/protobuf/ptypes/wrappers"
)
var (
marshaler = Marshaler{}
marshalerAllOptions = Marshaler{
Indent: " ",
}
simpleObject = &pb.Simple{
OInt32: proto.Int32(-32),
OInt64: proto.Int64(-6400000000),
OUint32: proto.Uint32(32),
OUint64: proto.Uint64(6400000000),
OSint32: proto.Int32(-13),
OSint64: proto.Int64(-2600000000),
OFloat: proto.Float32(3.14),
ODouble: proto.Float64(6.02214179e23),
OBool: proto.Bool(true),
OString: proto.String("hello \"there\""),
OBytes: []byte("beep boop"),
}
simpleObjectJSON = `{` +
`"oBool":true,` +
`"oInt32":-32,` +
`"oInt64":"-6400000000",` +
`"oUint32":32,` +
`"oUint64":"6400000000",` +
`"oSint32":-13,` +
`"oSint64":"-2600000000",` +
`"oFloat":3.14,` +
`"oDouble":6.02214179e+23,` +
`"oString":"hello \"there\"",` +
`"oBytes":"YmVlcCBib29w"` +
`}`
simpleObjectPrettyJSON = `{
"oBool": true,
"oInt32": -32,
"oInt64": "-6400000000",
"oUint32": 32,
"oUint64": "6400000000",
"oSint32": -13,
"oSint64": "-2600000000",
"oFloat": 3.14,
"oDouble": 6.02214179e+23,
"oString": "hello \"there\"",
"oBytes": "YmVlcCBib29w"
}`
repeatsObject = &pb.Repeats{
RBool: []bool{true, false, true},
RInt32: []int32{-3, -4, -5},
RInt64: []int64{-123456789, -987654321},
RUint32: []uint32{1, 2, 3},
RUint64: []uint64{6789012345, 3456789012},
RSint32: []int32{-1, -2, -3},
RSint64: []int64{-6789012345, -3456789012},
RFloat: []float32{3.14, 6.28},
RDouble: []float64{299792458 * 1e20, 6.62606957e-34},
RString: []string{"happy", "days"},
RBytes: [][]byte{[]byte("skittles"), []byte("m&m's")},
}
repeatsObjectJSON = `{` +
`"rBool":[true,false,true],` +
`"rInt32":[-3,-4,-5],` +
`"rInt64":["-123456789","-987654321"],` +
`"rUint32":[1,2,3],` +
`"rUint64":["6789012345","3456789012"],` +
`"rSint32":[-1,-2,-3],` +
`"rSint64":["-6789012345","-3456789012"],` +
`"rFloat":[3.14,6.28],` +
`"rDouble":[2.99792458e+28,6.62606957e-34],` +
`"rString":["happy","days"],` +
`"rBytes":["c2tpdHRsZXM=","bSZtJ3M="]` +
`}`
repeatsObjectPrettyJSON = `{
"rBool": [
true,
false,
true
],
"rInt32": [
-3,
-4,
-5
],
"rInt64": [
"-123456789",
"-987654321"
],
"rUint32": [
1,
2,
3
],
"rUint64": [
"6789012345",
"3456789012"
],
"rSint32": [
-1,
-2,
-3
],
"rSint64": [
"-6789012345",
"-3456789012"
],
"rFloat": [
3.14,
6.28
],
"rDouble": [
2.99792458e+28,
6.62606957e-34
],
"rString": [
"happy",
"days"
],
"rBytes": [
"c2tpdHRsZXM=",
"bSZtJ3M="
]
}`
innerSimple = &pb.Simple{OInt32: proto.Int32(-32)}
innerSimple2 = &pb.Simple{OInt64: proto.Int64(25)}
innerRepeats = &pb.Repeats{RString: []string{"roses", "red"}}
innerRepeats2 = &pb.Repeats{RString: []string{"violets", "blue"}}
complexObject = &pb.Widget{
Color: pb.Widget_GREEN.Enum(),
RColor: []pb.Widget_Color{pb.Widget_RED, pb.Widget_GREEN, pb.Widget_BLUE},
Simple: innerSimple,
RSimple: []*pb.Simple{innerSimple, innerSimple2},
Repeats: innerRepeats,
RRepeats: []*pb.Repeats{innerRepeats, innerRepeats2},
}
complexObjectJSON = `{"color":"GREEN",` +
`"rColor":["RED","GREEN","BLUE"],` +
`"simple":{"oInt32":-32},` +
`"rSimple":[{"oInt32":-32},{"oInt64":"25"}],` +
`"repeats":{"rString":["roses","red"]},` +
`"rRepeats":[{"rString":["roses","red"]},{"rString":["violets","blue"]}]` +
`}`
complexObjectPrettyJSON = `{
"color": "GREEN",
"rColor": [
"RED",
"GREEN",
"BLUE"
],
"simple": {
"oInt32": -32
},
"rSimple": [
{
"oInt32": -32
},
{
"oInt64": "25"
}
],
"repeats": {
"rString": [
"roses",
"red"
]
},
"rRepeats": [
{
"rString": [
"roses",
"red"
]
},
{
"rString": [
"violets",
"blue"
]
}
]
}`
colorPrettyJSON = `{
"color": 2
}`
colorListPrettyJSON = `{
"color": 1000,
"rColor": [
"RED"
]
}`
nummyPrettyJSON = `{
"nummy": {
"1": 2,
"3": 4
}
}`
objjyPrettyJSON = `{
"objjy": {
"1": {
"dub": 1
}
}
}`
realNumber = &pb.Real{Value: proto.Float64(3.14159265359)}
realNumberName = "Pi"
complexNumber = &pb.Complex{Imaginary: proto.Float64(0.5772156649)}
realNumberJSON = `{` +
`"value":3.14159265359,` +
`"[jsonpb.Complex.real_extension]":{"imaginary":0.5772156649},` +
`"[jsonpb.name]":"Pi"` +
`}`
anySimple = &pb.KnownTypes{
An: &anypb.Any{
TypeUrl: "something.example.com/jsonpb.Simple",
Value: []byte{
// &pb.Simple{OBool:true}
1 << 3, 1,
},
},
}
anySimpleJSON = `{"an":{"@type":"something.example.com/jsonpb.Simple","oBool":true}}`
anySimplePrettyJSON = `{
"an": {
"@type": "something.example.com/jsonpb.Simple",
"oBool": true
}
}`
anyWellKnown = &pb.KnownTypes{
An: &anypb.Any{
TypeUrl: "type.googleapis.com/google.protobuf.Duration",
Value: []byte{
// &durpb.Duration{Seconds: 1, Nanos: 212000000 }
1 << 3, 1, // seconds
2 << 3, 0x80, 0xba, 0x8b, 0x65, // nanos
},
},
}
anyWellKnownJSON = `{"an":{"@type":"type.googleapis.com/google.protobuf.Duration","value":"1.212s"}}`
anyWellKnownPrettyJSON = `{
"an": {
"@type": "type.googleapis.com/google.protobuf.Duration",
"value": "1.212s"
}
}`
nonFinites = &pb.NonFinites{
FNan: proto.Float32(float32(math.NaN())),
FPinf: proto.Float32(float32(math.Inf(1))),
FNinf: proto.Float32(float32(math.Inf(-1))),
DNan: proto.Float64(float64(math.NaN())),
DPinf: proto.Float64(float64(math.Inf(1))),
DNinf: proto.Float64(float64(math.Inf(-1))),
}
nonFinitesJSON = `{` +
`"fNan":"NaN",` +
`"fPinf":"Infinity",` +
`"fNinf":"-Infinity",` +
`"dNan":"NaN",` +
`"dPinf":"Infinity",` +
`"dNinf":"-Infinity"` +
`}`
)
func init() {
if err := proto.SetExtension(realNumber, pb.E_Name, &realNumberName); err != nil {
panic(err)
}
if err := proto.SetExtension(realNumber, pb.E_Complex_RealExtension, complexNumber); err != nil {
panic(err)
}
}
var marshalingTests = []struct {
desc string
marshaler Marshaler
pb proto.Message
json string
}{
{"simple flat object", marshaler, simpleObject, simpleObjectJSON},
{"simple pretty object", marshalerAllOptions, simpleObject, simpleObjectPrettyJSON},
{"non-finite floats fields object", marshaler, nonFinites, nonFinitesJSON},
{"repeated fields flat object", marshaler, repeatsObject, repeatsObjectJSON},
{"repeated fields pretty object", marshalerAllOptions, repeatsObject, repeatsObjectPrettyJSON},
{"nested message/enum flat object", marshaler, complexObject, complexObjectJSON},
{"nested message/enum pretty object", marshalerAllOptions, complexObject, complexObjectPrettyJSON},
{"enum-string flat object", Marshaler{},
&pb.Widget{Color: pb.Widget_BLUE.Enum()}, `{"color":"BLUE"}`},
{"enum-value pretty object", Marshaler{EnumsAsInts: true, Indent: " "},
&pb.Widget{Color: pb.Widget_BLUE.Enum()}, colorPrettyJSON},
{"unknown enum value object", marshalerAllOptions,
&pb.Widget{Color: pb.Widget_Color(1000).Enum(), RColor: []pb.Widget_Color{pb.Widget_RED}}, colorListPrettyJSON},
{"repeated proto3 enum", Marshaler{},
&proto3pb.Message{RFunny: []proto3pb.Message_Humour{
proto3pb.Message_PUNS,
proto3pb.Message_SLAPSTICK,
}},
`{"rFunny":["PUNS","SLAPSTICK"]}`},
{"repeated proto3 enum as int", Marshaler{EnumsAsInts: true},
&proto3pb.Message{RFunny: []proto3pb.Message_Humour{
proto3pb.Message_PUNS,
proto3pb.Message_SLAPSTICK,
}},
`{"rFunny":[1,2]}`},
{"empty value", marshaler, &pb.Simple3{}, `{}`},
{"empty value emitted", Marshaler{EmitDefaults: true}, &pb.Simple3{}, `{"dub":0}`},
{"empty repeated emitted", Marshaler{EmitDefaults: true}, &pb.SimpleSlice3{}, `{"slices":[]}`},
{"empty map emitted", Marshaler{EmitDefaults: true}, &pb.SimpleMap3{}, `{"stringy":{}}`},
{"nested struct null", Marshaler{EmitDefaults: true}, &pb.SimpleNull3{}, `{"simple":null}`},
{"map<int64, int32>", marshaler, &pb.Mappy{Nummy: map[int64]int32{1: 2, 3: 4}}, `{"nummy":{"1":2,"3":4}}`},
{"map<int64, int32>", marshalerAllOptions, &pb.Mappy{Nummy: map[int64]int32{1: 2, 3: 4}}, nummyPrettyJSON},
{"map<string, string>", marshaler,
&pb.Mappy{Strry: map[string]string{`"one"`: "two", "three": "four"}},
`{"strry":{"\"one\"":"two","three":"four"}}`},
{"map<int32, Object>", marshaler,
&pb.Mappy{Objjy: map[int32]*pb.Simple3{1: {Dub: 1}}}, `{"objjy":{"1":{"dub":1}}}`},
{"map<int32, Object>", marshalerAllOptions,
&pb.Mappy{Objjy: map[int32]*pb.Simple3{1: {Dub: 1}}}, objjyPrettyJSON},
{"map<int64, string>", marshaler, &pb.Mappy{Buggy: map[int64]string{1234: "yup"}},
`{"buggy":{"1234":"yup"}}`},
{"map<bool, bool>", marshaler, &pb.Mappy{Booly: map[bool]bool{false: true}}, `{"booly":{"false":true}}`},
// TODO: This is broken.
//{"map<string, enum>", marshaler, &pb.Mappy{Enumy: map[string]pb.Numeral{"XIV": pb.Numeral_ROMAN}}, `{"enumy":{"XIV":"ROMAN"}`},
{"map<string, enum as int>", Marshaler{EnumsAsInts: true}, &pb.Mappy{Enumy: map[string]pb.Numeral{"XIV": pb.Numeral_ROMAN}}, `{"enumy":{"XIV":2}}`},
{"map<int32, bool>", marshaler, &pb.Mappy{S32Booly: map[int32]bool{1: true, 3: false, 10: true, 12: false}}, `{"s32booly":{"1":true,"3":false,"10":true,"12":false}}`},
{"map<int64, bool>", marshaler, &pb.Mappy{S64Booly: map[int64]bool{1: true, 3: false, 10: true, 12: false}}, `{"s64booly":{"1":true,"3":false,"10":true,"12":false}}`},
{"map<uint32, bool>", marshaler, &pb.Mappy{U32Booly: map[uint32]bool{1: true, 3: false, 10: true, 12: false}}, `{"u32booly":{"1":true,"3":false,"10":true,"12":false}}`},
{"map<uint64, bool>", marshaler, &pb.Mappy{U64Booly: map[uint64]bool{1: true, 3: false, 10: true, 12: false}}, `{"u64booly":{"1":true,"3":false,"10":true,"12":false}}`},
{"proto2 map<int64, string>", marshaler, &pb.Maps{MInt64Str: map[int64]string{213: "cat"}},
`{"mInt64Str":{"213":"cat"}}`},
{"proto2 map<bool, Object>", marshaler,
&pb.Maps{MBoolSimple: map[bool]*pb.Simple{true: {OInt32: proto.Int32(1)}}},
`{"mBoolSimple":{"true":{"oInt32":1}}}`},
{"oneof, not set", marshaler, &pb.MsgWithOneof{}, `{}`},
{"oneof, set", marshaler, &pb.MsgWithOneof{Union: &pb.MsgWithOneof_Title{"Grand Poobah"}}, `{"title":"Grand Poobah"}`},
{"force orig_name", Marshaler{OrigName: true}, &pb.Simple{OInt32: proto.Int32(4)},
`{"o_int32":4}`},
{"proto2 extension", marshaler, realNumber, realNumberJSON},
{"Any with message", marshaler, anySimple, anySimpleJSON},
{"Any with message and indent", marshalerAllOptions, anySimple, anySimplePrettyJSON},
{"Any with WKT", marshaler, anyWellKnown, anyWellKnownJSON},
{"Any with WKT and indent", marshalerAllOptions, anyWellKnown, anyWellKnownPrettyJSON},
{"Duration", marshaler, &pb.KnownTypes{Dur: &durpb.Duration{Seconds: 3}}, `{"dur":"3.000s"}`},
{"Duration", marshaler, &pb.KnownTypes{Dur: &durpb.Duration{Seconds: 100000000, Nanos: 1}}, `{"dur":"100000000.000000001s"}`},
{"Struct", marshaler, &pb.KnownTypes{St: &stpb.Struct{
Fields: map[string]*stpb.Value{
"one": {Kind: &stpb.Value_StringValue{"loneliest number"}},
"two": {Kind: &stpb.Value_NullValue{stpb.NullValue_NULL_VALUE}},
},
}}, `{"st":{"one":"loneliest number","two":null}}`},
{"empty ListValue", marshaler, &pb.KnownTypes{Lv: &stpb.ListValue{}}, `{"lv":[]}`},
{"basic ListValue", marshaler, &pb.KnownTypes{Lv: &stpb.ListValue{Values: []*stpb.Value{
{Kind: &stpb.Value_StringValue{"x"}},
{Kind: &stpb.Value_NullValue{}},
{Kind: &stpb.Value_NumberValue{3}},
{Kind: &stpb.Value_BoolValue{true}},
}}}, `{"lv":["x",null,3,true]}`},
{"Timestamp", marshaler, &pb.KnownTypes{Ts: &tspb.Timestamp{Seconds: 14e8, Nanos: 21e6}}, `{"ts":"2014-05-13T16:53:20.021Z"}`},
{"number Value", marshaler, &pb.KnownTypes{Val: &stpb.Value{Kind: &stpb.Value_NumberValue{1}}}, `{"val":1}`},
{"null Value", marshaler, &pb.KnownTypes{Val: &stpb.Value{Kind: &stpb.Value_NullValue{stpb.NullValue_NULL_VALUE}}}, `{"val":null}`},
{"string number value", marshaler, &pb.KnownTypes{Val: &stpb.Value{Kind: &stpb.Value_StringValue{"9223372036854775807"}}}, `{"val":"9223372036854775807"}`},
{"list of lists Value", marshaler, &pb.KnownTypes{Val: &stpb.Value{
Kind: &stpb.Value_ListValue{&stpb.ListValue{
Values: []*stpb.Value{
{Kind: &stpb.Value_StringValue{"x"}},
{Kind: &stpb.Value_ListValue{&stpb.ListValue{
Values: []*stpb.Value{
{Kind: &stpb.Value_ListValue{&stpb.ListValue{
Values: []*stpb.Value{{Kind: &stpb.Value_StringValue{"y"}}},
}}},
{Kind: &stpb.Value_StringValue{"z"}},
},
}}},
},
}},
}}, `{"val":["x",[["y"],"z"]]}`},
{"DoubleValue", marshaler, &pb.KnownTypes{Dbl: &wpb.DoubleValue{Value: 1.2}}, `{"dbl":1.2}`},
{"FloatValue", marshaler, &pb.KnownTypes{Flt: &wpb.FloatValue{Value: 1.2}}, `{"flt":1.2}`},
{"Int64Value", marshaler, &pb.KnownTypes{I64: &wpb.Int64Value{Value: -3}}, `{"i64":"-3"}`},
{"UInt64Value", marshaler, &pb.KnownTypes{U64: &wpb.UInt64Value{Value: 3}}, `{"u64":"3"}`},
{"Int32Value", marshaler, &pb.KnownTypes{I32: &wpb.Int32Value{Value: -4}}, `{"i32":-4}`},
{"UInt32Value", marshaler, &pb.KnownTypes{U32: &wpb.UInt32Value{Value: 4}}, `{"u32":4}`},
{"BoolValue", marshaler, &pb.KnownTypes{Bool: &wpb.BoolValue{Value: true}}, `{"bool":true}`},
{"StringValue", marshaler, &pb.KnownTypes{Str: &wpb.StringValue{Value: "plush"}}, `{"str":"plush"}`},
{"BytesValue", marshaler, &pb.KnownTypes{Bytes: &wpb.BytesValue{Value: []byte("wow")}}, `{"bytes":"d293"}`},
}
func TestMarshaling(t *testing.T) {
for _, tt := range marshalingTests {
json, err := tt.marshaler.MarshalToString(tt.pb)
if err != nil {
t.Errorf("%s: marshaling error: %v", tt.desc, err)
} else if tt.json != json {
t.Errorf("%s: got [%v] want [%v]", tt.desc, json, tt.json)
}
}
}
func TestMarshalJSONPBMarshaler(t *testing.T) {
rawJson := `{ "foo": "bar", "baz": [0, 1, 2, 3] }`
msg := dynamicMessage{rawJson: rawJson}
str, err := new(Marshaler).MarshalToString(&msg)
if err != nil {
t.Errorf("an unexpected error occurred when marshalling JSONPBMarshaler: %v", err)
}
if str != rawJson {
t.Errorf("marshalling JSON produced incorrect output: got %s, wanted %s", str, rawJson)
}
}
func TestMarshalAnyJSONPBMarshaler(t *testing.T) {
msg := dynamicMessage{rawJson: `{ "foo": "bar", "baz": [0, 1, 2, 3] }`}
a, err := ptypes.MarshalAny(&msg)
if err != nil {
t.Errorf("an unexpected error occurred when marshalling to Any: %v", err)
}
str, err := new(Marshaler).MarshalToString(a)
if err != nil {
t.Errorf("an unexpected error occurred when marshalling Any to JSON: %v", err)
}
// after custom marshaling, it's round-tripped through JSON decoding/encoding already,
// so the keys are sorted, whitespace is compacted, and "@type" key has been added
expected := `{"@type":"type.googleapis.com/` + dynamicMessageName + `","baz":[0,1,2,3],"foo":"bar"}`
if str != expected {
t.Errorf("marshalling JSON produced incorrect output: got %s, wanted %s", str, expected)
}
}
var unmarshalingTests = []struct {
desc string
unmarshaler Unmarshaler
json string
pb proto.Message
}{
{"simple flat object", Unmarshaler{}, simpleObjectJSON, simpleObject},
{"simple pretty object", Unmarshaler{}, simpleObjectPrettyJSON, simpleObject},
{"repeated fields flat object", Unmarshaler{}, repeatsObjectJSON, repeatsObject},
{"repeated fields pretty object", Unmarshaler{}, repeatsObjectPrettyJSON, repeatsObject},
{"nested message/enum flat object", Unmarshaler{}, complexObjectJSON, complexObject},
{"nested message/enum pretty object", Unmarshaler{}, complexObjectPrettyJSON, complexObject},
{"enum-string object", Unmarshaler{}, `{"color":"BLUE"}`, &pb.Widget{Color: pb.Widget_BLUE.Enum()}},
{"enum-value object", Unmarshaler{}, "{\n \"color\": 2\n}", &pb.Widget{Color: pb.Widget_BLUE.Enum()}},
{"unknown field with allowed option", Unmarshaler{AllowUnknownFields: true}, `{"unknown": "foo"}`, new(pb.Simple)},
{"proto3 enum string", Unmarshaler{}, `{"hilarity":"PUNS"}`, &proto3pb.Message{Hilarity: proto3pb.Message_PUNS}},
{"proto3 enum value", Unmarshaler{}, `{"hilarity":1}`, &proto3pb.Message{Hilarity: proto3pb.Message_PUNS}},
{"unknown enum value object",
Unmarshaler{},
"{\n \"color\": 1000,\n \"r_color\": [\n \"RED\"\n ]\n}",
&pb.Widget{Color: pb.Widget_Color(1000).Enum(), RColor: []pb.Widget_Color{pb.Widget_RED}}},
{"repeated proto3 enum", Unmarshaler{}, `{"rFunny":["PUNS","SLAPSTICK"]}`,
&proto3pb.Message{RFunny: []proto3pb.Message_Humour{
proto3pb.Message_PUNS,
proto3pb.Message_SLAPSTICK,
}}},
{"repeated proto3 enum as int", Unmarshaler{}, `{"rFunny":[1,2]}`,
&proto3pb.Message{RFunny: []proto3pb.Message_Humour{
proto3pb.Message_PUNS,
proto3pb.Message_SLAPSTICK,
}}},
{"repeated proto3 enum as mix of strings and ints", Unmarshaler{}, `{"rFunny":["PUNS",2]}`,
&proto3pb.Message{RFunny: []proto3pb.Message_Humour{
proto3pb.Message_PUNS,
proto3pb.Message_SLAPSTICK,
}}},
{"unquoted int64 object", Unmarshaler{}, `{"oInt64":-314}`, &pb.Simple{OInt64: proto.Int64(-314)}},
{"unquoted uint64 object", Unmarshaler{}, `{"oUint64":123}`, &pb.Simple{OUint64: proto.Uint64(123)}},
{"NaN", Unmarshaler{}, `{"oDouble":"NaN"}`, &pb.Simple{ODouble: proto.Float64(math.NaN())}},
{"Inf", Unmarshaler{}, `{"oFloat":"Infinity"}`, &pb.Simple{OFloat: proto.Float32(float32(math.Inf(1)))}},
{"-Inf", Unmarshaler{}, `{"oDouble":"-Infinity"}`, &pb.Simple{ODouble: proto.Float64(math.Inf(-1))}},
{"map<int64, int32>", Unmarshaler{}, `{"nummy":{"1":2,"3":4}}`, &pb.Mappy{Nummy: map[int64]int32{1: 2, 3: 4}}},
{"map<string, string>", Unmarshaler{}, `{"strry":{"\"one\"":"two","three":"four"}}`, &pb.Mappy{Strry: map[string]string{`"one"`: "two", "three": "four"}}},
{"map<int32, Object>", Unmarshaler{}, `{"objjy":{"1":{"dub":1}}}`, &pb.Mappy{Objjy: map[int32]*pb.Simple3{1: {Dub: 1}}}},
{"proto2 extension", Unmarshaler{}, realNumberJSON, realNumber},
{"Any with message", Unmarshaler{}, anySimpleJSON, anySimple},
{"Any with message and indent", Unmarshaler{}, anySimplePrettyJSON, anySimple},
{"Any with WKT", Unmarshaler{}, anyWellKnownJSON, anyWellKnown},
{"Any with WKT and indent", Unmarshaler{}, anyWellKnownPrettyJSON, anyWellKnown},
// TODO: This is broken.
//{"map<string, enum>", Unmarshaler{}, `{"enumy":{"XIV":"ROMAN"}`, &pb.Mappy{Enumy: map[string]pb.Numeral{"XIV": pb.Numeral_ROMAN}}},
{"map<string, enum as int>", Unmarshaler{}, `{"enumy":{"XIV":2}}`, &pb.Mappy{Enumy: map[string]pb.Numeral{"XIV": pb.Numeral_ROMAN}}},
{"oneof", Unmarshaler{}, `{"salary":31000}`, &pb.MsgWithOneof{Union: &pb.MsgWithOneof_Salary{31000}}},
{"oneof spec name", Unmarshaler{}, `{"Country":"Australia"}`, &pb.MsgWithOneof{Union: &pb.MsgWithOneof_Country{"Australia"}}},
{"oneof orig_name", Unmarshaler{}, `{"Country":"Australia"}`, &pb.MsgWithOneof{Union: &pb.MsgWithOneof_Country{"Australia"}}},
{"oneof spec name2", Unmarshaler{}, `{"homeAddress":"Australia"}`, &pb.MsgWithOneof{Union: &pb.MsgWithOneof_HomeAddress{"Australia"}}},
{"oneof orig_name2", Unmarshaler{}, `{"home_address":"Australia"}`, &pb.MsgWithOneof{Union: &pb.MsgWithOneof_HomeAddress{"Australia"}}},
{"orig_name input", Unmarshaler{}, `{"o_bool":true}`, &pb.Simple{OBool: proto.Bool(true)}},
{"camelName input", Unmarshaler{}, `{"oBool":true}`, &pb.Simple{OBool: proto.Bool(true)}},
{"Duration", Unmarshaler{}, `{"dur":"3.000s"}`, &pb.KnownTypes{Dur: &durpb.Duration{Seconds: 3}}},
{"null Duration", Unmarshaler{}, `{"dur":null}`, &pb.KnownTypes{Dur: nil}},
{"Timestamp", Unmarshaler{}, `{"ts":"2014-05-13T16:53:20.021Z"}`, &pb.KnownTypes{Ts: &tspb.Timestamp{Seconds: 14e8, Nanos: 21e6}}},
{"PreEpochTimestamp", Unmarshaler{}, `{"ts":"1969-12-31T23:59:58.999999995Z"}`, &pb.KnownTypes{Ts: &tspb.Timestamp{Seconds: -2, Nanos: 999999995}}},
{"ZeroTimeTimestamp", Unmarshaler{}, `{"ts":"0001-01-01T00:00:00Z"}`, &pb.KnownTypes{Ts: &tspb.Timestamp{Seconds: -62135596800, Nanos: 0}}},
{"null Timestamp", Unmarshaler{}, `{"ts":null}`, &pb.KnownTypes{Ts: nil}},
{"null Struct", Unmarshaler{}, `{"st": null}`, &pb.KnownTypes{St: nil}},
{"empty Struct", Unmarshaler{}, `{"st": {}}`, &pb.KnownTypes{St: &stpb.Struct{}}},
{"basic Struct", Unmarshaler{}, `{"st": {"a": "x", "b": null, "c": 3, "d": true}}`, &pb.KnownTypes{St: &stpb.Struct{Fields: map[string]*stpb.Value{
"a": {Kind: &stpb.Value_StringValue{"x"}},
"b": {Kind: &stpb.Value_NullValue{}},
"c": {Kind: &stpb.Value_NumberValue{3}},
"d": {Kind: &stpb.Value_BoolValue{true}},
}}}},
{"nested Struct", Unmarshaler{}, `{"st": {"a": {"b": 1, "c": [{"d": true}, "f"]}}}`, &pb.KnownTypes{St: &stpb.Struct{Fields: map[string]*stpb.Value{
"a": {Kind: &stpb.Value_StructValue{&stpb.Struct{Fields: map[string]*stpb.Value{
"b": {Kind: &stpb.Value_NumberValue{1}},
"c": {Kind: &stpb.Value_ListValue{&stpb.ListValue{Values: []*stpb.Value{
{Kind: &stpb.Value_StructValue{&stpb.Struct{Fields: map[string]*stpb.Value{"d": {Kind: &stpb.Value_BoolValue{true}}}}}},
{Kind: &stpb.Value_StringValue{"f"}},
}}}},
}}}},
}}}},
{"null ListValue", Unmarshaler{}, `{"lv": null}`, &pb.KnownTypes{Lv: nil}},
{"empty ListValue", Unmarshaler{}, `{"lv": []}`, &pb.KnownTypes{Lv: &stpb.ListValue{}}},
{"basic ListValue", Unmarshaler{}, `{"lv": ["x", null, 3, true]}`, &pb.KnownTypes{Lv: &stpb.ListValue{Values: []*stpb.Value{
{Kind: &stpb.Value_StringValue{"x"}},
{Kind: &stpb.Value_NullValue{}},
{Kind: &stpb.Value_NumberValue{3}},
{Kind: &stpb.Value_BoolValue{true}},
}}}},
{"number Value", Unmarshaler{}, `{"val":1}`, &pb.KnownTypes{Val: &stpb.Value{Kind: &stpb.Value_NumberValue{1}}}},
{"null Value", Unmarshaler{}, `{"val":null}`, &pb.KnownTypes{Val: &stpb.Value{Kind: &stpb.Value_NullValue{stpb.NullValue_NULL_VALUE}}}},
{"bool Value", Unmarshaler{}, `{"val":true}`, &pb.KnownTypes{Val: &stpb.Value{Kind: &stpb.Value_BoolValue{true}}}},
{"string Value", Unmarshaler{}, `{"val":"x"}`, &pb.KnownTypes{Val: &stpb.Value{Kind: &stpb.Value_StringValue{"x"}}}},
{"string number value", Unmarshaler{}, `{"val":"9223372036854775807"}`, &pb.KnownTypes{Val: &stpb.Value{Kind: &stpb.Value_StringValue{"9223372036854775807"}}}},
{"list of lists Value", Unmarshaler{}, `{"val":["x", [["y"], "z"]]}`, &pb.KnownTypes{Val: &stpb.Value{
Kind: &stpb.Value_ListValue{&stpb.ListValue{
Values: []*stpb.Value{
{Kind: &stpb.Value_StringValue{"x"}},
{Kind: &stpb.Value_ListValue{&stpb.ListValue{
Values: []*stpb.Value{
{Kind: &stpb.Value_ListValue{&stpb.ListValue{
Values: []*stpb.Value{{Kind: &stpb.Value_StringValue{"y"}}},
}}},
{Kind: &stpb.Value_StringValue{"z"}},
},
}}},
},
}}}}},
{"DoubleValue", Unmarshaler{}, `{"dbl":1.2}`, &pb.KnownTypes{Dbl: &wpb.DoubleValue{Value: 1.2}}},
{"FloatValue", Unmarshaler{}, `{"flt":1.2}`, &pb.KnownTypes{Flt: &wpb.FloatValue{Value: 1.2}}},
{"Int64Value", Unmarshaler{}, `{"i64":"-3"}`, &pb.KnownTypes{I64: &wpb.Int64Value{Value: -3}}},
{"UInt64Value", Unmarshaler{}, `{"u64":"3"}`, &pb.KnownTypes{U64: &wpb.UInt64Value{Value: 3}}},
{"Int32Value", Unmarshaler{}, `{"i32":-4}`, &pb.KnownTypes{I32: &wpb.Int32Value{Value: -4}}},
{"UInt32Value", Unmarshaler{}, `{"u32":4}`, &pb.KnownTypes{U32: &wpb.UInt32Value{Value: 4}}},
{"BoolValue", Unmarshaler{}, `{"bool":true}`, &pb.KnownTypes{Bool: &wpb.BoolValue{Value: true}}},
{"StringValue", Unmarshaler{}, `{"str":"plush"}`, &pb.KnownTypes{Str: &wpb.StringValue{Value: "plush"}}},
{"BytesValue", Unmarshaler{}, `{"bytes":"d293"}`, &pb.KnownTypes{Bytes: &wpb.BytesValue{Value: []byte("wow")}}},
// Ensure that `null` as a value ends up with a nil pointer instead of a [type]Value struct.
{"null DoubleValue", Unmarshaler{}, `{"dbl":null}`, &pb.KnownTypes{Dbl: nil}},
{"null FloatValue", Unmarshaler{}, `{"flt":null}`, &pb.KnownTypes{Flt: nil}},
{"null Int64Value", Unmarshaler{}, `{"i64":null}`, &pb.KnownTypes{I64: nil}},
{"null UInt64Value", Unmarshaler{}, `{"u64":null}`, &pb.KnownTypes{U64: nil}},
{"null Int32Value", Unmarshaler{}, `{"i32":null}`, &pb.KnownTypes{I32: nil}},
{"null UInt32Value", Unmarshaler{}, `{"u32":null}`, &pb.KnownTypes{U32: nil}},
{"null BoolValue", Unmarshaler{}, `{"bool":null}`, &pb.KnownTypes{Bool: nil}},
{"null StringValue", Unmarshaler{}, `{"str":null}`, &pb.KnownTypes{Str: nil}},
{"null BytesValue", Unmarshaler{}, `{"bytes":null}`, &pb.KnownTypes{Bytes: nil}},
}
func TestUnmarshaling(t *testing.T) {
for _, tt := range unmarshalingTests {
// Make a new instance of the type of our expected object.
p := reflect.New(reflect.TypeOf(tt.pb).Elem()).Interface().(proto.Message)
err := tt.unmarshaler.Unmarshal(strings.NewReader(tt.json), p)
if err != nil {
t.Errorf("%s: %v", tt.desc, err)
continue
}
// For easier diffs, compare text strings of the protos.
exp := proto.MarshalTextString(tt.pb)
act := proto.MarshalTextString(p)
if string(exp) != string(act) {
t.Errorf("%s: got [%s] want [%s]", tt.desc, act, exp)
}
}
}
func TestUnmarshalNullArray(t *testing.T) {
var repeats pb.Repeats
if err := UnmarshalString(`{"rBool":null}`, &repeats); err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(repeats, pb.Repeats{}) {
t.Errorf("got non-nil fields in [%#v]", repeats)
}
}
func TestUnmarshalNullObject(t *testing.T) {
var maps pb.Maps
if err := UnmarshalString(`{"mInt64Str":null}`, &maps); err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(maps, pb.Maps{}) {
t.Errorf("got non-nil fields in [%#v]", maps)
}
}
func TestUnmarshalNext(t *testing.T) {
// We only need to check against a few, not all of them.
tests := unmarshalingTests[:5]
// Create a buffer with many concatenated JSON objects.
var b bytes.Buffer
for _, tt := range tests {
b.WriteString(tt.json)
}
dec := json.NewDecoder(&b)
for _, tt := range tests {
// Make a new instance of the type of our expected object.
p := reflect.New(reflect.TypeOf(tt.pb).Elem()).Interface().(proto.Message)
err := tt.unmarshaler.UnmarshalNext(dec, p)
if err != nil {
t.Errorf("%s: %v", tt.desc, err)
continue
}
// For easier diffs, compare text strings of the protos.
exp := proto.MarshalTextString(tt.pb)
act := proto.MarshalTextString(p)
if string(exp) != string(act) {
t.Errorf("%s: got [%s] want [%s]", tt.desc, act, exp)
}
}
p := &pb.Simple{}
err := new(Unmarshaler).UnmarshalNext(dec, p)
if err != io.EOF {
t.Errorf("eof: got %v, expected io.EOF", err)
}
}
var unmarshalingShouldError = []struct {
desc string
in string
pb proto.Message
}{
{"a value", "666", new(pb.Simple)},
{"gibberish", "{adskja123;l23=-=", new(pb.Simple)},
{"unknown field", `{"unknown": "foo"}`, new(pb.Simple)},
{"unknown enum name", `{"hilarity":"DAVE"}`, new(proto3pb.Message)},
}
func TestUnmarshalingBadInput(t *testing.T) {
for _, tt := range unmarshalingShouldError {
err := UnmarshalString(tt.in, tt.pb)
if err == nil {
t.Errorf("an error was expected when parsing %q instead of an object", tt.desc)
}
}
}
type funcResolver func(turl string) (proto.Message, error)
func (fn funcResolver) Resolve(turl string) (proto.Message, error) {
return fn(turl)
}
func TestAnyWithCustomResolver(t *testing.T) {
var resolvedTypeUrls []string
resolver := funcResolver(func(turl string) (proto.Message, error) {
resolvedTypeUrls = append(resolvedTypeUrls, turl)
return new(pb.Simple), nil
})
msg := &pb.Simple{
OBytes: []byte{1, 2, 3, 4},
OBool: proto.Bool(true),
OString: proto.String("foobar"),
OInt64: proto.Int64(1020304),
}
msgBytes, err := proto.Marshal(msg)
if err != nil {
t.Errorf("an unexpected error occurred when marshaling message: %v", err)
}
// make an Any with a type URL that won't resolve w/out custom resolver
any := &anypb.Any{
TypeUrl: "https://foobar.com/some.random.MessageKind",
Value: msgBytes,
}
m := Marshaler{AnyResolver: resolver}
js, err := m.MarshalToString(any)
if err != nil {
t.Errorf("an unexpected error occurred when marshaling any to JSON: %v", err)
}
if len(resolvedTypeUrls) != 1 {
t.Errorf("custom resolver was not invoked during marshaling")
} else if resolvedTypeUrls[0] != "https://foobar.com/some.random.MessageKind" {
t.Errorf("custom resolver was invoked with wrong URL: got %q, wanted %q", resolvedTypeUrls[0], "https://foobar.com/some.random.MessageKind")
}
wanted := `{"@type":"https://foobar.com/some.random.MessageKind","oBool":true,"oInt64":"1020304","oString":"foobar","oBytes":"AQIDBA=="}`
if js != wanted {
t.Errorf("marshalling JSON produced incorrect output: got %s, wanted %s", js, wanted)
}
u := Unmarshaler{AnyResolver: resolver}
roundTrip := &anypb.Any{}
err = u.Unmarshal(bytes.NewReader([]byte(js)), roundTrip)
if err != nil {
t.Errorf("an unexpected error occurred when unmarshaling any from JSON: %v", err)
}
if len(resolvedTypeUrls) != 2 {
t.Errorf("custom resolver was not invoked during marshaling")
} else if resolvedTypeUrls[1] != "https://foobar.com/some.random.MessageKind" {
t.Errorf("custom resolver was invoked with wrong URL: got %q, wanted %q", resolvedTypeUrls[1], "https://foobar.com/some.random.MessageKind")
}
if !proto.Equal(any, roundTrip) {
t.Errorf("message contents not set correctly after unmarshalling JSON: got %s, wanted %s", roundTrip, any)
}
}
func TestUnmarshalJSONPBUnmarshaler(t *testing.T) {
rawJson := `{ "foo": "bar", "baz": [0, 1, 2, 3] }`
var msg dynamicMessage
if err := Unmarshal(strings.NewReader(rawJson), &msg); err != nil {
t.Errorf("an unexpected error occurred when parsing into JSONPBUnmarshaler: %v", err)
}
if msg.rawJson != rawJson {
t.Errorf("message contents not set correctly after unmarshalling JSON: got %s, wanted %s", msg.rawJson, rawJson)
}
}
func TestUnmarshalNullWithJSONPBUnmarshaler(t *testing.T) {
rawJson := `{"stringField":null}`
var ptrFieldMsg ptrFieldMessage
if err := Unmarshal(strings.NewReader(rawJson), &ptrFieldMsg); err != nil {
t.Errorf("unmarshal error: %v", err)
}
want := ptrFieldMessage{StringField: &stringField{IsSet: true, StringValue: "null"}}
if !proto.Equal(&ptrFieldMsg, &want) {
t.Errorf("unmarshal result StringField: got %v, want %v", ptrFieldMsg, want)
}
}
func TestUnmarshalAnyJSONPBUnmarshaler(t *testing.T) {
rawJson := `{ "@type": "blah.com/` + dynamicMessageName + `", "foo": "bar", "baz": [0, 1, 2, 3] }`
var got anypb.Any
if err := Unmarshal(strings.NewReader(rawJson), &got); err != nil {
t.Errorf("an unexpected error occurred when parsing into JSONPBUnmarshaler: %v", err)
}
dm := &dynamicMessage{rawJson: `{"baz":[0,1,2,3],"foo":"bar"}`}
var want anypb.Any
if b, err := proto.Marshal(dm); err != nil {
t.Errorf("an unexpected error occurred when marshaling message: %v", err)
} else {
want.TypeUrl = "blah.com/" + dynamicMessageName
want.Value = b
}
if !proto.Equal(&got, &want) {
t.Errorf("message contents not set correctly after unmarshalling JSON: got %s, wanted %s", got, want)
}
}
const (
dynamicMessageName = "google.protobuf.jsonpb.testing.dynamicMessage"
)
func init() {
// we register the custom type below so that we can use it in Any types
proto.RegisterType((*dynamicMessage)(nil), dynamicMessageName)
}
type ptrFieldMessage struct {
StringField *stringField `protobuf:"bytes,1,opt,name=stringField"`
}
func (m *ptrFieldMessage) Reset() {
}
func (m *ptrFieldMessage) String() string {
return m.StringField.StringValue
}
func (m *ptrFieldMessage) ProtoMessage() {
}
type stringField struct {
IsSet bool `protobuf:"varint,1,opt,name=isSet"`
StringValue string `protobuf:"bytes,2,opt,name=stringValue"`
}
func (s *stringField) Reset() {
}
func (s *stringField) String() string {
return s.StringValue
}
func (s *stringField) ProtoMessage() {
}
func (s *stringField) UnmarshalJSONPB(jum *Unmarshaler, js []byte) error {
s.IsSet = true
s.StringValue = string(js)
return nil
}
// dynamicMessage implements protobuf.Message but is not a normal generated message type.
// It provides implementations of JSONPBMarshaler and JSONPBUnmarshaler for JSON support.
type dynamicMessage struct {
rawJson string `protobuf:"bytes,1,opt,name=rawJson"`
}
func (m *dynamicMessage) Reset() {
m.rawJson = "{}"
}
func (m *dynamicMessage) String() string {
return m.rawJson
}
func (m *dynamicMessage) ProtoMessage() {
}
func (m *dynamicMessage) MarshalJSONPB(jm *Marshaler) ([]byte, error) {
return []byte(m.rawJson), nil
}
func (m *dynamicMessage) UnmarshalJSONPB(jum *Unmarshaler, js []byte) error {
m.rawJson = string(js)
return nil
}

View File

@ -0,0 +1,380 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: google/protobuf/struct.proto
/*
Package structpb is a generated protocol buffer package.
It is generated from these files:
google/protobuf/struct.proto
It has these top-level messages:
Struct
Value
ListValue
*/
package structpb
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
// `NullValue` is a singleton enumeration to represent the null value for the
// `Value` type union.
//
// The JSON representation for `NullValue` is JSON `null`.
type NullValue int32
const (
// Null value.
NullValue_NULL_VALUE NullValue = 0
)
var NullValue_name = map[int32]string{
0: "NULL_VALUE",
}
var NullValue_value = map[string]int32{
"NULL_VALUE": 0,
}
func (x NullValue) String() string {
return proto.EnumName(NullValue_name, int32(x))
}
func (NullValue) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
func (NullValue) XXX_WellKnownType() string { return "NullValue" }
// `Struct` represents a structured data value, consisting of fields
// which map to dynamically typed values. In some languages, `Struct`
// might be supported by a native representation. For example, in
// scripting languages like JS a struct is represented as an
// object. The details of that representation are described together
// with the proto support for the language.
//
// The JSON representation for `Struct` is JSON object.
type Struct struct {
// Unordered map of dynamically typed values.
Fields map[string]*Value `protobuf:"bytes,1,rep,name=fields" json:"fields,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
}
func (m *Struct) Reset() { *m = Struct{} }
func (m *Struct) String() string { return proto.CompactTextString(m) }
func (*Struct) ProtoMessage() {}
func (*Struct) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
func (*Struct) XXX_WellKnownType() string { return "Struct" }
func (m *Struct) GetFields() map[string]*Value {
if m != nil {
return m.Fields
}
return nil
}
// `Value` represents a dynamically typed value which can be either
// null, a number, a string, a boolean, a recursive struct value, or a
// list of values. A producer of value is expected to set one of that
// variants, absence of any variant indicates an error.
//
// The JSON representation for `Value` is JSON value.
type Value struct {
// The kind of value.
//
// Types that are valid to be assigned to Kind:
// *Value_NullValue
// *Value_NumberValue
// *Value_StringValue
// *Value_BoolValue
// *Value_StructValue
// *Value_ListValue
Kind isValue_Kind `protobuf_oneof:"kind"`
}
func (m *Value) Reset() { *m = Value{} }
func (m *Value) String() string { return proto.CompactTextString(m) }
func (*Value) ProtoMessage() {}
func (*Value) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
func (*Value) XXX_WellKnownType() string { return "Value" }
type isValue_Kind interface {
isValue_Kind()
}
type Value_NullValue struct {
NullValue NullValue `protobuf:"varint,1,opt,name=null_value,json=nullValue,enum=google.protobuf.NullValue,oneof"`
}
type Value_NumberValue struct {
NumberValue float64 `protobuf:"fixed64,2,opt,name=number_value,json=numberValue,oneof"`
}
type Value_StringValue struct {
StringValue string `protobuf:"bytes,3,opt,name=string_value,json=stringValue,oneof"`
}
type Value_BoolValue struct {
BoolValue bool `protobuf:"varint,4,opt,name=bool_value,json=boolValue,oneof"`
}
type Value_StructValue struct {
StructValue *Struct `protobuf:"bytes,5,opt,name=struct_value,json=structValue,oneof"`
}
type Value_ListValue struct {
ListValue *ListValue `protobuf:"bytes,6,opt,name=list_value,json=listValue,oneof"`
}
func (*Value_NullValue) isValue_Kind() {}
func (*Value_NumberValue) isValue_Kind() {}
func (*Value_StringValue) isValue_Kind() {}
func (*Value_BoolValue) isValue_Kind() {}
func (*Value_StructValue) isValue_Kind() {}
func (*Value_ListValue) isValue_Kind() {}
func (m *Value) GetKind() isValue_Kind {
if m != nil {
return m.Kind
}
return nil
}
func (m *Value) GetNullValue() NullValue {
if x, ok := m.GetKind().(*Value_NullValue); ok {
return x.NullValue
}
return NullValue_NULL_VALUE
}
func (m *Value) GetNumberValue() float64 {
if x, ok := m.GetKind().(*Value_NumberValue); ok {
return x.NumberValue
}
return 0
}
func (m *Value) GetStringValue() string {
if x, ok := m.GetKind().(*Value_StringValue); ok {
return x.StringValue
}
return ""
}
func (m *Value) GetBoolValue() bool {
if x, ok := m.GetKind().(*Value_BoolValue); ok {
return x.BoolValue
}
return false
}
func (m *Value) GetStructValue() *Struct {
if x, ok := m.GetKind().(*Value_StructValue); ok {
return x.StructValue
}
return nil
}
func (m *Value) GetListValue() *ListValue {
if x, ok := m.GetKind().(*Value_ListValue); ok {
return x.ListValue
}
return nil
}
// XXX_OneofFuncs is for the internal use of the proto package.
func (*Value) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) {
return _Value_OneofMarshaler, _Value_OneofUnmarshaler, _Value_OneofSizer, []interface{}{
(*Value_NullValue)(nil),
(*Value_NumberValue)(nil),
(*Value_StringValue)(nil),
(*Value_BoolValue)(nil),
(*Value_StructValue)(nil),
(*Value_ListValue)(nil),
}
}
func _Value_OneofMarshaler(msg proto.Message, b *proto.Buffer) error {
m := msg.(*Value)
// kind
switch x := m.Kind.(type) {
case *Value_NullValue:
b.EncodeVarint(1<<3 | proto.WireVarint)
b.EncodeVarint(uint64(x.NullValue))
case *Value_NumberValue:
b.EncodeVarint(2<<3 | proto.WireFixed64)
b.EncodeFixed64(math.Float64bits(x.NumberValue))
case *Value_StringValue:
b.EncodeVarint(3<<3 | proto.WireBytes)
b.EncodeStringBytes(x.StringValue)
case *Value_BoolValue:
t := uint64(0)
if x.BoolValue {
t = 1
}
b.EncodeVarint(4<<3 | proto.WireVarint)
b.EncodeVarint(t)
case *Value_StructValue:
b.EncodeVarint(5<<3 | proto.WireBytes)
if err := b.EncodeMessage(x.StructValue); err != nil {
return err
}
case *Value_ListValue:
b.EncodeVarint(6<<3 | proto.WireBytes)
if err := b.EncodeMessage(x.ListValue); err != nil {
return err
}
case nil:
default:
return fmt.Errorf("Value.Kind has unexpected type %T", x)
}
return nil
}
func _Value_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) {
m := msg.(*Value)
switch tag {
case 1: // kind.null_value
if wire != proto.WireVarint {
return true, proto.ErrInternalBadWireType
}
x, err := b.DecodeVarint()
m.Kind = &Value_NullValue{NullValue(x)}
return true, err
case 2: // kind.number_value
if wire != proto.WireFixed64 {
return true, proto.ErrInternalBadWireType
}
x, err := b.DecodeFixed64()
m.Kind = &Value_NumberValue{math.Float64frombits(x)}
return true, err
case 3: // kind.string_value
if wire != proto.WireBytes {
return true, proto.ErrInternalBadWireType
}
x, err := b.DecodeStringBytes()
m.Kind = &Value_StringValue{x}
return true, err
case 4: // kind.bool_value
if wire != proto.WireVarint {
return true, proto.ErrInternalBadWireType
}
x, err := b.DecodeVarint()
m.Kind = &Value_BoolValue{x != 0}
return true, err
case 5: // kind.struct_value
if wire != proto.WireBytes {
return true, proto.ErrInternalBadWireType
}
msg := new(Struct)
err := b.DecodeMessage(msg)
m.Kind = &Value_StructValue{msg}
return true, err
case 6: // kind.list_value
if wire != proto.WireBytes {
return true, proto.ErrInternalBadWireType
}
msg := new(ListValue)
err := b.DecodeMessage(msg)
m.Kind = &Value_ListValue{msg}
return true, err
default:
return false, nil
}
}
func _Value_OneofSizer(msg proto.Message) (n int) {
m := msg.(*Value)
// kind
switch x := m.Kind.(type) {
case *Value_NullValue:
n += proto.SizeVarint(1<<3 | proto.WireVarint)
n += proto.SizeVarint(uint64(x.NullValue))
case *Value_NumberValue:
n += proto.SizeVarint(2<<3 | proto.WireFixed64)
n += 8
case *Value_StringValue:
n += proto.SizeVarint(3<<3 | proto.WireBytes)
n += proto.SizeVarint(uint64(len(x.StringValue)))
n += len(x.StringValue)
case *Value_BoolValue:
n += proto.SizeVarint(4<<3 | proto.WireVarint)
n += 1
case *Value_StructValue:
s := proto.Size(x.StructValue)
n += proto.SizeVarint(5<<3 | proto.WireBytes)
n += proto.SizeVarint(uint64(s))
n += s
case *Value_ListValue:
s := proto.Size(x.ListValue)
n += proto.SizeVarint(6<<3 | proto.WireBytes)
n += proto.SizeVarint(uint64(s))
n += s
case nil:
default:
panic(fmt.Sprintf("proto: unexpected type %T in oneof", x))
}
return n
}
// `ListValue` is a wrapper around a repeated field of values.
//
// The JSON representation for `ListValue` is JSON array.
type ListValue struct {
// Repeated field of dynamically typed values.
Values []*Value `protobuf:"bytes,1,rep,name=values" json:"values,omitempty"`
}
func (m *ListValue) Reset() { *m = ListValue{} }
func (m *ListValue) String() string { return proto.CompactTextString(m) }
func (*ListValue) ProtoMessage() {}
func (*ListValue) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
func (*ListValue) XXX_WellKnownType() string { return "ListValue" }
func (m *ListValue) GetValues() []*Value {
if m != nil {
return m.Values
}
return nil
}
func init() {
proto.RegisterType((*Struct)(nil), "google.protobuf.Struct")
proto.RegisterType((*Value)(nil), "google.protobuf.Value")
proto.RegisterType((*ListValue)(nil), "google.protobuf.ListValue")
proto.RegisterEnum("google.protobuf.NullValue", NullValue_name, NullValue_value)
}
func init() { proto.RegisterFile("google/protobuf/struct.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 417 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x92, 0x41, 0x8b, 0xd3, 0x40,
0x14, 0xc7, 0x3b, 0xc9, 0x36, 0x98, 0x17, 0x59, 0x97, 0x11, 0xb4, 0xac, 0xa2, 0xa1, 0x7b, 0x09,
0x22, 0x29, 0xd6, 0x8b, 0x18, 0x2f, 0x06, 0xd6, 0x5d, 0x30, 0x2c, 0x31, 0xba, 0x15, 0xbc, 0x94,
0x26, 0x4d, 0x63, 0xe8, 0x74, 0x26, 0x24, 0x33, 0x4a, 0x8f, 0x7e, 0x0b, 0xcf, 0x1e, 0x3d, 0xfa,
0xe9, 0x3c, 0xca, 0xcc, 0x24, 0xa9, 0xb4, 0xf4, 0x94, 0xbc, 0xf7, 0x7e, 0xef, 0x3f, 0xef, 0xff,
0x66, 0xe0, 0x71, 0xc1, 0x58, 0x41, 0xf2, 0x49, 0x55, 0x33, 0xce, 0x52, 0xb1, 0x9a, 0x34, 0xbc,
0x16, 0x19, 0xf7, 0x55, 0x8c, 0xef, 0xe9, 0xaa, 0xdf, 0x55, 0xc7, 0x3f, 0x11, 0x58, 0x1f, 0x15,
0x81, 0x03, 0xb0, 0x56, 0x65, 0x4e, 0x96, 0xcd, 0x08, 0xb9, 0xa6, 0xe7, 0x4c, 0x2f, 0xfc, 0x3d,
0xd8, 0xd7, 0xa0, 0xff, 0x4e, 0x51, 0x97, 0x94, 0xd7, 0xdb, 0xa4, 0x6d, 0x39, 0xff, 0x00, 0xce,
0x7f, 0x69, 0x7c, 0x06, 0xe6, 0x3a, 0xdf, 0x8e, 0x90, 0x8b, 0x3c, 0x3b, 0x91, 0xbf, 0xf8, 0x39,
0x0c, 0xbf, 0x2d, 0x88, 0xc8, 0x47, 0x86, 0x8b, 0x3c, 0x67, 0xfa, 0xe0, 0x40, 0x7c, 0x26, 0xab,
0x89, 0x86, 0x5e, 0x1b, 0xaf, 0xd0, 0xf8, 0x8f, 0x01, 0x43, 0x95, 0xc4, 0x01, 0x00, 0x15, 0x84,
0xcc, 0xb5, 0x80, 0x14, 0x3d, 0x9d, 0x9e, 0x1f, 0x08, 0xdc, 0x08, 0x42, 0x14, 0x7f, 0x3d, 0x48,
0x6c, 0xda, 0x05, 0xf8, 0x02, 0xee, 0x52, 0xb1, 0x49, 0xf3, 0x7a, 0xbe, 0x3b, 0x1f, 0x5d, 0x0f,
0x12, 0x47, 0x67, 0x7b, 0xa8, 0xe1, 0x75, 0x49, 0x8b, 0x16, 0x32, 0xe5, 0xe0, 0x12, 0xd2, 0x59,
0x0d, 0x3d, 0x05, 0x48, 0x19, 0xeb, 0xc6, 0x38, 0x71, 0x91, 0x77, 0x47, 0x1e, 0x25, 0x73, 0x1a,
0x78, 0xa3, 0x54, 0x44, 0xc6, 0x5b, 0x64, 0xa8, 0xac, 0x3e, 0x3c, 0xb2, 0xc7, 0x56, 0x5e, 0x64,
0xbc, 0x77, 0x49, 0xca, 0xa6, 0xeb, 0xb5, 0x54, 0xef, 0xa1, 0xcb, 0xa8, 0x6c, 0x78, 0xef, 0x92,
0x74, 0x41, 0x68, 0xc1, 0xc9, 0xba, 0xa4, 0xcb, 0x71, 0x00, 0x76, 0x4f, 0x60, 0x1f, 0x2c, 0x25,
0xd6, 0xdd, 0xe8, 0xb1, 0xa5, 0xb7, 0xd4, 0xb3, 0x47, 0x60, 0xf7, 0x4b, 0xc4, 0xa7, 0x00, 0x37,
0xb7, 0x51, 0x34, 0x9f, 0xbd, 0x8d, 0x6e, 0x2f, 0xcf, 0x06, 0xe1, 0x0f, 0x04, 0xf7, 0x33, 0xb6,
0xd9, 0x97, 0x08, 0x1d, 0xed, 0x26, 0x96, 0x71, 0x8c, 0xbe, 0xbc, 0x28, 0x4a, 0xfe, 0x55, 0xa4,
0x7e, 0xc6, 0x36, 0x93, 0x82, 0x91, 0x05, 0x2d, 0x76, 0x4f, 0xb1, 0xe2, 0xdb, 0x2a, 0x6f, 0xda,
0x17, 0x19, 0xe8, 0x4f, 0x95, 0xfe, 0x45, 0xe8, 0x97, 0x61, 0x5e, 0xc5, 0xe1, 0x6f, 0xe3, 0xc9,
0x95, 0x16, 0x8f, 0xbb, 0xf9, 0x3e, 0xe7, 0x84, 0xbc, 0xa7, 0xec, 0x3b, 0xfd, 0x24, 0x3b, 0x53,
0x4b, 0x49, 0xbd, 0xfc, 0x17, 0x00, 0x00, 0xff, 0xff, 0xe8, 0x1b, 0x59, 0xf8, 0xe5, 0x02, 0x00,
0x00,
}

View File

@ -0,0 +1,96 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto3";
package google.protobuf;
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
option cc_enable_arenas = true;
option go_package = "github.com/golang/protobuf/ptypes/struct;structpb";
option java_package = "com.google.protobuf";
option java_outer_classname = "StructProto";
option java_multiple_files = true;
option objc_class_prefix = "GPB";
// `Struct` represents a structured data value, consisting of fields
// which map to dynamically typed values. In some languages, `Struct`
// might be supported by a native representation. For example, in
// scripting languages like JS a struct is represented as an
// object. The details of that representation are described together
// with the proto support for the language.
//
// The JSON representation for `Struct` is JSON object.
message Struct {
// Unordered map of dynamically typed values.
map<string, Value> fields = 1;
}
// `Value` represents a dynamically typed value which can be either
// null, a number, a string, a boolean, a recursive struct value, or a
// list of values. A producer of value is expected to set one of that
// variants, absence of any variant indicates an error.
//
// The JSON representation for `Value` is JSON value.
message Value {
// The kind of value.
oneof kind {
// Represents a null value.
NullValue null_value = 1;
// Represents a double value.
double number_value = 2;
// Represents a string value.
string string_value = 3;
// Represents a boolean value.
bool bool_value = 4;
// Represents a structured value.
Struct struct_value = 5;
// Represents a repeated `Value`.
ListValue list_value = 6;
}
}
// `NullValue` is a singleton enumeration to represent the null value for the
// `Value` type union.
//
// The JSON representation for `NullValue` is JSON `null`.
enum NullValue {
// Null value.
NULL_VALUE = 0;
}
// `ListValue` is a wrapper around a repeated field of values.
//
// The JSON representation for `ListValue` is JSON array.
message ListValue {
// Repeated field of dynamically typed values.
repeated Value values = 1;
}

7
vendor/github.com/twitchtv/twirp/.gitignore generated vendored Normal file
View File

@ -0,0 +1,7 @@
*.test
/bin
clientcompat/pycompat/ENV
*.pyc
build

62
vendor/github.com/twitchtv/twirp/CONTRIBUTING.md generated vendored Normal file
View File

@ -0,0 +1,62 @@
# Contributing #
Thanks for helping make Twirp better! This is great!
First, if you have run into a bug, please file an issue. We try to get back to
issue reporters within a day or two. We might be able to help you right away.
If you'd rather not publicly discuss the issue, please email spencer@twitch.tv
and/or security@twitch.tv.
Issues are also a good place to present experience reports or requests for new
features.
If you'd like to make changes to Twirp, read on:
## Setup Requirements ##
You will need git, Go 1.9+, and Python 2.7 installed and on your system's path.
Install them however you feel.
We work on a branch called `develop`. We periodically release this branch as a
new version, then accumulate more changes on the develop branch until the next
release. Use `develop` as the base for your branches.
## Developer Loop ##
Generally you want to make changes and run `make`, which will install all
dependencies we know about, build the core, and run all of the tests that we
have against all of the languages we support.
Most tests of the Go server are in `internal/twirptest/service_test.go`. Tests
of cross-language clients are in the [clientcompat](./clientcompat) directory.
## Contributing Code ##
Twirp uses github pull requests. Fork a branch from `develop`, hack away at your
changes, run the test suite with `make`, and submit a PR.
## Releasing Versions ##
Releasing versions is the responsibility of the core maintainers. Most people
don't need to know this stuff.
Twirp uses [Semantic versioning](http://semver.org/): `v<major>.<minor>.<patch>`.
* Increment major if you're making a backwards-incompatible change.
* Increment minor if you're adding a feature that's backwards-compatible.
* Increment patch if you're making a bugfix.
To make a release, remember to update the version number in
[internal/gen/version.go](./internal/gen/version.go).
Twirp uses Github releases. To make a new release:
1. Merge all changes that should be included in the release into the master
branch.
2. Add a new commit to master with a message like "Version vX.X.X release".
3. Tag the commit you just made: `git tag <version number>` and `git push
origin --tags`
3. Go to Github https://github.com/twitchtv/twirp/releases and
"Draft a new release".
4. Make sure to document changes, specially when upgrade instructions are
needed.

201
vendor/github.com/twitchtv/twirp/LICENSE generated vendored Normal file
View File

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2018 Twitch Interactive, 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.

51
vendor/github.com/twitchtv/twirp/Makefile generated vendored Normal file
View File

@ -0,0 +1,51 @@
RETOOL=$(CURDIR)/_tools/bin/retool
PATH := ${PWD}/bin:${PWD}/ENV/bin:${PATH}
.DEFAULT_GOAL := all
all: setup test_all
.PHONY: test test_all test_core test_clients test_go_client test_python_client generate
# Phony commands:
generate:
PATH=$(CURDIR)/_tools/bin:$(PATH) GOBIN="${PWD}/bin" go install -v ./protoc-gen-...
$(RETOOL) do go generate ./...
test_all: setup test_core test_clients
test_core: generate
$(RETOOL) do errcheck -blank ./internal/twirptest
go test -race $(shell go list ./... | grep -v /vendor/ | grep -v /_tools/)
test_clients: test_go_client test_python_client
test_go_client: generate build/clientcompat build/gocompat
./build/clientcompat -client ./build/gocompat
test_python_client: generate build/clientcompat build/pycompat
./build/clientcompat -client ./build/pycompat
setup:
./install_proto.bash
GOPATH=$(CURDIR)/_tools go install github.com/twitchtv/retool/...
$(RETOOL) build
# Actual files for testing clients:
./build:
mkdir build
./build/gocompat: ./build
go build -o build/gocompat ./clientcompat/gocompat
./build/clientcompat: ./build
go build -o build/clientcompat ./clientcompat
./build/venv: ./build
virtualenv ./build/venv
./build/venv/bin/pycompat.py: ./build/venv
./build/venv/bin/pip install --upgrade ./clientcompat/pycompat
./build/pycompat: ./build/venv/bin/pycompat.py
cp ./clientcompat/pycompat/pycompat.sh ./build/pycompat
chmod +x ./build/pycompat

34
vendor/github.com/twitchtv/twirp/README.md generated vendored Normal file
View File

@ -0,0 +1,34 @@
![Twirp Logo](./logo.png)
---
Twirp is a framework for service-to-service communication emphasizing simplicity
and minimalism. It generates routing and serialization from API definition files
and lets you focus on your application's logic instead of thinking about
folderol like HTTP methods and paths and JSON.
Define your service in a
[Protobuf](https://developers.google.com/protocol-buffers/docs/proto3) file and
then Twirp autogenerates Go code with a server interface and fully functional
clients. It's similar to [gRPC](http://www.grpc.io/), but without the custom
HTTP server and transport implementations: it runs on the standard library's
extremely-well-tested-and-high-performance `net/http` Server. It can run on HTTP
1.1, not just http/2, and supports JSON clients for easy integrations across
languages
Twirp handles routing and serialization for you in a well-tested, standardized,
thoughtful way so you don't have to. Serialization and deserialization code is
error-prone and tricky, and you shouldn't be wasting your time deciding whether
it should be "POST /friends/:id/new" or "POST /:id/friend" or whatever. Just
get to the real work of building services!
Along the way, you get an autogenerated client and a simple, smart framework for
passing error messages. Nice!
### Releases
Twirp follows semantic versioning through git tags, and uses Github Releases for
release notes and upgrade guides:
[Twirp Releases](https://github.com/twitchtv/twirp/releases)
### Contributing
Check out [CONTRIBUTING.md](./CONTRIBUTING.md) for notes on making contributions.

109
vendor/github.com/twitchtv/twirp/context.go generated vendored Normal file
View File

@ -0,0 +1,109 @@
package twirp
import (
"context"
"errors"
"net/http"
"github.com/twitchtv/twirp/internal/contextkeys"
)
// MethodName extracts the name of the method being handled in the given
// context. If it is not known, it returns ("", false).
func MethodName(ctx context.Context) (string, bool) {
name, ok := ctx.Value(contextkeys.MethodNameKey).(string)
return name, ok
}
// ServiceName extracts the name of the service handling the given context. If
// it is not known, it returns ("", false).
func ServiceName(ctx context.Context) (string, bool) {
name, ok := ctx.Value(contextkeys.ServiceNameKey).(string)
return name, ok
}
// PackageName extracts the fully-qualified protobuf package name of the service
// handling the given context. If it is not known, it returns ("", false). If
// the service comes from a proto file that does not declare a package name, it
// returns ("", true).
//
// Note that the protobuf package name can be very different than the go package
// name; the two are unrelated.
func PackageName(ctx context.Context) (string, bool) {
name, ok := ctx.Value(contextkeys.PackageNameKey).(string)
return name, ok
}
// StatusCode retrieves the status code of the response (as string like "200").
// If it is known returns (status, true).
// If it is not known, it returns ("", false).
func StatusCode(ctx context.Context) (string, bool) {
code, ok := ctx.Value(contextkeys.StatusCodeKey).(string)
return code, ok
}
// WithHTTPRequestHeaders stores an http.Header in a context.Context. When
// using a Twirp-generated client, you can pass the returned context
// into any of the request methods, and the stored header will be
// included in outbound HTTP requests.
//
// This can be used to set custom HTTP headers like authorization tokens or
// client IDs. But note that HTTP headers are a Twirp implementation detail,
// only visible by middleware, not by the server implementtion.
//
// WithHTTPRequestHeaders returns an error if the provided http.Header
// would overwrite a header that is needed by Twirp, like "Content-Type".
func WithHTTPRequestHeaders(ctx context.Context, h http.Header) (context.Context, error) {
if _, ok := h["Content-Type"]; ok {
return nil, errors.New("provided header cannot set Content-Type")
}
if _, ok := h["Twirp-Version"]; ok {
return nil, errors.New("provided header cannot set Twirp-Version")
}
copied := make(http.Header, len(h))
for k, vv := range h {
if vv == nil {
copied[k] = nil
continue
}
copied[k] = make([]string, len(vv))
copy(copied[k], vv)
}
return context.WithValue(ctx, contextkeys.RequestHeaderKey, copied), nil
}
func HTTPRequestHeaders(ctx context.Context) (http.Header, bool) {
h, ok := ctx.Value(contextkeys.RequestHeaderKey).(http.Header)
return h, ok
}
// SetHTTPResponseHeader sets an HTTP header key-value pair using a context
// provided by a twirp-generated server, or a child of that context.
// The server will include the header in its response for that request context.
//
// This can be used to respond with custom HTTP headers like "Cache-Control".
// But note that HTTP headers are a Twirp implementation detail,
// only visible by middleware, not by the clients or their responses.
//
// The header will be ignored (noop) if the context is invalid (i.e. using a new
// context.Background() instead of passing the context from the handler).
//
// If called multiple times with the same key, it replaces any existing values
// associated with that key.
//
// SetHTTPResponseHeader returns an error if the provided header key
// would overwrite a header that is needed by Twirp, like "Content-Type".
func SetHTTPResponseHeader(ctx context.Context, key, value string) error {
if key == "Content-Type" {
return errors.New("header key can not be Content-Type")
}
responseWriter, ok := ctx.Value(contextkeys.ResponseWriterKey).(http.ResponseWriter)
if ok {
responseWriter.Header().Set(key, value)
} // invalid context is ignored, not an error, this is to allow easy unit testing with mock servers
return nil
}

View File

@ -0,0 +1,34 @@
// Package ctxsetters is an implementation detail for twirp generated code, used
// by the generated servers to set values in contexts for later access with the
// twirp package's accessors.
//
// Do not use ctxsetters outside of twirp's generated code.
package ctxsetters
import (
"context"
"net/http"
"strconv"
"github.com/twitchtv/twirp/internal/contextkeys"
)
func WithMethodName(ctx context.Context, name string) context.Context {
return context.WithValue(ctx, contextkeys.MethodNameKey, name)
}
func WithServiceName(ctx context.Context, name string) context.Context {
return context.WithValue(ctx, contextkeys.ServiceNameKey, name)
}
func WithPackageName(ctx context.Context, name string) context.Context {
return context.WithValue(ctx, contextkeys.PackageNameKey, name)
}
func WithStatusCode(ctx context.Context, code int) context.Context {
return context.WithValue(ctx, contextkeys.StatusCodeKey, strconv.Itoa(code))
}
func WithResponseWriter(ctx context.Context, w http.ResponseWriter) context.Context {
return context.WithValue(ctx, contextkeys.ResponseWriterKey, w)
}

328
vendor/github.com/twitchtv/twirp/errors.go generated vendored Normal file
View File

@ -0,0 +1,328 @@
// package twirp provides core types used in generated Twirp servers and client.
//
// Twirp services handle errors using the `twirp.Error` interface.
//
// For example, a server method may return an InvalidArgumentError:
//
// if req.Order != "DESC" && req.Order != "ASC" {
// return nil, twirp.InvalidArgumentError("Order", "must be DESC or ASC")
// }
//
// And the same twirp.Error is returned by the client, for example:
//
// resp, err := twirpClient.RPCMethod(ctx, req)
// if err != nil {
// if twerr := err.(twirp.Error) {
// switch twerr.Code() {
// case twirp.InvalidArgument:
// log.Error("invalid argument "+twirp.Meta("argument"))
// default:
// log.Error(twerr.Error())
// }
// }
// }
//
// Clients may also return Internal errors if something failed on the system:
// the server, the network, or the client itself (i.e. failure parsing
// response).
//
package twirp
import "fmt"
// Error represents an error in a Twirp service call.
type Error interface {
// Code is of the valid error codes.
Code() ErrorCode
// Msg returns a human-readable, unstructured messages describing the error.
Msg() string
// WithMeta returns a copy of the Error with the given key-value pair attached
// as metadata. If the key is already set, it is overwritten.
WithMeta(key string, val string) Error
// Meta returns the stored value for the given key. If the key has no set
// value, Meta returns an empty string. There is no way to distinguish between
// an unset value and an explicit empty string.
Meta(key string) string
// MetaMap returns the complete key-value metadata map stored on the error.
MetaMap() map[string]string
// Error returns a string of the form "twirp error <Type>: <Msg>"
Error() string
}
// NewError is the generic constructor for a twirp.Error. The ErrorCode must be
// one of the valid predefined constants, otherwise it will be converted to an
// error {type: Internal, msg: "invalid error type {{code}}"}. If you need to
// add metadata, use .WithMeta(key, value) method after building the error.
func NewError(code ErrorCode, msg string) Error {
if IsValidErrorCode(code) {
return &twerr{
code: code,
msg: msg,
}
}
return &twerr{
code: Internal,
msg: "invalid error type " + string(code),
}
}
// NotFoundError constructor for the common NotFound error.
func NotFoundError(msg string) Error {
return NewError(NotFound, msg)
}
// InvalidArgumentError constructor for the common InvalidArgument error. Can be
// used when an argument has invalid format, is a number out of range, is a bad
// option, etc).
func InvalidArgumentError(argument string, validationMsg string) Error {
err := NewError(InvalidArgument, argument+" "+validationMsg)
err = err.WithMeta("argument", argument)
return err
}
// RequiredArgumentError is a more scpecific constructor for InvalidArgument
// error. Should be used when the argument is required (expected to have a
// non-zero value).
func RequiredArgumentError(argument string) Error {
return InvalidArgumentError(argument, "is required")
}
// InternalError constructor for the common Internal error. Should be used to
// specify that something bad or unexpected happened.
func InternalError(msg string) Error {
return NewError(Internal, msg)
}
// InternalErrorWith is an easy way to wrap another error. It adds the
// underlying error's type as metadata with a key of "cause", which can be
// useful for debugging. Should be used in the common case of an unexpected
// error returned from another API, but sometimes it is better to build a more
// specific error (like with NewError(Unknown, err.Error()), for example).
//
// The returned error also has a Cause() method which will return the original
// error, if it is known. This can be used with the github.com/pkg/errors
// package to extract the root cause of an error. Information about the root
// cause of an error is lost when it is serialized, so this doesn't let a client
// know the exact root cause of a server's error.
func InternalErrorWith(err error) Error {
msg := err.Error()
twerr := NewError(Internal, msg)
twerr = twerr.WithMeta("cause", fmt.Sprintf("%T", err)) // to easily tell apart wrapped internal errors from explicit ones
return &wrappedErr{
wrapper: twerr,
cause: err,
}
}
// ErrorCode represents a Twirp error type.
type ErrorCode string
// Valid Twirp error types. Most error types are equivalent to GRPC status codes
// and follow the same semantics.
const (
// Canceled indicates the operation was cancelled (typically by the caller).
Canceled ErrorCode = "canceled"
// Unknown error. For example when handling errors raised by APIs that do not
// return enough error information.
Unknown ErrorCode = "unknown"
// InvalidArgument indicates client specified an invalid argument. It
// indicates arguments that are problematic regardless of the state of the
// system (i.e. a malformed file name, required argument, number out of range,
// etc.).
InvalidArgument ErrorCode = "invalid_argument"
// DeadlineExceeded means operation expired before completion. For operations
// that change the state of the system, this error may be returned even if the
// operation has completed successfully (timeout).
DeadlineExceeded ErrorCode = "deadline_exceeded"
// NotFound means some requested entity was not found.
NotFound ErrorCode = "not_found"
// BadRoute means that the requested URL path wasn't routable to a Twirp
// service and method. This is returned by the generated server, and usually
// shouldn't be returned by applications. Instead, applications should use
// NotFound or Unimplemented.
BadRoute ErrorCode = "bad_route"
// AlreadyExists means an attempt to create an entity failed because one
// already exists.
AlreadyExists ErrorCode = "already_exists"
// PermissionDenied indicates the caller does not have permission to execute
// the specified operation. It must not be used if the caller cannot be
// identified (Unauthenticated).
PermissionDenied ErrorCode = "permission_denied"
// Unauthenticated indicates the request does not have valid authentication
// credentials for the operation.
Unauthenticated ErrorCode = "unauthenticated"
// ResourceExhausted indicates some resource has been exhausted, perhaps a
// per-user quota, or perhaps the entire file system is out of space.
ResourceExhausted ErrorCode = "resource_exhausted"
// FailedPrecondition indicates operation was rejected because the system is
// not in a state required for the operation's execution. For example, doing
// an rmdir operation on a directory that is non-empty, or on a non-directory
// object, or when having conflicting read-modify-write on the same resource.
FailedPrecondition ErrorCode = "failed_precondition"
// Aborted indicates the operation was aborted, typically due to a concurrency
// issue like sequencer check failures, transaction aborts, etc.
Aborted ErrorCode = "aborted"
// OutOfRange means operation was attempted past the valid range. For example,
// seeking or reading past end of a paginated collection.
//
// Unlike InvalidArgument, this error indicates a problem that may be fixed if
// the system state changes (i.e. adding more items to the collection).
//
// There is a fair bit of overlap between FailedPrecondition and OutOfRange.
// We recommend using OutOfRange (the more specific error) when it applies so
// that callers who are iterating through a space can easily look for an
// OutOfRange error to detect when they are done.
OutOfRange ErrorCode = "out_of_range"
// Unimplemented indicates operation is not implemented or not
// supported/enabled in this service.
Unimplemented ErrorCode = "unimplemented"
// Internal errors. When some invariants expected by the underlying system
// have been broken. In other words, something bad happened in the library or
// backend service. Do not confuse with HTTP Internal Server Error; an
// Internal error could also happen on the client code, i.e. when parsing a
// server response.
Internal ErrorCode = "internal"
// Unavailable indicates the service is currently unavailable. This is a most
// likely a transient condition and may be corrected by retrying with a
// backoff.
Unavailable ErrorCode = "unavailable"
// DataLoss indicates unrecoverable data loss or corruption.
DataLoss ErrorCode = "data_loss"
// NoError is the zero-value, is considered an empty error and should not be
// used.
NoError ErrorCode = ""
)
// ServerHTTPStatusFromErrorCode maps a Twirp error type into a similar HTTP
// response status. It is used by the Twirp server handler to set the HTTP
// response status code. Returns 0 if the ErrorCode is invalid.
func ServerHTTPStatusFromErrorCode(code ErrorCode) int {
switch code {
case Canceled:
return 408 // RequestTimeout
case Unknown:
return 500 // Internal Server Error
case InvalidArgument:
return 400 // BadRequest
case DeadlineExceeded:
return 408 // RequestTimeout
case NotFound:
return 404 // Not Found
case BadRoute:
return 404 // Not Found
case AlreadyExists:
return 409 // Conflict
case PermissionDenied:
return 403 // Forbidden
case Unauthenticated:
return 401 // Unauthorized
case ResourceExhausted:
return 403 // Forbidden
case FailedPrecondition:
return 412 // Precondition Failed
case Aborted:
return 409 // Conflict
case OutOfRange:
return 400 // Bad Request
case Unimplemented:
return 501 // Not Implemented
case Internal:
return 500 // Internal Server Error
case Unavailable:
return 503 // Service Unavailable
case DataLoss:
return 500 // Internal Server Error
case NoError:
return 200 // OK
default:
return 0 // Invalid!
}
}
// IsValidErrorCode returns true if is one of the valid predefined constants.
func IsValidErrorCode(code ErrorCode) bool {
return ServerHTTPStatusFromErrorCode(code) != 0
}
// twirp.Error implementation
type twerr struct {
code ErrorCode
msg string
meta map[string]string
}
func (e *twerr) Code() ErrorCode { return e.code }
func (e *twerr) Msg() string { return e.msg }
func (e *twerr) Meta(key string) string {
if e.meta != nil {
return e.meta[key] // also returns "" if key is not in meta map
}
return ""
}
func (e *twerr) WithMeta(key string, value string) Error {
newErr := &twerr{
code: e.code,
msg: e.msg,
meta: make(map[string]string, len(e.meta)),
}
for k, v := range e.meta {
newErr.meta[k] = v
}
newErr.meta[key] = value
return newErr
}
func (e *twerr) MetaMap() map[string]string {
return e.meta
}
func (e *twerr) Error() string {
return fmt.Sprintf("twirp error %s: %s", e.code, e.msg)
}
// wrappedErr fulfills the twirp.Error interface and the
// github.com/pkg/errors.Causer interface. It exposes all the twirp error
// methods, but root cause of an error can be retrieved with
// (*wrappedErr).Cause. This is expected to be used with the InternalErrorWith
// function.
type wrappedErr struct {
wrapper Error
cause error
}
func (e *wrappedErr) Code() ErrorCode { return e.wrapper.Code() }
func (e *wrappedErr) Msg() string { return e.wrapper.Msg() }
func (e *wrappedErr) Meta(key string) string { return e.wrapper.Meta(key) }
func (e *wrappedErr) MetaMap() map[string]string { return e.wrapper.MetaMap() }
func (e *wrappedErr) Error() string { return e.wrapper.Error() }
func (e *wrappedErr) WithMeta(key string, val string) Error {
return &wrappedErr{
wrapper: e.wrapper.WithMeta(key, val),
cause: e.cause,
}
}
func (e *wrappedErr) Cause() error { return e.cause }

38
vendor/github.com/twitchtv/twirp/errors_test.go generated vendored Normal file
View File

@ -0,0 +1,38 @@
package twirp
import (
"fmt"
"sync"
"testing"
"github.com/pkg/errors"
)
func TestWithMetaRaces(t *testing.T) {
err := NewError(Internal, "msg")
err = err.WithMeta("k1", "v1")
var wg sync.WaitGroup
for i := 0; i < 1000; i++ {
wg.Add(1)
go func(i int) {
_ = err.WithMeta(fmt.Sprintf("k-%d", i), "v")
wg.Done()
}(i)
}
wg.Wait()
if len(err.MetaMap()) != 1 {
t.Errorf("err was mutated")
}
}
func TestErrorCause(t *testing.T) {
rootCause := fmt.Errorf("this is only a test")
twerr := InternalErrorWith(rootCause)
cause := errors.Cause(twerr)
if cause != rootCause {
t.Errorf("got wrong cause for err. have=%q, want=%q", cause, rootCause)
}
}

108
vendor/github.com/twitchtv/twirp/hooks.go generated vendored Normal file
View File

@ -0,0 +1,108 @@
package twirp
import "context"
// ServerHooks is a container for callbacks that can instrument a
// Twirp-generated server. These callbacks all accept a context and return a
// context. They can use this to add to the request context as it threads
// through the system, appending values or deadlines to it.
//
// The RequestReceived and RequestRouted hooks are special: they can return
// errors. If they return a non-nil error, handling for that request will be
// stopped at that point. The Error hook will be triggered, and the error will
// be sent to the client. This can be used for stuff like auth checks before
// deserializing a request.
//
// The RequestReceived hook is always called first, and it is called for every
// request that the Twirp server handles. The last hook to be called in a
// request's lifecycle is always ResponseSent, even in the case of an error.
//
// Details on the timing of each hook are documented as comments on the fields
// of the ServerHooks type.
type ServerHooks struct {
// RequestReceived is called as soon as a request enters the Twirp
// server at the earliest available moment.
RequestReceived func(context.Context) (context.Context, error)
// RequestRouted is called when a request has been routed to a
// particular method of the Twirp server.
RequestRouted func(context.Context) (context.Context, error)
// ResponsePrepared is called when a request has been handled and a
// response is ready to be sent to the client.
ResponsePrepared func(context.Context) context.Context
// ResponseSent is called when all bytes of a response (including an error
// response) have been written. Because the ResponseSent hook is terminal, it
// does not return a context.
ResponseSent func(context.Context)
// Error hook is called when a request responds with an Error,
// either by the service implementation or by Twirp itself.
// The Error is passed as argument to the hook.
Error func(context.Context, Error) context.Context
}
// ChainHooks creates a new *ServerHooks which chains the callbacks in
// each of the constituent hooks passed in. Each hook function will be
// called in the order of the ServerHooks values passed in.
//
// For the erroring hooks, RequestReceived and RequestRouted, any returned
// errors prevent processing by later hooks.
func ChainHooks(hooks ...*ServerHooks) *ServerHooks {
if len(hooks) == 0 {
return nil
}
if len(hooks) == 1 {
return hooks[0]
}
return &ServerHooks{
RequestReceived: func(ctx context.Context) (context.Context, error) {
var err error
for _, h := range hooks {
if h != nil && h.RequestReceived != nil {
ctx, err = h.RequestReceived(ctx)
if err != nil {
return ctx, err
}
}
}
return ctx, nil
},
RequestRouted: func(ctx context.Context) (context.Context, error) {
var err error
for _, h := range hooks {
if h != nil && h.RequestRouted != nil {
ctx, err = h.RequestRouted(ctx)
if err != nil {
return ctx, err
}
}
}
return ctx, nil
},
ResponsePrepared: func(ctx context.Context) context.Context {
for _, h := range hooks {
if h != nil && h.ResponsePrepared != nil {
ctx = h.ResponsePrepared(ctx)
}
}
return ctx
},
ResponseSent: func(ctx context.Context) {
for _, h := range hooks {
if h != nil && h.ResponseSent != nil {
h.ResponseSent(ctx)
}
}
},
Error: func(ctx context.Context, twerr Error) context.Context {
for _, h := range hooks {
if h != nil && h.Error != nil {
ctx = h.Error(ctx, twerr)
}
}
return ctx
},
}
}

75
vendor/github.com/twitchtv/twirp/hooks_test.go generated vendored Normal file
View File

@ -0,0 +1,75 @@
package twirp
import (
"context"
"reflect"
"testing"
)
func TestChainHooks(t *testing.T) {
var (
hook1 = new(ServerHooks)
hook2 = new(ServerHooks)
hook3 = new(ServerHooks)
)
const key = "key"
hook1.RequestReceived = func(ctx context.Context) (context.Context, error) {
return context.WithValue(ctx, key, []string{"hook1"}), nil
}
hook2.RequestReceived = func(ctx context.Context) (context.Context, error) {
v := ctx.Value(key).([]string)
return context.WithValue(ctx, key, append(v, "hook2")), nil
}
hook3.RequestReceived = func(ctx context.Context) (context.Context, error) {
v := ctx.Value(key).([]string)
return context.WithValue(ctx, key, append(v, "hook3")), nil
}
hook1.RequestRouted = func(ctx context.Context) (context.Context, error) {
return context.WithValue(ctx, key, []string{"hook1"}), nil
}
hook2.ResponsePrepared = func(ctx context.Context) context.Context {
return context.WithValue(ctx, key, []string{"hook2"})
}
chain := ChainHooks(hook1, hook2, hook3)
ctx := context.Background()
// When all three chained hooks have a handler, all should be called in order.
want := []string{"hook1", "hook2", "hook3"}
haveCtx, err := chain.RequestReceived(ctx)
if err != nil {
t.Fatalf("RequestReceived chain has unexpected err %v", err)
}
have := haveCtx.Value(key)
if !reflect.DeepEqual(want, have) {
t.Errorf("RequestReceived chain has unexpected ctx, have=%v, want=%v", have, want)
}
// When only the first chained hook has a handler, it should be called, and
// there should be no panic.
want = []string{"hook1"}
haveCtx, err = chain.RequestRouted(ctx)
if err != nil {
t.Fatalf("RequestRouted chain has unexpected err %v", err)
}
have = haveCtx.Value(key)
if !reflect.DeepEqual(want, have) {
t.Errorf("RequestRouted chain has unexpected ctx, have=%v, want=%v", have, want)
}
// When only the second chained hook has a handler, it should be called, and
// there should be no panic.
want = []string{"hook2"}
have = chain.ResponsePrepared(ctx).Value(key)
if !reflect.DeepEqual(want, have) {
t.Errorf("RequestRouted chain has unexpected ctx, have=%v, want=%v", have, want)
}
// When none of the chained hooks has a handler there should be no panic.
chain.ResponseSent(ctx)
}

33
vendor/github.com/twitchtv/twirp/install_proto.bash generated vendored Executable file
View File

@ -0,0 +1,33 @@
#!/usr/bin/env bash
which protoc
PROTOC_EXISTS=$?
if [ $PROTOC_EXISTS -eq 0 ]; then
echo "Protoc already installed"
exit 0
fi
if [ "$(uname)" == "Darwin" ]; then
brew install protobuf
elif [ `whoami` == "root" ]; then
mkdir -p /usr/local/src/protoc
pushd /usr/local/src/protoc
wget https://github.com/google/protobuf/releases/download/v3.1.0/protoc-3.1.0-linux-x86_64.zip -O /usr/local/src/protoc-3.1.0-linux-x86_64.zip
unzip -x ../protoc-3.1.0-linux-x86_64.zip
if [ ! -e /usr/local/bin/protoc ]; then
ln -s `pwd`/bin/protoc /usr/local/bin/protoc
fi
popd
elif [ "$(expr substr $(uname -s) 1 5)" == "Linux" ]; then
echo "Project setup needs sudo to put protoc in /usr/local/src, so it will ask a few times"
sudo chmod a+w /usr/local/src
mkdir -p /usr/local/src/protoc
pushd /usr/local/src/protoc
wget https://github.com/google/protobuf/releases/download/v3.1.0/protoc-3.1.0-linux-x86_64.zip -O /usr/local/src/protoc-3.1.0-linux-x86_64.zip
unzip -x ../protoc-3.1.0-linux-x86_64.zip
if [ ! -e /usr/local/bin/protoc ]; then
sudo ln -s `pwd`/bin/protoc /usr/local/bin/protoc
fi
popd
fi
exit 0

View File

@ -0,0 +1,15 @@
// Package contextkeys stores the keys to the context accessor
// functions, letting generated code safely set values in contexts
// without exposing the setters to the outside world.
package contextkeys
type contextKey int
const (
MethodNameKey contextKey = 1 + iota
ServiceNameKey
PackageNameKey
StatusCodeKey
RequestHeaderKey
ResponseWriterKey
)

13
vendor/github.com/twitchtv/twirp/internal/gogo_protoc_gen.sh generated vendored Executable file
View File

@ -0,0 +1,13 @@
#!/usr/bin/env bash
set -euo pipefail
# gogo_protoc_gen.sh foo.proto will compile foo.proto using
# github.com/gogo/protobuf/protoc-gen-gofast, an alternative generator used
# sometimes at Twitch.. Should be run in the same directory as its input.
# Handles multi-element GOPATHs so it works with retool.
# Append '/src' to every element in GOPATH.
PROTOPATH=${GOPATH/://src:}/src
protoc --proto_path="${PROTOPATH}:." --twirp_out=. --gofast_out=. "$@"

12
vendor/github.com/twitchtv/twirp/internal/protoc_gen.sh generated vendored Executable file
View File

@ -0,0 +1,12 @@
#!/usr/bin/env bash
set -euo pipefail
# protoc_gen.sh foo.proto will compile foo.proto. Should be run in the same
# directory as its input. Handles multi-element GOPATHs so it works with retool.
# Append '/src' to every element in GOPATH.
PROTOPATH=${GOPATH/://src:}/src
protoc --proto_path="${PROTOPATH}:." --twirp_out=. --go_out=. "$@"
protoc --proto_path="${PROTOPATH}:." --python_out=. --twirp_python_out=. "$@"

BIN
vendor/github.com/twitchtv/twirp/logo.png generated vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

7
vendor/github.com/twitchtv/twirp/requirements.txt generated vendored Normal file
View File

@ -0,0 +1,7 @@
certifi==2017.4.17
chardet==3.0.4
idna==2.5
protobuf==3.3.0
requests==2.17.3
six==1.10.0
urllib3==1.21.1

20
vendor/github.com/twitchtv/twirp/tools.json generated vendored Normal file
View File

@ -0,0 +1,20 @@
{
"Tools": [
{
"Repository": "github.com/golang/protobuf/protoc-gen-go",
"Commit": "c9c7427a2a70d2eb3bafa0ab2dc163e45f143317"
},
{
"Repository": "github.com/kisielk/errcheck",
"Commit": "db0ca22445717d1b2c51ac1034440e0a2a2de645"
},
{
"Repository": "github.com/gogo/protobuf/protoc-gen-gofast",
"Commit": "30433562cfbf487fe1df7cd26c7bab168d2f14d0"
},
{
"Repository": "github.com/twitchtv/retool",
"Commit": "6f6d4930d88c40e23d2b54d12e64f0444e1fb4ef"
}
]
}