2019-01-15 14:32:05 +00:00
package gengateway
import (
"bytes"
2020-02-17 21:13:33 +00:00
"errors"
2019-01-15 14:32:05 +00:00
"fmt"
"strings"
"text/template"
"github.com/golang/glog"
2020-06-04 05:55:56 +00:00
"github.com/grpc-ecosystem/grpc-gateway/internal/casing"
2019-01-15 14:32:05 +00:00
"github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/descriptor"
"github.com/grpc-ecosystem/grpc-gateway/utilities"
)
type param struct {
* descriptor . File
Imports [ ] descriptor . GoPackage
UseRequestContext bool
RegisterFuncSuffix string
2019-04-04 09:55:32 +00:00
AllowPatchFeature bool
2020-11-19 14:02:19 +00:00
OmitPackageDoc bool
2019-01-15 14:32:05 +00:00
}
type binding struct {
* descriptor . Binding
2019-04-04 09:55:32 +00:00
Registry * descriptor . Registry
AllowPatchFeature bool
2019-01-15 14:32:05 +00:00
}
// GetBodyFieldPath returns the binding body's fieldpath.
func ( b binding ) GetBodyFieldPath ( ) string {
if b . Body != nil && len ( b . Body . FieldPath ) != 0 {
return b . Body . FieldPath . String ( )
}
return "*"
}
2020-02-17 21:13:33 +00:00
// GetBodyFieldPath returns the binding body's struct field name.
func ( b binding ) GetBodyFieldStructName ( ) ( string , error ) {
if b . Body != nil && len ( b . Body . FieldPath ) != 0 {
2020-06-04 05:55:56 +00:00
return casing . Camel ( b . Body . FieldPath . String ( ) ) , nil
2020-02-17 21:13:33 +00:00
}
return "" , errors . New ( "No body field found" )
}
2019-01-15 14:32:05 +00:00
// HasQueryParam determines if the binding needs parameters in query string.
//
// It sometimes returns true even though actually the binding does not need.
// But it is not serious because it just results in a small amount of extra codes generated.
func ( b binding ) HasQueryParam ( ) bool {
if b . Body != nil && len ( b . Body . FieldPath ) == 0 {
return false
}
fields := make ( map [ string ] bool )
for _ , f := range b . Method . RequestType . Fields {
fields [ f . GetName ( ) ] = true
}
if b . Body != nil {
delete ( fields , b . Body . FieldPath . String ( ) )
}
for _ , p := range b . PathParams {
delete ( fields , p . FieldPath . String ( ) )
}
return len ( fields ) > 0
}
func ( b binding ) QueryParamFilter ( ) queryParamFilter {
var seqs [ ] [ ] string
if b . Body != nil {
seqs = append ( seqs , strings . Split ( b . Body . FieldPath . String ( ) , "." ) )
}
for _ , p := range b . PathParams {
seqs = append ( seqs , strings . Split ( p . FieldPath . String ( ) , "." ) )
}
return queryParamFilter { utilities . NewDoubleArray ( seqs ) }
}
// HasEnumPathParam returns true if the path parameter slice contains a parameter
// that maps to an enum proto field that is not repeated, if not false is returned.
func ( b binding ) HasEnumPathParam ( ) bool {
return b . hasEnumPathParam ( false )
}
// HasRepeatedEnumPathParam returns true if the path parameter slice contains a parameter
// that maps to a repeated enum proto field, if not false is returned.
func ( b binding ) HasRepeatedEnumPathParam ( ) bool {
return b . hasEnumPathParam ( true )
}
// hasEnumPathParam returns true if the path parameter slice contains a parameter
// that maps to a enum proto field and that the enum proto field is or isn't repeated
// based on the provided 'repeated' parameter.
func ( b binding ) hasEnumPathParam ( repeated bool ) bool {
for _ , p := range b . PathParams {
if p . IsEnum ( ) && p . IsRepeated ( ) == repeated {
return true
}
}
return false
}
// LookupEnum looks up a enum type by path parameter.
func ( b binding ) LookupEnum ( p descriptor . Parameter ) * descriptor . Enum {
e , err := b . Registry . LookupEnum ( "" , p . Target . GetTypeName ( ) )
if err != nil {
return nil
}
return e
}
// FieldMaskField returns the golang-style name of the variable for a FieldMask, if there is exactly one of that type in
// the message. Otherwise, it returns an empty string.
func ( b binding ) FieldMaskField ( ) string {
var fieldMaskField * descriptor . Field
for _ , f := range b . Method . RequestType . Fields {
if f . GetTypeName ( ) == ".google.protobuf.FieldMask" {
// if there is more than 1 FieldMask for this request, then return none
if fieldMaskField != nil {
return ""
}
fieldMaskField = f
}
}
if fieldMaskField != nil {
2020-06-04 05:55:56 +00:00
return casing . Camel ( fieldMaskField . GetName ( ) )
2019-01-15 14:32:05 +00:00
}
return ""
}
// queryParamFilter is a wrapper of utilities.DoubleArray which provides String() to output DoubleArray.Encoding in a stable and predictable format.
type queryParamFilter struct {
* utilities . DoubleArray
}
func ( f queryParamFilter ) String ( ) string {
encodings := make ( [ ] string , len ( f . Encoding ) )
for str , enc := range f . Encoding {
encodings [ enc ] = fmt . Sprintf ( "%q: %d" , str , enc )
}
e := strings . Join ( encodings , ", " )
return fmt . Sprintf ( "&utilities.DoubleArray{Encoding: map[string]int{%s}, Base: %#v, Check: %#v}" , e , f . Base , f . Check )
}
type trailerParams struct {
Services [ ] * descriptor . Service
UseRequestContext bool
RegisterFuncSuffix string
2019-08-14 09:00:39 +00:00
AssumeColonVerb bool
2019-01-15 14:32:05 +00:00
}
func applyTemplate ( p param , reg * descriptor . Registry ) ( string , error ) {
w := bytes . NewBuffer ( nil )
if err := headerTemplate . Execute ( w , p ) ; err != nil {
return "" , err
}
var targetServices [ ] * descriptor . Service
2019-04-04 09:55:32 +00:00
for _ , msg := range p . Messages {
2020-06-04 05:55:56 +00:00
msgName := casing . Camel ( * msg . Name )
2019-04-04 09:55:32 +00:00
msg . Name = & msgName
}
2019-01-15 14:32:05 +00:00
for _ , svc := range p . Services {
var methodWithBindingsSeen bool
2020-06-04 05:55:56 +00:00
svcName := casing . Camel ( * svc . Name )
2019-01-15 14:32:05 +00:00
svc . Name = & svcName
for _ , meth := range svc . Methods {
glog . V ( 2 ) . Infof ( "Processing %s.%s" , svc . GetName ( ) , meth . GetName ( ) )
2020-06-04 05:55:56 +00:00
methName := casing . Camel ( * meth . Name )
2019-01-15 14:32:05 +00:00
meth . Name = & methName
for _ , b := range meth . Bindings {
methodWithBindingsSeen = true
2019-04-04 09:55:32 +00:00
if err := handlerTemplate . Execute ( w , binding {
Binding : b ,
Registry : reg ,
AllowPatchFeature : p . AllowPatchFeature ,
} ) ; err != nil {
2019-01-15 14:32:05 +00:00
return "" , err
}
2020-02-17 21:13:33 +00:00
// Local
if err := localHandlerTemplate . Execute ( w , binding {
Binding : b ,
Registry : reg ,
AllowPatchFeature : p . AllowPatchFeature ,
} ) ; err != nil {
return "" , err
}
2019-01-15 14:32:05 +00:00
}
}
if methodWithBindingsSeen {
targetServices = append ( targetServices , svc )
}
}
if len ( targetServices ) == 0 {
return "" , errNoTargetService
}
2019-08-14 09:00:39 +00:00
assumeColonVerb := true
if reg != nil {
assumeColonVerb = ! reg . GetAllowColonFinalSegments ( )
}
2019-01-15 14:32:05 +00:00
tp := trailerParams {
Services : targetServices ,
UseRequestContext : p . UseRequestContext ,
RegisterFuncSuffix : p . RegisterFuncSuffix ,
2019-08-14 09:00:39 +00:00
AssumeColonVerb : assumeColonVerb ,
2019-01-15 14:32:05 +00:00
}
2020-02-17 21:13:33 +00:00
// Local
if err := localTrailerTemplate . Execute ( w , tp ) ; err != nil {
return "" , err
}
2019-01-15 14:32:05 +00:00
if err := trailerTemplate . Execute ( w , tp ) ; err != nil {
return "" , err
}
return w . String ( ) , nil
}
var (
headerTemplate = template . Must ( template . New ( "header" ) . Parse ( `
// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
// source: {{.GetName}}
2020-11-19 14:02:19 +00:00
{ { if not . OmitPackageDoc } } / *
2019-01-15 14:32:05 +00:00
Package { { . GoPkg . Name } } is a reverse proxy .
It translates gRPC into RESTful JSON APIs .
2020-11-19 14:02:19 +00:00
* / { { end } }
2019-01-15 14:32:05 +00:00
package { { . GoPkg . Name } }
import (
{ { range $ i := . Imports } } { { if $ i . Standard } } { { $ i | printf "%s\n" } } { { end } } { { end } }
{ { range $ i := . Imports } } { { if not $ i . Standard } } { { $ i | printf "%s\n" } } { { end } } { { end } }
)
2020-02-17 21:13:33 +00:00
// Suppress "imported and not used" errors
2019-01-15 14:32:05 +00:00
var _ codes . Code
var _ io . Reader
var _ status . Status
var _ = runtime . String
var _ = utilities . NewDoubleArray
2020-02-17 21:13:33 +00:00
var _ = descriptor . ForMessage
2020-10-08 07:26:01 +00:00
var _ = metadata . Join
2019-01-15 14:32:05 +00:00
` ) )
handlerTemplate = template . Must ( template . New ( "handler" ) . Parse ( `
{ { if and . Method . GetClientStreaming . Method . GetServerStreaming } }
{ { template "bidi-streaming-request-func" . } }
{ { else if . Method . GetClientStreaming } }
{ { template "client-streaming-request-func" . } }
{ { else } }
{ { template "client-rpc-request-func" . } }
{ { end } }
` ) )
_ = template . Must ( handlerTemplate . New ( "request-func-signature" ) . Parse ( strings . Replace ( `
{ { if . Method . GetServerStreaming } }
func request_ { { . Method . Service . GetName } } _ { { . Method . GetName } } _ { { . Index } } ( ctx context . Context , marshaler runtime . Marshaler , client { { . Method . Service . GetName } } Client , req * http . Request , pathParams map [ string ] string ) ( { { . Method . Service . GetName } } _ { { . Method . GetName } } Client , runtime . ServerMetadata , error )
{ { else } }
func request_ { { . Method . Service . GetName } } _ { { . Method . GetName } } _ { { . Index } } ( ctx context . Context , marshaler runtime . Marshaler , client { { . Method . Service . GetName } } Client , req * http . Request , pathParams map [ string ] string ) ( proto . Message , runtime . ServerMetadata , error )
{ { end } } ` , "\n" , "" , - 1 ) ) )
_ = template . Must ( handlerTemplate . New ( "client-streaming-request-func" ) . Parse ( `
{ { template "request-func-signature" . } } {
var metadata runtime . ServerMetadata
stream , err := client . { { . Method . GetName } } ( ctx )
if err != nil {
grpclog . Infof ( "Failed to start streaming: %v" , err )
return nil , metadata , err
}
2019-04-04 09:55:32 +00:00
dec := marshaler . NewDecoder ( req . Body )
2019-01-15 14:32:05 +00:00
for {
var protoReq { { . Method . RequestType . GoType . Method . Service . File . GoPkg . Path } }
err = dec . Decode ( & protoReq )
if err == io . EOF {
break
}
if err != nil {
grpclog . Infof ( "Failed to decode request: %v" , err )
return nil , metadata , status . Errorf ( codes . InvalidArgument , "%v" , err )
}
if err = stream . Send ( & protoReq ) ; err != nil {
2019-08-14 09:00:39 +00:00
if err == io . EOF {
break
}
2019-01-15 14:32:05 +00:00
grpclog . Infof ( "Failed to send request: %v" , err )
return nil , metadata , err
}
}
if err := stream . CloseSend ( ) ; err != nil {
grpclog . Infof ( "Failed to terminate client stream: %v" , err )
return nil , metadata , err
}
header , err := stream . Header ( )
if err != nil {
grpclog . Infof ( "Failed to get header from client: %v" , err )
return nil , metadata , err
}
metadata . HeaderMD = header
{ { if . Method . GetServerStreaming } }
return stream , metadata , nil
{ { else } }
msg , err := stream . CloseAndRecv ( )
metadata . TrailerMD = stream . Trailer ( )
return msg , metadata , err
{ { end } }
}
` ) )
_ = template . Must ( handlerTemplate . New ( "client-rpc-request-func" ) . Parse ( `
2019-04-04 09:55:32 +00:00
{ { $ AllowPatchFeature := . AllowPatchFeature } }
2019-01-15 14:32:05 +00:00
{ { if . HasQueryParam } }
var (
filter_ { { . Method . Service . GetName } } _ { { . Method . GetName } } _ { { . Index } } = { { . QueryParamFilter } }
)
{ { end } }
{ { template "request-func-signature" . } } {
var protoReq { { . Method . RequestType . GoType . Method . Service . File . GoPkg . Path } }
var metadata runtime . ServerMetadata
{ { if . Body } }
newReader , berr := utilities . IOReaderFactory ( req . Body )
if berr != nil {
return nil , metadata , status . Errorf ( codes . InvalidArgument , "%v" , berr )
}
if err := marshaler . NewDecoder ( newReader ( ) ) . Decode ( & { { . Body . AssignableExpr "protoReq" } } ) ; err != nil && err != io . EOF {
return nil , metadata , status . Errorf ( codes . InvalidArgument , "%v" , err )
}
2020-02-17 21:13:33 +00:00
{ { - if and $ AllowPatchFeature ( eq ( . HTTPMethod ) "PATCH" ) ( . FieldMaskField ) ( not ( eq "*" . GetBodyFieldPath ) ) } }
if protoReq . { { . FieldMaskField } } == nil || len ( protoReq . { { . FieldMaskField } } . GetPaths ( ) ) == 0 {
_ , md := descriptor . ForMessage ( protoReq . { { . GetBodyFieldStructName } } )
if fieldMask , err := runtime . FieldMaskFromRequestBody ( newReader ( ) , md ) ; err != nil {
2019-01-15 14:32:05 +00:00
return nil , metadata , status . Errorf ( codes . InvalidArgument , "%v" , err )
} else {
protoReq . { { . FieldMaskField } } = fieldMask
2019-04-04 09:55:32 +00:00
}
2020-02-17 21:13:33 +00:00
}
2019-01-15 14:32:05 +00:00
{ { end } }
{ { end } }
{ { if . PathParams } }
var (
val string
{ { - if . HasEnumPathParam } }
e int32
{ { - end } }
{ { - if . HasRepeatedEnumPathParam } }
es [ ] int32
{ { - end } }
ok bool
err error
_ = err
)
{ { $ binding := . } }
{ { range $ param := . PathParams } }
{ { $ enum := $ binding . LookupEnum $ param } }
val , ok = pathParams [ { { $ param | printf "%q" } } ]
if ! ok {
return nil , metadata , status . Errorf ( codes . InvalidArgument , "missing parameter %s" , { { $ param | printf "%q" } } )
}
{ { if $ param . IsNestedProto3 } }
err = runtime . PopulateFieldFromPath ( & protoReq , { { $ param | printf "%q" } } , val )
2020-02-17 21:13:33 +00:00
{ { if $ enum } }
2020-10-08 07:26:01 +00:00
e { { if $ param . IsRepeated } } s { { end } } , err = { { $ param . ConvertFuncExpr } } ( val { { if $ param . IsRepeated } } , { { $ binding . Registry . GetRepeatedPathParamSeparator | printf "%c" | printf "%q" } } { { end } } , { { $ enum . GoType $ param . Method . Service . File . GoPkg . Path } } _value )
2020-02-17 21:13:33 +00:00
{ { end } }
2019-01-15 14:32:05 +00:00
{ { else if $ enum } }
2020-10-08 07:26:01 +00:00
e { { if $ param . IsRepeated } } s { { end } } , err = { { $ param . ConvertFuncExpr } } ( val { { if $ param . IsRepeated } } , { { $ binding . Registry . GetRepeatedPathParamSeparator | printf "%c" | printf "%q" } } { { end } } , { { $ enum . GoType $ param . Method . Service . File . GoPkg . Path } } _value )
2019-01-15 14:32:05 +00:00
{ { else } }
{ { $ param . AssignableExpr "protoReq" } } , err = { { $ param . ConvertFuncExpr } } ( val { { if $ param . IsRepeated } } , { { $ binding . Registry . GetRepeatedPathParamSeparator | printf "%c" | printf "%q" } } { { end } } )
{ { end } }
if err != nil {
return nil , metadata , status . Errorf ( codes . InvalidArgument , "type mismatch, parameter: %s, error: %v" , { { $ param | printf "%q" } } , err )
}
{ { if and $ enum $ param . IsRepeated } }
2020-10-08 07:26:01 +00:00
s := make ( [ ] { { $ enum . GoType $ param . Method . Service . File . GoPkg . Path } } , len ( es ) )
2019-01-15 14:32:05 +00:00
for i , v := range es {
2020-10-08 07:26:01 +00:00
s [ i ] = { { $ enum . GoType $ param . Method . Service . File . GoPkg . Path } } ( v )
2019-01-15 14:32:05 +00:00
}
{ { $ param . AssignableExpr "protoReq" } } = s
{ { else if $ enum } }
2020-10-08 07:26:01 +00:00
{ { $ param . AssignableExpr "protoReq" } } = { { $ enum . GoType $ param . Method . Service . File . GoPkg . Path } } ( e )
2019-01-15 14:32:05 +00:00
{ { end } }
{ { end } }
{ { end } }
{ { if . HasQueryParam } }
2019-08-14 09:00:39 +00:00
if err := req . ParseForm ( ) ; err != nil {
return nil , metadata , status . Errorf ( codes . InvalidArgument , "%v" , err )
}
if err := runtime . PopulateQueryParameters ( & protoReq , req . Form , filter_ { { . Method . Service . GetName } } _ { { . Method . GetName } } _ { { . Index } } ) ; err != nil {
2019-01-15 14:32:05 +00:00
return nil , metadata , status . Errorf ( codes . InvalidArgument , "%v" , err )
}
{ { end } }
{ { if . Method . GetServerStreaming } }
stream , err := client . { { . Method . GetName } } ( ctx , & protoReq )
if err != nil {
return nil , metadata , err
}
header , err := stream . Header ( )
if err != nil {
return nil , metadata , err
}
metadata . HeaderMD = header
return stream , metadata , nil
{ { else } }
msg , err := client . { { . Method . GetName } } ( ctx , & protoReq , grpc . Header ( & metadata . HeaderMD ) , grpc . Trailer ( & metadata . TrailerMD ) )
return msg , metadata , err
{ { end } }
} ` ) )
_ = template . Must ( handlerTemplate . New ( "bidi-streaming-request-func" ) . Parse ( `
{ { template "request-func-signature" . } } {
var metadata runtime . ServerMetadata
stream , err := client . { { . Method . GetName } } ( ctx )
if err != nil {
grpclog . Infof ( "Failed to start streaming: %v" , err )
return nil , metadata , err
}
2019-04-04 09:55:32 +00:00
dec := marshaler . NewDecoder ( req . Body )
2019-01-15 14:32:05 +00:00
handleSend := func ( ) error {
var protoReq { { . Method . RequestType . GoType . Method . Service . File . GoPkg . Path } }
err := dec . Decode ( & protoReq )
if err == io . EOF {
return err
}
if err != nil {
grpclog . Infof ( "Failed to decode request: %v" , err )
return err
}
if err := stream . Send ( & protoReq ) ; err != nil {
grpclog . Infof ( "Failed to send request: %v" , err )
return err
}
return nil
}
if err := handleSend ( ) ; err != nil {
if cerr := stream . CloseSend ( ) ; cerr != nil {
grpclog . Infof ( "Failed to terminate client stream: %v" , cerr )
}
if err == io . EOF {
return stream , metadata , nil
}
return nil , metadata , err
}
go func ( ) {
for {
if err := handleSend ( ) ; err != nil {
break
}
}
if err := stream . CloseSend ( ) ; err != nil {
grpclog . Infof ( "Failed to terminate client stream: %v" , err )
}
} ( )
header , err := stream . Header ( )
if err != nil {
grpclog . Infof ( "Failed to get header from client: %v" , err )
return nil , metadata , err
}
metadata . HeaderMD = header
return stream , metadata , nil
}
` ) )
2020-02-17 21:13:33 +00:00
localHandlerTemplate = template . Must ( template . New ( "local-handler" ) . Parse ( `
{ { if and . Method . GetClientStreaming . Method . GetServerStreaming } }
{ { else if . Method . GetClientStreaming } }
{ { else if . Method . GetServerStreaming } }
{ { else } }
{ { template "local-client-rpc-request-func" . } }
{ { end } }
` ) )
_ = template . Must ( localHandlerTemplate . New ( "local-request-func-signature" ) . Parse ( strings . Replace ( `
{ { if . Method . GetServerStreaming } }
{ { else } }
func local_request_ { { . Method . Service . GetName } } _ { { . Method . GetName } } _ { { . Index } } ( ctx context . Context , marshaler runtime . Marshaler , server { { . Method . Service . GetName } } Server , req * http . Request , pathParams map [ string ] string ) ( proto . Message , runtime . ServerMetadata , error )
{ { end } } ` , "\n" , "" , - 1 ) ) )
_ = template . Must ( localHandlerTemplate . New ( "local-client-rpc-request-func" ) . Parse ( `
{ { $ AllowPatchFeature := . AllowPatchFeature } }
{ { template "local-request-func-signature" . } } {
var protoReq { { . Method . RequestType . GoType . Method . Service . File . GoPkg . Path } }
var metadata runtime . ServerMetadata
{ { if . Body } }
newReader , berr := utilities . IOReaderFactory ( req . Body )
if berr != nil {
return nil , metadata , status . Errorf ( codes . InvalidArgument , "%v" , berr )
}
if err := marshaler . NewDecoder ( newReader ( ) ) . Decode ( & { { . Body . AssignableExpr "protoReq" } } ) ; err != nil && err != io . EOF {
return nil , metadata , status . Errorf ( codes . InvalidArgument , "%v" , err )
}
{ { - if and $ AllowPatchFeature ( eq ( . HTTPMethod ) "PATCH" ) ( . FieldMaskField ) ( not ( eq "*" . GetBodyFieldPath ) ) } }
if protoReq . { { . FieldMaskField } } == nil || len ( protoReq . { { . FieldMaskField } } . GetPaths ( ) ) == 0 {
_ , md := descriptor . ForMessage ( protoReq . { { . GetBodyFieldStructName } } )
if fieldMask , err := runtime . FieldMaskFromRequestBody ( newReader ( ) , md ) ; err != nil {
return nil , metadata , status . Errorf ( codes . InvalidArgument , "%v" , err )
} else {
protoReq . { { . FieldMaskField } } = fieldMask
}
}
{ { end } }
{ { end } }
{ { if . PathParams } }
var (
val string
{ { - if . HasEnumPathParam } }
e int32
{ { - end } }
{ { - if . HasRepeatedEnumPathParam } }
es [ ] int32
{ { - end } }
ok bool
err error
_ = err
)
{ { $ binding := . } }
{ { range $ param := . PathParams } }
{ { $ enum := $ binding . LookupEnum $ param } }
val , ok = pathParams [ { { $ param | printf "%q" } } ]
if ! ok {
return nil , metadata , status . Errorf ( codes . InvalidArgument , "missing parameter %s" , { { $ param | printf "%q" } } )
}
{ { if $ param . IsNestedProto3 } }
err = runtime . PopulateFieldFromPath ( & protoReq , { { $ param | printf "%q" } } , val )
{ { if $ enum } }
2020-10-08 07:26:01 +00:00
e { { if $ param . IsRepeated } } s { { end } } , err = { { $ param . ConvertFuncExpr } } ( val { { if $ param . IsRepeated } } , { { $ binding . Registry . GetRepeatedPathParamSeparator | printf "%c" | printf "%q" } } { { end } } , { { $ enum . GoType $ param . Method . Service . File . GoPkg . Path } } _value )
2020-02-17 21:13:33 +00:00
{ { end } }
{ { else if $ enum } }
2020-10-08 07:26:01 +00:00
e { { if $ param . IsRepeated } } s { { end } } , err = { { $ param . ConvertFuncExpr } } ( val { { if $ param . IsRepeated } } , { { $ binding . Registry . GetRepeatedPathParamSeparator | printf "%c" | printf "%q" } } { { end } } , { { $ enum . GoType $ param . Method . Service . File . GoPkg . Path } } _value )
2020-02-17 21:13:33 +00:00
{ { else } }
{ { $ param . AssignableExpr "protoReq" } } , err = { { $ param . ConvertFuncExpr } } ( val { { if $ param . IsRepeated } } , { { $ binding . Registry . GetRepeatedPathParamSeparator | printf "%c" | printf "%q" } } { { end } } )
{ { end } }
if err != nil {
return nil , metadata , status . Errorf ( codes . InvalidArgument , "type mismatch, parameter: %s, error: %v" , { { $ param | printf "%q" } } , err )
}
{ { if and $ enum $ param . IsRepeated } }
2020-10-08 07:26:01 +00:00
s := make ( [ ] { { $ enum . GoType $ param . Method . Service . File . GoPkg . Path } } , len ( es ) )
2020-02-17 21:13:33 +00:00
for i , v := range es {
2020-10-08 07:26:01 +00:00
s [ i ] = { { $ enum . GoType $ param . Method . Service . File . GoPkg . Path } } ( v )
2020-02-17 21:13:33 +00:00
}
{ { $ param . AssignableExpr "protoReq" } } = s
{ { else if $ enum } }
2020-10-08 07:26:01 +00:00
{ { $ param . AssignableExpr "protoReq" } } = { { $ enum . GoType $ param . Method . Service . File . GoPkg . Path } } ( e )
2020-02-17 21:13:33 +00:00
{ { end } }
{ { end } }
{ { end } }
{ { if . HasQueryParam } }
2020-06-04 05:55:56 +00:00
if err := req . ParseForm ( ) ; err != nil {
return nil , metadata , status . Errorf ( codes . InvalidArgument , "%v" , err )
}
if err := runtime . PopulateQueryParameters ( & protoReq , req . Form , filter_ { { . Method . Service . GetName } } _ { { . Method . GetName } } _ { { . Index } } ) ; err != nil {
2020-02-17 21:13:33 +00:00
return nil , metadata , status . Errorf ( codes . InvalidArgument , "%v" , err )
}
{ { end } }
{ { if . Method . GetServerStreaming } }
// TODO
{ { else } }
msg , err := server . { { . Method . GetName } } ( ctx , & protoReq )
return msg , metadata , err
{ { end } }
} ` ) )
localTrailerTemplate = template . Must ( template . New ( "local-trailer" ) . Parse ( `
{ { $ UseRequestContext := . UseRequestContext } }
{ { range $ svc := . Services } }
// Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}Server registers the http handlers for service {{$svc.GetName}} to "mux".
// UnaryRPC :call {{$svc.GetName}}Server directly.
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
2020-10-08 07:26:01 +00:00
// Note that using this registration option will cause many gRPC library features to stop working. Consider using Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}FromEndpoint instead.
2020-02-17 21:13:33 +00:00
func Register { { $ svc . GetName } } { { $ . RegisterFuncSuffix } } Server ( ctx context . Context , mux * runtime . ServeMux , server { { $ svc . GetName } } Server ) error {
{ { range $ m := $ svc . Methods } }
{ { range $ b := $ m . Bindings } }
{ { if or $ m . GetClientStreaming $ m . GetServerStreaming } }
mux . Handle ( { { $ b . HTTPMethod | printf "%q" } } , pattern_ { { $ svc . GetName } } _ { { $ m . GetName } } _ { { $ b . Index } } , func ( w http . ResponseWriter , req * http . Request , pathParams map [ string ] string ) {
err := status . Error ( codes . Unimplemented , "streaming calls are not yet supported in the in-process transport" )
_ , outboundMarshaler := runtime . MarshalerForRequest ( mux , req )
runtime . HTTPError ( ctx , mux , outboundMarshaler , w , req , err )
return
} )
{ { else } }
mux . Handle ( { { $ b . HTTPMethod | printf "%q" } } , pattern_ { { $ svc . GetName } } _ { { $ m . GetName } } _ { { $ b . Index } } , func ( w http . ResponseWriter , req * http . Request , pathParams map [ string ] string ) {
{ { - if $ UseRequestContext } }
ctx , cancel := context . WithCancel ( req . Context ( ) )
{ { - else - } }
ctx , cancel := context . WithCancel ( ctx )
{ { - end } }
defer cancel ( )
2020-10-08 07:26:01 +00:00
var stream runtime . ServerTransportStream
ctx = grpc . NewContextWithServerTransportStream ( ctx , & stream )
2020-02-17 21:13:33 +00:00
inboundMarshaler , outboundMarshaler := runtime . MarshalerForRequest ( mux , req )
rctx , err := runtime . AnnotateIncomingContext ( ctx , mux , req )
if err != nil {
runtime . HTTPError ( ctx , mux , outboundMarshaler , w , req , err )
return
}
resp , md , err := local_request_ { { $ svc . GetName } } _ { { $ m . GetName } } _ { { $ b . Index } } ( rctx , inboundMarshaler , server , req , pathParams )
2020-10-08 07:26:01 +00:00
md . HeaderMD , md . TrailerMD = metadata . Join ( md . HeaderMD , stream . Header ( ) ) , metadata . Join ( md . TrailerMD , stream . Trailer ( ) )
2020-02-17 21:13:33 +00:00
ctx = runtime . NewServerMetadataContext ( ctx , md )
if err != nil {
runtime . HTTPError ( ctx , mux , outboundMarshaler , w , req , err )
return
}
{ { if $ b . ResponseBody } }
forward_ { { $ svc . GetName } } _ { { $ m . GetName } } _ { { $ b . Index } } ( ctx , mux , outboundMarshaler , w , req , response_ { { $ svc . GetName } } _ { { $ m . GetName } } _ { { $ b . Index } } { resp } , mux . GetForwardResponseOptions ( ) ... )
{ { else } }
forward_ { { $ svc . GetName } } _ { { $ m . GetName } } _ { { $ b . Index } } ( ctx , mux , outboundMarshaler , w , req , resp , mux . GetForwardResponseOptions ( ) ... )
{ { end } }
} )
{ { end } }
{ { end } }
{ { end } }
return nil
}
{ { end } } ` ) )
2019-01-15 14:32:05 +00:00
trailerTemplate = template . Must ( template . New ( "trailer" ) . Parse ( `
{ { $ UseRequestContext := . UseRequestContext } }
{ { range $ svc := . Services } }
// Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}FromEndpoint is same as Register{{$svc.GetName}}{{$.RegisterFuncSuffix}} but
// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
func Register { { $ svc . GetName } } { { $ . RegisterFuncSuffix } } FromEndpoint ( ctx context . Context , mux * runtime . ServeMux , endpoint string , opts [ ] grpc . DialOption ) ( err error ) {
conn , err := grpc . Dial ( endpoint , opts ... )
if err != nil {
return err
}
defer func ( ) {
if err != nil {
if cerr := conn . Close ( ) ; cerr != nil {
grpclog . Infof ( "Failed to close conn to %s: %v" , endpoint , cerr )
}
return
}
go func ( ) {
<- ctx . Done ( )
if cerr := conn . Close ( ) ; cerr != nil {
grpclog . Infof ( "Failed to close conn to %s: %v" , endpoint , cerr )
}
} ( )
} ( )
return Register { { $ svc . GetName } } { { $ . RegisterFuncSuffix } } ( ctx , mux , conn )
}
// Register{{$svc.GetName}}{{$.RegisterFuncSuffix}} registers the http handlers for service {{$svc.GetName}} to "mux".
// The handlers forward requests to the grpc endpoint over "conn".
func Register { { $ svc . GetName } } { { $ . RegisterFuncSuffix } } ( ctx context . Context , mux * runtime . ServeMux , conn * grpc . ClientConn ) error {
return Register { { $ svc . GetName } } { { $ . RegisterFuncSuffix } } Client ( ctx , mux , New { { $ svc . GetName } } Client ( conn ) )
}
// Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}Client registers the http handlers for service {{$svc.GetName}}
// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "{{$svc.GetName}}Client".
// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "{{$svc.GetName}}Client"
// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
// "{{$svc.GetName}}Client" to call the correct interceptors.
func Register { { $ svc . GetName } } { { $ . RegisterFuncSuffix } } Client ( ctx context . Context , mux * runtime . ServeMux , client { { $ svc . GetName } } Client ) error {
{ { range $ m := $ svc . Methods } }
{ { range $ b := $ m . Bindings } }
mux . Handle ( { { $ b . HTTPMethod | printf "%q" } } , pattern_ { { $ svc . GetName } } _ { { $ m . GetName } } _ { { $ b . Index } } , func ( w http . ResponseWriter , req * http . Request , pathParams map [ string ] string ) {
{ { - if $ UseRequestContext } }
ctx , cancel := context . WithCancel ( req . Context ( ) )
{ { - else - } }
ctx , cancel := context . WithCancel ( ctx )
{ { - end } }
defer cancel ( )
inboundMarshaler , outboundMarshaler := runtime . MarshalerForRequest ( mux , req )
rctx , err := runtime . AnnotateContext ( ctx , mux , req )
if err != nil {
runtime . HTTPError ( ctx , mux , outboundMarshaler , w , req , err )
return
}
resp , md , err := request_ { { $ svc . GetName } } _ { { $ m . GetName } } _ { { $ b . Index } } ( rctx , inboundMarshaler , client , req , pathParams )
ctx = runtime . NewServerMetadataContext ( ctx , md )
if err != nil {
runtime . HTTPError ( ctx , mux , outboundMarshaler , w , req , err )
return
}
{ { if $ m . GetServerStreaming } }
2020-04-23 10:17:08 +00:00
{ { if $ b . ResponseBody } }
forward_ { { $ svc . GetName } } _ { { $ m . GetName } } _ { { $ b . Index } } ( ctx , mux , outboundMarshaler , w , req , func ( ) ( proto . Message , error ) {
res , err := resp . Recv ( )
return response_ { { $ svc . GetName } } _ { { $ m . GetName } } _ { { $ b . Index } } { res } , err
} , mux . GetForwardResponseOptions ( ) ... )
{ { else } }
2019-01-15 14:32:05 +00:00
forward_ { { $ svc . GetName } } _ { { $ m . GetName } } _ { { $ b . Index } } ( ctx , mux , outboundMarshaler , w , req , func ( ) ( proto . Message , error ) { return resp . Recv ( ) } , mux . GetForwardResponseOptions ( ) ... )
2020-04-23 10:17:08 +00:00
{ { end } }
2019-01-15 14:32:05 +00:00
{ { else } }
{ { if $ b . ResponseBody } }
forward_ { { $ svc . GetName } } _ { { $ m . GetName } } _ { { $ b . Index } } ( ctx , mux , outboundMarshaler , w , req , response_ { { $ svc . GetName } } _ { { $ m . GetName } } _ { { $ b . Index } } { resp } , mux . GetForwardResponseOptions ( ) ... )
{ { else } }
forward_ { { $ svc . GetName } } _ { { $ m . GetName } } _ { { $ b . Index } } ( ctx , mux , outboundMarshaler , w , req , resp , mux . GetForwardResponseOptions ( ) ... )
{ { end } }
{ { end } }
} )
{ { end } }
{ { end } }
return nil
}
{ { range $ m := $ svc . Methods } }
{ { range $ b := $ m . Bindings } }
{ { if $ b . ResponseBody } }
type response_ { { $ svc . GetName } } _ { { $ m . GetName } } _ { { $ b . Index } } struct {
proto . Message
}
func ( m response_ { { $ svc . GetName } } _ { { $ m . GetName } } _ { { $ b . Index } } ) XXX_ResponseBody ( ) interface { } {
response := m . Message . ( * { { $ m . ResponseType . GoType $ m . Service . File . GoPkg . Path } } )
return { { $ b . ResponseBody . AssignableExpr "response" } }
}
{ { end } }
{ { end } }
{ { end } }
var (
{ { range $ m := $ svc . Methods } }
{ { range $ b := $ m . Bindings } }
2019-08-14 09:00:39 +00:00
pattern_ { { $ svc . GetName } } _ { { $ m . GetName } } _ { { $ b . Index } } = runtime . MustPattern ( runtime . NewPattern ( { { $ b . PathTmpl . Version } } , { { $ b . PathTmpl . OpCodes | printf "%#v" } } , { { $ b . PathTmpl . Pool | printf "%#v" } } , { { $ b . PathTmpl . Verb | printf "%q" } } , runtime . AssumeColonVerbOpt ( { { $ . AssumeColonVerb } } ) ) )
2019-01-15 14:32:05 +00:00
{ { end } }
{ { end } }
)
var (
{ { range $ m := $ svc . Methods } }
{ { range $ b := $ m . Bindings } }
forward_ { { $ svc . GetName } } _ { { $ m . GetName } } _ { { $ b . Index } } = { { if $ m . GetServerStreaming } } runtime . ForwardResponseStream { { else } } runtime . ForwardResponseMessage { { end } }
{ { end } }
{ { end } }
)
{ { end } } ` ) )
2020-06-04 05:55:56 +00:00
)