From 8635a1019520dfce39e239a96bad3eb1e08d85b7 Mon Sep 17 00:00:00 2001 From: chenbin1314 Date: Mon, 6 Jul 2020 20:52:08 +0800 Subject: [PATCH 01/56] Update go.mod --- go.mod | 3 +- go.sum | 3 + httpoptions/annotations.pb.go | 614 ++++++++++++++++++++++++++++++++++ httpoptions/http.pb.go | 323 ++++++++++++++++++ 4 files changed, 942 insertions(+), 1 deletion(-) create mode 100755 httpoptions/annotations.pb.go create mode 100755 httpoptions/http.pb.go diff --git a/go.mod b/go.mod index d129ac2..6192b81 100644 --- a/go.mod +++ b/go.mod @@ -5,10 +5,11 @@ go 1.13 replace ( github.com/coreos/bbolt v1.3.4 => go.etcd.io/bbolt v1.3.4 github.com/coreos/bbolt v1.3.5 => go.etcd.io/bbolt v1.3.5 + google.golang.org/grpc v1.30.0 => google.golang.org/grpc v1.27.1 ) require ( - github.com/binchencoder/gateway-proto v0.0.3 // indirect + github.com/binchencoder/gateway-proto v0.0.5 github.com/binchencoder/letsgo v0.0.3 github.com/binchencoder/skylb-api v0.0.3 github.com/fatih/color v1.9.0 diff --git a/go.sum b/go.sum index c0b7558..7a72654 100644 --- a/go.sum +++ b/go.sum @@ -29,6 +29,8 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/binchencoder/gateway-proto v0.0.3 h1:xU2ZVx5Zjub5P/WIl12FeCII1vGdV2THWtfm7fUR7z8= github.com/binchencoder/gateway-proto v0.0.3/go.mod h1:081rlF+665EejkDRHi7gTLpZvK0eDwVX23xviXQCjV0= +github.com/binchencoder/gateway-proto v0.0.5 h1:2oh9Y8/qlMX1K3m73XDMU9U3mA06WMkLmJrMi4nFlCc= +github.com/binchencoder/gateway-proto v0.0.5/go.mod h1:853l4bAOm0Gt8XrDy+9obeKRlBLwP4HAk9tVYbgnSmU= github.com/binchencoder/letsgo v0.0.3 h1:hEDDOeGdX9R/JPYMdVo9N/9iQa5BeBLluTssrNYy/ng= github.com/binchencoder/letsgo v0.0.3/go.mod h1:WbqNFa5gFsogqe3gtycvPYswprKV7eGJIxScwQhAg44= github.com/binchencoder/skylb-api v0.0.3 h1:NnlPmEjTgOjH+s9TK3rBEY4Kn9aEzZkuEBUV2aR8UTM= @@ -441,6 +443,7 @@ google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRn google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0 h1:M5a8xTlYTxwMn5ZFkwhRabsygDY5G8TYLyQDBxJNAxE= diff --git a/httpoptions/annotations.pb.go b/httpoptions/annotations.pb.go new file mode 100755 index 0000000..73842ca --- /dev/null +++ b/httpoptions/annotations.pb.go @@ -0,0 +1,614 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: httpoptions/annotations.proto + +package ease_api + +import ( + fmt "fmt" + data "github.com/binchencoder/gateway-proto/data" + proto "github.com/golang/protobuf/proto" + descriptor "github.com/golang/protobuf/protoc-gen-go/descriptor" + 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.ProtoPackageIsVersion3 // please upgrade the proto package + +type ApiSourceType int32 + +const ( + ApiSourceType_EASE_GATEWAY ApiSourceType = 0 + ApiSourceType_OPEN_GATEWAY ApiSourceType = 1 +) + +var ApiSourceType_name = map[int32]string{ + 0: "EASE_GATEWAY", + 1: "OPEN_GATEWAY", +} + +var ApiSourceType_value = map[string]int32{ + "EASE_GATEWAY": 0, + "OPEN_GATEWAY": 1, +} + +func (x ApiSourceType) String() string { + return proto.EnumName(ApiSourceType_name, int32(x)) +} + +func (ApiSourceType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_1be5d6cda9fc6cfe, []int{0} +} + +type AuthTokenType int32 + +const ( + AuthTokenType_EASE_AUTH_TOKEN AuthTokenType = 0 + AuthTokenType_BASE_ACCESS_TOKEN AuthTokenType = 1 +) + +var AuthTokenType_name = map[int32]string{ + 0: "EASE_AUTH_TOKEN", + 1: "BASE_ACCESS_TOKEN", +} + +var AuthTokenType_value = map[string]int32{ + "EASE_AUTH_TOKEN": 0, + "BASE_ACCESS_TOKEN": 1, +} + +func (x AuthTokenType) String() string { + return proto.EnumName(AuthTokenType_name, int32(x)) +} + +func (AuthTokenType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_1be5d6cda9fc6cfe, []int{1} +} + +type SpecSourceType int32 + +const ( + SpecSourceType_UNSPECIFIED SpecSourceType = 0 + SpecSourceType_WEB SpecSourceType = 1 +) + +var SpecSourceType_name = map[int32]string{ + 0: "UNSPECIFIED", + 1: "WEB", +} + +var SpecSourceType_value = map[string]int32{ + "UNSPECIFIED": 0, + "WEB": 1, +} + +func (x SpecSourceType) String() string { + return proto.EnumName(SpecSourceType_name, int32(x)) +} + +func (SpecSourceType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_1be5d6cda9fc6cfe, []int{2} +} + +type LoadBalancer int32 + +const ( + LoadBalancer_ROUND_ROBIN LoadBalancer = 0 + LoadBalancer_CONSISTENT LoadBalancer = 1 +) + +var LoadBalancer_name = map[int32]string{ + 0: "ROUND_ROBIN", + 1: "CONSISTENT", +} + +var LoadBalancer_value = map[string]int32{ + "ROUND_ROBIN": 0, + "CONSISTENT": 1, +} + +func (x LoadBalancer) String() string { + return proto.EnumName(LoadBalancer_name, int32(x)) +} + +func (LoadBalancer) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_1be5d6cda9fc6cfe, []int{3} +} + +type OperatorType int32 + +const ( + OperatorType_OPERATOR_TYPE_UNKNOWN OperatorType = 0 + OperatorType_GT OperatorType = 1 + OperatorType_LT OperatorType = 2 + OperatorType_EQ OperatorType = 3 + OperatorType_MATCH OperatorType = 4 + OperatorType_NON_NIL OperatorType = 5 + OperatorType_LEN_GT OperatorType = 6 + OperatorType_LEN_LT OperatorType = 7 + OperatorType_LEN_EQ OperatorType = 8 +) + +var OperatorType_name = map[int32]string{ + 0: "OPERATOR_TYPE_UNKNOWN", + 1: "GT", + 2: "LT", + 3: "EQ", + 4: "MATCH", + 5: "NON_NIL", + 6: "LEN_GT", + 7: "LEN_LT", + 8: "LEN_EQ", +} + +var OperatorType_value = map[string]int32{ + "OPERATOR_TYPE_UNKNOWN": 0, + "GT": 1, + "LT": 2, + "EQ": 3, + "MATCH": 4, + "NON_NIL": 5, + "LEN_GT": 6, + "LEN_LT": 7, + "LEN_EQ": 8, +} + +func (x OperatorType) String() string { + return proto.EnumName(OperatorType_name, int32(x)) +} + +func (OperatorType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_1be5d6cda9fc6cfe, []int{4} +} + +type FunctionType int32 + +const ( + FunctionType_FUNCTION_TYPE_UNKNOWN FunctionType = 0 + FunctionType_TRIM FunctionType = 1 +) + +var FunctionType_name = map[int32]string{ + 0: "FUNCTION_TYPE_UNKNOWN", + 1: "TRIM", +} + +var FunctionType_value = map[string]int32{ + "FUNCTION_TYPE_UNKNOWN": 0, + "TRIM": 1, +} + +func (x FunctionType) String() string { + return proto.EnumName(FunctionType_name, int32(x)) +} + +func (FunctionType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_1be5d6cda9fc6cfe, []int{5} +} + +type ValueType int32 + +const ( + ValueType_VALUE_TYPE_UNKNOWN ValueType = 0 + ValueType_NUMBER ValueType = 1 + ValueType_STRING ValueType = 2 + ValueType_OBJ ValueType = 3 +) + +var ValueType_name = map[int32]string{ + 0: "VALUE_TYPE_UNKNOWN", + 1: "NUMBER", + 2: "STRING", + 3: "OBJ", +} + +var ValueType_value = map[string]int32{ + "VALUE_TYPE_UNKNOWN": 0, + "NUMBER": 1, + "STRING": 2, + "OBJ": 3, +} + +func (x ValueType) String() string { + return proto.EnumName(ValueType_name, int32(x)) +} + +func (ValueType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_1be5d6cda9fc6cfe, []int{6} +} + +type ApiMethod struct { + LoginNotRequired bool `protobuf:"varint,1,opt,name=login_not_required,json=loginNotRequired,proto3" json:"login_not_required,omitempty"` + ClientSignRequired bool `protobuf:"varint,2,opt,name=client_sign_required,json=clientSignRequired,proto3" json:"client_sign_required,omitempty"` + HashKey string `protobuf:"bytes,3,opt,name=hash_key,json=hashKey,proto3" json:"hash_key,omitempty"` + IsThirdParty bool `protobuf:"varint,4,opt,name=is_third_party,json=isThirdParty,proto3" json:"is_third_party,omitempty"` + Timeout string `protobuf:"bytes,5,opt,name=timeout,proto3" json:"timeout,omitempty"` + ApiSource ApiSourceType `protobuf:"varint,6,opt,name=api_source,json=apiSource,proto3,enum=ease.api.ApiSourceType" json:"api_source,omitempty"` + TokenType AuthTokenType `protobuf:"varint,7,opt,name=token_type,json=tokenType,proto3,enum=ease.api.AuthTokenType" json:"token_type,omitempty"` + SpecSourceType SpecSourceType `protobuf:"varint,8,opt,name=spec_source_type,json=specSourceType,proto3,enum=ease.api.SpecSourceType" json:"spec_source_type,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ApiMethod) Reset() { *m = ApiMethod{} } +func (m *ApiMethod) String() string { return proto.CompactTextString(m) } +func (*ApiMethod) ProtoMessage() {} +func (*ApiMethod) Descriptor() ([]byte, []int) { + return fileDescriptor_1be5d6cda9fc6cfe, []int{0} +} + +func (m *ApiMethod) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ApiMethod.Unmarshal(m, b) +} +func (m *ApiMethod) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ApiMethod.Marshal(b, m, deterministic) +} +func (m *ApiMethod) XXX_Merge(src proto.Message) { + xxx_messageInfo_ApiMethod.Merge(m, src) +} +func (m *ApiMethod) XXX_Size() int { + return xxx_messageInfo_ApiMethod.Size(m) +} +func (m *ApiMethod) XXX_DiscardUnknown() { + xxx_messageInfo_ApiMethod.DiscardUnknown(m) +} + +var xxx_messageInfo_ApiMethod proto.InternalMessageInfo + +func (m *ApiMethod) GetLoginNotRequired() bool { + if m != nil { + return m.LoginNotRequired + } + return false +} + +func (m *ApiMethod) GetClientSignRequired() bool { + if m != nil { + return m.ClientSignRequired + } + return false +} + +func (m *ApiMethod) GetHashKey() string { + if m != nil { + return m.HashKey + } + return "" +} + +func (m *ApiMethod) GetIsThirdParty() bool { + if m != nil { + return m.IsThirdParty + } + return false +} + +func (m *ApiMethod) GetTimeout() string { + if m != nil { + return m.Timeout + } + return "" +} + +func (m *ApiMethod) GetApiSource() ApiSourceType { + if m != nil { + return m.ApiSource + } + return ApiSourceType_EASE_GATEWAY +} + +func (m *ApiMethod) GetTokenType() AuthTokenType { + if m != nil { + return m.TokenType + } + return AuthTokenType_EASE_AUTH_TOKEN +} + +func (m *ApiMethod) GetSpecSourceType() SpecSourceType { + if m != nil { + return m.SpecSourceType + } + return SpecSourceType_UNSPECIFIED +} + +type ServiceSpec struct { + ServiceId data.ServiceId `protobuf:"varint,1,opt,name=service_id,json=serviceId,proto3,enum=data.ServiceId" json:"service_id,omitempty"` + PortName string `protobuf:"bytes,2,opt,name=port_name,json=portName,proto3" json:"port_name,omitempty"` + Namespace string `protobuf:"bytes,3,opt,name=namespace,proto3" json:"namespace,omitempty"` + GenController bool `protobuf:"varint,4,opt,name=gen_controller,json=genController,proto3" json:"gen_controller,omitempty"` + Balancer LoadBalancer `protobuf:"varint,5,opt,name=balancer,proto3,enum=ease.api.LoadBalancer" json:"balancer,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ServiceSpec) Reset() { *m = ServiceSpec{} } +func (m *ServiceSpec) String() string { return proto.CompactTextString(m) } +func (*ServiceSpec) ProtoMessage() {} +func (*ServiceSpec) Descriptor() ([]byte, []int) { + return fileDescriptor_1be5d6cda9fc6cfe, []int{1} +} + +func (m *ServiceSpec) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ServiceSpec.Unmarshal(m, b) +} +func (m *ServiceSpec) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ServiceSpec.Marshal(b, m, deterministic) +} +func (m *ServiceSpec) XXX_Merge(src proto.Message) { + xxx_messageInfo_ServiceSpec.Merge(m, src) +} +func (m *ServiceSpec) XXX_Size() int { + return xxx_messageInfo_ServiceSpec.Size(m) +} +func (m *ServiceSpec) XXX_DiscardUnknown() { + xxx_messageInfo_ServiceSpec.DiscardUnknown(m) +} + +var xxx_messageInfo_ServiceSpec proto.InternalMessageInfo + +func (m *ServiceSpec) GetServiceId() data.ServiceId { + if m != nil { + return m.ServiceId + } + return data.ServiceId_SERVICE_NONE +} + +func (m *ServiceSpec) GetPortName() string { + if m != nil { + return m.PortName + } + return "" +} + +func (m *ServiceSpec) GetNamespace() string { + if m != nil { + return m.Namespace + } + return "" +} + +func (m *ServiceSpec) GetGenController() bool { + if m != nil { + return m.GenController + } + return false +} + +func (m *ServiceSpec) GetBalancer() LoadBalancer { + if m != nil { + return m.Balancer + } + return LoadBalancer_ROUND_ROBIN +} + +type ValidationRule struct { + Operator OperatorType `protobuf:"varint,1,opt,name=operator,proto3,enum=ease.api.OperatorType" json:"operator,omitempty"` + Type ValueType `protobuf:"varint,2,opt,name=type,proto3,enum=ease.api.ValueType" json:"type,omitempty"` + Value string `protobuf:"bytes,3,opt,name=value,proto3" json:"value,omitempty"` + Function FunctionType `protobuf:"varint,4,opt,name=function,proto3,enum=ease.api.FunctionType" json:"function,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ValidationRule) Reset() { *m = ValidationRule{} } +func (m *ValidationRule) String() string { return proto.CompactTextString(m) } +func (*ValidationRule) ProtoMessage() {} +func (*ValidationRule) Descriptor() ([]byte, []int) { + return fileDescriptor_1be5d6cda9fc6cfe, []int{2} +} + +func (m *ValidationRule) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ValidationRule.Unmarshal(m, b) +} +func (m *ValidationRule) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ValidationRule.Marshal(b, m, deterministic) +} +func (m *ValidationRule) XXX_Merge(src proto.Message) { + xxx_messageInfo_ValidationRule.Merge(m, src) +} +func (m *ValidationRule) XXX_Size() int { + return xxx_messageInfo_ValidationRule.Size(m) +} +func (m *ValidationRule) XXX_DiscardUnknown() { + xxx_messageInfo_ValidationRule.DiscardUnknown(m) +} + +var xxx_messageInfo_ValidationRule proto.InternalMessageInfo + +func (m *ValidationRule) GetOperator() OperatorType { + if m != nil { + return m.Operator + } + return OperatorType_OPERATOR_TYPE_UNKNOWN +} + +func (m *ValidationRule) GetType() ValueType { + if m != nil { + return m.Type + } + return ValueType_VALUE_TYPE_UNKNOWN +} + +func (m *ValidationRule) GetValue() string { + if m != nil { + return m.Value + } + return "" +} + +func (m *ValidationRule) GetFunction() FunctionType { + if m != nil { + return m.Function + } + return FunctionType_FUNCTION_TYPE_UNKNOWN +} + +type ValidationRules struct { + Rules []*ValidationRule `protobuf:"bytes,1,rep,name=rules,proto3" json:"rules,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ValidationRules) Reset() { *m = ValidationRules{} } +func (m *ValidationRules) String() string { return proto.CompactTextString(m) } +func (*ValidationRules) ProtoMessage() {} +func (*ValidationRules) Descriptor() ([]byte, []int) { + return fileDescriptor_1be5d6cda9fc6cfe, []int{3} +} + +func (m *ValidationRules) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ValidationRules.Unmarshal(m, b) +} +func (m *ValidationRules) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ValidationRules.Marshal(b, m, deterministic) +} +func (m *ValidationRules) XXX_Merge(src proto.Message) { + xxx_messageInfo_ValidationRules.Merge(m, src) +} +func (m *ValidationRules) XXX_Size() int { + return xxx_messageInfo_ValidationRules.Size(m) +} +func (m *ValidationRules) XXX_DiscardUnknown() { + xxx_messageInfo_ValidationRules.DiscardUnknown(m) +} + +var xxx_messageInfo_ValidationRules proto.InternalMessageInfo + +func (m *ValidationRules) GetRules() []*ValidationRule { + if m != nil { + return m.Rules + } + return nil +} + +var E_Http = &proto.ExtensionDesc{ + ExtendedType: (*descriptor.MethodOptions)(nil), + ExtensionType: (*HttpRule)(nil), + Field: 108345, + Name: "ease.api.http", + Tag: "bytes,108345,opt,name=http", + Filename: "httpoptions/annotations.proto", +} + +var E_Method = &proto.ExtensionDesc{ + ExtendedType: (*descriptor.MethodOptions)(nil), + ExtensionType: (*ApiMethod)(nil), + Field: 108361, + Name: "ease.api.method", + Tag: "bytes,108361,opt,name=method", + Filename: "httpoptions/annotations.proto", +} + +var E_ServiceSpec = &proto.ExtensionDesc{ + ExtendedType: (*descriptor.ServiceOptions)(nil), + ExtensionType: (*ServiceSpec)(nil), + Field: 108349, + Name: "ease.api.service_spec", + Tag: "bytes,108349,opt,name=service_spec", + Filename: "httpoptions/annotations.proto", +} + +var E_Rules = &proto.ExtensionDesc{ + ExtendedType: (*descriptor.FieldOptions)(nil), + ExtensionType: (*ValidationRules)(nil), + Field: 108102, + Name: "ease.api.rules", + Tag: "bytes,108102,opt,name=rules", + Filename: "httpoptions/annotations.proto", +} + +func init() { + proto.RegisterEnum("ease.api.ApiSourceType", ApiSourceType_name, ApiSourceType_value) + proto.RegisterEnum("ease.api.AuthTokenType", AuthTokenType_name, AuthTokenType_value) + proto.RegisterEnum("ease.api.SpecSourceType", SpecSourceType_name, SpecSourceType_value) + proto.RegisterEnum("ease.api.LoadBalancer", LoadBalancer_name, LoadBalancer_value) + proto.RegisterEnum("ease.api.OperatorType", OperatorType_name, OperatorType_value) + proto.RegisterEnum("ease.api.FunctionType", FunctionType_name, FunctionType_value) + proto.RegisterEnum("ease.api.ValueType", ValueType_name, ValueType_value) + proto.RegisterType((*ApiMethod)(nil), "ease.api.ApiMethod") + proto.RegisterType((*ServiceSpec)(nil), "ease.api.ServiceSpec") + proto.RegisterType((*ValidationRule)(nil), "ease.api.ValidationRule") + proto.RegisterType((*ValidationRules)(nil), "ease.api.ValidationRules") + proto.RegisterExtension(E_Http) + proto.RegisterExtension(E_Method) + proto.RegisterExtension(E_ServiceSpec) + proto.RegisterExtension(E_Rules) +} + +func init() { proto.RegisterFile("httpoptions/annotations.proto", fileDescriptor_1be5d6cda9fc6cfe) } + +var fileDescriptor_1be5d6cda9fc6cfe = []byte{ + // 966 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x55, 0x4d, 0x6f, 0xe3, 0x54, + 0x17, 0xae, 0xd3, 0x34, 0x1f, 0x27, 0x69, 0x7a, 0xdf, 0xdb, 0x69, 0x5f, 0x77, 0x60, 0x20, 0xaa, + 0x40, 0x94, 0x08, 0x39, 0x28, 0x95, 0x58, 0x94, 0x95, 0x93, 0xba, 0xad, 0x69, 0x62, 0x67, 0x6c, + 0xa7, 0xd5, 0x88, 0x85, 0xe5, 0x3a, 0x77, 0x12, 0x6b, 0x1c, 0x5f, 0x63, 0xdf, 0x8c, 0x94, 0x05, + 0x7f, 0x86, 0x3f, 0x81, 0x58, 0xb0, 0x45, 0x42, 0x42, 0x6c, 0xf8, 0x37, 0xac, 0xd0, 0xbd, 0xb6, + 0xf3, 0x31, 0x15, 0x62, 0x13, 0x9f, 0xf3, 0x9c, 0xe7, 0x3c, 0xc7, 0xf7, 0xdc, 0xe3, 0x13, 0x78, + 0x35, 0x67, 0x2c, 0xa6, 0x31, 0x0b, 0x68, 0x94, 0x76, 0xbd, 0x28, 0xa2, 0xcc, 0x13, 0xb6, 0x12, + 0x27, 0x94, 0x51, 0x5c, 0x23, 0x5e, 0x4a, 0x14, 0x2f, 0x0e, 0x5e, 0xb6, 0x67, 0x94, 0xce, 0x42, + 0xd2, 0x15, 0xf8, 0xd3, 0xf2, 0x6d, 0x77, 0x4a, 0x52, 0x3f, 0x09, 0x62, 0x46, 0x93, 0x8c, 0xfb, + 0xf2, 0x74, 0x5b, 0x8a, 0xdb, 0x39, 0x7e, 0x34, 0xf5, 0x98, 0xd7, 0xe5, 0x3f, 0x19, 0x70, 0xfe, + 0x77, 0x09, 0xea, 0x6a, 0x1c, 0x8c, 0x08, 0x9b, 0xd3, 0x29, 0xfe, 0x0a, 0x70, 0x48, 0x67, 0x41, + 0xe4, 0x46, 0x94, 0xb9, 0x09, 0xf9, 0x61, 0x19, 0x24, 0x64, 0x2a, 0x4b, 0x6d, 0xe9, 0xa2, 0x66, + 0x21, 0x11, 0x31, 0x28, 0xb3, 0x72, 0x1c, 0x7f, 0x0d, 0x2f, 0xfc, 0x30, 0x20, 0x11, 0x73, 0xd3, + 0x60, 0x16, 0x6d, 0xf8, 0x25, 0xc1, 0xc7, 0x59, 0xcc, 0x0e, 0x66, 0xd1, 0x3a, 0xe3, 0x0c, 0x6a, + 0x73, 0x2f, 0x9d, 0xbb, 0xef, 0xc8, 0x4a, 0xde, 0x6f, 0x4b, 0x17, 0x75, 0xab, 0xca, 0xfd, 0x7b, + 0xb2, 0xc2, 0x9f, 0x41, 0x2b, 0x48, 0x5d, 0x36, 0x0f, 0x92, 0xa9, 0x1b, 0x7b, 0x09, 0x5b, 0xc9, + 0x65, 0x21, 0xd3, 0x0c, 0x52, 0x87, 0x83, 0x63, 0x8e, 0x61, 0x19, 0xaa, 0x2c, 0x58, 0x10, 0xba, + 0x64, 0xf2, 0x41, 0x96, 0x9f, 0xbb, 0xf8, 0x1b, 0x00, 0x2f, 0x0e, 0xdc, 0x94, 0x2e, 0x13, 0x9f, + 0xc8, 0x95, 0xb6, 0x74, 0xd1, 0xea, 0xfd, 0x5f, 0x29, 0x5a, 0xa6, 0xa8, 0x71, 0x60, 0x8b, 0x90, + 0xb3, 0x8a, 0x89, 0x55, 0xf7, 0x0a, 0x97, 0xe7, 0x31, 0xfa, 0x8e, 0x44, 0x2e, 0x5b, 0xc5, 0x44, + 0xae, 0x3e, 0xcb, 0x5b, 0xb2, 0xb9, 0xc3, 0xe3, 0x59, 0x1e, 0x2b, 0x4c, 0xdc, 0x07, 0x94, 0xc6, + 0xc4, 0xcf, 0x0b, 0x66, 0xd9, 0x35, 0x91, 0x2d, 0x6f, 0xb2, 0xed, 0x98, 0xf8, 0x5b, 0x65, 0x5b, + 0xe9, 0x8e, 0x7f, 0xfe, 0x97, 0x04, 0x0d, 0x9b, 0x24, 0xef, 0x03, 0x9f, 0x70, 0x26, 0x56, 0x00, + 0xd2, 0xcc, 0x75, 0x83, 0xac, 0xed, 0xad, 0xde, 0x91, 0x22, 0x6e, 0x2b, 0xa7, 0xe9, 0x53, 0xab, + 0x9e, 0x16, 0x26, 0xfe, 0x08, 0xea, 0x31, 0x4d, 0x98, 0x1b, 0x79, 0x0b, 0x22, 0xba, 0x5e, 0xb7, + 0x6a, 0x1c, 0x30, 0xbc, 0x05, 0xc1, 0x1f, 0x43, 0x9d, 0xe3, 0x69, 0xec, 0xf9, 0x24, 0x6f, 0xf6, + 0x06, 0xc0, 0x9f, 0x43, 0x6b, 0x46, 0x22, 0xd7, 0xa7, 0x11, 0x4b, 0x68, 0x18, 0x92, 0x24, 0x6f, + 0xf7, 0xe1, 0x8c, 0x44, 0x83, 0x35, 0x88, 0x7b, 0x50, 0x7b, 0xf2, 0x42, 0x2f, 0xf2, 0x49, 0x22, + 0x1a, 0xde, 0xea, 0x9d, 0x6e, 0x4e, 0x37, 0xa4, 0xde, 0xb4, 0x9f, 0x47, 0xad, 0x35, 0xef, 0xfc, + 0x67, 0x09, 0x5a, 0x0f, 0x5e, 0x18, 0x4c, 0xc5, 0xf4, 0x5a, 0xcb, 0x90, 0x70, 0x19, 0x1a, 0x93, + 0xc4, 0x63, 0x34, 0xc9, 0x8f, 0xb5, 0x25, 0x63, 0xe6, 0x11, 0xd1, 0xa2, 0x35, 0x0f, 0x7f, 0x01, + 0x65, 0xd1, 0xd4, 0x92, 0xe0, 0x1f, 0x6f, 0xf8, 0x0f, 0x5e, 0xb8, 0xcc, 0xfa, 0x29, 0x08, 0xf8, + 0x05, 0x1c, 0xbc, 0xe7, 0x50, 0x7e, 0xc8, 0xcc, 0xe1, 0x25, 0xdf, 0x2e, 0x23, 0x9f, 0xbf, 0x82, + 0x38, 0xda, 0x4e, 0xc9, 0x9b, 0x3c, 0x92, 0x95, 0x2c, 0x78, 0xe7, 0x2a, 0x1c, 0xed, 0xbe, 0x78, + 0x8a, 0x15, 0x38, 0x48, 0xb8, 0x21, 0x4b, 0xed, 0xfd, 0x8b, 0xc6, 0xf6, 0xdd, 0xee, 0x32, 0xad, + 0x8c, 0xd6, 0xb9, 0x84, 0xc3, 0x9d, 0x51, 0xc3, 0x08, 0x9a, 0x9a, 0x6a, 0x6b, 0xee, 0xad, 0xea, + 0x68, 0x8f, 0xea, 0x1b, 0xb4, 0xc7, 0x11, 0x73, 0xac, 0x19, 0x6b, 0x44, 0xea, 0x7c, 0x0b, 0x87, + 0x3b, 0x73, 0x86, 0x8f, 0xe1, 0x48, 0x24, 0xa9, 0x13, 0xe7, 0xce, 0x75, 0xcc, 0x7b, 0xcd, 0x40, + 0x7b, 0xf8, 0x04, 0xfe, 0xd7, 0x17, 0xe0, 0x60, 0xa0, 0xd9, 0x76, 0x0e, 0x4b, 0x9d, 0x0e, 0xb4, + 0x76, 0xc7, 0x0c, 0x1f, 0x41, 0x63, 0x62, 0xd8, 0x63, 0x6d, 0xa0, 0xdf, 0xe8, 0xda, 0x35, 0xda, + 0xc3, 0x55, 0xd8, 0x7f, 0xd4, 0xfa, 0x48, 0xea, 0x74, 0xa1, 0xb9, 0x7d, 0x69, 0x9c, 0x69, 0x99, + 0x13, 0xe3, 0xda, 0xb5, 0xcc, 0xbe, 0xce, 0x6b, 0xb4, 0x00, 0x06, 0xa6, 0x61, 0xeb, 0xb6, 0xa3, + 0x19, 0x0e, 0x92, 0x3a, 0x3f, 0x42, 0x73, 0xfb, 0x7a, 0xf0, 0x19, 0x9c, 0x98, 0x63, 0xcd, 0x52, + 0x1d, 0xd3, 0x72, 0x9d, 0x37, 0x63, 0xcd, 0x9d, 0x18, 0xf7, 0x86, 0xf9, 0xc8, 0x53, 0x2b, 0x50, + 0xba, 0x75, 0x90, 0xc4, 0x9f, 0x43, 0x07, 0x95, 0xf8, 0x53, 0x7b, 0x8d, 0xf6, 0x71, 0x1d, 0x0e, + 0x46, 0xaa, 0x33, 0xb8, 0x43, 0x65, 0xdc, 0x80, 0xaa, 0x61, 0x1a, 0xae, 0xa1, 0x0f, 0xd1, 0x01, + 0x06, 0xa8, 0x0c, 0x79, 0x17, 0x1c, 0x54, 0x29, 0xec, 0xa1, 0x83, 0xaa, 0x85, 0xad, 0xbd, 0x46, + 0xb5, 0xce, 0x25, 0x34, 0xb7, 0xaf, 0x8a, 0x97, 0xbf, 0x99, 0x18, 0x03, 0x47, 0x37, 0x8d, 0x0f, + 0xcb, 0xd7, 0xa0, 0xec, 0x58, 0xfa, 0x08, 0x49, 0x9d, 0x6b, 0xa8, 0xaf, 0x47, 0x04, 0x9f, 0x02, + 0x7e, 0x50, 0x87, 0x13, 0xed, 0x43, 0x3a, 0x40, 0xc5, 0x98, 0x8c, 0xfa, 0x9a, 0x85, 0x24, 0x6e, + 0xdb, 0x8e, 0xa5, 0x1b, 0xb7, 0xa8, 0xc4, 0x5b, 0x65, 0xf6, 0xbf, 0x43, 0xfb, 0x57, 0x77, 0x50, + 0xe6, 0x7b, 0x13, 0x7f, 0xa2, 0x64, 0xcb, 0x56, 0x29, 0x96, 0xad, 0x92, 0xed, 0x4a, 0x33, 0x5b, + 0xae, 0xf2, 0x2f, 0x7f, 0xf2, 0x5d, 0xd3, 0xe8, 0xe1, 0xcd, 0x64, 0xdc, 0x31, 0x16, 0x8b, 0x99, + 0x10, 0x0a, 0x57, 0x23, 0xa8, 0x2c, 0xb2, 0xf5, 0xfa, 0x5f, 0x5a, 0xbf, 0xe7, 0x5a, 0xc7, 0x3b, + 0x7b, 0x2b, 0xe3, 0x58, 0xb9, 0xc8, 0xd5, 0xf7, 0xd0, 0x2c, 0x96, 0x04, 0x5f, 0x27, 0xf8, 0xd3, + 0x67, 0xa2, 0xf9, 0xae, 0x28, 0x54, 0x7f, 0xcd, 0x55, 0x4f, 0xb6, 0xf6, 0xd2, 0x66, 0xe9, 0x58, + 0x8d, 0x74, 0xe3, 0x5c, 0x8d, 0xf3, 0x71, 0xc7, 0xaf, 0x9e, 0xa9, 0xde, 0x04, 0x24, 0x5c, 0xbf, + 0xe9, 0x6f, 0x7f, 0x64, 0x9a, 0x67, 0xff, 0xf6, 0x3d, 0xa4, 0xf9, 0x07, 0xd1, 0xff, 0x12, 0x9a, + 0x3e, 0x5d, 0xac, 0x69, 0x7d, 0xa4, 0x6e, 0xfe, 0xd8, 0xc6, 0x5c, 0x7b, 0x2c, 0xfd, 0x54, 0x2a, + 0x6b, 0xea, 0x58, 0x7f, 0xaa, 0x88, 0x5a, 0x97, 0xff, 0x04, 0x00, 0x00, 0xff, 0xff, 0x31, 0x32, + 0xc5, 0x86, 0x08, 0x07, 0x00, 0x00, +} diff --git a/httpoptions/http.pb.go b/httpoptions/http.pb.go new file mode 100755 index 0000000..d874d90 --- /dev/null +++ b/httpoptions/http.pb.go @@ -0,0 +1,323 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: httpoptions/http.proto + +package ease_api + +import ( + fmt "fmt" + proto "github.com/golang/protobuf/proto" + 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.ProtoPackageIsVersion3 // please upgrade the proto package + +type Http struct { + Rules []*HttpRule `protobuf:"bytes,1,rep,name=rules,proto3" json:"rules,omitempty"` + FullyDecodeReservedExpansion bool `protobuf:"varint,2,opt,name=fully_decode_reserved_expansion,json=fullyDecodeReservedExpansion,proto3" json:"fully_decode_reserved_expansion,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Http) Reset() { *m = Http{} } +func (m *Http) String() string { return proto.CompactTextString(m) } +func (*Http) ProtoMessage() {} +func (*Http) Descriptor() ([]byte, []int) { + return fileDescriptor_855b53eccb99bc99, []int{0} +} + +func (m *Http) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Http.Unmarshal(m, b) +} +func (m *Http) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Http.Marshal(b, m, deterministic) +} +func (m *Http) XXX_Merge(src proto.Message) { + xxx_messageInfo_Http.Merge(m, src) +} +func (m *Http) XXX_Size() int { + return xxx_messageInfo_Http.Size(m) +} +func (m *Http) XXX_DiscardUnknown() { + xxx_messageInfo_Http.DiscardUnknown(m) +} + +var xxx_messageInfo_Http proto.InternalMessageInfo + +func (m *Http) GetRules() []*HttpRule { + if m != nil { + return m.Rules + } + return nil +} + +func (m *Http) GetFullyDecodeReservedExpansion() bool { + if m != nil { + return m.FullyDecodeReservedExpansion + } + return false +} + +type HttpRule struct { + Selector string `protobuf:"bytes,1,opt,name=selector,proto3" json:"selector,omitempty"` + // Types that are valid to be assigned to Pattern: + // *HttpRule_Get + // *HttpRule_Put + // *HttpRule_Post + // *HttpRule_Delete + // *HttpRule_Patch + // *HttpRule_Custom + Pattern isHttpRule_Pattern `protobuf_oneof:"pattern"` + Body string `protobuf:"bytes,7,opt,name=body,proto3" json:"body,omitempty"` + ResponseBody string `protobuf:"bytes,12,opt,name=response_body,json=responseBody,proto3" json:"response_body,omitempty"` + AdditionalBindings []*HttpRule `protobuf:"bytes,11,rep,name=additional_bindings,json=additionalBindings,proto3" json:"additional_bindings,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *HttpRule) Reset() { *m = HttpRule{} } +func (m *HttpRule) String() string { return proto.CompactTextString(m) } +func (*HttpRule) ProtoMessage() {} +func (*HttpRule) Descriptor() ([]byte, []int) { + return fileDescriptor_855b53eccb99bc99, []int{1} +} + +func (m *HttpRule) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_HttpRule.Unmarshal(m, b) +} +func (m *HttpRule) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_HttpRule.Marshal(b, m, deterministic) +} +func (m *HttpRule) XXX_Merge(src proto.Message) { + xxx_messageInfo_HttpRule.Merge(m, src) +} +func (m *HttpRule) XXX_Size() int { + return xxx_messageInfo_HttpRule.Size(m) +} +func (m *HttpRule) XXX_DiscardUnknown() { + xxx_messageInfo_HttpRule.DiscardUnknown(m) +} + +var xxx_messageInfo_HttpRule proto.InternalMessageInfo + +func (m *HttpRule) GetSelector() string { + if m != nil { + return m.Selector + } + return "" +} + +type isHttpRule_Pattern interface { + isHttpRule_Pattern() +} + +type HttpRule_Get struct { + Get string `protobuf:"bytes,2,opt,name=get,proto3,oneof"` +} + +type HttpRule_Put struct { + Put string `protobuf:"bytes,3,opt,name=put,proto3,oneof"` +} + +type HttpRule_Post struct { + Post string `protobuf:"bytes,4,opt,name=post,proto3,oneof"` +} + +type HttpRule_Delete struct { + Delete string `protobuf:"bytes,5,opt,name=delete,proto3,oneof"` +} + +type HttpRule_Patch struct { + Patch string `protobuf:"bytes,6,opt,name=patch,proto3,oneof"` +} + +type HttpRule_Custom struct { + Custom *CustomHttpPattern `protobuf:"bytes,8,opt,name=custom,proto3,oneof"` +} + +func (*HttpRule_Get) isHttpRule_Pattern() {} + +func (*HttpRule_Put) isHttpRule_Pattern() {} + +func (*HttpRule_Post) isHttpRule_Pattern() {} + +func (*HttpRule_Delete) isHttpRule_Pattern() {} + +func (*HttpRule_Patch) isHttpRule_Pattern() {} + +func (*HttpRule_Custom) isHttpRule_Pattern() {} + +func (m *HttpRule) GetPattern() isHttpRule_Pattern { + if m != nil { + return m.Pattern + } + return nil +} + +func (m *HttpRule) GetGet() string { + if x, ok := m.GetPattern().(*HttpRule_Get); ok { + return x.Get + } + return "" +} + +func (m *HttpRule) GetPut() string { + if x, ok := m.GetPattern().(*HttpRule_Put); ok { + return x.Put + } + return "" +} + +func (m *HttpRule) GetPost() string { + if x, ok := m.GetPattern().(*HttpRule_Post); ok { + return x.Post + } + return "" +} + +func (m *HttpRule) GetDelete() string { + if x, ok := m.GetPattern().(*HttpRule_Delete); ok { + return x.Delete + } + return "" +} + +func (m *HttpRule) GetPatch() string { + if x, ok := m.GetPattern().(*HttpRule_Patch); ok { + return x.Patch + } + return "" +} + +func (m *HttpRule) GetCustom() *CustomHttpPattern { + if x, ok := m.GetPattern().(*HttpRule_Custom); ok { + return x.Custom + } + return nil +} + +func (m *HttpRule) GetBody() string { + if m != nil { + return m.Body + } + return "" +} + +func (m *HttpRule) GetResponseBody() string { + if m != nil { + return m.ResponseBody + } + return "" +} + +func (m *HttpRule) GetAdditionalBindings() []*HttpRule { + if m != nil { + return m.AdditionalBindings + } + return nil +} + +// XXX_OneofWrappers is for the internal use of the proto package. +func (*HttpRule) XXX_OneofWrappers() []interface{} { + return []interface{}{ + (*HttpRule_Get)(nil), + (*HttpRule_Put)(nil), + (*HttpRule_Post)(nil), + (*HttpRule_Delete)(nil), + (*HttpRule_Patch)(nil), + (*HttpRule_Custom)(nil), + } +} + +type CustomHttpPattern struct { + Kind string `protobuf:"bytes,1,opt,name=kind,proto3" json:"kind,omitempty"` + Path string `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CustomHttpPattern) Reset() { *m = CustomHttpPattern{} } +func (m *CustomHttpPattern) String() string { return proto.CompactTextString(m) } +func (*CustomHttpPattern) ProtoMessage() {} +func (*CustomHttpPattern) Descriptor() ([]byte, []int) { + return fileDescriptor_855b53eccb99bc99, []int{2} +} + +func (m *CustomHttpPattern) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CustomHttpPattern.Unmarshal(m, b) +} +func (m *CustomHttpPattern) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CustomHttpPattern.Marshal(b, m, deterministic) +} +func (m *CustomHttpPattern) XXX_Merge(src proto.Message) { + xxx_messageInfo_CustomHttpPattern.Merge(m, src) +} +func (m *CustomHttpPattern) XXX_Size() int { + return xxx_messageInfo_CustomHttpPattern.Size(m) +} +func (m *CustomHttpPattern) XXX_DiscardUnknown() { + xxx_messageInfo_CustomHttpPattern.DiscardUnknown(m) +} + +var xxx_messageInfo_CustomHttpPattern proto.InternalMessageInfo + +func (m *CustomHttpPattern) GetKind() string { + if m != nil { + return m.Kind + } + return "" +} + +func (m *CustomHttpPattern) GetPath() string { + if m != nil { + return m.Path + } + return "" +} + +func init() { + proto.RegisterType((*Http)(nil), "ease.api.Http") + proto.RegisterType((*HttpRule)(nil), "ease.api.HttpRule") + proto.RegisterType((*CustomHttpPattern)(nil), "ease.api.CustomHttpPattern") +} + +func init() { proto.RegisterFile("httpoptions/http.proto", fileDescriptor_855b53eccb99bc99) } + +var fileDescriptor_855b53eccb99bc99 = []byte{ + // 377 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x92, 0xc1, 0x8e, 0xd3, 0x30, + 0x10, 0x86, 0x49, 0x9b, 0x66, 0x93, 0x69, 0x39, 0x60, 0xd0, 0xca, 0x02, 0x24, 0xa2, 0x70, 0xc9, + 0x29, 0x48, 0x8b, 0x38, 0x71, 0x22, 0x4b, 0xa5, 0x72, 0xab, 0xf2, 0x02, 0x91, 0x1b, 0x0f, 0x6d, + 0x44, 0x6a, 0x5b, 0xf1, 0x04, 0xe8, 0xeb, 0xf0, 0x50, 0x3c, 0x0f, 0xb2, 0x93, 0xb4, 0x07, 0xb4, + 0xb7, 0xf9, 0xff, 0xf9, 0x34, 0xfe, 0x35, 0x1e, 0xb8, 0x3f, 0x11, 0x19, 0x6d, 0xa8, 0xd5, 0xca, + 0x7e, 0x70, 0x75, 0x61, 0x7a, 0x4d, 0x9a, 0xc5, 0x28, 0x2c, 0x16, 0xc2, 0xb4, 0xd9, 0x2f, 0x08, + 0x77, 0x44, 0x86, 0xe5, 0xb0, 0xea, 0x87, 0x0e, 0x2d, 0x0f, 0xd2, 0x65, 0xbe, 0x7e, 0x60, 0xc5, + 0x4c, 0x14, 0xae, 0x5d, 0x0d, 0x1d, 0x56, 0x23, 0xc0, 0xb6, 0xf0, 0xee, 0xfb, 0xd0, 0x75, 0x97, + 0x5a, 0x62, 0xa3, 0x25, 0xd6, 0x3d, 0x5a, 0xec, 0x7f, 0xa2, 0xac, 0xf1, 0xb7, 0x11, 0xca, 0xb6, + 0x5a, 0xf1, 0x45, 0x1a, 0xe4, 0x71, 0xf5, 0xd6, 0x63, 0x5f, 0x3d, 0x55, 0x4d, 0xd0, 0x76, 0x66, + 0xb2, 0xbf, 0x0b, 0x88, 0xe7, 0xd1, 0xec, 0x35, 0xc4, 0x16, 0x3b, 0x6c, 0x48, 0xf7, 0x3c, 0x48, + 0x83, 0x3c, 0xa9, 0xae, 0x9a, 0x31, 0x58, 0x1e, 0x91, 0xfc, 0xcc, 0x64, 0xf7, 0xac, 0x72, 0xc2, + 0x79, 0x66, 0x20, 0xbe, 0x9c, 0x3d, 0x33, 0x10, 0x7b, 0x05, 0xa1, 0xd1, 0x96, 0x78, 0x38, 0x99, + 0x5e, 0x31, 0x0e, 0x91, 0xc4, 0x0e, 0x09, 0xf9, 0x6a, 0xf2, 0x27, 0xcd, 0xee, 0x61, 0x65, 0x04, + 0x35, 0x27, 0x1e, 0x4d, 0x8d, 0x51, 0xb2, 0x4f, 0x10, 0x35, 0x83, 0x25, 0x7d, 0xe6, 0x71, 0x1a, + 0xe4, 0xeb, 0x87, 0x37, 0xb7, 0x55, 0x3c, 0x7a, 0xdf, 0xa5, 0xde, 0x0b, 0x22, 0xec, 0x95, 0x1b, + 0x37, 0xc2, 0x8c, 0x41, 0x78, 0xd0, 0xf2, 0xc2, 0xef, 0x7c, 0x7c, 0x5f, 0xb3, 0xf7, 0xf0, 0xbc, + 0x47, 0x6b, 0xb4, 0xb2, 0x58, 0xfb, 0xe6, 0xc6, 0x37, 0x37, 0xb3, 0x59, 0x3a, 0xe8, 0x11, 0x5e, + 0x0a, 0x29, 0x5b, 0xf7, 0x47, 0xa2, 0xab, 0x0f, 0xad, 0x92, 0xad, 0x3a, 0x5a, 0xbe, 0x7e, 0xf2, + 0x1f, 0xd8, 0x0d, 0x2f, 0x27, 0xba, 0x4c, 0xe0, 0xce, 0x8c, 0x91, 0xb2, 0xcf, 0xf0, 0xe2, 0xbf, + 0x9c, 0x2e, 0xdd, 0x8f, 0x56, 0xc9, 0x69, 0xb9, 0xbe, 0x76, 0x9e, 0x11, 0x74, 0x1a, 0x37, 0x5b, + 0xf9, 0xba, 0xcc, 0x60, 0xd3, 0xe8, 0xf3, 0xf5, 0xd1, 0x32, 0xf1, 0x43, 0xdc, 0xcd, 0xec, 0x83, + 0x3f, 0x8b, 0x70, 0xfb, 0x65, 0xff, 0xed, 0x10, 0xf9, 0x1b, 0xfa, 0xf8, 0x2f, 0x00, 0x00, 0xff, + 0xff, 0x64, 0x5b, 0xb8, 0x5e, 0x5d, 0x02, 0x00, 0x00, +} From 63b2f23230c708c819e663ba7730610e2aa17ee8 Mon Sep 17 00:00:00 2001 From: chenbin1314 Date: Mon, 6 Jul 2020 21:26:46 +0800 Subject: [PATCH 02/56] Upgrade com_github_binchencoder_skylb_api to v0.0.4 --- go.mod | 3 +-- go.sum | 4 ++++ repositories.bzl | 4 ++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 6192b81..0a55c39 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ replace ( require ( github.com/binchencoder/gateway-proto v0.0.5 github.com/binchencoder/letsgo v0.0.3 - github.com/binchencoder/skylb-api v0.0.3 + github.com/binchencoder/skylb-api v0.0.4 github.com/fatih/color v1.9.0 github.com/ghodss/yaml v1.0.0 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b @@ -23,5 +23,4 @@ require ( golang.org/x/net v0.0.0-20200625001655-4c5254603344 google.golang.org/genproto v0.0.0-20200702021140-07506425bd67 google.golang.org/grpc v1.30.0 - google.golang.org/grpc/examples v0.0.0-20200630190442-3de8449f8555 // indirect ) diff --git a/go.sum b/go.sum index 7a72654..9d332eb 100644 --- a/go.sum +++ b/go.sum @@ -27,6 +27,7 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/binchencoder/ease-gateway v0.0.4/go.mod h1:L8fCaUA1FaYO0ReFNAri15ozAj9NeJ9B+Q6CQAyPFqY= github.com/binchencoder/gateway-proto v0.0.3 h1:xU2ZVx5Zjub5P/WIl12FeCII1vGdV2THWtfm7fUR7z8= github.com/binchencoder/gateway-proto v0.0.3/go.mod h1:081rlF+665EejkDRHi7gTLpZvK0eDwVX23xviXQCjV0= github.com/binchencoder/gateway-proto v0.0.5 h1:2oh9Y8/qlMX1K3m73XDMU9U3mA06WMkLmJrMi4nFlCc= @@ -35,6 +36,8 @@ github.com/binchencoder/letsgo v0.0.3 h1:hEDDOeGdX9R/JPYMdVo9N/9iQa5BeBLluTssrNY github.com/binchencoder/letsgo v0.0.3/go.mod h1:WbqNFa5gFsogqe3gtycvPYswprKV7eGJIxScwQhAg44= github.com/binchencoder/skylb-api v0.0.3 h1:NnlPmEjTgOjH+s9TK3rBEY4Kn9aEzZkuEBUV2aR8UTM= github.com/binchencoder/skylb-api v0.0.3/go.mod h1:j/ATHuW3TU7M5+fWeTqrvOzmFQI7Z4AVerdP6JYOkUk= +github.com/binchencoder/skylb-api v0.0.4 h1:HFQk6U+IerXWuQD6bxtGR6Zf7Q2Ulj87CZAd9G0vcnc= +github.com/binchencoder/skylb-api v0.0.4/go.mod h1:HoLyR+KbCm7bI2sRp+AA1pj159KRutdVYow6w3tbOLs= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= @@ -313,6 +316,7 @@ github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtX github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= diff --git a/repositories.bzl b/repositories.bzl index 2484216..b5221fe 100644 --- a/repositories.bzl +++ b/repositories.bzl @@ -10,8 +10,8 @@ def go_repositories(): go_repository( name = "com_github_binchencoder_skylb_api", importpath = "github.com/binchencoder/skylb-api", - sum = "h1:NnlPmEjTgOjH+s9TK3rBEY4Kn9aEzZkuEBUV2aR8UTM=", - version = "v0.0.3", + sum = "h1:HFQk6U+IerXWuQD6bxtGR6Zf7Q2Ulj87CZAd9G0vcnc=", + version = "v0.0.4", ) go_repository( name = "com_github_binchencoder_gateway_proto", From a32564a38e16b0276be82ae8fc20f05f823a3372 Mon Sep 17 00:00:00 2001 From: binchen Date: Tue, 7 Jul 2020 11:15:33 +0800 Subject: [PATCH 03/56] Upgrade com_github_binchencoder_skylb_api version to v0.0.5 --- go.mod | 3 +-- go.sum | 2 ++ repositories.bzl | 8 ++++---- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 0a55c39..8300b39 100644 --- a/go.mod +++ b/go.mod @@ -5,13 +5,12 @@ go 1.13 replace ( github.com/coreos/bbolt v1.3.4 => go.etcd.io/bbolt v1.3.4 github.com/coreos/bbolt v1.3.5 => go.etcd.io/bbolt v1.3.5 - google.golang.org/grpc v1.30.0 => google.golang.org/grpc v1.27.1 ) require ( github.com/binchencoder/gateway-proto v0.0.5 github.com/binchencoder/letsgo v0.0.3 - github.com/binchencoder/skylb-api v0.0.4 + github.com/binchencoder/skylb-api v0.0.5 github.com/fatih/color v1.9.0 github.com/ghodss/yaml v1.0.0 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b diff --git a/go.sum b/go.sum index 9d332eb..a979252 100644 --- a/go.sum +++ b/go.sum @@ -38,6 +38,8 @@ github.com/binchencoder/skylb-api v0.0.3 h1:NnlPmEjTgOjH+s9TK3rBEY4Kn9aEzZkuEBUV github.com/binchencoder/skylb-api v0.0.3/go.mod h1:j/ATHuW3TU7M5+fWeTqrvOzmFQI7Z4AVerdP6JYOkUk= github.com/binchencoder/skylb-api v0.0.4 h1:HFQk6U+IerXWuQD6bxtGR6Zf7Q2Ulj87CZAd9G0vcnc= github.com/binchencoder/skylb-api v0.0.4/go.mod h1:HoLyR+KbCm7bI2sRp+AA1pj159KRutdVYow6w3tbOLs= +github.com/binchencoder/skylb-api v0.0.5 h1:BM11MtrX7DrUKacLTEqudd4hietFlXRNr8Nh6dLSOCk= +github.com/binchencoder/skylb-api v0.0.5/go.mod h1:fUK5XeSBmuARvLeg+pab1FplK4x2+Q9zsmg4U8KNDBQ= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= diff --git a/repositories.bzl b/repositories.bzl index b5221fe..9318432 100644 --- a/repositories.bzl +++ b/repositories.bzl @@ -10,14 +10,14 @@ def go_repositories(): go_repository( name = "com_github_binchencoder_skylb_api", importpath = "github.com/binchencoder/skylb-api", - sum = "h1:HFQk6U+IerXWuQD6bxtGR6Zf7Q2Ulj87CZAd9G0vcnc=", - version = "v0.0.4", + sum = "h1:BM11MtrX7DrUKacLTEqudd4hietFlXRNr8Nh6dLSOCk=", + version = "v0.0.5", ) go_repository( name = "com_github_binchencoder_gateway_proto", importpath = "github.com/binchencoder/gateway-proto", - sum = "h1:xU2ZVx5Zjub5P/WIl12FeCII1vGdV2THWtfm7fUR7z8=", - version = "v0.0.3", + sum = "h1:2oh9Y8/qlMX1K3m73XDMU9U3mA06WMkLmJrMi4nFlCc=", + version = "v0.0.5", ) go_repository( From ed980c5fa6e8a8af8e691e5e6d37c1a570a352d5 Mon Sep 17 00:00:00 2001 From: binchen Date: Wed, 8 Jul 2020 18:11:56 +0800 Subject: [PATCH 04/56] Update: upgrade com_github_binchencoder_skylb_api version to v0.0.6 --- go.mod | 11 ++++++----- repositories.bzl | 4 ++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index 8300b39..a0b15c5 100644 --- a/go.mod +++ b/go.mod @@ -2,11 +2,6 @@ module github.com/binchencoder/ease-gateway go 1.13 -replace ( - github.com/coreos/bbolt v1.3.4 => go.etcd.io/bbolt v1.3.4 - github.com/coreos/bbolt v1.3.5 => go.etcd.io/bbolt v1.3.5 -) - require ( github.com/binchencoder/gateway-proto v0.0.5 github.com/binchencoder/letsgo v0.0.3 @@ -23,3 +18,9 @@ require ( google.golang.org/genproto v0.0.0-20200702021140-07506425bd67 google.golang.org/grpc v1.30.0 ) + +replace ( + github.com/coreos/bbolt v1.3.4 => go.etcd.io/bbolt v1.3.4 + github.com/coreos/bbolt v1.3.5 => go.etcd.io/bbolt v1.3.5 + google.golang.org/grpc v1.30.0 => google.golang.org/grpc v1.27.1 +) diff --git a/repositories.bzl b/repositories.bzl index 9318432..c7fb2f3 100644 --- a/repositories.bzl +++ b/repositories.bzl @@ -10,8 +10,8 @@ def go_repositories(): go_repository( name = "com_github_binchencoder_skylb_api", importpath = "github.com/binchencoder/skylb-api", - sum = "h1:BM11MtrX7DrUKacLTEqudd4hietFlXRNr8Nh6dLSOCk=", - version = "v0.0.5", + sum = "h1:neSwlmR8As4mQkT9ITFv5SLBZ5f45i+HwXzKPso8gn0=", + version = "v0.0.6", ) go_repository( name = "com_github_binchencoder_gateway_proto", From e56ae843aa7ebff1f1fa8ec8d380196978b8a4d0 Mon Sep 17 00:00:00 2001 From: binchen Date: Thu, 9 Jul 2020 13:32:09 +0800 Subject: [PATCH 05/56] Upgrade com_github_grpc_ecosystem_grpc_gateway version to v1.14.6, sync //gateway code in the directory --- WORKSPACE | 4 +- gateway/HISTORY.md | 16 + gateway/README.md | 15 +- gateway/codegenerator/BUILD.bazel | 26 - gateway/codegenerator/doc.go | 4 - gateway/codegenerator/parse_req.go | 23 - gateway/codegenerator/parse_req_test.go | 69 --- gateway/protoc-gen-grpc-gateway/BUILD.bazel | 4 +- .../descriptor/grpc_api_configuration.go | 2 +- .../descriptor/registry.go | 64 +++ .../descriptor/registry_test.go | 40 ++ .../descriptor/services.go | 2 +- .../descriptor/services_test.go | 59 +++ .../{ => internal}/gengateway/BUILD.bazel | 2 +- .../{ => internal}/gengateway/doc.go | 0 .../{ => internal}/gengateway/generator.go | 0 .../gengateway/generator_test.go | 0 .../{ => internal}/gengateway/template.go | 0 .../gengateway/template_test.go | 0 gateway/protoc-gen-grpc-gateway/main.go | 16 +- gateway/protoc-gen-swagger/BUILD.bazel | 2 +- gateway/protoc-gen-swagger/defs.bzl | 217 ++++---- gateway/protoc-gen-swagger/main.go | 11 +- .../protoc-gen-swagger/options/BUILD.bazel | 2 +- .../options/openapiv2.pb.go | 496 +++++++++++------- .../options/openapiv2.proto | 185 +++++-- gateway/runtime/mux.go | 15 +- gateway/runtime/query.go | 19 +- gateway/runtime/query_test.go | 9 + repositories.bzl | 4 +- 30 files changed, 811 insertions(+), 495 deletions(-) delete mode 100644 gateway/codegenerator/BUILD.bazel delete mode 100644 gateway/codegenerator/doc.go delete mode 100644 gateway/codegenerator/parse_req.go delete mode 100644 gateway/codegenerator/parse_req_test.go rename gateway/protoc-gen-grpc-gateway/{ => internal}/gengateway/BUILD.bazel (96%) rename gateway/protoc-gen-grpc-gateway/{ => internal}/gengateway/doc.go (100%) rename gateway/protoc-gen-grpc-gateway/{ => internal}/gengateway/generator.go (100%) rename gateway/protoc-gen-grpc-gateway/{ => internal}/gengateway/generator_test.go (100%) rename gateway/protoc-gen-grpc-gateway/{ => internal}/gengateway/template.go (100%) rename gateway/protoc-gen-grpc-gateway/{ => internal}/gengateway/template_test.go (100%) diff --git a/WORKSPACE b/WORKSPACE index eddb400..e75fb52 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -5,9 +5,9 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") # ----------从github下载扩展 io_bazel_rules_go ---------- http_archive( name = "io_bazel_rules_go", - sha256 = "7b9bbe3ea1fccb46dcfa6c3f3e29ba7ec740d8733370e21cdc8937467b4a4349", + sha256 = "87f0fb9747854cb76a0a82430adccb6269f7d394237104a4523b51061c469171", urls = [ - "https://github.com/bazelbuild/rules_go/releases/download/v0.22.4/rules_go-v0.22.4.tar.gz", + "https://github.com/bazelbuild/rules_go/releases/download/v0.23.1/rules_go-v0.23.1.tar.gz", ], ) diff --git a/gateway/HISTORY.md b/gateway/HISTORY.md index 1cfc441..69c9781 100644 --- a/gateway/HISTORY.md +++ b/gateway/HISTORY.md @@ -9,6 +9,22 @@ Hosted on https://github.com/grpc-ecosystem/grpc-gateway. ## Update History +### 2020/05/25 + +Based on commit ID [58a91c2b3020ee25e5d3cf49cf7d342544ab773d](https://github.com/grpc-ecosystem/grpc-gateway/commit/7988867d3206f7e90ca3e8d4ab67e060734a297a) + +Commit message + +``` +commit 7988867d3206f7e90ca3e8d4ab67e060734a297a (HEAD, tag: v2.0.0-beta.2, tag: v1.14.6) +Author: Johan Brandhorst +Date: Mon May 25 11:42:27 2020 +0100 + + Generate changelog for 1.14.6 + + Fixed the issue where it would include v2 merges +``` + ### 2019/11/03 Based on commit ID 58a91c2b3020ee25e5d3cf49cf7d342544ab773d diff --git a/gateway/README.md b/gateway/README.md index 031b4d9..30a7196 100644 --- a/gateway/README.md +++ b/gateway/README.md @@ -14,16 +14,7 @@ grpc-gateway 是一款非常优秀的网关服务器,负责转化和代理转 以下详细说明了我基于grpc-gateway修改了哪些目录下的代码 -## codegenerator - -Link [grpc-ecosystem/grpc-gateway/codegenerator](https://github.com/grpc-ecosystem/grpc-gateway/tree/master/codegenerator) - -这个目录下没有修改核心代码,只修改path - -- package default_visibility -- import "github.com/binchencoder/ease-gateway/gateway/codegenerator" => "github.com/grpc-ecosystem/grpc-gateway/codegenerator" - -## options +## httpoptions 这个目录下的内容并不是grpc-gateway的源码,是基于[Google // APIs](https://github.com/googleapis/googleapis) 修改的,为了支持: @@ -32,7 +23,7 @@ Link [grpc-ecosystem/grpc-gateway/codegenerator](https://github.com/grpc-ecosys - loadbalancer - parameter validation(定义validation rules) -> **NOTE :** 移到根目录下 => httpoptions +> **NOTE :** 这是新增加的目录 ## protoc-gen-grpc-gateway @@ -71,7 +62,7 @@ protoc -I/usr/local/include -I. \ - BUILD.bazel - generator.go (只修改import path) -### gengateway +### internal/gengateway **这个目录下改动比较大**, 修改文件: diff --git a/gateway/codegenerator/BUILD.bazel b/gateway/codegenerator/BUILD.bazel deleted file mode 100644 index a865f97..0000000 --- a/gateway/codegenerator/BUILD.bazel +++ /dev/null @@ -1,26 +0,0 @@ -load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") - -package(default_visibility = ["//visibility:public"]) - -go_library( - name = "go_default_library", - srcs = [ - "doc.go", - "parse_req.go", - ], - importpath = "github.com/binchencoder/ease-gateway/gateway/codegenerator", - deps = [ - "@com_github_golang_protobuf//proto:go_default_library", - "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", - ], -) - -go_test( - name = "go_default_test", - srcs = ["parse_req_test.go"], - embed = [":go_default_library"], - deps = [ - "@com_github_golang_protobuf//proto:go_default_library", - "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", - ], -) diff --git a/gateway/codegenerator/doc.go b/gateway/codegenerator/doc.go deleted file mode 100644 index 3645317..0000000 --- a/gateway/codegenerator/doc.go +++ /dev/null @@ -1,4 +0,0 @@ -/* -Package codegenerator contains reusable functions used by the code generators. -*/ -package codegenerator diff --git a/gateway/codegenerator/parse_req.go b/gateway/codegenerator/parse_req.go deleted file mode 100644 index e74575b..0000000 --- a/gateway/codegenerator/parse_req.go +++ /dev/null @@ -1,23 +0,0 @@ -package codegenerator - -import ( - "fmt" - "io" - "io/ioutil" - - "github.com/golang/protobuf/proto" - plugin "github.com/golang/protobuf/protoc-gen-go/plugin" -) - -// ParseRequest parses a code generator request from a proto Message. -func ParseRequest(r io.Reader) (*plugin.CodeGeneratorRequest, error) { - input, err := ioutil.ReadAll(r) - if err != nil { - return nil, fmt.Errorf("failed to read code generator request: %v", err) - } - req := new(plugin.CodeGeneratorRequest) - if err = proto.Unmarshal(input, req); err != nil { - return nil, fmt.Errorf("failed to unmarshal code generator request: %v", err) - } - return req, nil -} diff --git a/gateway/codegenerator/parse_req_test.go b/gateway/codegenerator/parse_req_test.go deleted file mode 100644 index 7f0da0a..0000000 --- a/gateway/codegenerator/parse_req_test.go +++ /dev/null @@ -1,69 +0,0 @@ -package codegenerator_test - -import ( - "bytes" - "fmt" - "io" - "reflect" - "strings" - "testing" - - "github.com/golang/protobuf/proto" - plugin "github.com/golang/protobuf/protoc-gen-go/plugin" - "github.com/binchencoder/ease-gateway/gateway/codegenerator" -) - -var parseReqTests = []struct { - name string - in io.Reader - out *plugin.CodeGeneratorRequest - err error -}{ - { - "Empty input should produce empty output", - mustGetReader(&plugin.CodeGeneratorRequest{}), - &plugin.CodeGeneratorRequest{}, - nil, - }, - { - "Invalid reader should produce error", - &invalidReader{}, - nil, - fmt.Errorf("failed to read code generator request: invalid reader"), - }, - { - "Invalid proto message should produce error", - strings.NewReader("{}"), - nil, - fmt.Errorf("failed to unmarshal code generator request: unexpected EOF"), - }, -} - -func TestParseRequest(t *testing.T) { - for _, tt := range parseReqTests { - t.Run(tt.name, func(t *testing.T) { - out, err := codegenerator.ParseRequest(tt.in) - if !reflect.DeepEqual(err, tt.err) { - t.Errorf("got %v, want %v", err, tt.err) - } - if err == nil && !reflect.DeepEqual(*out, *tt.out) { - t.Errorf("got %v, want %v", *out, *tt.out) - } - }) - } -} - -func mustGetReader(pb proto.Message) io.Reader { - b, err := proto.Marshal(pb) - if err != nil { - panic(err) - } - return bytes.NewBuffer(b) -} - -type invalidReader struct { -} - -func (*invalidReader) Read(p []byte) (int, error) { - return 0, fmt.Errorf("invalid reader") -} diff --git a/gateway/protoc-gen-grpc-gateway/BUILD.bazel b/gateway/protoc-gen-grpc-gateway/BUILD.bazel index 7141bfc..6eeb869 100644 --- a/gateway/protoc-gen-grpc-gateway/BUILD.bazel +++ b/gateway/protoc-gen-grpc-gateway/BUILD.bazel @@ -8,11 +8,11 @@ go_library( srcs = ["main.go"], importpath = "github.com/binchencoder/ease-gateway/gateway/protoc-gen-grpc-gateway", deps = [ - "//gateway/codegenerator:go_default_library", "//gateway/protoc-gen-grpc-gateway/descriptor:go_default_library", - "//gateway/protoc-gen-grpc-gateway/gengateway:go_default_library", + "//gateway/protoc-gen-grpc-gateway/internal/gengateway:go_default_library", "@com_github_golang_glog//:go_default_library", "@com_github_golang_protobuf//proto:go_default_library", + "@com_github_grpc_ecosystem_grpc_gateway//codegenerator:go_default_library", "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", ], ) diff --git a/gateway/protoc-gen-grpc-gateway/descriptor/grpc_api_configuration.go b/gateway/protoc-gen-grpc-gateway/descriptor/grpc_api_configuration.go index ca68ed7..0ebc7c8 100644 --- a/gateway/protoc-gen-grpc-gateway/descriptor/grpc_api_configuration.go +++ b/gateway/protoc-gen-grpc-gateway/descriptor/grpc_api_configuration.go @@ -16,7 +16,7 @@ func loadGrpcAPIServiceFromYAML(yamlFileContents []byte, yamlSourceLogName strin return nil, fmt.Errorf("Failed to convert gRPC API Configuration from YAML in '%v' to JSON: %v", yamlSourceLogName, err) } - // As our GrpcAPIService is incomplete accept unkown fields. + // As our GrpcAPIService is incomplete accept unknown fields. unmarshaler := jsonpb.Unmarshaler{ AllowUnknownFields: true, } diff --git a/gateway/protoc-gen-grpc-gateway/descriptor/registry.go b/gateway/protoc-gen-grpc-gateway/descriptor/registry.go index 620da49..b2b6b13 100644 --- a/gateway/protoc-gen-grpc-gateway/descriptor/registry.go +++ b/gateway/protoc-gen-grpc-gateway/descriptor/registry.go @@ -77,6 +77,17 @@ type Registry struct { // useGoTemplate determines whether you want to use GO templates // in your protofile comments useGoTemplate bool + + // enumsAsInts render enum as integer, as opposed to string + enumsAsInts bool + + // disableDefaultErrors disables the generation of the default error types. + // This is useful for users who have defined custom error handling. + disableDefaultErrors bool + + // simpleOperationIDs removes the service prefix from the generated + // operationIDs. This risks generating duplicate operationIDs. + simpleOperationIDs bool } type repeatedFieldSeparator struct { @@ -279,6 +290,29 @@ func (r *Registry) AddExternalHTTPRule(qualifiedMethodName string, rule *annotat r.externalHTTPRules[qualifiedMethodName] = append(r.externalHTTPRules[qualifiedMethodName], rule) } +// UnboundExternalHTTPRules returns the list of External HTTPRules +// which does not have a matching method in the registry +func (r *Registry) UnboundExternalHTTPRules() []string { + allServiceMethods := make(map[string]struct{}) + for _, f := range r.files { + for _, s := range f.GetService() { + svc := &Service{File: f, ServiceDescriptorProto: s} + for _, m := range s.GetMethod() { + method := &Method{Service: svc, MethodDescriptorProto: m} + allServiceMethods[method.FQMN()] = struct{}{} + } + } + } + + var missingMethods []string + for httpRuleMethod := range r.externalHTTPRules { + if _, ok := allServiceMethods[httpRuleMethod]; !ok { + missingMethods = append(missingMethods, httpRuleMethod) + } + } + return missingMethods +} + // AddPkgMap adds a mapping from a .proto file to proto package name. func (r *Registry) AddPkgMap(file, protoPkg string) { r.pkgMap[file] = protoPkg @@ -475,6 +509,36 @@ func (r *Registry) GetUseGoTemplate() bool { return r.useGoTemplate } +// SetEnumsAsInts set enumsAsInts +func (r *Registry) SetEnumsAsInts(enumsAsInts bool) { + r.enumsAsInts = enumsAsInts +} + +// GetEnumsAsInts returns enumsAsInts +func (r *Registry) GetEnumsAsInts() bool { + return r.enumsAsInts +} + +// SetDisableDefaultErrors sets disableDefaultErrors +func (r *Registry) SetDisableDefaultErrors(use bool) { + r.disableDefaultErrors = use +} + +// GetDisableDefaultErrors returns disableDefaultErrors +func (r *Registry) GetDisableDefaultErrors() bool { + return r.disableDefaultErrors +} + +// SetSimpleOperationIDs sets simpleOperationIDs +func (r *Registry) SetSimpleOperationIDs(use bool) { + r.simpleOperationIDs = use +} + +// GetSimpleOperationIDs returns simpleOperationIDs +func (r *Registry) GetSimpleOperationIDs() bool { + return r.simpleOperationIDs +} + // sanitizePackageName replaces unallowed character in package name // with allowed character. func sanitizePackageName(pkgName string) string { diff --git a/gateway/protoc-gen-grpc-gateway/descriptor/registry_test.go b/gateway/protoc-gen-grpc-gateway/descriptor/registry_test.go index 16e7665..36c53d6 100644 --- a/gateway/protoc-gen-grpc-gateway/descriptor/registry_test.go +++ b/gateway/protoc-gen-grpc-gateway/descriptor/registry_test.go @@ -586,3 +586,43 @@ func TestLoadGoPackageInputPath(t *testing.T) { t.Errorf("file.GoPkg = %#v; want %#v", got, want) } } + +func TestUnboundExternalHTTPRules(t *testing.T) { + reg := NewRegistry() + methodName := ".example.ExampleService.Echo" + reg.AddExternalHTTPRule(methodName, nil) + assertStringSlice(t, "unbound external HTTP rules", reg.UnboundExternalHTTPRules(), []string{methodName}) + loadFile(t, reg, ` + name: "path/to/example.proto", + package: "example" + message_type < + name: "StringMessage" + field < + name: "string" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_STRING + > + > + service < + name: "ExampleService" + method < + name: "Echo" + input_type: "StringMessage" + output_type: "StringMessage" + > + > + `) + assertStringSlice(t, "unbound external HTTP rules", reg.UnboundExternalHTTPRules(), []string{}) +} + +func assertStringSlice(t *testing.T, message string, got, want []string) { + if len(got) != len(want) { + t.Errorf("%s = %#v len(%d); want %#v len(%d)", message, got, len(got), want, len(want)) + } + for i := range want { + if got[i] != want[i] { + t.Errorf("%s[%d] = %#v; want %#v", message, i, got[i], want[i]) + } + } +} diff --git a/gateway/protoc-gen-grpc-gateway/descriptor/services.go b/gateway/protoc-gen-grpc-gateway/descriptor/services.go index b895ec9..1f8acea 100644 --- a/gateway/protoc-gen-grpc-gateway/descriptor/services.go +++ b/gateway/protoc-gen-grpc-gateway/descriptor/services.go @@ -64,7 +64,7 @@ func (r *Registry) loadServices(file *File) error { optsList = append(optsList, opts) } if len(optsList) == 0 { - glog.V(1).Infof("Found non-target method: %s.%s", svc.GetName(), md.GetName()) + glog.Warningf("No HttpRule found for method: %s.%s", svc.GetName(), md.GetName()) } meth, err := r.newMethod(svc, md, optsList, mopts) if err != nil { diff --git a/gateway/protoc-gen-grpc-gateway/descriptor/services_test.go b/gateway/protoc-gen-grpc-gateway/descriptor/services_test.go index 3b69074..1fa2693 100644 --- a/gateway/protoc-gen-grpc-gateway/descriptor/services_test.go +++ b/gateway/protoc-gen-grpc-gateway/descriptor/services_test.go @@ -220,6 +220,65 @@ func TestExtractServicesSimple(t *testing.T) { testExtractServices(t, []*descriptor.FileDescriptorProto{&fd}, "path/to/example.proto", file.Services) } +func TestExtractServicesWithoutAnnotation(t *testing.T) { + src := ` + name: "path/to/example.proto", + package: "example" + message_type < + name: "StringMessage" + field < + name: "string" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_STRING + > + > + service < + name: "ExampleService" + method < + name: "Echo" + input_type: "StringMessage" + output_type: "StringMessage" + > + > + ` + var fd descriptor.FileDescriptorProto + if err := proto.UnmarshalText(src, &fd); err != nil { + t.Fatalf("proto.UnmarshalText(%s, &fd) failed with %v; want success", src, err) + } + msg := &Message{ + DescriptorProto: fd.MessageType[0], + Fields: []*Field{ + { + FieldDescriptorProto: fd.MessageType[0].Field[0], + }, + }, + } + file := &File{ + FileDescriptorProto: &fd, + GoPkg: GoPackage{ + Path: "path/to/example.pb", + Name: "example_pb", + }, + Messages: []*Message{msg}, + Services: []*Service{ + { + ServiceDescriptorProto: fd.Service[0], + Methods: []*Method{ + { + MethodDescriptorProto: fd.Service[0].Method[0], + RequestType: msg, + ResponseType: msg, + }, + }, + }, + }, + } + + crossLinkFixture(file) + testExtractServices(t, []*descriptor.FileDescriptorProto{&fd}, "path/to/example.proto", file.Services) +} + func TestExtractServicesCrossPackage(t *testing.T) { srcs := []string{ ` diff --git a/gateway/protoc-gen-grpc-gateway/gengateway/BUILD.bazel b/gateway/protoc-gen-grpc-gateway/internal/gengateway/BUILD.bazel similarity index 96% rename from gateway/protoc-gen-grpc-gateway/gengateway/BUILD.bazel rename to gateway/protoc-gen-grpc-gateway/internal/gengateway/BUILD.bazel index 35955e2..0124921 100644 --- a/gateway/protoc-gen-grpc-gateway/gengateway/BUILD.bazel +++ b/gateway/protoc-gen-grpc-gateway/internal/gengateway/BUILD.bazel @@ -9,7 +9,7 @@ go_library( "generator.go", "template.go", ], - importpath = "github.com/binchencoder/ease-gateway/gateway/protoc-gen-grpc-gateway/gengateway", + importpath = "github.com/binchencoder/ease-gateway/gateway/protoc-gen-grpc-gateway/internal/gengateway", deps = [ "//httpoptions:go_default_library", "//gateway/runtime:go_default_library", diff --git a/gateway/protoc-gen-grpc-gateway/gengateway/doc.go b/gateway/protoc-gen-grpc-gateway/internal/gengateway/doc.go similarity index 100% rename from gateway/protoc-gen-grpc-gateway/gengateway/doc.go rename to gateway/protoc-gen-grpc-gateway/internal/gengateway/doc.go diff --git a/gateway/protoc-gen-grpc-gateway/gengateway/generator.go b/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator.go similarity index 100% rename from gateway/protoc-gen-grpc-gateway/gengateway/generator.go rename to gateway/protoc-gen-grpc-gateway/internal/gengateway/generator.go diff --git a/gateway/protoc-gen-grpc-gateway/gengateway/generator_test.go b/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator_test.go similarity index 100% rename from gateway/protoc-gen-grpc-gateway/gengateway/generator_test.go rename to gateway/protoc-gen-grpc-gateway/internal/gengateway/generator_test.go diff --git a/gateway/protoc-gen-grpc-gateway/gengateway/template.go b/gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go similarity index 100% rename from gateway/protoc-gen-grpc-gateway/gengateway/template.go rename to gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go diff --git a/gateway/protoc-gen-grpc-gateway/gengateway/template_test.go b/gateway/protoc-gen-grpc-gateway/internal/gengateway/template_test.go similarity index 100% rename from gateway/protoc-gen-grpc-gateway/gengateway/template_test.go rename to gateway/protoc-gen-grpc-gateway/internal/gengateway/template_test.go diff --git a/gateway/protoc-gen-grpc-gateway/main.go b/gateway/protoc-gen-grpc-gateway/main.go index 2ff25a2..5913b0e 100644 --- a/gateway/protoc-gen-grpc-gateway/main.go +++ b/gateway/protoc-gen-grpc-gateway/main.go @@ -18,14 +18,13 @@ import ( "github.com/golang/protobuf/proto" plugin "github.com/golang/protobuf/protoc-gen-go/plugin" - // "github.com/grpc-ecosystem/grpc-gateway/codegenerator" - "github.com/binchencoder/ease-gateway/gateway/codegenerator" + "github.com/grpc-ecosystem/grpc-gateway/codegenerator" // "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/descriptor" "github.com/binchencoder/ease-gateway/gateway/protoc-gen-grpc-gateway/descriptor" - - // "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/gengateway" - "github.com/binchencoder/ease-gateway/gateway/protoc-gen-grpc-gateway/gengateway" + + // "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/internal/gengateway" + "github.com/binchencoder/ease-gateway/gateway/protoc-gen-grpc-gateway/internal/gengateway" ) var ( @@ -40,7 +39,7 @@ var ( repeatedPathParamSeparator = flag.String("repeated_path_param_separator", "csv", "configures how repeated fields should be split. Allowed values are `csv`, `pipes`, `ssv` and `tsv`.") allowPatchFeature = flag.Bool("allow_patch_feature", true, "determines whether to use PATCH feature involving update masks (using google.protobuf.FieldMask).") allowColonFinalSegments = flag.Bool("allow_colon_final_segments", false, "determines whether colons are permitted in the final segment of a path") - versionFlag = flag.Bool("version", false, "print the current verison") + versionFlag = flag.Bool("version", false, "print the current version") ) // Variables set by goreleaser at build time @@ -110,6 +109,11 @@ func main() { emitError(err) return } + unboundHTTPRules := reg.UnboundExternalHTTPRules() + if len(unboundHTTPRules) != 0 { + emitError(fmt.Errorf("HTTP rules without a matching selector: %s", strings.Join(unboundHTTPRules, ", "))) + return + } var targets []*descriptor.File for _, target := range req.FileToGenerate { diff --git a/gateway/protoc-gen-swagger/BUILD.bazel b/gateway/protoc-gen-swagger/BUILD.bazel index 938be05..e2dc53d 100644 --- a/gateway/protoc-gen-swagger/BUILD.bazel +++ b/gateway/protoc-gen-swagger/BUILD.bazel @@ -7,11 +7,11 @@ go_library( srcs = ["main.go"], importpath = "github.com/binchencoder/ease-gateway/gateway/protoc-gen-swagger", deps = [ - "//gateway/codegenerator:go_default_library", "//gateway/protoc-gen-grpc-gateway/descriptor:go_default_library", "//gateway/protoc-gen-swagger/genswagger:go_default_library", "@com_github_golang_glog//:go_default_library", "@com_github_golang_protobuf//proto:go_default_library", + "@com_github_grpc_ecosystem_grpc_gateway//codegenerator:go_default_library", "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", ], ) diff --git a/gateway/protoc-gen-swagger/defs.bzl b/gateway/protoc-gen-swagger/defs.bzl index 565827c..f1fac21 100644 --- a/gateway/protoc-gen-swagger/defs.bzl +++ b/gateway/protoc-gen-swagger/defs.bzl @@ -4,130 +4,165 @@ Reads the the api spec in protobuf format and generate an open-api spec. Optionally applies settings from the grpc-service configuration. """ -def _collect_includes(gen_dir, srcs): - """Build an include path mapping. +load("@rules_proto//proto:defs.bzl", "ProtoInfo") - It is important to not just collect unique dirnames, to also support - proto files of the same name from different packages. +# TODO(yannic): Replace with |proto_common.direct_source_infos| when +# https://github.com/bazelbuild/rules_proto/pull/22 lands. +def _direct_source_infos(proto_info, provided_sources = []): + """Returns sequence of `ProtoFileInfo` for `proto_info`'s direct sources. - The implementation below is similar to what bazel does in its - ProtoCompileActionBuilder.java + Files that are both in `proto_info`'s direct sources and in + `provided_sources` are skipped. This is useful, e.g., for well-known + protos that are already provided by the Protobuf runtime. + + Args: + proto_info: An instance of `ProtoInfo`. + provided_sources: Optional. A sequence of files to ignore. + Usually, these files are already provided by the + Protocol Buffer runtime (e.g. Well-Known protos). + + Returns: A sequence of `ProtoFileInfo` containing information about + `proto_info`'s direct sources. """ - includes = [] - for src in srcs: - ref_path = src.path - if ref_path.startswith(gen_dir): - ref_path = ref_path[len(gen_dir):].lstrip("/") + source_root = proto_info.proto_source_root + if "." == source_root: + return [struct(file = src, import_path = src.path) for src in proto_info.direct_sources] + + offset = len(source_root) + 1 # + '/'. + + infos = [] + for src in proto_info.direct_sources: + # TODO(yannic): Remove this hack when we drop support for Bazel < 1.0. + local_offset = offset + if src.root.path and not source_root.startswith(src.root.path): + # Before Bazel 1.0, `proto_source_root` wasn't guaranteed to be a + # prefix of `src.path`. This could happend, e.g., if `file` was + # generated (https://github.com/bazelbuild/bazel/issues/9215). + local_offset += len(src.root.path) + 1 # + '/'. + infos.append(struct(file = src, import_path = src.path[local_offset:])) + + return infos + +def _run_proto_gen_swagger( + actions, + proto_info, + target_name, + transitive_proto_srcs, + protoc, + protoc_gen_swagger, + grpc_api_configuration, + single_output, + json_names_for_fields): + args = actions.args() + + args.add("--plugin", "protoc-gen-swagger=%s" % protoc_gen_swagger.path) + + args.add("--swagger_opt", "logtostderr=true") + args.add("--swagger_opt", "allow_repeated_fields_in_body=true") + + extra_inputs = [] + if grpc_api_configuration: + extra_inputs.append(grpc_api_configuration) + args.add("--swagger_opt", "grpc_api_configuration=%s" % grpc_api_configuration.path) - if src.owner.workspace_root: - workspace_root = src.owner.workspace_root - ref_path = ref_path[len(workspace_root):].lstrip("/") + if json_names_for_fields: + args.add("--swagger_opt", "json_names_for_fields=true") - include = ref_path + "=" + src.path - if include not in includes: - includes.append(include) + proto_file_infos = _direct_source_infos(proto_info) - return includes + # TODO(yannic): Use |proto_info.transitive_descriptor_sets| when + # https://github.com/bazelbuild/bazel/issues/9337 is fixed. + args.add_all(proto_info.transitive_proto_path, format_each = "--proto_path=%s") -def _run_proto_gen_swagger(ctx, direct_proto_srcs, transitive_proto_srcs, actions, protoc, protoc_gen_swagger, grpc_api_configuration, single_output): - swagger_files = [] + if single_output: + args.add("--swagger_opt", "allow_merge=true") + args.add("--swagger_opt", "merge_file_name=%s" % target_name) - inputs = direct_proto_srcs + transitive_proto_srcs - tools = [protoc_gen_swagger] + swagger_file = actions.declare_file("%s.swagger.json" % target_name) + args.add("--swagger_out", swagger_file.dirname) - options = ["logtostderr=true", "allow_repeated_fields_in_body=true"] - if grpc_api_configuration: - options.append("grpc_api_configuration=%s" % grpc_api_configuration.path) - inputs.append(grpc_api_configuration) + args.add_all([f.import_path for f in proto_file_infos]) - includes = _collect_includes(ctx.genfiles_dir.path, direct_proto_srcs + transitive_proto_srcs) + actions.run( + executable = protoc, + tools = [protoc_gen_swagger], + inputs = depset( + direct = extra_inputs, + transitive = [transitive_proto_srcs], + ), + outputs = [swagger_file], + arguments = [args], + ) - if single_output: + return [swagger_file] + + # TODO(yannic): We may be able to generate all files in a single action, + # but that will change at least the semantics of `use_go_template.proto`. + swagger_files = [] + for proto_file_info in proto_file_infos: + # TODO(yannic): This probably doesn't work as expected: we only add this + # option after we have seen it, so `.proto` sources that happen to be + # in the list of `.proto` files before `use_go_template.proto` will be + # compiled without this option, and all sources that get compiled after + # `use_go_template.proto` will have this option on. + if proto_file_info.file.basename == "use_go_template.proto": + args.add("--swagger_opt", "use_go_templates=true") + + file_name = "%s.swagger.json" % proto_file_info.import_path[:-len(".proto")] swagger_file = actions.declare_file( - "%s.swagger.json" % ctx.attr.name, - sibling = direct_proto_srcs[0], + "_virtual_imports/%s/%s" % (target_name, file_name), ) - output_dir = ctx.bin_dir.path - if direct_proto_srcs[0].owner.workspace_root: - output_dir = "/".join([output_dir, direct_proto_srcs[0].owner.workspace_root]) - output_dir = "/".join([output_dir, direct_proto_srcs[0].dirname]) + file_args = actions.args() - options.append("allow_merge=true") - options.append("merge_file_name=%s" % ctx.attr.name) + offset = len(file_name) + 1 # + '/'. + file_args.add("--swagger_out", swagger_file.path[:-offset]) - args = actions.args() - args.add("--plugin=%s" % protoc_gen_swagger.path) - args.add("--swagger_out=%s:%s" % (",".join(options), output_dir)) - args.add_all(["-I%s" % include for include in includes]) - args.add_all([src.path for src in direct_proto_srcs]) + file_args.add(proto_file_info.import_path) actions.run( executable = protoc, - inputs = inputs, - tools = tools, + tools = [protoc_gen_swagger], + inputs = depset( + direct = extra_inputs, + transitive = [transitive_proto_srcs], + ), outputs = [swagger_file], - arguments = [args], + arguments = [args, file_args], ) - swagger_files.append(swagger_file) - else: - for proto in direct_proto_srcs: - if proto.basename == "use_go_template.proto": - options.append("use_go_templates=true") - - swagger_file = actions.declare_file( - "%s.swagger.json" % proto.basename[:-len(".proto")], - sibling = proto, - ) - - output_dir = ctx.bin_dir.path - if proto.owner.workspace_root: - output_dir = "/".join([output_dir, proto.owner.workspace_root]) - - args = actions.args() - args.add("--plugin=%s" % protoc_gen_swagger.path) - args.add("--swagger_out=%s:%s" % (",".join(options), output_dir)) - args.add_all(["-I%s" % include for include in includes]) - args.add(proto.path) - - actions.run( - executable = protoc, - inputs = inputs, - tools = tools, - outputs = [swagger_file], - arguments = [args], - ) - swagger_files.append(swagger_file) return swagger_files def _proto_gen_swagger_impl(ctx): proto = ctx.attr.proto[ProtoInfo] - grpc_api_configuration = ctx.file.grpc_api_configuration - - return [DefaultInfo( - files = depset( - _run_proto_gen_swagger( - ctx, - direct_proto_srcs = proto.direct_sources, - transitive_proto_srcs = ctx.files._well_known_protos + proto.transitive_sources.to_list(), - actions = ctx.actions, - protoc = ctx.executable._protoc, - protoc_gen_swagger = ctx.executable._protoc_gen_swagger, - grpc_api_configuration = grpc_api_configuration, - single_output = ctx.attr.single_output, + return [ + DefaultInfo( + files = depset( + _run_proto_gen_swagger( + actions = ctx.actions, + proto_info = proto, + target_name = ctx.attr.name, + transitive_proto_srcs = depset( + direct = ctx.files._well_known_protos, + transitive = [proto.transitive_sources], + ), + protoc = ctx.executable._protoc, + protoc_gen_swagger = ctx.executable._protoc_gen_swagger, + grpc_api_configuration = ctx.file.grpc_api_configuration, + single_output = ctx.attr.single_output, + json_names_for_fields = ctx.attr.json_names_for_fields, + ), ), ), - )] + ] protoc_gen_swagger = rule( attrs = { "proto": attr.label( - allow_rules = ["proto_library"], mandatory = True, - providers = ["proto"], + providers = [ProtoInfo], ), "grpc_api_configuration": attr.label( allow_single_file = True, @@ -137,6 +172,10 @@ protoc_gen_swagger = rule( default = False, mandatory = False, ), + "json_names_for_fields": attr.bool( + default = False, + mandatory = False, + ), "_protoc": attr.label( default = "@com_google_protobuf//:protoc", executable = True, diff --git a/gateway/protoc-gen-swagger/main.go b/gateway/protoc-gen-swagger/main.go index 22ecf14..b805bfe 100644 --- a/gateway/protoc-gen-swagger/main.go +++ b/gateway/protoc-gen-swagger/main.go @@ -10,8 +10,7 @@ import ( "github.com/golang/protobuf/proto" plugin "github.com/golang/protobuf/protoc-gen-go/plugin" - // "github.com/grpc-ecosystem/grpc-gateway/codegenerator" - "github.com/binchencoder/ease-gateway/gateway/codegenerator" + "github.com/grpc-ecosystem/grpc-gateway/codegenerator" // "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/descriptor" "github.com/binchencoder/ease-gateway/gateway/protoc-gen-grpc-gateway/descriptor" @@ -29,11 +28,14 @@ var ( mergeFileName = flag.String("merge_file_name", "apidocs", "target swagger file name prefix after merge") useJSONNamesForFields = flag.Bool("json_names_for_fields", false, "if it sets Field.GetJsonName() will be used for generating swagger definitions, otherwise Field.GetName() will be used") repeatedPathParamSeparator = flag.String("repeated_path_param_separator", "csv", "configures how repeated fields should be split. Allowed values are `csv`, `pipes`, `ssv` and `tsv`.") - versionFlag = flag.Bool("version", false, "print the current verison") + versionFlag = flag.Bool("version", false, "print the current version") allowRepeatedFieldsInBody = flag.Bool("allow_repeated_fields_in_body", false, "allows to use repeated field in `body` and `response_body` field of `google.api.http` annotation option") includePackageInTags = flag.Bool("include_package_in_tags", false, "if unset, the gRPC service name is added to the `Tags` field of each operation. if set and the `package` directive is shown in the proto file, the package name will be prepended to the service name") useFQNForSwaggerName = flag.Bool("fqn_for_swagger_name", false, "if set, the object's swagger names will use the fully qualify name from the proto definition (ie my.package.MyMessage.MyInnerMessage") useGoTemplate = flag.Bool("use_go_templates", false, "if set, you can use Go templates in protofile comments") + disableDefaultErrors = flag.Bool("disable_default_errors", false, "if set, disables generation of default errors. This is useful if you have defined custom error handling") + enumsAsInts = flag.Bool("enums_as_ints", false, "whether to render enum values as integers, as opposed to string values") + simpleOperationIDs = flag.Bool("simple_operation_ids", false, "whether to remove the service prefix in the operationID generation. Can introduce duplicate operationIDs, use with caution.") ) // Variables set by goreleaser at build time @@ -86,6 +88,9 @@ func main() { reg.SetIncludePackageInTags(*includePackageInTags) reg.SetUseFQNForSwaggerName(*useFQNForSwaggerName) reg.SetUseGoTemplate(*useGoTemplate) + reg.SetEnumsAsInts(*enumsAsInts) + reg.SetDisableDefaultErrors(*disableDefaultErrors) + reg.SetSimpleOperationIDs(*simpleOperationIDs) if err := reg.SetRepeatedPathParamSeparator(*repeatedPathParamSeparator); err != nil { emitError(err) return diff --git a/gateway/protoc-gen-swagger/options/BUILD.bazel b/gateway/protoc-gen-swagger/options/BUILD.bazel index 7c39c66..19e4b0e 100644 --- a/gateway/protoc-gen-swagger/options/BUILD.bazel +++ b/gateway/protoc-gen-swagger/options/BUILD.bazel @@ -1,3 +1,4 @@ +load("@rules_proto//proto:defs.bzl", "proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library") load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") @@ -32,7 +33,6 @@ proto_library( go_proto_library( name = "options_go_proto", - compilers = ["@io_bazel_rules_go//proto:go_grpc"], importpath = "github.com/binchencoder/ease-gateway/gateway/protoc-gen-swagger/options", proto = ":options_proto", ) diff --git a/gateway/protoc-gen-swagger/options/openapiv2.pb.go b/gateway/protoc-gen-swagger/options/openapiv2.pb.go index 727ca52..c15e2d1 100644 --- a/gateway/protoc-gen-swagger/options/openapiv2.pb.go +++ b/gateway/protoc-gen-swagger/options/openapiv2.pb.go @@ -99,7 +99,7 @@ func (JSONSchema_JSONSchemaSimpleTypes) EnumDescriptor() ([]byte, []int) { return fileDescriptor_ba35ad8af024fb48, []int{8, 0} } -// Required. The type of the security scheme. Valid values are "basic", +// The type of the security scheme. Valid values are "basic", // "apiKey" or "oauth2". type SecurityScheme_Type int32 @@ -132,7 +132,7 @@ func (SecurityScheme_Type) EnumDescriptor() ([]byte, []int) { return fileDescriptor_ba35ad8af024fb48, []int{11, 0} } -// Required. The location of the API key. Valid values are "query" or "header". +// The location of the API key. Valid values are "query" or "header". type SecurityScheme_In int32 const ( @@ -161,7 +161,7 @@ func (SecurityScheme_In) EnumDescriptor() ([]byte, []int) { return fileDescriptor_ba35ad8af024fb48, []int{11, 1} } -// Required. The flow used by the OAuth2 security scheme. Valid values are +// The flow used by the OAuth2 security scheme. Valid values are // "implicit", "password", "application" or "accessCode". type SecurityScheme_Flow int32 @@ -201,24 +201,52 @@ func (SecurityScheme_Flow) EnumDescriptor() ([]byte, []int) { // // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#swaggerObject // -// TODO(ivucica): document fields type Swagger struct { + // Specifies the Swagger Specification version being used. It can be + // used by the Swagger UI and other clients to interpret the API listing. The + // value MUST be "2.0". Swagger string `protobuf:"bytes,1,opt,name=swagger,proto3" json:"swagger,omitempty"` - Info *Info `protobuf:"bytes,2,opt,name=info,proto3" json:"info,omitempty"` - Host string `protobuf:"bytes,3,opt,name=host,proto3" json:"host,omitempty"` - // `base_path` is the common prefix path used on all API endpoints (ie. /api, /v1, etc.). By adding this, - // it allows you to remove this portion from the path endpoints in your Swagger file making them easier - // to read. Note that using `base_path` does not change the endpoint paths that are generated in the resulting - // Swagger file. If you wish to use `base_path` with relatively generated Swagger paths, the - // `base_path` prefix must be manually removed from your `google.api.http` paths and your code changed to + // Provides metadata about the API. The metadata can be used by the + // clients if needed. + Info *Info `protobuf:"bytes,2,opt,name=info,proto3" json:"info,omitempty"` + // The host (name or ip) serving the API. This MUST be the host only and does + // not include the scheme nor sub-paths. It MAY include a port. If the host is + // not included, the host serving the documentation is to be used (including + // the port). The host does not support path templating. + Host string `protobuf:"bytes,3,opt,name=host,proto3" json:"host,omitempty"` + // The base path on which the API is served, which is relative to the host. If + // it is not included, the API is served directly under the host. The value + // MUST start with a leading slash (/). The basePath does not support path + // templating. + // Note that using `base_path` does not change the endpoint paths that are + // generated in the resulting Swagger file. If you wish to use `base_path` + // with relatively generated Swagger paths, the `base_path` prefix must be + // manually removed from your `google.api.http` paths and your code changed to // serve the API from the `base_path`. - BasePath string `protobuf:"bytes,4,opt,name=base_path,json=basePath,proto3" json:"base_path,omitempty"` - Schemes []Swagger_SwaggerScheme `protobuf:"varint,5,rep,packed,name=schemes,proto3,enum=grpc.gateway.protoc_gen_swagger.options.Swagger_SwaggerScheme" json:"schemes,omitempty"` - Consumes []string `protobuf:"bytes,6,rep,name=consumes,proto3" json:"consumes,omitempty"` - Produces []string `protobuf:"bytes,7,rep,name=produces,proto3" json:"produces,omitempty"` - Responses map[string]*Response `protobuf:"bytes,10,rep,name=responses,proto3" json:"responses,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - SecurityDefinitions *SecurityDefinitions `protobuf:"bytes,11,opt,name=security_definitions,json=securityDefinitions,proto3" json:"security_definitions,omitempty"` - Security []*SecurityRequirement `protobuf:"bytes,12,rep,name=security,proto3" json:"security,omitempty"` + BasePath string `protobuf:"bytes,4,opt,name=base_path,json=basePath,proto3" json:"base_path,omitempty"` + // The transfer protocol of the API. Values MUST be from the list: "http", + // "https", "ws", "wss". If the schemes is not included, the default scheme to + // be used is the one used to access the Swagger definition itself. + Schemes []Swagger_SwaggerScheme `protobuf:"varint,5,rep,packed,name=schemes,proto3,enum=grpc.gateway.protoc_gen_swagger.options.Swagger_SwaggerScheme" json:"schemes,omitempty"` + // A list of MIME types the APIs can consume. This is global to all APIs but + // can be overridden on specific API calls. Value MUST be as described under + // Mime Types. + Consumes []string `protobuf:"bytes,6,rep,name=consumes,proto3" json:"consumes,omitempty"` + // A list of MIME types the APIs can produce. This is global to all APIs but + // can be overridden on specific API calls. Value MUST be as described under + // Mime Types. + Produces []string `protobuf:"bytes,7,rep,name=produces,proto3" json:"produces,omitempty"` + // An object to hold responses that can be used across operations. This + // property does not define global responses for all operations. + Responses map[string]*Response `protobuf:"bytes,10,rep,name=responses,proto3" json:"responses,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + // Security scheme definitions that can be used across the specification. + SecurityDefinitions *SecurityDefinitions `protobuf:"bytes,11,opt,name=security_definitions,json=securityDefinitions,proto3" json:"security_definitions,omitempty"` + // A declaration of which security schemes are applied for the API as a whole. + // The list of values describes alternative security schemes that can be used + // (that is, there is a logical OR between the security requirements). + // Individual operations can override this definition. + Security []*SecurityRequirement `protobuf:"bytes,12,rep,name=security,proto3" json:"security,omitempty"` + // Additional external documentation. ExternalDocs *ExternalDocumentation `protobuf:"bytes,14,opt,name=external_docs,json=externalDocs,proto3" json:"external_docs,omitempty"` Extensions map[string]*_struct.Value `protobuf:"bytes,15,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` XXX_NoUnkeyedLiteral struct{} `json:"-"` @@ -339,18 +367,46 @@ func (m *Swagger) GetExtensions() map[string]*_struct.Value { // // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#operationObject // -// TODO(ivucica): document fields type Operation struct { - Tags []string `protobuf:"bytes,1,rep,name=tags,proto3" json:"tags,omitempty"` - Summary string `protobuf:"bytes,2,opt,name=summary,proto3" json:"summary,omitempty"` - Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"` - ExternalDocs *ExternalDocumentation `protobuf:"bytes,4,opt,name=external_docs,json=externalDocs,proto3" json:"external_docs,omitempty"` - OperationId string `protobuf:"bytes,5,opt,name=operation_id,json=operationId,proto3" json:"operation_id,omitempty"` - Consumes []string `protobuf:"bytes,6,rep,name=consumes,proto3" json:"consumes,omitempty"` - Produces []string `protobuf:"bytes,7,rep,name=produces,proto3" json:"produces,omitempty"` - Responses map[string]*Response `protobuf:"bytes,9,rep,name=responses,proto3" json:"responses,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - Schemes []string `protobuf:"bytes,10,rep,name=schemes,proto3" json:"schemes,omitempty"` - Deprecated bool `protobuf:"varint,11,opt,name=deprecated,proto3" json:"deprecated,omitempty"` + // A list of tags for API documentation control. Tags can be used for logical + // grouping of operations by resources or any other qualifier. + Tags []string `protobuf:"bytes,1,rep,name=tags,proto3" json:"tags,omitempty"` + // A short summary of what the operation does. For maximum readability in the + // swagger-ui, this field SHOULD be less than 120 characters. + Summary string `protobuf:"bytes,2,opt,name=summary,proto3" json:"summary,omitempty"` + // A verbose explanation of the operation behavior. GFM syntax can be used for + // rich text representation. + Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"` + // Additional external documentation for this operation. + ExternalDocs *ExternalDocumentation `protobuf:"bytes,4,opt,name=external_docs,json=externalDocs,proto3" json:"external_docs,omitempty"` + // Unique string used to identify the operation. The id MUST be unique among + // all operations described in the API. Tools and libraries MAY use the + // operationId to uniquely identify an operation, therefore, it is recommended + // to follow common programming naming conventions. + OperationId string `protobuf:"bytes,5,opt,name=operation_id,json=operationId,proto3" json:"operation_id,omitempty"` + // A list of MIME types the operation can consume. This overrides the consumes + // definition at the Swagger Object. An empty value MAY be used to clear the + // global definition. Value MUST be as described under Mime Types. + Consumes []string `protobuf:"bytes,6,rep,name=consumes,proto3" json:"consumes,omitempty"` + // A list of MIME types the operation can produce. This overrides the produces + // definition at the Swagger Object. An empty value MAY be used to clear the + // global definition. Value MUST be as described under Mime Types. + Produces []string `protobuf:"bytes,7,rep,name=produces,proto3" json:"produces,omitempty"` + // The list of possible responses as they are returned from executing this + // operation. + Responses map[string]*Response `protobuf:"bytes,9,rep,name=responses,proto3" json:"responses,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + // The transfer protocol for the operation. Values MUST be from the list: + // "http", "https", "ws", "wss". The value overrides the Swagger Object + // schemes definition. + Schemes []string `protobuf:"bytes,10,rep,name=schemes,proto3" json:"schemes,omitempty"` + // Declares this operation to be deprecated. Usage of the declared operation + // should be refrained. Default value is false. + Deprecated bool `protobuf:"varint,11,opt,name=deprecated,proto3" json:"deprecated,omitempty"` + // A declaration of which security schemes are applied for this operation. The + // list of values describes alternative security schemes that can be used + // (that is, there is a logical OR between the security requirements). This + // definition overrides any declared top-level security. To remove a top-level + // security declaration, an empty array can be used. Security []*SecurityRequirement `protobuf:"bytes,12,rep,name=security,proto3" json:"security,omitempty"` Extensions map[string]*_struct.Value `protobuf:"bytes,13,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` XXX_NoUnkeyedLiteral struct{} `json:"-"` @@ -477,7 +533,10 @@ type Response struct { Description string `protobuf:"bytes,1,opt,name=description,proto3" json:"description,omitempty"` // `Schema` optionally defines the structure of the response. // If `Schema` is not provided, it means there is no content to the response. - Schema *Schema `protobuf:"bytes,2,opt,name=schema,proto3" json:"schema,omitempty"` + Schema *Schema `protobuf:"bytes,2,opt,name=schema,proto3" json:"schema,omitempty"` + // `Examples` gives per-mimetype response examples. + // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#example-object + Examples map[string]string `protobuf:"bytes,4,rep,name=examples,proto3" json:"examples,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` Extensions map[string]*_struct.Value `protobuf:"bytes,5,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` @@ -523,6 +582,13 @@ func (m *Response) GetSchema() *Schema { return nil } +func (m *Response) GetExamples() map[string]string { + if m != nil { + return m.Examples + } + return nil +} + func (m *Response) GetExtensions() map[string]*_struct.Value { if m != nil { return m.Extensions @@ -534,13 +600,20 @@ func (m *Response) GetExtensions() map[string]*_struct.Value { // // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#infoObject // -// TODO(ivucica): document fields type Info struct { - Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` - Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` - TermsOfService string `protobuf:"bytes,3,opt,name=terms_of_service,json=termsOfService,proto3" json:"terms_of_service,omitempty"` - Contact *Contact `protobuf:"bytes,4,opt,name=contact,proto3" json:"contact,omitempty"` - License *License `protobuf:"bytes,5,opt,name=license,proto3" json:"license,omitempty"` + // The title of the application. + Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` + // A short description of the application. GFM syntax can be used for rich + // text representation. + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` + // The Terms of Service for the API. + TermsOfService string `protobuf:"bytes,3,opt,name=terms_of_service,json=termsOfService,proto3" json:"terms_of_service,omitempty"` + // The contact information for the exposed API. + Contact *Contact `protobuf:"bytes,4,opt,name=contact,proto3" json:"contact,omitempty"` + // The license information for the exposed API. + License *License `protobuf:"bytes,5,opt,name=license,proto3" json:"license,omitempty"` + // Provides the version of the application API (not to be confused + // with the specification version). Version string `protobuf:"bytes,6,opt,name=version,proto3" json:"version,omitempty"` Extensions map[string]*_struct.Value `protobuf:"bytes,7,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` XXX_NoUnkeyedLiteral struct{} `json:"-"` @@ -626,10 +699,14 @@ func (m *Info) GetExtensions() map[string]*_struct.Value { // // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#contactObject // -// TODO(ivucica): document fields type Contact struct { - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"` + // The identifying name of the contact person/organization. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // The URL pointing to the contact information. MUST be in the format of a + // URL. + Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"` + // The email address of the contact person/organization. MUST be in the format + // of an email address. Email string `protobuf:"bytes,3,opt,name=email,proto3" json:"email,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` @@ -687,9 +764,9 @@ func (m *Contact) GetEmail() string { // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#licenseObject // type License struct { - // Required. The license name used for the API. + // The license name used for the API. Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - // A URL to the license used for the API. + // A URL to the license used for the API. MUST be in the format of a URL. Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` @@ -740,9 +817,12 @@ func (m *License) GetUrl() string { // // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#externalDocumentationObject // -// TODO(ivucica): document fields type ExternalDocumentation struct { - Description string `protobuf:"bytes,1,opt,name=description,proto3" json:"description,omitempty"` + // A short description of the target documentation. GFM syntax can be used for + // rich text representation. + Description string `protobuf:"bytes,1,opt,name=description,proto3" json:"description,omitempty"` + // The URL for the target documentation. Value MUST be in the format + // of a URL. Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` @@ -792,16 +872,27 @@ func (m *ExternalDocumentation) GetUrl() string { // // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#schemaObject // -// TODO(ivucica): document fields type Schema struct { - JsonSchema *JSONSchema `protobuf:"bytes,1,opt,name=json_schema,json=jsonSchema,proto3" json:"json_schema,omitempty"` - Discriminator string `protobuf:"bytes,2,opt,name=discriminator,proto3" json:"discriminator,omitempty"` - ReadOnly bool `protobuf:"varint,3,opt,name=read_only,json=readOnly,proto3" json:"read_only,omitempty"` - ExternalDocs *ExternalDocumentation `protobuf:"bytes,5,opt,name=external_docs,json=externalDocs,proto3" json:"external_docs,omitempty"` - Example *any.Any `protobuf:"bytes,6,opt,name=example,proto3" json:"example,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + JsonSchema *JSONSchema `protobuf:"bytes,1,opt,name=json_schema,json=jsonSchema,proto3" json:"json_schema,omitempty"` + // Adds support for polymorphism. The discriminator is the schema property + // name that is used to differentiate between other schema that inherit this + // schema. The property name used MUST be defined at this schema and it MUST + // be in the required property list. When used, the value MUST be the name of + // this schema or any schema that inherits it. + Discriminator string `protobuf:"bytes,2,opt,name=discriminator,proto3" json:"discriminator,omitempty"` + // Relevant only for Schema "properties" definitions. Declares the property as + // "read only". This means that it MAY be sent as part of a response but MUST + // NOT be sent as part of the request. Properties marked as readOnly being + // true SHOULD NOT be in the required list of the defined schema. Default + // value is false. + ReadOnly bool `protobuf:"varint,3,opt,name=read_only,json=readOnly,proto3" json:"read_only,omitempty"` + // Additional external documentation for this schema. + ExternalDocs *ExternalDocumentation `protobuf:"bytes,5,opt,name=external_docs,json=externalDocs,proto3" json:"external_docs,omitempty"` + // A free-form property to include an example of an instance for this schema. + Example *any.Any `protobuf:"bytes,6,opt,name=example,proto3" json:"example,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *Schema) Reset() { *m = Schema{} } @@ -877,19 +968,25 @@ func (m *Schema) GetExample() *any.Any { // TODO(ivucica): document fields type JSONSchema struct { // Ref is used to define an external reference to include in the message. - // This could be a fully qualified proto message reference, and that type must be imported - // into the protofile. If no message is identified, the Ref will be used verbatim in - // the output. + // This could be a fully qualified proto message reference, and that type must + // be imported into the protofile. If no message is identified, the Ref will + // be used verbatim in the output. // For example: // `ref: ".google.protobuf.Timestamp"`. - Ref string `protobuf:"bytes,3,opt,name=ref,proto3" json:"ref,omitempty"` - Title string `protobuf:"bytes,5,opt,name=title,proto3" json:"title,omitempty"` - Description string `protobuf:"bytes,6,opt,name=description,proto3" json:"description,omitempty"` - Default string `protobuf:"bytes,7,opt,name=default,proto3" json:"default,omitempty"` - ReadOnly bool `protobuf:"varint,8,opt,name=read_only,json=readOnly,proto3" json:"read_only,omitempty"` - MultipleOf float64 `protobuf:"fixed64,10,opt,name=multiple_of,json=multipleOf,proto3" json:"multiple_of,omitempty"` - Maximum float64 `protobuf:"fixed64,11,opt,name=maximum,proto3" json:"maximum,omitempty"` - ExclusiveMaximum bool `protobuf:"varint,12,opt,name=exclusive_maximum,json=exclusiveMaximum,proto3" json:"exclusive_maximum,omitempty"` + Ref string `protobuf:"bytes,3,opt,name=ref,proto3" json:"ref,omitempty"` + // The title of the schema. + Title string `protobuf:"bytes,5,opt,name=title,proto3" json:"title,omitempty"` + // A short description of the schema. + Description string `protobuf:"bytes,6,opt,name=description,proto3" json:"description,omitempty"` + Default string `protobuf:"bytes,7,opt,name=default,proto3" json:"default,omitempty"` + ReadOnly bool `protobuf:"varint,8,opt,name=read_only,json=readOnly,proto3" json:"read_only,omitempty"` + MultipleOf float64 `protobuf:"fixed64,10,opt,name=multiple_of,json=multipleOf,proto3" json:"multiple_of,omitempty"` + // Maximum represents an inclusive upper limit for a numeric instance. The + // value of MUST be a number, + Maximum float64 `protobuf:"fixed64,11,opt,name=maximum,proto3" json:"maximum,omitempty"` + ExclusiveMaximum bool `protobuf:"varint,12,opt,name=exclusive_maximum,json=exclusiveMaximum,proto3" json:"exclusive_maximum,omitempty"` + // minimum represents an inclusive lower limit for a numeric instance. The + // value of MUST be a number, Minimum float64 `protobuf:"fixed64,13,opt,name=minimum,proto3" json:"minimum,omitempty"` ExclusiveMinimum bool `protobuf:"varint,14,opt,name=exclusive_minimum,json=exclusiveMinimum,proto3" json:"exclusive_minimum,omitempty"` MaxLength uint64 `protobuf:"varint,15,opt,name=max_length,json=maxLength,proto3" json:"max_length,omitempty"` @@ -1085,11 +1182,11 @@ func (m *JSONSchema) GetType() []JSONSchema_JSONSchemaSimpleTypes { // // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#tagObject // -// TODO(ivucica): document fields type Tag struct { - // TODO(ivucica): Description should be extracted from comments on the proto - // service object. - Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` + // A short description for the tag. GFM syntax can be used for rich text + // representation. + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` + // Additional external documentation for this tag. ExternalDocs *ExternalDocumentation `protobuf:"bytes,3,opt,name=external_docs,json=externalDocs,proto3" json:"external_docs,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` @@ -1144,7 +1241,8 @@ func (m *Tag) GetExternalDocs() *ExternalDocumentation { // specification. This does not enforce the security schemes on the operations // and only serves to provide the relevant details for each scheme. type SecurityDefinitions struct { - // A single security scheme definition, mapping a "name" to the scheme it defines. + // A single security scheme definition, mapping a "name" to the scheme it + // defines. Security map[string]*SecurityScheme `protobuf:"bytes,1,rep,name=security,proto3" json:"security,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` @@ -1193,36 +1291,31 @@ func (m *SecurityDefinitions) GetSecurity() map[string]*SecurityScheme { // a header or as a query parameter) and OAuth2's common flows (implicit, // password, application and access code). type SecurityScheme struct { - // Required. The type of the security scheme. Valid values are "basic", + // The type of the security scheme. Valid values are "basic", // "apiKey" or "oauth2". Type SecurityScheme_Type `protobuf:"varint,1,opt,name=type,proto3,enum=grpc.gateway.protoc_gen_swagger.options.SecurityScheme_Type" json:"type,omitempty"` // A short description for security scheme. Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` - // Required. The name of the header or query parameter to be used. - // + // The name of the header or query parameter to be used. // Valid for apiKey. Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` - // Required. The location of the API key. Valid values are "query" or "header". - // + // The location of the API key. Valid values are "query" or + // "header". // Valid for apiKey. In SecurityScheme_In `protobuf:"varint,4,opt,name=in,proto3,enum=grpc.gateway.protoc_gen_swagger.options.SecurityScheme_In" json:"in,omitempty"` - // Required. The flow used by the OAuth2 security scheme. Valid values are + // The flow used by the OAuth2 security scheme. Valid values are // "implicit", "password", "application" or "accessCode". - // // Valid for oauth2. Flow SecurityScheme_Flow `protobuf:"varint,5,opt,name=flow,proto3,enum=grpc.gateway.protoc_gen_swagger.options.SecurityScheme_Flow" json:"flow,omitempty"` - // Required. The authorization URL to be used for this flow. This SHOULD be in + // The authorization URL to be used for this flow. This SHOULD be in // the form of a URL. - // // Valid for oauth2/implicit and oauth2/accessCode. AuthorizationUrl string `protobuf:"bytes,6,opt,name=authorization_url,json=authorizationUrl,proto3" json:"authorization_url,omitempty"` - // Required. The token URL to be used for this flow. This SHOULD be in the + // The token URL to be used for this flow. This SHOULD be in the // form of a URL. - // // Valid for oauth2/password, oauth2/application and oauth2/accessCode. TokenUrl string `protobuf:"bytes,7,opt,name=token_url,json=tokenUrl,proto3" json:"token_url,omitempty"` - // Required. The available scopes for the OAuth2 security scheme. - // + // The available scopes for the OAuth2 security scheme. // Valid for oauth2. Scopes *Scopes `protobuf:"bytes,8,opt,name=scopes,proto3" json:"scopes,omitempty"` Extensions map[string]*_struct.Value `protobuf:"bytes,9,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` @@ -1478,6 +1571,7 @@ func init() { proto.RegisterMapType((map[string]*_struct.Value)(nil), "grpc.gateway.protoc_gen_swagger.options.Operation.ExtensionsEntry") proto.RegisterMapType((map[string]*Response)(nil), "grpc.gateway.protoc_gen_swagger.options.Operation.ResponsesEntry") proto.RegisterType((*Response)(nil), "grpc.gateway.protoc_gen_swagger.options.Response") + proto.RegisterMapType((map[string]string)(nil), "grpc.gateway.protoc_gen_swagger.options.Response.ExamplesEntry") proto.RegisterMapType((map[string]*_struct.Value)(nil), "grpc.gateway.protoc_gen_swagger.options.Response.ExtensionsEntry") proto.RegisterType((*Info)(nil), "grpc.gateway.protoc_gen_swagger.options.Info") proto.RegisterMapType((map[string]*_struct.Value)(nil), "grpc.gateway.protoc_gen_swagger.options.Info.ExtensionsEntry") @@ -1503,123 +1597,125 @@ func init() { } var fileDescriptor_ba35ad8af024fb48 = []byte{ - // 1884 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x58, 0x5b, 0x73, 0xdb, 0xc6, - 0xf5, 0x0f, 0x48, 0x90, 0x04, 0x0f, 0x45, 0x7a, 0xbd, 0x96, 0xf3, 0x47, 0x18, 0xdb, 0x7f, 0x85, - 0x4d, 0xa7, 0x1a, 0xbb, 0xa6, 0x12, 0xe5, 0xa1, 0x99, 0x4c, 0x6f, 0x94, 0xc4, 0xc8, 0x80, 0x65, - 0x92, 0x05, 0xa9, 0x28, 0xee, 0x8c, 0x07, 0x85, 0xc0, 0x25, 0x85, 0x18, 0x17, 0x06, 0x17, 0x49, - 0xec, 0x27, 0xe8, 0x73, 0xa7, 0xaf, 0xf9, 0x1e, 0x9d, 0x69, 0x9f, 0xfa, 0x09, 0xfa, 0x59, 0xda, - 0xe9, 0x7b, 0x67, 0x2f, 0x20, 0x41, 0x91, 0xf1, 0x90, 0x72, 0x3c, 0x79, 0xe8, 0x13, 0xf7, 0xdc, - 0x7e, 0xbb, 0x7b, 0xce, 0x9e, 0x0b, 0x08, 0x8f, 0x27, 0x61, 0x10, 0x07, 0xf6, 0xd3, 0x31, 0xf1, - 0x9f, 0x46, 0x57, 0xd6, 0x78, 0x4c, 0xc2, 0xbd, 0x60, 0x12, 0x3b, 0x81, 0x1f, 0xed, 0x05, 0x13, - 0xe2, 0x5b, 0x13, 0xe7, 0x72, 0xbf, 0xc9, 0x94, 0xf0, 0xcf, 0xc6, 0xe1, 0xc4, 0x6e, 0x8e, 0xad, - 0x98, 0x5c, 0x59, 0x53, 0xce, 0xb3, 0xcd, 0x31, 0xf1, 0x4d, 0x61, 0xd8, 0x14, 0x86, 0xf5, 0x0f, - 0xc6, 0x41, 0x30, 0x76, 0xc9, 0x1e, 0x53, 0x39, 0x4f, 0x46, 0x7b, 0x96, 0x2f, 0xf4, 0xeb, 0x0f, - 0x6e, 0x8a, 0xa2, 0x38, 0x4c, 0xec, 0x98, 0x4b, 0x1b, 0x7f, 0x55, 0xa0, 0xd4, 0xe7, 0x60, 0x58, - 0x85, 0x92, 0xc0, 0x55, 0xa5, 0x1d, 0x69, 0xb7, 0x6c, 0xa4, 0x24, 0x6e, 0x81, 0xec, 0xf8, 0xa3, - 0x40, 0xcd, 0xed, 0x48, 0xbb, 0x95, 0xfd, 0xa7, 0xcd, 0x35, 0x8f, 0xd5, 0xd4, 0xfc, 0x51, 0x60, - 0x30, 0x53, 0x8c, 0x41, 0xbe, 0x08, 0xa2, 0x58, 0xcd, 0x33, 0x64, 0xb6, 0xc6, 0x1f, 0x42, 0xf9, - 0xdc, 0x8a, 0x88, 0x39, 0xb1, 0xe2, 0x0b, 0x55, 0x66, 0x02, 0x85, 0x32, 0x7a, 0x56, 0x7c, 0x81, - 0xbf, 0x86, 0x52, 0x64, 0x5f, 0x10, 0x8f, 0x44, 0x6a, 0x61, 0x27, 0xbf, 0x5b, 0xdb, 0xff, 0xf5, - 0xda, 0xdb, 0x8a, 0x0b, 0xa5, 0xbf, 0x7d, 0x06, 0x63, 0xa4, 0x70, 0xb8, 0x0e, 0x8a, 0x1d, 0xf8, - 0x51, 0x42, 0xa1, 0x8b, 0x3b, 0x79, 0xba, 0x6b, 0x4a, 0x53, 0xd9, 0x24, 0x0c, 0x86, 0x89, 0x4d, - 0x22, 0xb5, 0xc4, 0x65, 0x29, 0x8d, 0x5f, 0x41, 0x39, 0x24, 0xd1, 0x24, 0xf0, 0x23, 0x12, 0xa9, - 0xb0, 0x93, 0xdf, 0xad, 0xec, 0xff, 0x66, 0xe3, 0x33, 0x19, 0x29, 0x42, 0xdb, 0x8f, 0xc3, 0xa9, - 0x31, 0x47, 0xc4, 0x01, 0x6c, 0x47, 0xc4, 0x4e, 0x42, 0x27, 0x9e, 0x9a, 0x43, 0x32, 0x72, 0x7c, - 0x87, 0x59, 0xaa, 0x15, 0xe6, 0xf4, 0x5f, 0xae, 0xbf, 0x93, 0x00, 0x39, 0x9a, 0x63, 0x18, 0xf7, - 0xa2, 0x65, 0x26, 0xfe, 0x1a, 0x94, 0x94, 0xad, 0x6e, 0xb1, 0xeb, 0x6c, 0xbe, 0x89, 0x41, 0xbe, - 0x4d, 0x9c, 0x90, 0x78, 0xc4, 0x8f, 0x8d, 0x19, 0x1a, 0xb6, 0xa1, 0x4a, 0xae, 0x63, 0x12, 0xfa, - 0x96, 0x6b, 0x0e, 0x03, 0x3b, 0x52, 0x6b, 0xec, 0x0e, 0xeb, 0x47, 0xb0, 0x2d, 0xac, 0x8f, 0x02, - 0x3b, 0xa1, 0xd8, 0x16, 0x65, 0x1b, 0x5b, 0x64, 0xce, 0x8e, 0xf0, 0x1f, 0x00, 0x28, 0xed, 0x47, - 0xcc, 0x4b, 0x77, 0xd8, 0x05, 0x7e, 0xbb, 0x71, 0x3c, 0xda, 0x33, 0x08, 0x1e, 0x90, 0x0c, 0x66, - 0x3d, 0x80, 0xda, 0x62, 0xb8, 0x30, 0x82, 0xfc, 0x6b, 0x32, 0x15, 0xe9, 0x41, 0x97, 0xf8, 0x18, - 0x0a, 0x97, 0x96, 0x9b, 0x10, 0x91, 0x1b, 0x9f, 0xae, 0x7d, 0x80, 0x14, 0xd9, 0xe0, 0xf6, 0x5f, - 0xe4, 0x3e, 0x97, 0xea, 0xa7, 0x70, 0xe7, 0xc6, 0x79, 0x56, 0xec, 0xf8, 0xf3, 0xc5, 0x1d, 0xdf, - 0x6f, 0xf2, 0x04, 0x6f, 0xa6, 0x09, 0xde, 0xfc, 0x8a, 0x4a, 0x33, 0xb0, 0x8d, 0x03, 0xa8, 0x2e, - 0xa4, 0x02, 0xae, 0x40, 0xe9, 0xb4, 0xf3, 0xbc, 0xd3, 0x3d, 0xeb, 0xa0, 0xf7, 0xb0, 0x02, 0xf2, - 0xb3, 0xc1, 0xa0, 0x87, 0x24, 0x5c, 0x86, 0x02, 0x5d, 0xf5, 0x51, 0x0e, 0x17, 0x21, 0x77, 0xd6, - 0x47, 0x79, 0x5c, 0x82, 0xfc, 0x59, 0xbf, 0x8f, 0x64, 0x5d, 0x56, 0x14, 0x54, 0xd6, 0x65, 0xa5, - 0x8c, 0x40, 0x97, 0x95, 0x2a, 0xaa, 0x35, 0xfe, 0x51, 0x84, 0x72, 0x77, 0x42, 0x42, 0x16, 0x1b, - 0x9a, 0xdf, 0xb1, 0x35, 0x8e, 0x54, 0x89, 0x25, 0x0d, 0x5b, 0xb3, 0x82, 0x92, 0x78, 0x9e, 0x15, - 0x4e, 0xd9, 0x59, 0x69, 0x41, 0xe1, 0x24, 0xde, 0x81, 0xca, 0x90, 0x44, 0x76, 0xe8, 0x30, 0x67, - 0x88, 0xa2, 0x90, 0x65, 0x2d, 0x3f, 0x21, 0xf9, 0x1d, 0x3c, 0xa1, 0x8f, 0x60, 0x2b, 0x48, 0x6f, - 0x60, 0x3a, 0x43, 0xb5, 0xc0, 0xcf, 0x31, 0xe3, 0x69, 0xc3, 0x5b, 0x17, 0x0b, 0x33, 0x5b, 0x2c, - 0xca, 0xec, 0x71, 0xb6, 0xd6, 0x3e, 0xfb, 0xcc, 0xad, 0x6f, 0x28, 0x17, 0xea, 0xbc, 0x3e, 0x02, - 0xdb, 0x7b, 0x56, 0xdf, 0x1e, 0x01, 0x0c, 0xc9, 0x24, 0x24, 0xb6, 0x15, 0x93, 0x21, 0x2b, 0x1f, - 0x8a, 0x91, 0xe1, 0xbc, 0xc3, 0xbc, 0x3f, 0x5f, 0x48, 0xc9, 0x2a, 0xc3, 0x3e, 0xb8, 0xc5, 0xad, - 0xff, 0x07, 0x92, 0x92, 0x27, 0x54, 0xe3, 0x6f, 0x39, 0x50, 0xd2, 0x4d, 0x6f, 0x66, 0x85, 0xb4, - 0x9c, 0x15, 0xc7, 0x50, 0x64, 0x51, 0xb6, 0xc4, 0x3e, 0x7b, 0xeb, 0x07, 0x8e, 0x99, 0x19, 0xc2, - 0x1c, 0x5b, 0x0b, 0x91, 0x2a, 0x6c, 0xf8, 0x3e, 0xd3, 0x13, 0xbf, 0x31, 0x50, 0xef, 0xcc, 0x6f, - 0x79, 0x56, 0x8e, 0x64, 0x54, 0x68, 0xfc, 0x33, 0x0f, 0x32, 0x9d, 0x31, 0xf0, 0x36, 0x14, 0x62, - 0x27, 0x76, 0x89, 0x80, 0xe6, 0xc4, 0x4d, 0x7f, 0xe6, 0x96, 0xfd, 0xb9, 0x0b, 0x28, 0x26, 0xa1, - 0x17, 0x99, 0xc1, 0xc8, 0x8c, 0x48, 0x78, 0xe9, 0xd8, 0x44, 0x14, 0xa3, 0x1a, 0xe3, 0x77, 0x47, - 0x7d, 0xce, 0xc5, 0x3a, 0x94, 0xec, 0xc0, 0x8f, 0x2d, 0x3b, 0x16, 0x95, 0xe8, 0x93, 0xb5, 0xbd, - 0x75, 0xc8, 0xed, 0x8c, 0x14, 0x80, 0x62, 0xb9, 0x8e, 0x4d, 0xfc, 0x88, 0xb0, 0x8a, 0xb3, 0x09, - 0xd6, 0x09, 0xb7, 0x33, 0x52, 0x00, 0x5a, 0x06, 0x2e, 0x49, 0x48, 0x7d, 0xac, 0x16, 0x79, 0x8d, - 0x15, 0x24, 0x7e, 0xb5, 0x10, 0xe2, 0x12, 0x0b, 0xf1, 0xaf, 0x36, 0x1a, 0xdd, 0x7e, 0x84, 0xf0, - 0x36, 0xda, 0x50, 0x12, 0xfe, 0xa2, 0x2d, 0xc5, 0xb7, 0xbc, 0x34, 0xa6, 0x6c, 0x4d, 0xb7, 0x48, - 0x42, 0x57, 0x84, 0x92, 0x2e, 0x69, 0xe8, 0x89, 0x67, 0x39, 0xae, 0x88, 0x1b, 0x27, 0x1a, 0x7b, - 0x50, 0x12, 0xae, 0x5a, 0x0f, 0xa6, 0xf1, 0x1c, 0xee, 0xaf, 0xec, 0x18, 0x6b, 0x24, 0xe5, 0x32, - 0xd8, 0xdf, 0x73, 0x50, 0xe4, 0x09, 0x87, 0x07, 0x50, 0xf9, 0x26, 0x0a, 0x7c, 0x53, 0xa4, 0xad, - 0xc4, 0xfc, 0xf0, 0xd9, 0xda, 0x61, 0xd0, 0xfb, 0xdd, 0x8e, 0x48, 0x5d, 0xa0, 0x38, 0x02, 0xf5, - 0x63, 0xa8, 0x0e, 0x1d, 0x7a, 0x02, 0xcf, 0xf1, 0xad, 0x38, 0x08, 0xc5, 0xe6, 0x8b, 0x4c, 0x3a, - 0x5f, 0x87, 0xc4, 0x1a, 0x9a, 0x81, 0xef, 0x4e, 0x99, 0x7b, 0x14, 0x43, 0xa1, 0x8c, 0xae, 0xef, - 0xae, 0x98, 0xd1, 0x0a, 0xef, 0xa0, 0xc1, 0x36, 0xa1, 0x44, 0xae, 0x2d, 0x6f, 0xe2, 0x12, 0xf6, - 0x3a, 0x2b, 0xfb, 0xdb, 0x4b, 0x2f, 0xa0, 0xe5, 0x4f, 0x8d, 0x54, 0x49, 0xa4, 0xf5, 0x77, 0x25, - 0x80, 0xf9, 0xc5, 0xa9, 0x7f, 0x43, 0x32, 0x12, 0xf1, 0xa5, 0xcb, 0x79, 0xba, 0x17, 0xde, 0x90, - 0xee, 0xc5, 0xe5, 0x48, 0xa9, 0x50, 0x1a, 0x92, 0x91, 0x95, 0xb8, 0xb1, 0x5a, 0xe2, 0xc9, 0x22, - 0xc8, 0x45, 0x57, 0x29, 0x37, 0x5c, 0xf5, 0xff, 0x50, 0xf1, 0x12, 0x37, 0x76, 0x26, 0x2e, 0x31, - 0x83, 0x91, 0x0a, 0x3b, 0xd2, 0xae, 0x64, 0x40, 0xca, 0xea, 0x8e, 0x28, 0xae, 0x67, 0x5d, 0x3b, - 0x5e, 0xe2, 0xb1, 0x76, 0x2b, 0x19, 0x29, 0x89, 0x9f, 0xc0, 0x5d, 0x72, 0x6d, 0xbb, 0x49, 0xe4, - 0x5c, 0x12, 0x33, 0xd5, 0xd9, 0x62, 0xf8, 0x68, 0x26, 0x78, 0x21, 0x94, 0x29, 0x8c, 0xe3, 0x33, - 0x95, 0xaa, 0x80, 0xe1, 0xe4, 0x0d, 0x18, 0xa1, 0x53, 0xbb, 0x09, 0x23, 0x94, 0x1f, 0x02, 0x78, - 0xd6, 0xb5, 0xe9, 0x12, 0x7f, 0x1c, 0x5f, 0xa8, 0x77, 0x76, 0xa4, 0x5d, 0xd9, 0x28, 0x7b, 0xd6, - 0xf5, 0x09, 0x63, 0x30, 0xb1, 0xe3, 0xa7, 0x62, 0x24, 0xc4, 0x8e, 0x2f, 0xc4, 0x2a, 0x94, 0x26, - 0x56, 0x4c, 0x63, 0xa8, 0xde, 0xe5, 0x3e, 0x12, 0x24, 0xf5, 0x11, 0xc5, 0x75, 0x62, 0xe2, 0x45, - 0xea, 0x36, 0xb3, 0x53, 0x3c, 0xeb, 0x5a, 0xa3, 0x34, 0x13, 0x3a, 0xbe, 0x10, 0xde, 0x17, 0x42, - 0xc7, 0xe7, 0xc2, 0x8f, 0x60, 0x2b, 0xf1, 0x9d, 0x6f, 0x13, 0x22, 0xe4, 0xef, 0xb3, 0x93, 0x57, - 0x38, 0x8f, 0xab, 0xfc, 0x14, 0x6a, 0x14, 0x7c, 0x12, 0xd2, 0xe1, 0x2b, 0x76, 0x48, 0xa4, 0xaa, - 0x0c, 0xa4, 0xea, 0x59, 0xd7, 0xbd, 0x19, 0x93, 0xa9, 0x39, 0x7e, 0x56, 0xed, 0x03, 0xa1, 0xe6, - 0xf8, 0x19, 0xb5, 0x3a, 0x28, 0x21, 0x9f, 0x50, 0x86, 0x6a, 0x9d, 0x4f, 0x66, 0x29, 0x4d, 0x1f, - 0x8f, 0x15, 0x86, 0xd6, 0x54, 0x6d, 0x30, 0x01, 0x27, 0xf0, 0x2b, 0x90, 0xe3, 0xe9, 0x84, 0xa8, - 0x3f, 0x61, 0xdf, 0x9a, 0xda, 0x2d, 0x12, 0x34, 0xb3, 0xec, 0x3b, 0xf4, 0x35, 0x0f, 0xa6, 0x13, - 0x12, 0x19, 0x0c, 0xb6, 0x71, 0x05, 0xf7, 0x57, 0x8a, 0x17, 0x47, 0xf1, 0x32, 0x14, 0x5a, 0x86, - 0xd1, 0x7a, 0x89, 0x24, 0xca, 0x3f, 0xe8, 0x76, 0x4f, 0xda, 0xad, 0x0e, 0xca, 0x51, 0x42, 0xeb, - 0x0c, 0xda, 0xc7, 0x6d, 0x03, 0xe5, 0xe9, 0xbc, 0xde, 0x39, 0x3d, 0x39, 0x41, 0x32, 0x06, 0x28, - 0x76, 0x4e, 0x5f, 0x1c, 0xb4, 0x0d, 0x54, 0xa0, 0xeb, 0xee, 0x81, 0xde, 0x3e, 0x1c, 0xa0, 0x22, - 0x5d, 0xf7, 0x07, 0x86, 0xd6, 0x39, 0x46, 0x25, 0x5d, 0x56, 0x24, 0x94, 0xd3, 0x65, 0x25, 0x87, - 0xf2, 0x3c, 0xbb, 0x66, 0x33, 0x3c, 0x46, 0xf7, 0x74, 0x59, 0xb9, 0x87, 0xb6, 0x75, 0x59, 0xf9, - 0x3f, 0xa4, 0xea, 0xb2, 0xf2, 0x21, 0x7a, 0xa0, 0xcb, 0xca, 0x03, 0xf4, 0x50, 0x97, 0x95, 0x87, - 0xe8, 0x91, 0x2e, 0x2b, 0x8f, 0x50, 0x43, 0x97, 0x95, 0x8f, 0xd1, 0x63, 0x5d, 0x56, 0x1e, 0xa3, - 0x27, 0xba, 0xac, 0x3c, 0x41, 0xcd, 0xc6, 0x9f, 0x25, 0xc8, 0x0f, 0xac, 0xf1, 0x1a, 0xfd, 0x75, - 0xa9, 0xc8, 0xe4, 0x7f, 0xf8, 0x22, 0xc3, 0xaf, 0xd8, 0xf8, 0xb7, 0x04, 0xf7, 0x56, 0x7c, 0xfa, - 0xe2, 0x51, 0x66, 0xda, 0x95, 0x58, 0x13, 0xd4, 0xdf, 0xe6, 0x53, 0x7a, 0xc6, 0xe3, 0x1d, 0x71, - 0x86, 0x5d, 0x8f, 0xa1, 0xba, 0x20, 0x5a, 0xd1, 0x0d, 0x5f, 0x2c, 0x76, 0xc3, 0x5f, 0x6c, 0x7c, - 0x0e, 0xf1, 0x4f, 0x46, 0xa6, 0x5d, 0xfe, 0xa7, 0x08, 0xb5, 0x45, 0x29, 0xee, 0x89, 0x97, 0x4c, - 0x37, 0xae, 0xdd, 0x62, 0xb4, 0xe7, 0x30, 0x4d, 0xfa, 0x3c, 0xf9, 0xe3, 0x5d, 0x23, 0xce, 0x69, - 0x8f, 0xcd, 0x67, 0x7a, 0xac, 0x0e, 0x39, 0xc7, 0x67, 0xc3, 0x52, 0x6d, 0xff, 0x8b, 0xdb, 0x9e, - 0x42, 0xf3, 0x8d, 0x9c, 0xe3, 0xd3, 0x3b, 0x8d, 0xdc, 0xe0, 0x8a, 0xd5, 0xfb, 0xb7, 0xb8, 0xd3, - 0x97, 0x6e, 0x70, 0x65, 0x30, 0x24, 0x5a, 0x51, 0xad, 0x24, 0xbe, 0x08, 0x42, 0xe7, 0x8f, 0xfc, - 0xf3, 0x8f, 0xb6, 0x70, 0xde, 0x32, 0xd0, 0x82, 0xe0, 0x34, 0x74, 0x69, 0x71, 0x8b, 0x83, 0xd7, - 0x84, 0x2b, 0xf1, 0xce, 0xa1, 0x30, 0x06, 0x15, 0xb2, 0x99, 0x3c, 0x98, 0x90, 0x88, 0xf5, 0x8d, - 0xcd, 0x66, 0x72, 0x6a, 0x66, 0x08, 0x73, 0x3c, 0x5e, 0x18, 0xd8, 0xf8, 0x37, 0xe3, 0xf1, 0x6d, - 0xaf, 0xfa, 0x23, 0x8c, 0x6e, 0xcf, 0x41, 0xa6, 0x8f, 0x06, 0x23, 0xd8, 0x1a, 0xbc, 0xec, 0xb5, - 0x4d, 0xad, 0xf3, 0x55, 0xeb, 0x44, 0x3b, 0x42, 0xef, 0xe1, 0x1a, 0x00, 0xe3, 0x1c, 0xb4, 0xfa, - 0xda, 0x21, 0x92, 0x66, 0x1a, 0xad, 0x9e, 0x66, 0x3e, 0x6f, 0xbf, 0x44, 0x39, 0x7c, 0x07, 0x2a, - 0x8c, 0xd3, 0x6d, 0x9d, 0x0e, 0x9e, 0xed, 0xa3, 0x7c, 0xe3, 0x53, 0xc8, 0x69, 0x3e, 0x35, 0xd4, - 0x3a, 0x19, 0xa0, 0x2d, 0x50, 0xb4, 0x8e, 0xf9, 0xbb, 0xd3, 0xb6, 0x41, 0x6b, 0x64, 0x15, 0xca, - 0x5a, 0xc7, 0x7c, 0xd6, 0x6e, 0x1d, 0xb5, 0x0d, 0x94, 0x6b, 0x7c, 0x03, 0x32, 0x0d, 0x30, 0x45, - 0xff, 0xf2, 0xa4, 0x7b, 0x96, 0x31, 0xbb, 0x0b, 0x55, 0xce, 0x79, 0xd1, 0x3b, 0xd1, 0x0e, 0xb5, - 0x01, 0x92, 0x66, 0xac, 0x5e, 0xab, 0xdf, 0x3f, 0xeb, 0x1a, 0x47, 0x28, 0x87, 0xb7, 0x01, 0x31, - 0x56, 0xab, 0x47, 0xb5, 0x5a, 0x03, 0xad, 0xdb, 0x41, 0xf9, 0x39, 0xf7, 0xf0, 0xb0, 0xdd, 0xef, - 0x9b, 0x87, 0xdd, 0xa3, 0x36, 0x92, 0x1b, 0xff, 0xca, 0xcd, 0xab, 0x4d, 0xe6, 0x5b, 0x18, 0xff, - 0x49, 0xca, 0xfc, 0x8b, 0x17, 0xce, 0x05, 0xa2, 0xf4, 0x9c, 0xbe, 0xcd, 0x87, 0xf6, 0x2a, 0x1e, - 0x0f, 0xee, 0xec, 0xef, 0xbd, 0x8c, 0xa4, 0xfe, 0x09, 0xa8, 0x2b, 0x0c, 0x58, 0xd4, 0x68, 0x0f, - 0x64, 0x8f, 0x4e, 0xfc, 0x5d, 0xc3, 0x89, 0xfa, 0x77, 0xd2, 0x4a, 0x93, 0xef, 0x7b, 0x21, 0xaf, - 0x17, 0x5f, 0xc8, 0x0f, 0x7e, 0xb7, 0xa5, 0x07, 0xf6, 0x17, 0x89, 0x8e, 0xd5, 0x2c, 0x57, 0x7a, - 0xd9, 0x0b, 0x54, 0x36, 0xa9, 0x2f, 0xcc, 0x9e, 0xff, 0x70, 0xe7, 0x89, 0xcb, 0x7f, 0x0e, 0x30, - 0x67, 0xae, 0xb8, 0xed, 0x76, 0xf6, 0xb6, 0xe5, 0xcc, 0xb1, 0x0e, 0x0e, 0x7f, 0xdf, 0x1a, 0x3b, - 0xf1, 0x45, 0x72, 0xde, 0xb4, 0x03, 0x6f, 0x8f, 0x1e, 0xe4, 0x29, 0xb1, 0x83, 0x68, 0x1a, 0xc5, - 0x44, 0x90, 0xe2, 0x5c, 0x7b, 0xdf, 0xff, 0xd7, 0xff, 0x79, 0x91, 0xc9, 0x3e, 0xfb, 0x6f, 0x00, - 0x00, 0x00, 0xff, 0xff, 0x29, 0x5a, 0xd3, 0x93, 0x1f, 0x18, 0x00, 0x00, + // 1910 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x59, 0x5b, 0x73, 0x1a, 0xd7, + 0x1d, 0xcf, 0xc2, 0x02, 0xcb, 0x1f, 0x81, 0x8f, 0x8f, 0xe5, 0x74, 0x43, 0x6c, 0x57, 0xa1, 0xe9, + 0x54, 0x63, 0xd7, 0x28, 0x51, 0x1e, 0x9a, 0x49, 0xaf, 0x48, 0x22, 0xf2, 0xae, 0x65, 0xa0, 0x0b, + 0x8a, 0xe2, 0x76, 0x3c, 0xdb, 0xd5, 0x72, 0x40, 0x1b, 0xef, 0x85, 0xec, 0x45, 0x12, 0xfd, 0x04, + 0x7d, 0xee, 0xf4, 0x35, 0xdf, 0xa3, 0x0f, 0x7d, 0xea, 0x17, 0x68, 0x3f, 0x4b, 0x3b, 0x7d, 0xef, + 0x9c, 0xcb, 0xc2, 0x22, 0x61, 0x0f, 0xc8, 0x76, 0xfb, 0x90, 0x27, 0xce, 0xff, 0xf6, 0x3b, 0x97, + 0xff, 0xed, 0x9c, 0x05, 0x1e, 0x4e, 0xc2, 0x20, 0x0e, 0xec, 0xc7, 0x63, 0xe2, 0x3f, 0x8e, 0x2e, + 0xac, 0xf1, 0x98, 0x84, 0x3b, 0xc1, 0x24, 0x76, 0x02, 0x3f, 0xda, 0x09, 0x26, 0xc4, 0xb7, 0x26, + 0xce, 0xf9, 0x6e, 0x93, 0x29, 0xe1, 0x9f, 0x8c, 0xc3, 0x89, 0xdd, 0x1c, 0x5b, 0x31, 0xb9, 0xb0, + 0xa6, 0x9c, 0x67, 0x9b, 0x63, 0xe2, 0x9b, 0xc2, 0xb0, 0x29, 0x0c, 0xeb, 0x1f, 0x8c, 0x83, 0x60, + 0xec, 0x92, 0x1d, 0xa6, 0x72, 0x9a, 0x8c, 0x76, 0x2c, 0x5f, 0xe8, 0xd7, 0xef, 0x5d, 0x15, 0x45, + 0x71, 0x98, 0xd8, 0x31, 0x97, 0x36, 0xfe, 0xaa, 0x40, 0xa9, 0xcf, 0xc1, 0xb0, 0x0a, 0x25, 0x81, + 0xab, 0x4a, 0x5b, 0xd2, 0x76, 0xd9, 0x48, 0x49, 0xdc, 0x02, 0xd9, 0xf1, 0x47, 0x81, 0x9a, 0xdb, + 0x92, 0xb6, 0x2b, 0xbb, 0x8f, 0x9b, 0x2b, 0x2e, 0xab, 0xa9, 0xf9, 0xa3, 0xc0, 0x60, 0xa6, 0x18, + 0x83, 0x7c, 0x16, 0x44, 0xb1, 0x9a, 0x67, 0xc8, 0x6c, 0x8c, 0x3f, 0x84, 0xf2, 0xa9, 0x15, 0x11, + 0x73, 0x62, 0xc5, 0x67, 0xaa, 0xcc, 0x04, 0x0a, 0x65, 0xf4, 0xac, 0xf8, 0x0c, 0x7f, 0x0d, 0xa5, + 0xc8, 0x3e, 0x23, 0x1e, 0x89, 0xd4, 0xc2, 0x56, 0x7e, 0xbb, 0xb6, 0xfb, 0xab, 0x95, 0xa7, 0x15, + 0x1b, 0x4a, 0x7f, 0xfb, 0x0c, 0xc6, 0x48, 0xe1, 0x70, 0x1d, 0x14, 0x3b, 0xf0, 0xa3, 0x84, 0x42, + 0x17, 0xb7, 0xf2, 0x74, 0xd6, 0x94, 0xa6, 0xb2, 0x49, 0x18, 0x0c, 0x13, 0x9b, 0x44, 0x6a, 0x89, + 0xcb, 0x52, 0x1a, 0xbf, 0x80, 0x72, 0x48, 0xa2, 0x49, 0xe0, 0x47, 0x24, 0x52, 0x61, 0x2b, 0xbf, + 0x5d, 0xd9, 0xfd, 0xf5, 0xda, 0x6b, 0x32, 0x52, 0x84, 0xb6, 0x1f, 0x87, 0x53, 0x63, 0x8e, 0x88, + 0x03, 0xd8, 0x8c, 0x88, 0x9d, 0x84, 0x4e, 0x3c, 0x35, 0x87, 0x64, 0xe4, 0xf8, 0x0e, 0xb3, 0x54, + 0x2b, 0xec, 0xd0, 0x7f, 0xb1, 0xfa, 0x4c, 0x02, 0xe4, 0x60, 0x8e, 0x61, 0xdc, 0x89, 0xae, 0x33, + 0xf1, 0xd7, 0xa0, 0xa4, 0x6c, 0x75, 0x83, 0x6d, 0x67, 0xfd, 0x49, 0x0c, 0xf2, 0x6d, 0xe2, 0x84, + 0xc4, 0x23, 0x7e, 0x6c, 0xcc, 0xd0, 0xb0, 0x0d, 0x55, 0x72, 0x19, 0x93, 0xd0, 0xb7, 0x5c, 0x73, + 0x18, 0xd8, 0x91, 0x5a, 0x63, 0x7b, 0x58, 0xdd, 0x83, 0x6d, 0x61, 0x7d, 0x10, 0xd8, 0x09, 0xc5, + 0xb6, 0x28, 0xdb, 0xd8, 0x20, 0x73, 0x76, 0x84, 0xff, 0x00, 0x40, 0x69, 0x3f, 0x62, 0xa7, 0x74, + 0x8b, 0x6d, 0xe0, 0x37, 0x6b, 0xfb, 0xa3, 0x3d, 0x83, 0xe0, 0x0e, 0xc9, 0x60, 0xd6, 0x03, 0xa8, + 0x2d, 0xba, 0x0b, 0x23, 0xc8, 0xbf, 0x24, 0x53, 0x91, 0x1e, 0x74, 0x88, 0x0f, 0xa1, 0x70, 0x6e, + 0xb9, 0x09, 0x11, 0xb9, 0xf1, 0xe9, 0xca, 0x0b, 0x48, 0x91, 0x0d, 0x6e, 0xff, 0x45, 0xee, 0x73, + 0xa9, 0x7e, 0x0c, 0xb7, 0xae, 0xac, 0x67, 0xc9, 0x8c, 0x3f, 0x5d, 0x9c, 0xf1, 0xfd, 0x26, 0x4f, + 0xf0, 0x66, 0x9a, 0xe0, 0xcd, 0xaf, 0xa8, 0x34, 0x03, 0xdb, 0xd8, 0x83, 0xea, 0x42, 0x2a, 0xe0, + 0x0a, 0x94, 0x8e, 0x3b, 0x4f, 0x3b, 0xdd, 0x93, 0x0e, 0x7a, 0x0f, 0x2b, 0x20, 0x3f, 0x19, 0x0c, + 0x7a, 0x48, 0xc2, 0x65, 0x28, 0xd0, 0x51, 0x1f, 0xe5, 0x70, 0x11, 0x72, 0x27, 0x7d, 0x94, 0xc7, + 0x25, 0xc8, 0x9f, 0xf4, 0xfb, 0x48, 0xd6, 0x65, 0x45, 0x41, 0x65, 0x5d, 0x56, 0xca, 0x08, 0x74, + 0x59, 0xa9, 0xa2, 0x5a, 0xe3, 0xef, 0x45, 0x28, 0x77, 0x27, 0x24, 0x64, 0xbe, 0xa1, 0xf9, 0x1d, + 0x5b, 0xe3, 0x48, 0x95, 0x58, 0xd2, 0xb0, 0x31, 0x2b, 0x28, 0x89, 0xe7, 0x59, 0xe1, 0x94, 0xad, + 0x95, 0x16, 0x14, 0x4e, 0xe2, 0x2d, 0xa8, 0x0c, 0x49, 0x64, 0x87, 0x0e, 0x3b, 0x0c, 0x51, 0x14, + 0xb2, 0xac, 0xeb, 0x21, 0x24, 0xbf, 0x83, 0x10, 0xfa, 0x08, 0x36, 0x82, 0x74, 0x07, 0xa6, 0x33, + 0x54, 0x0b, 0x7c, 0x1d, 0x33, 0x9e, 0x36, 0xbc, 0x71, 0xb1, 0x30, 0xb3, 0xc5, 0xa2, 0xcc, 0x82, + 0xb3, 0xb5, 0xf2, 0xda, 0x67, 0xc7, 0xfa, 0x9a, 0x72, 0xa1, 0xce, 0xeb, 0x23, 0xb0, 0xb9, 0x67, + 0xf5, 0xed, 0x01, 0xc0, 0x90, 0x4c, 0x42, 0x62, 0x5b, 0x31, 0x19, 0xb2, 0xf2, 0xa1, 0x18, 0x19, + 0xce, 0x3b, 0xcc, 0xfb, 0xd3, 0x85, 0x94, 0xac, 0x32, 0xec, 0xbd, 0x1b, 0xec, 0xfa, 0x7b, 0x90, + 0x94, 0x3c, 0xa1, 0x1a, 0xff, 0xc8, 0x83, 0x92, 0x4e, 0x7a, 0x35, 0x2b, 0xa4, 0xeb, 0x59, 0x71, + 0x08, 0x45, 0xe6, 0x65, 0x4b, 0xcc, 0xb3, 0xb3, 0xba, 0xe3, 0x98, 0x99, 0x21, 0xcc, 0xf1, 0xef, + 0x41, 0x21, 0x97, 0x96, 0x37, 0x71, 0x09, 0xcd, 0xac, 0xf5, 0x5a, 0x59, 0xba, 0xde, 0x66, 0x5b, + 0x20, 0x70, 0x27, 0xcd, 0x00, 0xb1, 0xb5, 0x10, 0x06, 0x85, 0x35, 0x83, 0x3f, 0x03, 0xff, 0xea, + 0x28, 0xf8, 0x39, 0x54, 0x17, 0x66, 0x5f, 0xe2, 0x92, 0xcd, 0xac, 0x4b, 0xca, 0xff, 0x13, 0x8f, + 0xe6, 0x91, 0xdc, 0xf8, 0x67, 0x1e, 0x64, 0x7a, 0xef, 0xa1, 0xf3, 0xc7, 0x4e, 0xec, 0x12, 0x01, + 0xca, 0x89, 0xab, 0x3e, 0xce, 0x5d, 0xf7, 0xf1, 0x36, 0xa0, 0x98, 0x84, 0x5e, 0x64, 0x06, 0x23, + 0x33, 0x22, 0xe1, 0xb9, 0x63, 0x13, 0x51, 0x20, 0x6b, 0x8c, 0xdf, 0x1d, 0xf5, 0x39, 0x17, 0xeb, + 0x50, 0xb2, 0x03, 0x3f, 0xb6, 0xec, 0x58, 0x54, 0xc7, 0x4f, 0x56, 0x3e, 0xe4, 0x7d, 0x6e, 0x67, + 0xa4, 0x00, 0x14, 0xcb, 0x75, 0x6c, 0xe2, 0x47, 0x84, 0x55, 0xc1, 0x75, 0xb0, 0x8e, 0xb8, 0x9d, + 0x91, 0x02, 0xd0, 0xd2, 0x74, 0x4e, 0x42, 0x7a, 0xba, 0x6a, 0x91, 0xd7, 0x7d, 0x41, 0xe2, 0x17, + 0x0b, 0x91, 0x51, 0x62, 0x91, 0xf1, 0xcb, 0xb5, 0xae, 0x93, 0xaf, 0x8d, 0x8a, 0x77, 0xd4, 0x3f, + 0xdb, 0x50, 0x12, 0xe7, 0x45, 0xdb, 0x9c, 0x6f, 0x79, 0xa9, 0x4f, 0xd9, 0x98, 0x4e, 0x91, 0x84, + 0xae, 0x70, 0x25, 0x1d, 0x52, 0xd7, 0x13, 0xcf, 0x72, 0x5c, 0xe1, 0x37, 0x4e, 0x34, 0x76, 0xa0, + 0x24, 0x8e, 0x6a, 0x35, 0x98, 0xc6, 0x53, 0xb8, 0xbb, 0xb4, 0x8b, 0xad, 0x50, 0x28, 0xae, 0x83, + 0xfd, 0x2d, 0x07, 0x45, 0x5e, 0x04, 0xf0, 0x00, 0x2a, 0xdf, 0x44, 0x81, 0x6f, 0x8a, 0x52, 0x22, + 0xb1, 0x73, 0xf8, 0x6c, 0x65, 0x37, 0xe8, 0xfd, 0x6e, 0x47, 0x94, 0x13, 0xa0, 0x38, 0x02, 0xf5, + 0x63, 0xa8, 0x0e, 0x1d, 0xba, 0x02, 0xcf, 0xf1, 0xad, 0x38, 0x08, 0xc5, 0xe4, 0x8b, 0x4c, 0x7a, + 0xe7, 0x0f, 0x89, 0x35, 0x34, 0x03, 0xdf, 0x9d, 0xb2, 0xe3, 0x51, 0x0c, 0x85, 0x32, 0xba, 0xbe, + 0xbb, 0xe4, 0xde, 0x58, 0x78, 0x07, 0x4d, 0xbf, 0x09, 0x25, 0x51, 0xa9, 0x58, 0x74, 0x56, 0x76, + 0x37, 0xaf, 0x45, 0x40, 0xcb, 0x9f, 0x1a, 0xa9, 0x92, 0x2e, 0x2b, 0x32, 0x2a, 0x34, 0xbe, 0x2b, + 0x01, 0xcc, 0x37, 0x4e, 0xcf, 0x37, 0x24, 0x23, 0xe1, 0x5f, 0x3a, 0x9c, 0xa7, 0x7b, 0xe1, 0x35, + 0xe9, 0x5e, 0xbc, 0xee, 0x29, 0x15, 0x4a, 0x43, 0x32, 0xb2, 0x12, 0x37, 0x56, 0x4b, 0x3c, 0x59, + 0x04, 0xb9, 0x78, 0x54, 0xca, 0x95, 0xa3, 0xfa, 0x21, 0x54, 0xbc, 0xc4, 0x8d, 0x9d, 0x89, 0x4b, + 0xcc, 0x60, 0xa4, 0xc2, 0x96, 0xb4, 0x2d, 0x19, 0x90, 0xb2, 0xba, 0x23, 0x8a, 0xeb, 0x59, 0x97, + 0x8e, 0x97, 0x78, 0xec, 0x0a, 0x20, 0x19, 0x29, 0x89, 0x1f, 0xc1, 0x6d, 0x72, 0x69, 0xbb, 0x49, + 0xe4, 0x9c, 0x13, 0x33, 0xd5, 0xd9, 0x60, 0xf8, 0x68, 0x26, 0x78, 0x26, 0x94, 0x29, 0x8c, 0xe3, + 0x33, 0x95, 0xaa, 0x80, 0xe1, 0xe4, 0x15, 0x18, 0xa1, 0x53, 0xbb, 0x0a, 0x23, 0x94, 0xef, 0x03, + 0x78, 0xd6, 0xa5, 0xe9, 0x12, 0x7f, 0x1c, 0x9f, 0xa9, 0xb7, 0xb6, 0xa4, 0x6d, 0xd9, 0x28, 0x7b, + 0xd6, 0xe5, 0x11, 0x63, 0x30, 0xb1, 0xe3, 0xa7, 0x62, 0x24, 0xc4, 0x8e, 0x2f, 0xc4, 0x2a, 0x94, + 0x26, 0x56, 0x4c, 0x7d, 0xa8, 0xde, 0xe6, 0x67, 0x24, 0x48, 0x7a, 0x46, 0x14, 0xd7, 0x89, 0x89, + 0x17, 0xa9, 0x9b, 0xcc, 0x4e, 0xf1, 0xac, 0x4b, 0x8d, 0xd2, 0x4c, 0xe8, 0xf8, 0x42, 0x78, 0x57, + 0x08, 0x1d, 0x9f, 0x0b, 0x3f, 0x82, 0x8d, 0xc4, 0x77, 0xbe, 0x4d, 0x88, 0x90, 0xbf, 0xcf, 0x56, + 0x5e, 0xe1, 0x3c, 0xae, 0xf2, 0x63, 0xa8, 0x51, 0xf0, 0x49, 0x48, 0x2f, 0x84, 0xb1, 0x43, 0x22, + 0x55, 0x65, 0x20, 0x55, 0xcf, 0xba, 0xec, 0xcd, 0x98, 0x4c, 0xcd, 0xf1, 0xb3, 0x6a, 0x1f, 0x08, + 0x35, 0xc7, 0xcf, 0xa8, 0xd5, 0x41, 0x09, 0xf9, 0xad, 0x69, 0xa8, 0xd6, 0xf9, 0x6d, 0x31, 0xa5, + 0x69, 0xf0, 0x58, 0x61, 0x68, 0x4d, 0xd5, 0x06, 0x13, 0x70, 0x02, 0xbf, 0x00, 0x39, 0x9e, 0x4e, + 0x88, 0xfa, 0x23, 0xf6, 0xfe, 0xd5, 0x6e, 0x90, 0xa0, 0x99, 0x61, 0xdf, 0xa1, 0xd1, 0x3c, 0x98, + 0x4e, 0x48, 0x64, 0x30, 0xd8, 0xc6, 0x05, 0xdc, 0x5d, 0x2a, 0x5e, 0x7c, 0x1e, 0x94, 0xa1, 0xd0, + 0x32, 0x8c, 0xd6, 0x73, 0x24, 0x51, 0xfe, 0x5e, 0xb7, 0x7b, 0xd4, 0x6e, 0x75, 0x50, 0x8e, 0x12, + 0x5a, 0x67, 0xd0, 0x3e, 0x6c, 0x1b, 0x28, 0x4f, 0xdf, 0x10, 0x9d, 0xe3, 0xa3, 0x23, 0x24, 0x63, + 0x80, 0x62, 0xe7, 0xf8, 0xd9, 0x5e, 0xdb, 0x40, 0x05, 0x3a, 0xee, 0xee, 0xe9, 0xed, 0xfd, 0x01, + 0x2a, 0xd2, 0x71, 0x7f, 0x60, 0x68, 0x9d, 0x43, 0x54, 0xd2, 0x65, 0x45, 0x42, 0x39, 0x5d, 0x56, + 0x72, 0x28, 0xcf, 0xb3, 0x6b, 0xf6, 0xae, 0xc0, 0xe8, 0x8e, 0x2e, 0x2b, 0x77, 0xd0, 0xa6, 0x2e, + 0x2b, 0x3f, 0x40, 0xaa, 0x2e, 0x2b, 0x1f, 0xa2, 0x7b, 0xba, 0xac, 0xdc, 0x43, 0xf7, 0x75, 0x59, + 0xb9, 0x8f, 0x1e, 0xe8, 0xb2, 0xf2, 0x00, 0x35, 0x74, 0x59, 0xf9, 0x18, 0x3d, 0xd4, 0x65, 0xe5, + 0x21, 0x7a, 0xa4, 0xcb, 0xca, 0x23, 0xd4, 0x6c, 0xfc, 0x59, 0x82, 0xfc, 0xc0, 0x1a, 0xaf, 0xd0, + 0x5f, 0xaf, 0x15, 0x99, 0xfc, 0xdb, 0x2f, 0x32, 0x7c, 0x8b, 0x8d, 0x7f, 0x4b, 0x70, 0x67, 0xc9, + 0x73, 0x1c, 0x8f, 0x32, 0x37, 0x70, 0x89, 0x35, 0x41, 0xfd, 0x4d, 0x9e, 0xf7, 0x33, 0x9e, 0xb8, + 0x88, 0xa5, 0xd8, 0xf5, 0x18, 0xaa, 0x0b, 0xa2, 0x25, 0xdd, 0xf0, 0xd9, 0x62, 0x37, 0xfc, 0xd9, + 0xda, 0xeb, 0x10, 0x5f, 0x57, 0x32, 0xed, 0xf2, 0x3f, 0x45, 0xa8, 0x2d, 0x4a, 0x71, 0x4f, 0x44, + 0x32, 0x9d, 0xb8, 0x76, 0x83, 0xe7, 0x06, 0x87, 0x69, 0xd2, 0xf0, 0xe4, 0xc1, 0xbb, 0x82, 0x9f, + 0xd3, 0x1e, 0x9b, 0xcf, 0xf4, 0x58, 0x1d, 0x72, 0x8e, 0xcf, 0x2e, 0x4b, 0xb5, 0xdd, 0x2f, 0x6e, + 0xba, 0x0a, 0xcd, 0x37, 0x72, 0x8e, 0x4f, 0xf7, 0x34, 0x72, 0x83, 0x0b, 0x56, 0xef, 0xdf, 0x60, + 0x4f, 0x5f, 0xba, 0xc1, 0x85, 0xc1, 0x90, 0x68, 0x45, 0xb5, 0x92, 0xf8, 0x2c, 0x08, 0x9d, 0x3f, + 0xf2, 0x27, 0x29, 0x6d, 0xe1, 0xbc, 0x65, 0xa0, 0x05, 0xc1, 0x71, 0xe8, 0xd2, 0xe2, 0x16, 0x07, + 0x2f, 0x09, 0x57, 0xe2, 0x9d, 0x43, 0x61, 0x0c, 0x2a, 0x64, 0xef, 0x84, 0x60, 0x42, 0x22, 0xd6, + 0x37, 0xd6, 0x7b, 0x27, 0x50, 0x33, 0x43, 0x98, 0xe3, 0xf1, 0xc2, 0x85, 0x8d, 0xbf, 0x63, 0x0f, + 0x6f, 0xba, 0xd5, 0xff, 0xc3, 0xd5, 0xed, 0x29, 0xc8, 0x34, 0x68, 0x30, 0x82, 0x8d, 0xc1, 0xf3, + 0x5e, 0xdb, 0xd4, 0x3a, 0x5f, 0xb5, 0x8e, 0xb4, 0x03, 0xf4, 0x1e, 0xae, 0x01, 0x30, 0xce, 0x5e, + 0xab, 0xaf, 0xed, 0x23, 0x69, 0xa6, 0xd1, 0xea, 0x69, 0xe6, 0xd3, 0xf6, 0x73, 0x94, 0xc3, 0xb7, + 0xa0, 0xc2, 0x38, 0xdd, 0xd6, 0xf1, 0xe0, 0xc9, 0x2e, 0xca, 0x37, 0x3e, 0x85, 0x9c, 0xe6, 0x53, + 0x43, 0xad, 0x93, 0x01, 0xda, 0x00, 0x45, 0xeb, 0x98, 0xbf, 0x3d, 0x6e, 0x1b, 0xb4, 0x46, 0x56, + 0xa1, 0xac, 0x75, 0xcc, 0x27, 0xed, 0xd6, 0x41, 0xdb, 0x40, 0xb9, 0xc6, 0x37, 0x20, 0x53, 0x07, + 0x53, 0xf4, 0x2f, 0x8f, 0xba, 0x27, 0x19, 0xb3, 0xdb, 0x50, 0xe5, 0x9c, 0x67, 0xbd, 0x23, 0x6d, + 0x5f, 0x1b, 0x20, 0x69, 0xc6, 0xea, 0xb5, 0xfa, 0xfd, 0x93, 0xae, 0x71, 0x80, 0x72, 0x78, 0x13, + 0x10, 0x63, 0xb5, 0x7a, 0x54, 0xab, 0x35, 0xd0, 0xba, 0x1d, 0x94, 0x9f, 0x73, 0xf7, 0xf7, 0xdb, + 0xfd, 0xbe, 0xb9, 0xdf, 0x3d, 0x68, 0x23, 0xb9, 0xf1, 0xaf, 0xdc, 0xbc, 0xda, 0x64, 0xde, 0xe7, + 0xf8, 0x4f, 0x52, 0xe6, 0xcb, 0x62, 0x38, 0x17, 0x88, 0xd2, 0x73, 0xfc, 0x26, 0x8f, 0xff, 0x65, + 0x3c, 0xee, 0xdc, 0xd9, 0x27, 0xc7, 0x8c, 0xa4, 0xfe, 0x09, 0xa8, 0x4b, 0x0c, 0x98, 0xd7, 0x68, + 0x0f, 0x64, 0x41, 0x27, 0x3e, 0x21, 0x71, 0xa2, 0xfe, 0x9d, 0xb4, 0xd4, 0xe4, 0x55, 0x11, 0xf2, + 0x72, 0x31, 0x42, 0xde, 0xfa, 0xde, 0xae, 0x05, 0xd8, 0x5f, 0x24, 0x7a, 0xad, 0x66, 0xb9, 0xd2, + 0xcb, 0x6e, 0xa0, 0xb2, 0x4e, 0x7d, 0x61, 0xf6, 0xfc, 0x87, 0x1f, 0x9e, 0xd8, 0xfc, 0xe7, 0x00, + 0x73, 0xe6, 0x3a, 0x4f, 0xdc, 0xbd, 0xfd, 0xdf, 0xb5, 0xc6, 0x4e, 0x7c, 0x96, 0x9c, 0x36, 0xed, + 0xc0, 0xdb, 0xa1, 0x0b, 0x79, 0x4c, 0xec, 0x20, 0x9a, 0x46, 0x31, 0x11, 0xa4, 0x58, 0xd7, 0xce, + 0xab, 0xff, 0x8e, 0x38, 0x2d, 0x32, 0xd9, 0x67, 0xff, 0x0d, 0x00, 0x00, 0xff, 0xff, 0xe3, 0xbc, + 0xdd, 0xdd, 0xb3, 0x18, 0x00, 0x00, } diff --git a/gateway/protoc-gen-swagger/options/openapiv2.proto b/gateway/protoc-gen-swagger/options/openapiv2.proto index 8b49024..419aeef 100644 --- a/gateway/protoc-gen-swagger/options/openapiv2.proto +++ b/gateway/protoc-gen-swagger/options/openapiv2.proto @@ -11,16 +11,27 @@ import "google/protobuf/struct.proto"; // // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#swaggerObject // -// TODO(ivucica): document fields message Swagger { + // Specifies the Swagger Specification version being used. It can be + // used by the Swagger UI and other clients to interpret the API listing. The + // value MUST be "2.0". string swagger = 1; + // Provides metadata about the API. The metadata can be used by the + // clients if needed. Info info = 2; + // The host (name or ip) serving the API. This MUST be the host only and does + // not include the scheme nor sub-paths. It MAY include a port. If the host is + // not included, the host serving the documentation is to be used (including + // the port). The host does not support path templating. string host = 3; - // `base_path` is the common prefix path used on all API endpoints (ie. /api, /v1, etc.). By adding this, - // it allows you to remove this portion from the path endpoints in your Swagger file making them easier - // to read. Note that using `base_path` does not change the endpoint paths that are generated in the resulting - // Swagger file. If you wish to use `base_path` with relatively generated Swagger paths, the - // `base_path` prefix must be manually removed from your `google.api.http` paths and your code changed to + // The base path on which the API is served, which is relative to the host. If + // it is not included, the API is served directly under the host. The value + // MUST start with a leading slash (/). The basePath does not support path + // templating. + // Note that using `base_path` does not change the endpoint paths that are + // generated in the resulting Swagger file. If you wish to use `base_path` + // with relatively generated Swagger paths, the `base_path` prefix must be + // manually removed from your `google.api.http` paths and your code changed to // serve the API from the `base_path`. string base_path = 4; enum SwaggerScheme { @@ -30,21 +41,38 @@ message Swagger { WS = 3; WSS = 4; } + // The transfer protocol of the API. Values MUST be from the list: "http", + // "https", "ws", "wss". If the schemes is not included, the default scheme to + // be used is the one used to access the Swagger definition itself. repeated SwaggerScheme schemes = 5; + // A list of MIME types the APIs can consume. This is global to all APIs but + // can be overridden on specific API calls. Value MUST be as described under + // Mime Types. repeated string consumes = 6; + // A list of MIME types the APIs can produce. This is global to all APIs but + // can be overridden on specific API calls. Value MUST be as described under + // Mime Types. repeated string produces = 7; // field 8 is reserved for 'paths'. reserved 8; // field 9 is reserved for 'definitions', which at this time are already // exposed as and customizable as proto messages. reserved 9; + // An object to hold responses that can be used across operations. This + // property does not define global responses for all operations. map responses = 10; + // Security scheme definitions that can be used across the specification. SecurityDefinitions security_definitions = 11; + // A declaration of which security schemes are applied for the API as a whole. + // The list of values describes alternative security schemes that can be used + // (that is, there is a logical OR between the security requirements). + // Individual operations can override this definition. repeated SecurityRequirement security = 12; // field 13 is reserved for 'tags', which are supposed to be exposed as and // customizable as proto services. TODO(ivucica): add processing of proto // service objects into OpenAPI v2 Tag objects. reserved 13; + // Additional external documentation. ExternalDocumentation external_docs = 14; map extensions = 15; } @@ -53,20 +81,48 @@ message Swagger { // // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#operationObject // -// TODO(ivucica): document fields message Operation { + // A list of tags for API documentation control. Tags can be used for logical + // grouping of operations by resources or any other qualifier. repeated string tags = 1; + // A short summary of what the operation does. For maximum readability in the + // swagger-ui, this field SHOULD be less than 120 characters. string summary = 2; + // A verbose explanation of the operation behavior. GFM syntax can be used for + // rich text representation. string description = 3; + // Additional external documentation for this operation. ExternalDocumentation external_docs = 4; + // Unique string used to identify the operation. The id MUST be unique among + // all operations described in the API. Tools and libraries MAY use the + // operationId to uniquely identify an operation, therefore, it is recommended + // to follow common programming naming conventions. string operation_id = 5; + // A list of MIME types the operation can consume. This overrides the consumes + // definition at the Swagger Object. An empty value MAY be used to clear the + // global definition. Value MUST be as described under Mime Types. repeated string consumes = 6; + // A list of MIME types the operation can produce. This overrides the produces + // definition at the Swagger Object. An empty value MAY be used to clear the + // global definition. Value MUST be as described under Mime Types. repeated string produces = 7; // field 8 is reserved for 'parameters'. reserved 8; + // The list of possible responses as they are returned from executing this + // operation. map responses = 9; + // The transfer protocol for the operation. Values MUST be from the list: + // "http", "https", "ws", "wss". The value overrides the Swagger Object + // schemes definition. repeated string schemes = 10; + // Declares this operation to be deprecated. Usage of the declared operation + // should be refrained. Default value is false. bool deprecated = 11; + // A declaration of which security schemes are applied for this operation. The + // list of values describes alternative security schemes that can be used + // (that is, there is a logical OR between the security requirements). This + // definition overrides any declared top-level security. To remove a top-level + // security declaration, an empty array can be used. repeated SecurityRequirement security = 12; map extensions = 13; } @@ -84,8 +140,9 @@ message Response { Schema schema = 2; // field 3 is reserved for 'headers'. reserved 3; - // field 3 is reserved for 'example'. - reserved 4; + // `Examples` gives per-mimetype response examples. + // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#example-object + map examples = 4; map extensions = 5; } @@ -93,13 +150,20 @@ message Response { // // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#infoObject // -// TODO(ivucica): document fields message Info { + // The title of the application. string title = 1; + // A short description of the application. GFM syntax can be used for rich + // text representation. string description = 2; + // The Terms of Service for the API. string terms_of_service = 3; + // The contact information for the exposed API. Contact contact = 4; + // The license information for the exposed API. License license = 5; + // Provides the version of the application API (not to be confused + // with the specification version). string version = 6; map extensions = 7; } @@ -108,10 +172,14 @@ message Info { // // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#contactObject // -// TODO(ivucica): document fields message Contact { + // The identifying name of the contact person/organization. string name = 1; + // The URL pointing to the contact information. MUST be in the format of a + // URL. string url = 2; + // The email address of the contact person/organization. MUST be in the format + // of an email address. string email = 3; } @@ -120,9 +188,9 @@ message Contact { // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#licenseObject // message License { - // Required. The license name used for the API. + // The license name used for the API. string name = 1; - // A URL to the license used for the API. + // A URL to the license used for the API. MUST be in the format of a URL. string url = 2; } @@ -131,9 +199,12 @@ message License { // // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#externalDocumentationObject // -// TODO(ivucica): document fields message ExternalDocumentation { + // A short description of the target documentation. GFM syntax can be used for + // rich text representation. string description = 1; + // The URL for the target documentation. Value MUST be in the format + // of a URL. string url = 2; } @@ -141,14 +212,25 @@ message ExternalDocumentation { // // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#schemaObject // -// TODO(ivucica): document fields message Schema { JSONSchema json_schema = 1; + // Adds support for polymorphism. The discriminator is the schema property + // name that is used to differentiate between other schema that inherit this + // schema. The property name used MUST be defined at this schema and it MUST + // be in the required property list. When used, the value MUST be the name of + // this schema or any schema that inherits it. string discriminator = 2; + // Relevant only for Schema "properties" definitions. Declares the property as + // "read only". This means that it MAY be sent as part of a response but MUST + // NOT be sent as part of the request. Properties marked as readOnly being + // true SHOULD NOT be in the required list of the defined schema. Default + // value is false. bool read_only = 3; // field 4 is reserved for 'xml'. reserved 4; + // Additional external documentation for this schema. ExternalDocumentation external_docs = 5; + // A free-form property to include an example of an instance for this schema. google.protobuf.Any example = 6; } @@ -169,23 +251,30 @@ message JSONSchema { // field 2 is reserved for '$schema', omitted from OpenAPI v2. reserved 2; // Ref is used to define an external reference to include in the message. - // This could be a fully qualified proto message reference, and that type must be imported - // into the protofile. If no message is identified, the Ref will be used verbatim in - // the output. + // This could be a fully qualified proto message reference, and that type must + // be imported into the protofile. If no message is identified, the Ref will + // be used verbatim in the output. // For example: // `ref: ".google.protobuf.Timestamp"`. string ref = 3; // field 4 is reserved for '$comment', omitted from OpenAPI v2. reserved 4; + // The title of the schema. string title = 5; + // A short description of the schema. string description = 6; string default = 7; bool read_only = 8; - // field 9 is reserved for 'examples', which is omitted from OpenAPI v2 in favor of 'example' field. + // field 9 is reserved for 'examples', which is omitted from OpenAPI v2 in + // favor of 'example' field. reserved 9; double multiple_of = 10; + // Maximum represents an inclusive upper limit for a numeric instance. The + // value of MUST be a number, double maximum = 11; bool exclusive_maximum = 12; + // minimum represents an inclusive lower limit for a numeric instance. The + // value of MUST be a number, double minimum = 13; bool exclusive_minimum = 14; uint64 max_length = 15; @@ -193,7 +282,8 @@ message JSONSchema { string pattern = 17; // field 18 is reserved for 'additionalItems', omitted from OpenAPI v2. reserved 18; - // field 19 is reserved for 'items', but in OpenAPI-specific way. TODO(ivucica): add 'items'? + // field 19 is reserved for 'items', but in OpenAPI-specific way. + // TODO(ivucica): add 'items'? reserved 19; uint64 max_items = 20; uint64 min_items = 21; @@ -203,13 +293,16 @@ message JSONSchema { uint64 max_properties = 24; uint64 min_properties = 25; repeated string required = 26; - // field 27 is reserved for 'additionalProperties', but in OpenAPI-specific way. TODO(ivucica): add 'additionalProperties'? + // field 27 is reserved for 'additionalProperties', but in OpenAPI-specific + // way. TODO(ivucica): add 'additionalProperties'? reserved 27; // field 28 is reserved for 'definitions', omitted from OpenAPI v2. reserved 28; - // field 29 is reserved for 'properties', but in OpenAPI-specific way. TODO(ivucica): add 'additionalProperties'? + // field 29 is reserved for 'properties', but in OpenAPI-specific way. + // TODO(ivucica): add 'additionalProperties'? reserved 29; - // following fields are reserved, as the properties have been omitted from OpenAPI v2: + // following fields are reserved, as the properties have been omitted from + // OpenAPI v2: // patternProperties, dependencies, propertyNames, const reserved 30 to 33; // Items in 'array' must be unique. @@ -227,12 +320,14 @@ message JSONSchema { } repeated JSONSchemaSimpleTypes type = 35; - // following fields are reserved, as the properties have been omitted from OpenAPI v2: - // format, contentMediaType, contentEncoding, if, then, else + // following fields are reserved, as the properties have been omitted from + // OpenAPI v2: format, contentMediaType, contentEncoding, if, then, else reserved 36 to 41; - // field 42 is reserved for 'allOf', but in OpenAPI-specific way. TODO(ivucica): add 'allOf'? + // field 42 is reserved for 'allOf', but in OpenAPI-specific way. + // TODO(ivucica): add 'allOf'? reserved 42; - // following fields are reserved, as the properties have been omitted from OpenAPI v2: + // following fields are reserved, as the properties have been omitted from + // OpenAPI v2: // anyOf, oneOf, not reserved 43 to 45; } @@ -241,7 +336,6 @@ message JSONSchema { // // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#tagObject // -// TODO(ivucica): document fields message Tag { // field 1 is reserved for 'name'. In our generator, this is (to be) extracted // from the name of proto service, and thus not exposed to the user, as @@ -252,9 +346,10 @@ message Tag { // global Tag object, then use that name to reference the tag throughout the // Swagger file. reserved 1; - // TODO(ivucica): Description should be extracted from comments on the proto - // service object. + // A short description for the tag. GFM syntax can be used for rich text + // representation. string description = 2; + // Additional external documentation for this tag. ExternalDocumentation external_docs = 3; } @@ -267,7 +362,8 @@ message Tag { // specification. This does not enforce the security schemes on the operations // and only serves to provide the relevant details for each scheme. message SecurityDefinitions { - // A single security scheme definition, mapping a "name" to the scheme it defines. + // A single security scheme definition, mapping a "name" to the scheme it + // defines. map security = 1; } @@ -281,7 +377,7 @@ message SecurityDefinitions { // a header or as a query parameter) and OAuth2's common flows (implicit, // password, application and access code). message SecurityScheme { - // Required. The type of the security scheme. Valid values are "basic", + // The type of the security scheme. Valid values are "basic", // "apiKey" or "oauth2". enum Type { TYPE_INVALID = 0; @@ -290,14 +386,14 @@ message SecurityScheme { TYPE_OAUTH2 = 3; } - // Required. The location of the API key. Valid values are "query" or "header". + // The location of the API key. Valid values are "query" or "header". enum In { IN_INVALID = 0; IN_QUERY = 1; IN_HEADER = 2; } - // Required. The flow used by the OAuth2 security scheme. Valid values are + // The flow used by the OAuth2 security scheme. Valid values are // "implicit", "password", "application" or "accessCode". enum Flow { FLOW_INVALID = 0; @@ -307,36 +403,31 @@ message SecurityScheme { FLOW_ACCESS_CODE = 4; } - // Required. The type of the security scheme. Valid values are "basic", + // The type of the security scheme. Valid values are "basic", // "apiKey" or "oauth2". Type type = 1; // A short description for security scheme. string description = 2; - // Required. The name of the header or query parameter to be used. - // + // The name of the header or query parameter to be used. // Valid for apiKey. string name = 3; - // Required. The location of the API key. Valid values are "query" or "header". - // + // The location of the API key. Valid values are "query" or + // "header". // Valid for apiKey. In in = 4; - // Required. The flow used by the OAuth2 security scheme. Valid values are + // The flow used by the OAuth2 security scheme. Valid values are // "implicit", "password", "application" or "accessCode". - // // Valid for oauth2. Flow flow = 5; - // Required. The authorization URL to be used for this flow. This SHOULD be in + // The authorization URL to be used for this flow. This SHOULD be in // the form of a URL. - // // Valid for oauth2/implicit and oauth2/accessCode. string authorization_url = 6; - // Required. The token URL to be used for this flow. This SHOULD be in the + // The token URL to be used for this flow. This SHOULD be in the // form of a URL. - // // Valid for oauth2/password, oauth2/application and oauth2/accessCode. string token_url = 7; - // Required. The available scopes for the OAuth2 security scheme. - // + // The available scopes for the OAuth2 security scheme. // Valid for oauth2. Scopes scopes = 8; map extensions = 9; diff --git a/gateway/runtime/mux.go b/gateway/runtime/mux.go index 6bda659..9a0171f 100644 --- a/gateway/runtime/mux.go +++ b/gateway/runtime/mux.go @@ -57,6 +57,15 @@ func WithForwardResponseOption(forwardResponseOption func(context.Context, http. } } +// SetQueryParameterParser sets the query parameter parser, used to populate message from query parameters. +// Configuring this will mean the generated swagger output is no longer correct, and it should be +// done with careful consideration. +func SetQueryParameterParser(queryParameterParser QueryParameterParser) ServeMuxOption { + return func(serveMux *ServeMux) { + currentQueryParser = queryParameterParser + } +} + // HeaderMatcherFunc checks whether a header key should be forwarded to/from gRPC context. type HeaderMatcherFunc func(string) (string, bool) @@ -104,11 +113,11 @@ func WithMetadata(annotator func(context.Context, *http.Request) metadata.MD) Se } } -// WithProtoErrorHandler returns a ServeMuxOption for passing metadata to a gRPC context. +// WithProtoErrorHandler returns a ServeMuxOption for configuring a custom error handler. // // This can be used to handle an error as general proto message defined by gRPC. -// The response including body and status is not backward compatible with the default error handler. -// When this option is used, HTTPError and OtherErrorHandler are overwritten on initialization. +// When this option is used, the mux uses the configured error handler instead of HTTPError and +// OtherErrorHandler. func WithProtoErrorHandler(fn ProtoErrorHandlerFunc) ServeMuxOption { return func(serveMux *ServeMux) { serveMux.protoErrorHandler = fn diff --git a/gateway/runtime/query.go b/gateway/runtime/query.go index ee0207e..4b9ef0f 100644 --- a/gateway/runtime/query.go +++ b/gateway/runtime/query.go @@ -17,9 +17,24 @@ import ( var valuesKeyRegexp = regexp.MustCompile("^(.*)\\[(.*)\\]$") -// PopulateQueryParameters populates "values" into "msg". -// A value is ignored if its key starts with one of the elements in "filter". +var currentQueryParser QueryParameterParser = &defaultQueryParser{} + +// QueryParameterParser defines interface for all query parameter parsers +type QueryParameterParser interface { + Parse(msg proto.Message, values url.Values, filter *utilities.DoubleArray) error +} + +// PopulateQueryParameters parses query parameters +// into "msg" using current query parser func PopulateQueryParameters(msg proto.Message, values url.Values, filter *utilities.DoubleArray) error { + return currentQueryParser.Parse(msg, values, filter) +} + +type defaultQueryParser struct{} + +// Parse populates "values" into "msg". +// A value is ignored if its key starts with one of the elements in "filter". +func (*defaultQueryParser) Parse(msg proto.Message, values url.Values, filter *utilities.DoubleArray) error { for key, values := range values { match := valuesKeyRegexp.FindStringSubmatch(key) if len(match) == 3 { diff --git a/gateway/runtime/query_test.go b/gateway/runtime/query_test.go index dff34c8..732541a 100644 --- a/gateway/runtime/query_test.go +++ b/gateway/runtime/query_test.go @@ -372,6 +372,15 @@ func TestPopulateParameters(t *testing.T) { OneofValue: &proto3Message_OneofStringValue{"foobar"}, }, }, + { + values: url.Values{ + "oneofStringValue": {"foobar"}, + }, + filter: utilities.NewDoubleArray(nil), + want: &proto3Message{ + OneofValue: &proto3Message_OneofStringValue{"foobar"}, + }, + }, { values: url.Values{ "oneof_bool_value": {"true"}, diff --git a/repositories.bzl b/repositories.bzl index c7fb2f3..f0805e5 100644 --- a/repositories.bzl +++ b/repositories.bzl @@ -23,8 +23,8 @@ def go_repositories(): go_repository( name = "com_github_grpc_ecosystem_grpc_gateway", importpath = "github.com/grpc-ecosystem/grpc-gateway", - sum = "h1:zCy2xE9ablevUOrUZc3Dl72Dt+ya2FNAvC2yLYMHzi4=", - version = "v1.12.1", + sum = "h1:8ERzHx8aj1Sc47mu9n/AksaKCSWrMchFtkdrS4BIj5o=", + version = "v1.14.6", ) go_repository( name = "com_github_grpc_ecosystem_grpc_opentracing", From 27343a5349aa77044233ced9eac6ec9a2b629d06 Mon Sep 17 00:00:00 2001 From: binchen Date: Thu, 9 Jul 2020 15:36:24 +0800 Subject: [PATCH 06/56] Synchronization with github.com/grpc-ecosystem/grpc-gateway //gateway code in the directory --- gateway/README.md | 4 +- gateway/runtime/BUILD.bazel | 9 +- gateway/runtime/context.go | 2 +- gateway/runtime/convert_test.go | 143 ++++ gateway/runtime/errors.go | 74 +- gateway/runtime/errors_test.go | 43 +- gateway/runtime/handler.go | 31 +- gateway/runtime/handler_test.go | 129 +++- gateway/runtime/marshal_httpbodyproto.go | 2 +- gateway/runtime/marshal_json_test.go | 260 +++++++ gateway/runtime/marshal_jsonpb_test.go | 809 +++++++++++++++++++++ gateway/runtime/marshal_proto_test.go | 91 +++ gateway/runtime/marshaler.go | 9 +- gateway/runtime/marshaler_registry.go | 15 +- gateway/runtime/marshaler_registry_test.go | 31 +- gateway/runtime/proto_errors.go | 6 +- gateway/runtime/query.go | 16 +- 17 files changed, 1588 insertions(+), 86 deletions(-) create mode 100644 gateway/runtime/convert_test.go create mode 100644 gateway/runtime/marshal_json_test.go create mode 100644 gateway/runtime/marshal_jsonpb_test.go create mode 100644 gateway/runtime/marshal_proto_test.go diff --git a/gateway/README.md b/gateway/README.md index 30a7196..5a457bd 100644 --- a/gateway/README.md +++ b/gateway/README.md @@ -127,6 +127,8 @@ Link [grpc-ecosystem/grpc-gateway/runtime](https://github.com/grpc-ecosystem/g - service.go - balancer_test.go - balancer.go +- hook.go +- hook_test.go 删除文件: @@ -136,8 +138,6 @@ Link [grpc-ecosystem/grpc-gateway/runtime](https://github.com/grpc-ecosystem/g 修改文件: -- add hook_test.go -- add hook.go - BUILD.bazel - context_test.go - error_test.go diff --git a/gateway/runtime/BUILD.bazel b/gateway/runtime/BUILD.bazel index 632174a..3d8cdae 100644 --- a/gateway/runtime/BUILD.bazel +++ b/gateway/runtime/BUILD.bazel @@ -9,7 +9,6 @@ go_library( exclude = ["*_test.go"], ), importpath = "github.com/binchencoder/ease-gateway/gateway/runtime", - visibility = ["//visibility:public"], deps = [ "//httpoptions:go_default_library", "@com_github_binchencoder_gateway_proto//data:go_default_library", @@ -17,7 +16,7 @@ go_library( "@com_github_binchencoder_letsgo//grpc:go_default_library", "@com_github_binchencoder_letsgo//hashring:go_default_library", "@com_github_binchencoder_skylb_api//proto:go_default_library", - "@com_github_golang_protobuf//descriptor:go_default_library_gen", + "@com_github_golang_protobuf//descriptor:go_default_library_gen", "@com_github_golang_protobuf//jsonpb:go_default_library_gen", "@com_github_golang_protobuf//proto:go_default_library", "@com_github_grpc_ecosystem_grpc_gateway//internal:go_default_library", @@ -34,7 +33,7 @@ go_library( "@org_golang_google_grpc//grpclog:go_default_library", "@org_golang_google_grpc//metadata:go_default_library", "@org_golang_google_grpc//status:go_default_library", - "@org_golang_google_grpc//:go_default_library", + "@org_golang_google_grpc//:go_default_library", "@org_golang_x_net//context:go_default_library", ], ) @@ -55,9 +54,7 @@ go_test( "pattern_test.go", "query_test.go", ], - embed = [ - ":go_default_library", - ], + embed = [":go_default_library"], deps = [ "//examples/proto:go_default_library", "//httpoptions:go_default_library", diff --git a/gateway/runtime/context.go b/gateway/runtime/context.go index f808382..07673f3 100644 --- a/gateway/runtime/context.go +++ b/gateway/runtime/context.go @@ -201,7 +201,7 @@ func timeoutUnitToDuration(u uint8) (d time.Duration, ok bool) { } // isPermanentHTTPHeader checks whether hdr belongs to the list of -// permenant request headers maintained by IANA. +// permanent request headers maintained by IANA. // http://www.iana.org/assignments/message-headers/message-headers.xml func isPermanentHTTPHeader(hdr string) bool { switch hdr { diff --git a/gateway/runtime/convert_test.go b/gateway/runtime/convert_test.go new file mode 100644 index 0000000..307e8c7 --- /dev/null +++ b/gateway/runtime/convert_test.go @@ -0,0 +1,143 @@ +package runtime_test + +import ( + "encoding/json" + "fmt" + "reflect" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes/duration" + "github.com/golang/protobuf/ptypes/timestamp" + "github.com/binchencoder/ease-gateway/gateway/runtime" +) + +func TestConvertTimestamp(t *testing.T) { + specs := []struct { + name string + input string + output *timestamp.Timestamp + wanterr error + }{ + { + name: "a valid RFC3339 timestamp", + input: `"2016-05-10T10:19:13.123Z"`, + output: ×tamp.Timestamp{ + Seconds: 1462875553, + Nanos: 123000000, + }, + wanterr: nil, + }, + { + name: "invalid timestamp", + input: `"05-10-2016T10:19:13.123Z"`, + output: nil, + wanterr: fmt.Errorf(`bad Timestamp: parsing time "05-10-2016T10:19:13.123Z" as "2006-01-02T15:04:05.999999999Z07:00": cannot parse "0-2016T10:19:13.123Z" as "2006"`), + }, + { + name: "JSON number", + input: "123", + output: nil, + wanterr: &json.UnmarshalTypeError{ + Value: "number", + Type: reflect.TypeOf("123"), + Offset: 3, + }, + }, + { + name: "JSON bool", + input: "true", + output: nil, + wanterr: &json.UnmarshalTypeError{ + Value: "bool", + Type: reflect.TypeOf("123"), + Offset: 4, + }, + }, + } + + for _, spec := range specs { + t.Run(spec.name, func(t *testing.T) { + ts, err := runtime.Timestamp(spec.input) + if spec.wanterr != nil { + if !reflect.DeepEqual(err, spec.wanterr) { + t.Errorf("got unexpected error\n%#v\nexpected\n%#v", err, spec.wanterr) + } + return + } + if !proto.Equal(ts, spec.output) { + t.Errorf( + "when testing %s; got\n%#v\nexpected\n%#v", + spec.name, + ts, + spec.output, + ) + } + }) + } +} + +func TestConvertDuration(t *testing.T) { + specs := []struct { + name string + input string + output *duration.Duration + wanterr error + }{ + { + name: "a valid duration", + input: `"123.456s"`, + output: &duration.Duration{ + Seconds: 123, + Nanos: 456000000, + }, + wanterr: nil, + }, + { + name: "invalid duration", + input: `"123years"`, + output: nil, + wanterr: fmt.Errorf(`bad Duration: time: unknown unit years in duration 123years`), + }, + { + name: "JSON number", + input: "123", + output: nil, + wanterr: &json.UnmarshalTypeError{ + Value: "number", + Type: reflect.TypeOf("123"), + Offset: 3, + }, + }, + { + name: "JSON bool", + input: "true", + output: nil, + wanterr: &json.UnmarshalTypeError{ + Value: "bool", + Type: reflect.TypeOf("123"), + Offset: 4, + }, + }, + } + + for _, spec := range specs { + t.Run(spec.name, func(t *testing.T) { + ts, err := runtime.Duration(spec.input) + if spec.wanterr != nil { + if !reflect.DeepEqual(err, spec.wanterr) { + t.Errorf("got unexpected error\n%#v\nexpected\n%#v", err, spec.wanterr) + } + return + } + if !proto.Equal(ts, spec.output) { + t.Errorf( + "when testing %s; got\n%#v\nexpected\n%#v", + spec.name, + ts, + spec.output, + ) + } + }) + } +} diff --git a/gateway/runtime/errors.go b/gateway/runtime/errors.go index 8198fc2..cf2cc85 100644 --- a/gateway/runtime/errors.go +++ b/gateway/runtime/errors.go @@ -4,6 +4,7 @@ import ( "context" "io" "net/http" + "strings" "github.com/golang/protobuf/jsonpb" "github.com/golang/protobuf/proto" @@ -62,13 +63,52 @@ func HTTPStatusFromCode(code codes.Code) int { } var ( - // HTTPError replies to the request with the error. - // You can set a custom function to this variable to customize error format. + // HTTPError replies to the request with an error. + // + // HTTPError is called: + // - From generated per-endpoint gateway handler code, when calling the backend results in an error. + // - From gateway runtime code, when forwarding the response message results in an error. + // + // The default value for HTTPError calls the custom error handler configured on the ServeMux via the + // WithProtoErrorHandler serve option if that option was used, calling GlobalHTTPErrorHandler otherwise. + // + // To customize the error handling of a particular ServeMux instance, use the WithProtoErrorHandler + // serve option. + // + // To customize the error format for all ServeMux instances not using the WithProtoErrorHandler serve + // option, set GlobalHTTPErrorHandler to a custom function. + // + // Setting this variable directly to customize error format is deprecated. HTTPError = DefaultHTTPError - // OtherErrorHandler handles the following error used by the gateway: StatusMethodNotAllowed StatusNotFound and StatusBadRequest + + // GlobalHTTPErrorHandler is the HTTPError handler for all ServeMux instances not using the + // WithProtoErrorHandler serve option. + // + // You can set a custom function to this variable to customize error format. + GlobalHTTPErrorHandler = DefaultHTTPError + + // OtherErrorHandler handles gateway errors from parsing and routing client requests for all + // ServeMux instances not using the WithProtoErrorHandler serve option. + // + // It returns the following error codes: StatusMethodNotAllowed StatusNotFound StatusBadRequest + // + // To customize parsing and routing error handling of a particular ServeMux instance, use the + // WithProtoErrorHandler serve option. + // + // To customize parsing and routing error handling of all ServeMux instances not using the + // WithProtoErrorHandler serve option, set a custom function to this variable. OtherErrorHandler = DefaultOtherErrorHandler ) +// MuxOrGlobalHTTPError uses the mux-configured error handler, falling back to GlobalErrorHandler. +func MuxOrGlobalHTTPError(ctx context.Context, mux *ServeMux, marshaler Marshaler, w http.ResponseWriter, r *http.Request, err error) { + if mux.protoErrorHandler != nil { + mux.protoErrorHandler(ctx, mux, marshaler, w, r, err) + } else { + GlobalHTTPErrorHandler(ctx, mux, marshaler, w, r, err) + } +} + type errorBody struct { Error *fpb.Error `protobuf:"bytes,1,name=error" json:"error"` // This is to make the error more compatible with users that expect errors to be Status objects: @@ -90,7 +130,7 @@ func (*errorBody) ProtoMessage() {} // // The response body returned by this function is a JSON object, // which contains a member whose key is "error" and whose value is err.Error(). -func DefaultHTTPError(ctx context.Context, mux *ServeMux, marshaler Marshaler, w http.ResponseWriter, _ *http.Request, err error) { +func DefaultHTTPError(ctx context.Context, mux *ServeMux, marshaler Marshaler, w http.ResponseWriter, r *http.Request, err error) { const fallback = `{"error": "failed to marshal error message"}` s, ok := status.FromError(err) @@ -99,14 +139,15 @@ func DefaultHTTPError(ctx context.Context, mux *ServeMux, marshaler Marshaler, w } w.Header().Del("Trailer") + w.Header().Del("Transfer-Encoding") contentType := marshaler.ContentType() - // Check marshaler on run time in order to keep backwards compatability + // Check marshaler on run time in order to keep backwards compatibility // An interface param needs to be added to the ContentType() function on // the Marshal interface to be able to remove this check - if httpBodyMarshaler, ok := marshaler.(*HTTPBodyMarshaler); ok { + if typeMarshaler, ok := marshaler.(contentTypeMarshaler); ok { pb := s.Proto() - contentType = httpBodyMarshaler.ContentTypeFromMessage(pb) + contentType = typeMarshaler.ContentTypeFromMessage(pb) } w.Header().Set("Content-Type", contentType) @@ -139,14 +180,29 @@ func DefaultHTTPError(ctx context.Context, mux *ServeMux, marshaler Marshaler, w } handleForwardResponseServerMetadata(w, mux, md) - handleForwardResponseTrailerHeader(w, md) + + // RFC 7230 https://tools.ietf.org/html/rfc7230#section-4.1.2 + // Unless the request includes a TE header field indicating "trailers" + // is acceptable, as described in Section 4.3, a server SHOULD NOT + // generate trailer fields that it believes are necessary for the user + // agent to receive. + var wantsTrailers bool + + if te := r.Header.Get("TE"); strings.Contains(strings.ToLower(te), "trailers") { + wantsTrailers = true + handleForwardResponseTrailerHeader(w, md) + w.Header().Set("Transfer-Encoding", "chunked") + } + st := HTTPStatusFromCode(s.Code()) w.WriteHeader(st) if _, err := w.Write(buf); err != nil { grpclog.Infof("Failed to write response: %v", err) } - handleForwardResponseTrailer(w, md) + if wantsTrailers { + handleForwardResponseTrailer(w, md) + } } // DefaultOtherErrorHandler is the default implementation of OtherErrorHandler. diff --git a/gateway/runtime/errors_test.go b/gateway/runtime/errors_test.go index 4026b14..d1589b7 100644 --- a/gateway/runtime/errors_test.go +++ b/gateway/runtime/errors_test.go @@ -23,26 +23,41 @@ func TestDefaultHTTPError(t *testing.T) { ) for _, spec := range []struct { - err error - status int - msg string - details string + err error + status int + msg string + marshaler runtime.Marshaler + contentType string + details string }{ { - err: fmt.Errorf("example error"), - status: http.StatusInternalServerError, - msg: "example error", + err: fmt.Errorf("example error"), + status: http.StatusInternalServerError, + marshaler: &runtime.JSONPb{}, + contentType: "application/json", + msg: "example error", }, { - err: status.Error(codes.NotFound, "no such resource"), - status: http.StatusNotFound, - msg: "no such resource", + err: status.Error(codes.NotFound, "no such resource"), + status: http.StatusNotFound, + marshaler: &runtime.JSONPb{}, + contentType: "application/json", + msg: "no such resource", }, { - err: statusWithDetails.Err(), - status: http.StatusBadRequest, - msg: "failed precondition", - details: "type.googleapis.com/google.rpc.PreconditionFailure", + err: statusWithDetails.Err(), + status: http.StatusBadRequest, + marshaler: &runtime.JSONPb{}, + contentType: "application/json", + msg: "failed precondition", + details: "type.googleapis.com/google.rpc.PreconditionFailure", + }, + { + err: fmt.Errorf("example error"), + status: http.StatusInternalServerError, + marshaler: &CustomMarshaler{&runtime.JSONPb{}}, + contentType: "Custom-Content-Type", + msg: "example error", }, } { w := httptest.NewRecorder() diff --git a/gateway/runtime/handler.go b/gateway/runtime/handler.go index 2af9006..e6e8f28 100644 --- a/gateway/runtime/handler.go +++ b/gateway/runtime/handler.go @@ -1,13 +1,13 @@ package runtime import ( + "context" "errors" "fmt" "io" "net/http" "net/textproto" - "context" "github.com/golang/protobuf/proto" "github.com/grpc-ecosystem/grpc-gateway/internal" "google.golang.org/grpc/grpclog" @@ -61,7 +61,19 @@ func ForwardResponseStream(ctx context.Context, mux *ServeMux, marshaler Marshal return } - buf, err := marshaler.Marshal(streamChunk(ctx, resp, mux.streamErrorHandler)) + var buf []byte + switch { + case resp == nil: + buf, err = marshaler.Marshal(errorChunk(streamError(ctx, mux.streamErrorHandler, errEmptyResponse))) + default: + result := map[string]interface{}{"result": resp} + if rb, ok := resp.(responseBody); ok { + result["result"] = rb.XXX_ResponseBody() + } + + buf, err = marshaler.Marshal(result) + } + if err != nil { grpclog.Infof("Failed to marshal response chunk: %v", err) handleForwardResponseStreamError(ctx, wroteHeader, marshaler, w, req, mux, err) @@ -123,11 +135,11 @@ func ForwardResponseMessage(ctx context.Context, mux *ServeMux, marshaler Marsha handleForwardResponseTrailerHeader(w, md) contentType := marshaler.ContentType() - // Check marshaler on run time in order to keep backwards compatability + // Check marshaler on run time in order to keep backwards compatibility // An interface param needs to be added to the ContentType() function on // the Marshal interface to be able to remove this check - if httpBodyMarshaler, ok := marshaler.(*HTTPBodyMarshaler); ok { - contentType = httpBodyMarshaler.ContentTypeFromMessage(resp) + if typeMarshaler, ok := marshaler.(contentTypeMarshaler); ok { + contentType = typeMarshaler.ContentTypeFromMessage(resp) } w.Header().Set("Content-Type", contentType) @@ -184,15 +196,6 @@ func handleForwardResponseStreamError(ctx context.Context, wroteHeader bool, mar } } -// streamChunk returns a chunk in a response stream for the given result. The -// given errHandler is used to render an error chunk if result is nil. -func streamChunk(ctx context.Context, result proto.Message, errHandler StreamErrorHandlerFunc) map[string]proto.Message { - if result == nil { - return errorChunk(streamError(ctx, errHandler, errEmptyResponse)) - } - return map[string]proto.Message{"result": result} -} - // streamError returns the payload for the final message in a response stream // that represents the given err. func streamError(ctx context.Context, errHandler StreamErrorHandlerFunc, err error) *StreamError { diff --git a/gateway/runtime/handler_test.go b/gateway/runtime/handler_test.go index a1dc65a..0d3fe80 100644 --- a/gateway/runtime/handler_test.go +++ b/gateway/runtime/handler_test.go @@ -1,31 +1,41 @@ package runtime_test import ( + "context" "io" "io/ioutil" "net/http" "net/http/httptest" "testing" - "context" - "github.com/golang/protobuf/proto" pb "github.com/binchencoder/ease-gateway/examples/proto" - "github.com/grpc-ecosystem/grpc-gateway/internal" "github.com/binchencoder/ease-gateway/gateway/runtime" - "google.golang.org/grpc" + "github.com/golang/protobuf/proto" + "github.com/grpc-ecosystem/grpc-gateway/internal" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) +type fakeReponseBodyWrapper struct { + proto.Message +} + +// XXX_ResponseBody returns id of SimpleMessage +func (r fakeReponseBodyWrapper) XXX_ResponseBody() interface{} { + resp := r.Message.(*pb.SimpleMessage) + return resp.Id +} + func TestForwardResponseStream(t *testing.T) { type msg struct { pb proto.Message err error } tests := []struct { - name string - msgs []msg - statusCode int + name string + msgs []msg + statusCode int + responseBody bool }{{ name: "encoding", msgs: []msg{ @@ -38,15 +48,31 @@ func TestForwardResponseStream(t *testing.T) { statusCode: http.StatusOK, }, { name: "error", - msgs: []msg{{nil, grpc.Errorf(codes.OutOfRange, "400")}}, + msgs: []msg{{nil, status.Errorf(codes.OutOfRange, "400")}}, statusCode: http.StatusBadRequest, }, { name: "stream_error", msgs: []msg{ {&pb.SimpleMessage{Id: "One"}, nil}, - {nil, grpc.Errorf(codes.OutOfRange, "400")}, + {nil, status.Errorf(codes.OutOfRange, "400")}, }, statusCode: http.StatusOK, + }, { + name: "response body stream case", + msgs: []msg{ + {fakeReponseBodyWrapper{&pb.SimpleMessage{Id: "One"}}, nil}, + {fakeReponseBodyWrapper{&pb.SimpleMessage{Id: "Two"}}, nil}, + }, + responseBody: true, + statusCode: http.StatusOK, + }, { + name: "response body stream error case", + msgs: []msg{ + {fakeReponseBodyWrapper{&pb.SimpleMessage{Id: "One"}}, nil}, + {nil, status.Errorf(codes.OutOfRange, "400")}, + }, + responseBody: true, + statusCode: http.StatusOK, }} newTestRecv := func(t *testing.T, msgs []msg) func() (proto.Message, error) { @@ -113,7 +139,22 @@ func TestForwardResponseStream(t *testing.T) { return } - b, err := marshaler.Marshal(map[string]proto.Message{"result": msg.pb}) + + var b []byte + + if tt.responseBody { + // responseBody interface is in runtime package and test is in runtime_test package. hence can't use responseBody directly + // So type casting to fakeReponseBodyWrapper struct to verify the data. + rb, ok := msg.pb.(fakeReponseBodyWrapper) + if !ok { + t.Errorf("stream responseBody failed %v", err) + } + + b, err = marshaler.Marshal(map[string]interface{}{"result": rb.XXX_ResponseBody()}) + } else { + b, err = marshaler.Marshal(map[string]interface{}{"result": msg.pb}) + } + if err != nil { t.Errorf("marshaler.Marshal() failed %v", err) } @@ -133,11 +174,12 @@ type CustomMarshaler struct { m *runtime.JSONPb } -func (c *CustomMarshaler) Marshal(v interface{}) ([]byte, error) { return c.m.Marshal(v) } -func (c *CustomMarshaler) Unmarshal(data []byte, v interface{}) error { return c.m.Unmarshal(data, v) } -func (c *CustomMarshaler) NewDecoder(r io.Reader) runtime.Decoder { return c.m.NewDecoder(r) } -func (c *CustomMarshaler) NewEncoder(w io.Writer) runtime.Encoder { return c.m.NewEncoder(w) } -func (c *CustomMarshaler) ContentType() string { return c.m.ContentType() } +func (c *CustomMarshaler) Marshal(v interface{}) ([]byte, error) { return c.m.Marshal(v) } +func (c *CustomMarshaler) Unmarshal(data []byte, v interface{}) error { return c.m.Unmarshal(data, v) } +func (c *CustomMarshaler) NewDecoder(r io.Reader) runtime.Decoder { return c.m.NewDecoder(r) } +func (c *CustomMarshaler) NewEncoder(w io.Writer) runtime.Encoder { return c.m.NewEncoder(w) } +func (c *CustomMarshaler) ContentType() string { return c.m.ContentType() } +func (c *CustomMarshaler) ContentTypeFromMessage(v interface{}) string { return "Custom-Content-Type" } func TestForwardResponseStreamCustomMarshaler(t *testing.T) { type msg struct { @@ -160,13 +202,13 @@ func TestForwardResponseStreamCustomMarshaler(t *testing.T) { statusCode: http.StatusOK, }, { name: "error", - msgs: []msg{{nil, grpc.Errorf(codes.OutOfRange, "400")}}, + msgs: []msg{{nil, status.Errorf(codes.OutOfRange, "400")}}, statusCode: http.StatusBadRequest, }, { name: "stream_error", msgs: []msg{ {&pb.SimpleMessage{Id: "One"}, nil}, - {nil, grpc.Errorf(codes.OutOfRange, "400")}, + {nil, status.Errorf(codes.OutOfRange, "400")}, }, statusCode: http.StatusOK, }} @@ -226,3 +268,56 @@ func TestForwardResponseStreamCustomMarshaler(t *testing.T) { }) } } + +func TestForwardResponseMessage(t *testing.T) { + msg := &pb.SimpleMessage{Id: "One"} + tests := []struct { + name string + marshaler runtime.Marshaler + contentType string + }{{ + name: "standard marshaler", + marshaler: &runtime.JSONPb{}, + contentType: "application/json", + }, { + name: "httpbody marshaler", + marshaler: &runtime.HTTPBodyMarshaler{&runtime.JSONPb{}}, + contentType: "application/json", + }, { + name: "custom marshaler", + marshaler: &CustomMarshaler{&runtime.JSONPb{}}, + contentType: "Custom-Content-Type", + }} + + ctx := runtime.NewServerMetadataContext(context.Background(), runtime.ServerMetadata{}) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + req := httptest.NewRequest("GET", "http://example.com/foo", nil) + resp := httptest.NewRecorder() + + runtime.ForwardResponseMessage(ctx, runtime.NewServeMux(), tt.marshaler, resp, req, msg) + + w := resp.Result() + if w.StatusCode != http.StatusOK { + t.Errorf("StatusCode %d want %d", w.StatusCode, http.StatusOK) + } + if h := w.Header.Get("Content-Type"); h != tt.contentType { + t.Errorf("Content-Type %v want %v", h, tt.contentType) + } + body, err := ioutil.ReadAll(w.Body) + if err != nil { + t.Errorf("Failed to read response body with %v", err) + } + w.Body.Close() + + want, err := tt.marshaler.Marshal(msg) + if err != nil { + t.Errorf("marshaler.Marshal() failed %v", err) + } + + if string(body) != string(want) { + t.Errorf("ForwardResponseMessage() = \"%s\" want \"%s\"", body, want) + } + }) + } +} diff --git a/gateway/runtime/marshal_httpbodyproto.go b/gateway/runtime/marshal_httpbodyproto.go index f55285b..525b033 100644 --- a/gateway/runtime/marshal_httpbodyproto.go +++ b/gateway/runtime/marshal_httpbodyproto.go @@ -19,7 +19,7 @@ type HTTPBodyMarshaler struct { Marshaler } -// ContentType implementation to keep backwards compatability with marshal interface +// ContentType implementation to keep backwards compatibility with marshal interface func (h *HTTPBodyMarshaler) ContentType() string { return h.ContentTypeFromMessage(nil) } diff --git a/gateway/runtime/marshal_json_test.go b/gateway/runtime/marshal_json_test.go new file mode 100644 index 0000000..e7610ce --- /dev/null +++ b/gateway/runtime/marshal_json_test.go @@ -0,0 +1,260 @@ +package runtime_test + +import ( + "bytes" + "encoding/json" + "reflect" + "strings" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes/empty" + structpb "github.com/golang/protobuf/ptypes/struct" + "github.com/golang/protobuf/ptypes/timestamp" + "github.com/golang/protobuf/ptypes/wrappers" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb" +) + +func TestJSONBuiltinMarshal(t *testing.T) { + var m runtime.JSONBuiltin + msg := examplepb.SimpleMessage{ + Id: "foo", + } + + buf, err := m.Marshal(&msg) + if err != nil { + t.Errorf("m.Marshal(%v) failed with %v; want success", &msg, err) + } + + var got examplepb.SimpleMessage + if err := json.Unmarshal(buf, &got); err != nil { + t.Errorf("json.Unmarshal(%q, &got) failed with %v; want success", buf, err) + } + if want := msg; !reflect.DeepEqual(got, want) { + t.Errorf("got = %v; want %v", &got, &want) + } +} + +func TestJSONBuiltinMarshalField(t *testing.T) { + var m runtime.JSONBuiltin + for _, fixt := range builtinFieldFixtures { + buf, err := m.Marshal(fixt.data) + if err != nil { + t.Errorf("m.Marshal(%v) failed with %v; want success", fixt.data, err) + } + if got, want := string(buf), fixt.json; got != want { + t.Errorf("got = %q; want %q; data = %#v", got, want, fixt.data) + } + } +} + +func TestJSONBuiltinMarshalFieldKnownErrors(t *testing.T) { + var m runtime.JSONBuiltin + for _, fixt := range builtinKnownErrors { + buf, err := m.Marshal(fixt.data) + if err != nil { + t.Errorf("m.Marshal(%v) failed with %v; want success", fixt.data, err) + } + if got, want := string(buf), fixt.json; got == want { + t.Errorf("surprisingly got = %q; as want %q; data = %#v", got, want, fixt.data) + } + } +} + +func TestJSONBuiltinsnmarshal(t *testing.T) { + var ( + m runtime.JSONBuiltin + got examplepb.SimpleMessage + + data = []byte(`{"id": "foo"}`) + ) + if err := m.Unmarshal(data, &got); err != nil { + t.Errorf("m.Unmarshal(%q, &got) failed with %v; want success", data, err) + } + + want := examplepb.SimpleMessage{ + Id: "foo", + } + if !reflect.DeepEqual(got, want) { + t.Errorf("got = %v; want = %v", &got, &want) + } +} + +func TestJSONBuiltinUnmarshalField(t *testing.T) { + var m runtime.JSONBuiltin + for _, fixt := range builtinFieldFixtures { + dest := alloc(reflect.TypeOf(fixt.data)) + if err := m.Unmarshal([]byte(fixt.json), dest.Interface()); err != nil { + t.Errorf("m.Unmarshal(%q, dest) failed with %v; want success", fixt.json, err) + } + + if got, want := dest.Elem().Interface(), fixt.data; !reflect.DeepEqual(got, want) { + t.Errorf("got = %#v; want = %#v; input = %q", got, want, fixt.json) + } + } +} + +func alloc(t reflect.Type) reflect.Value { + if t == nil { + return reflect.ValueOf(new(interface{})) + } else { + return reflect.New(t) + } +} + +func TestJSONBuiltinUnmarshalFieldKnownErrors(t *testing.T) { + var m runtime.JSONBuiltin + for _, fixt := range builtinKnownErrors { + dest := reflect.New(reflect.TypeOf(fixt.data)) + if err := m.Unmarshal([]byte(fixt.json), dest.Interface()); err == nil { + t.Errorf("m.Unmarshal(%q, dest) succeeded; want ane error", fixt.json) + } + } +} + +func TestJSONBuiltinEncoder(t *testing.T) { + var m runtime.JSONBuiltin + msg := examplepb.SimpleMessage{ + Id: "foo", + } + + var buf bytes.Buffer + enc := m.NewEncoder(&buf) + if err := enc.Encode(&msg); err != nil { + t.Errorf("enc.Encode(%v) failed with %v; want success", &msg, err) + } + + var got examplepb.SimpleMessage + if err := json.Unmarshal(buf.Bytes(), &got); err != nil { + t.Errorf("json.Unmarshal(%q, &got) failed with %v; want success", buf.String(), err) + } + if want := msg; !reflect.DeepEqual(got, want) { + t.Errorf("got = %v; want %v", &got, &want) + } +} + +func TestJSONBuiltinEncoderFields(t *testing.T) { + var m runtime.JSONBuiltin + for _, fixt := range builtinFieldFixtures { + var buf bytes.Buffer + enc := m.NewEncoder(&buf) + if err := enc.Encode(fixt.data); err != nil { + t.Errorf("enc.Encode(%#v) failed with %v; want success", fixt.data, err) + } + + if got, want := buf.String(), fixt.json+"\n"; got != want { + t.Errorf("got = %q; want %q; data = %#v", got, want, fixt.data) + } + } +} + +func TestJSONBuiltinDecoder(t *testing.T) { + var ( + m runtime.JSONBuiltin + got examplepb.SimpleMessage + + data = `{"id": "foo"}` + ) + r := strings.NewReader(data) + dec := m.NewDecoder(r) + if err := dec.Decode(&got); err != nil { + t.Errorf("m.Unmarshal(&got) failed with %v; want success", err) + } + + want := examplepb.SimpleMessage{ + Id: "foo", + } + if !reflect.DeepEqual(got, want) { + t.Errorf("got = %v; want = %v", &got, &want) + } +} + +func TestJSONBuiltinDecoderFields(t *testing.T) { + var m runtime.JSONBuiltin + for _, fixt := range builtinFieldFixtures { + r := strings.NewReader(fixt.json) + dec := m.NewDecoder(r) + dest := alloc(reflect.TypeOf(fixt.data)) + if err := dec.Decode(dest.Interface()); err != nil { + t.Errorf("dec.Decode(dest) failed with %v; want success; data = %q", err, fixt.json) + } + + if got, want := dest.Elem().Interface(), fixt.data; !reflect.DeepEqual(got, want) { + t.Errorf("got = %v; want = %v; input = %q", got, want, fixt.json) + } + } +} + +var ( + builtinFieldFixtures = []struct { + data interface{} + json string + }{ + {data: "", json: `""`}, + {data: proto.String(""), json: `""`}, + {data: "foo", json: `"foo"`}, + {data: proto.String("foo"), json: `"foo"`}, + {data: int32(-1), json: "-1"}, + {data: proto.Int32(-1), json: "-1"}, + {data: int64(-1), json: "-1"}, + {data: proto.Int64(-1), json: "-1"}, + {data: uint32(123), json: "123"}, + {data: proto.Uint32(123), json: "123"}, + {data: uint64(123), json: "123"}, + {data: proto.Uint64(123), json: "123"}, + {data: float32(-1.5), json: "-1.5"}, + {data: proto.Float32(-1.5), json: "-1.5"}, + {data: float64(-1.5), json: "-1.5"}, + {data: proto.Float64(-1.5), json: "-1.5"}, + {data: true, json: "true"}, + {data: proto.Bool(true), json: "true"}, + {data: (*string)(nil), json: "null"}, + {data: new(empty.Empty), json: "{}"}, + {data: examplepb.NumericEnum_ONE, json: "1"}, + {data: nil, json: "null"}, + {data: (*string)(nil), json: "null"}, + {data: []interface{}{nil, "foo", -1.0, 1.234, true}, json: `[null,"foo",-1,1.234,true]`}, + { + data: map[string]interface{}{"bar": nil, "baz": -1.0, "fiz": 1.234, "foo": true}, + json: `{"bar":null,"baz":-1,"fiz":1.234,"foo":true}`, + }, + { + data: (*examplepb.NumericEnum)(proto.Int32(int32(examplepb.NumericEnum_ONE))), + json: "1", + }, + } + builtinKnownErrors = []struct { + data interface{} + json string + }{ + {data: examplepb.NumericEnum_ONE, json: "ONE"}, + { + data: (*examplepb.NumericEnum)(proto.Int32(int32(examplepb.NumericEnum_ONE))), + json: "ONE", + }, + { + data: &examplepb.ABitOfEverything_OneofString{OneofString: "abc"}, + json: `"abc"`, + }, + { + data: ×tamp.Timestamp{ + Seconds: 1462875553, + Nanos: 123000000, + }, + json: `"2016-05-10T10:19:13.123Z"`, + }, + { + data: &wrappers.Int32Value{Value: 123}, + json: "123", + }, + { + data: &structpb.Value{ + Kind: &structpb.Value_StringValue{ + StringValue: "abc", + }, + }, + json: `"abc"`, + }, + } +) diff --git a/gateway/runtime/marshal_jsonpb_test.go b/gateway/runtime/marshal_jsonpb_test.go new file mode 100644 index 0000000..19d5bc8 --- /dev/null +++ b/gateway/runtime/marshal_jsonpb_test.go @@ -0,0 +1,809 @@ +package runtime_test + +import ( + "bytes" + "reflect" + "strconv" + "strings" + "testing" + + "github.com/golang/protobuf/jsonpb" + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes/duration" + "github.com/golang/protobuf/ptypes/empty" + structpb "github.com/golang/protobuf/ptypes/struct" + "github.com/golang/protobuf/ptypes/timestamp" + "github.com/golang/protobuf/ptypes/wrappers" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb" +) + +func TestJSONPbMarshal(t *testing.T) { + msg := examplepb.ABitOfEverything{ + SingleNested: &examplepb.ABitOfEverything_Nested{}, + RepeatedStringValue: []string{}, + MappedStringValue: map[string]string{}, + MappedNestedValue: map[string]*examplepb.ABitOfEverything_Nested{}, + RepeatedEnumValue: []examplepb.NumericEnum{}, + TimestampValue: ×tamp.Timestamp{}, + Uuid: "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", + Nested: []*examplepb.ABitOfEverything_Nested{ + { + Name: "foo", + Amount: 12345, + }, + }, + Uint64Value: 0xFFFFFFFFFFFFFFFF, + EnumValue: examplepb.NumericEnum_ONE, + OneofValue: &examplepb.ABitOfEverything_OneofString{ + OneofString: "bar", + }, + MapValue: map[string]examplepb.NumericEnum{ + "a": examplepb.NumericEnum_ONE, + "b": examplepb.NumericEnum_ZERO, + }, + RepeatedEnumAnnotation: []examplepb.NumericEnum{}, + EnumValueAnnotation: examplepb.NumericEnum_ONE, + RepeatedStringAnnotation: []string{}, + RepeatedNestedAnnotation: []*examplepb.ABitOfEverything_Nested{}, + NestedAnnotation: &examplepb.ABitOfEverything_Nested{}, + } + + for i, spec := range []struct { + enumsAsInts, emitDefaults bool + indent string + origName bool + verifier func(json string) + }{ + { + verifier: func(json string) { + if strings.ContainsAny(json, " \t\r\n") { + t.Errorf("strings.ContainsAny(%q, %q) = true; want false", json, " \t\r\n") + } + if !strings.Contains(json, "ONE") { + t.Errorf(`strings.Contains(%q, "ONE") = false; want true`, json) + } + if want := "uint64Value"; !strings.Contains(json, want) { + t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want) + } + }, + }, + { + enumsAsInts: true, + verifier: func(json string) { + if strings.Contains(json, "ONE") { + t.Errorf(`strings.Contains(%q, "ONE") = true; want false`, json) + } + }, + }, + { + emitDefaults: true, + verifier: func(json string) { + if want := `"sfixed32Value"`; !strings.Contains(json, want) { + t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want) + } + }, + }, + { + indent: "\t\t", + verifier: func(json string) { + if want := "\t\t\"amount\":"; !strings.Contains(json, want) { + t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want) + } + }, + }, + { + origName: true, + verifier: func(json string) { + if want := "uint64_value"; !strings.Contains(json, want) { + t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want) + } + }, + }, + } { + m := runtime.JSONPb{ + EnumsAsInts: spec.enumsAsInts, + EmitDefaults: spec.emitDefaults, + Indent: spec.indent, + OrigName: spec.origName, + } + buf, err := m.Marshal(&msg) + if err != nil { + t.Errorf("m.Marshal(%v) failed with %v; want success; spec=%v", &msg, err, spec) + } + + var got examplepb.ABitOfEverything + if err := jsonpb.UnmarshalString(string(buf), &got); err != nil { + t.Errorf("jsonpb.UnmarshalString(%q, &got) failed with %v; want success; spec=%v", string(buf), err, spec) + } + if want := msg; !reflect.DeepEqual(got, want) { + t.Errorf("case %d: got = %v; want %v; spec=%v", i, &got, &want, spec) + } + if spec.verifier != nil { + spec.verifier(string(buf)) + } + } +} + +func TestJSONPbMarshalFields(t *testing.T) { + var m runtime.JSONPb + m.EnumsAsInts = true // builtin fixtures include an enum, expected to be marshaled as int + for _, spec := range builtinFieldFixtures { + buf, err := m.Marshal(spec.data) + if err != nil { + t.Errorf("m.Marshal(%#v) failed with %v; want success", spec.data, err) + } + if got, want := string(buf), spec.json; got != want { + t.Errorf("m.Marshal(%#v) = %q; want %q", spec.data, got, want) + } + } + + m.EnumsAsInts = false + buf, err := m.Marshal(examplepb.NumericEnum_ONE) + if err != nil { + t.Errorf("m.Marshal(%#v) failed with %v; want success", examplepb.NumericEnum_ONE, err) + } + if got, want := string(buf), `"ONE"`; got != want { + t.Errorf("m.Marshal(%#v) = %q; want %q", examplepb.NumericEnum_ONE, got, want) + } +} + +func TestJSONPbUnmarshal(t *testing.T) { + var ( + m runtime.JSONPb + got examplepb.ABitOfEverything + ) + for i, data := range []string{ + `{ + "uuid": "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", + "nested": [ + {"name": "foo", "amount": 12345} + ], + "uint64Value": 18446744073709551615, + "enumValue": "ONE", + "oneofString": "bar", + "mapValue": { + "a": 1, + "b": 0 + } + }`, + `{ + "uuid": "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", + "nested": [ + {"name": "foo", "amount": 12345} + ], + "uint64Value": "18446744073709551615", + "enumValue": "ONE", + "oneofString": "bar", + "mapValue": { + "a": 1, + "b": 0 + } + }`, + `{ + "uuid": "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", + "nested": [ + {"name": "foo", "amount": 12345} + ], + "uint64Value": 18446744073709551615, + "enumValue": 1, + "oneofString": "bar", + "mapValue": { + "a": 1, + "b": 0 + } + }`, + } { + if err := m.Unmarshal([]byte(data), &got); err != nil { + t.Errorf("case %d: m.Unmarshal(%q, &got) failed with %v; want success", i, data, err) + } + + want := examplepb.ABitOfEverything{ + Uuid: "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", + Nested: []*examplepb.ABitOfEverything_Nested{ + { + Name: "foo", + Amount: 12345, + }, + }, + Uint64Value: 0xFFFFFFFFFFFFFFFF, + EnumValue: examplepb.NumericEnum_ONE, + OneofValue: &examplepb.ABitOfEverything_OneofString{ + OneofString: "bar", + }, + MapValue: map[string]examplepb.NumericEnum{ + "a": examplepb.NumericEnum_ONE, + "b": examplepb.NumericEnum_ZERO, + }, + } + + if !reflect.DeepEqual(got, want) { + t.Errorf("case %d: got = %v; want = %v", i, &got, &want) + } + } +} + +func TestJSONPbUnmarshalFields(t *testing.T) { + var m runtime.JSONPb + for _, fixt := range fieldFixtures { + if fixt.skipUnmarshal { + continue + } + + dest := reflect.New(reflect.TypeOf(fixt.data)) + if err := m.Unmarshal([]byte(fixt.json), dest.Interface()); err != nil { + t.Errorf("m.Unmarshal(%q, %T) failed with %v; want success", fixt.json, dest.Interface(), err) + } + if got, want := dest.Elem().Interface(), fixt.data; !reflect.DeepEqual(got, want) { + t.Errorf("dest = %#v; want %#v; input = %v", got, want, fixt.json) + } + } +} + +func TestJSONPbEncoder(t *testing.T) { + msg := examplepb.ABitOfEverything{ + SingleNested: &examplepb.ABitOfEverything_Nested{}, + RepeatedStringValue: []string{}, + MappedStringValue: map[string]string{}, + MappedNestedValue: map[string]*examplepb.ABitOfEverything_Nested{}, + RepeatedEnumValue: []examplepb.NumericEnum{}, + TimestampValue: ×tamp.Timestamp{}, + Uuid: "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", + Nested: []*examplepb.ABitOfEverything_Nested{ + { + Name: "foo", + Amount: 12345, + }, + }, + Uint64Value: 0xFFFFFFFFFFFFFFFF, + OneofValue: &examplepb.ABitOfEverything_OneofString{ + OneofString: "bar", + }, + MapValue: map[string]examplepb.NumericEnum{ + "a": examplepb.NumericEnum_ONE, + "b": examplepb.NumericEnum_ZERO, + }, + RepeatedEnumAnnotation: []examplepb.NumericEnum{}, + EnumValueAnnotation: examplepb.NumericEnum_ONE, + RepeatedStringAnnotation: []string{}, + RepeatedNestedAnnotation: []*examplepb.ABitOfEverything_Nested{}, + NestedAnnotation: &examplepb.ABitOfEverything_Nested{}, + } + + for i, spec := range []struct { + enumsAsInts, emitDefaults bool + indent string + origName bool + verifier func(json string) + }{ + { + verifier: func(json string) { + // remove trailing delimiter before verifying + json = strings.TrimSuffix(json, "\n") + + if strings.ContainsAny(json, " \t\r\n") { + t.Errorf("strings.ContainsAny(%q, %q) = true; want false", json, " \t\r\n") + } + if !strings.Contains(json, "ONE") { + t.Errorf(`strings.Contains(%q, "ONE") = false; want true`, json) + } + if want := "uint64Value"; !strings.Contains(json, want) { + t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want) + } + }, + }, + { + enumsAsInts: true, + verifier: func(json string) { + if strings.Contains(json, "ONE") { + t.Errorf(`strings.Contains(%q, "ONE") = true; want false`, json) + } + }, + }, + { + emitDefaults: true, + verifier: func(json string) { + if want := `"sfixed32Value"`; !strings.Contains(json, want) { + t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want) + } + }, + }, + { + indent: "\t\t", + verifier: func(json string) { + if want := "\t\t\"amount\":"; !strings.Contains(json, want) { + t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want) + } + }, + }, + { + origName: true, + verifier: func(json string) { + if want := "uint64_value"; !strings.Contains(json, want) { + t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want) + } + }, + }, + } { + m := runtime.JSONPb{ + EnumsAsInts: spec.enumsAsInts, + EmitDefaults: spec.emitDefaults, + Indent: spec.indent, + OrigName: spec.origName, + } + + var buf bytes.Buffer + enc := m.NewEncoder(&buf) + if err := enc.Encode(&msg); err != nil { + t.Errorf("enc.Encode(%v) failed with %v; want success; spec=%v", &msg, err, spec) + } + + var got examplepb.ABitOfEverything + if err := jsonpb.UnmarshalString(buf.String(), &got); err != nil { + t.Errorf("jsonpb.UnmarshalString(%q, &got) failed with %v; want success; spec=%v", buf.String(), err, spec) + } + if want := msg; !reflect.DeepEqual(got, want) { + t.Errorf("case %d: got = %v; want %v; spec=%v", i, &got, &want, spec) + } + if spec.verifier != nil { + spec.verifier(buf.String()) + } + } +} + +func TestJSONPbEncoderFields(t *testing.T) { + var m runtime.JSONPb + for _, fixt := range fieldFixtures { + var buf bytes.Buffer + enc := m.NewEncoder(&buf) + if err := enc.Encode(fixt.data); err != nil { + t.Errorf("enc.Encode(%#v) failed with %v; want success", fixt.data, err) + } + if got, want := buf.String(), fixt.json+string(m.Delimiter()); got != want { + t.Errorf("enc.Encode(%#v) = %q; want %q", fixt.data, got, want) + } + } + + m.EnumsAsInts = true + buf, err := m.Marshal(examplepb.NumericEnum_ONE) + if err != nil { + t.Errorf("m.Marshal(%#v) failed with %v; want success", examplepb.NumericEnum_ONE, err) + } + if got, want := string(buf), "1"; got != want { + t.Errorf("m.Marshal(%#v) = %q; want %q", examplepb.NumericEnum_ONE, got, want) + } +} + +func TestJSONPbDecoder(t *testing.T) { + var ( + m runtime.JSONPb + got examplepb.ABitOfEverything + ) + for _, data := range []string{ + `{ + "uuid": "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", + "nested": [ + {"name": "foo", "amount": 12345} + ], + "uint64Value": 18446744073709551615, + "enumValue": "ONE", + "oneofString": "bar", + "mapValue": { + "a": 1, + "b": 0 + } + }`, + `{ + "uuid": "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", + "nested": [ + {"name": "foo", "amount": 12345} + ], + "uint64Value": "18446744073709551615", + "enumValue": "ONE", + "oneofString": "bar", + "mapValue": { + "a": 1, + "b": 0 + } + }`, + `{ + "uuid": "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", + "nested": [ + {"name": "foo", "amount": 12345} + ], + "uint64Value": 18446744073709551615, + "enumValue": 1, + "oneofString": "bar", + "mapValue": { + "a": 1, + "b": 0 + } + }`, + } { + r := strings.NewReader(data) + dec := m.NewDecoder(r) + if err := dec.Decode(&got); err != nil { + t.Errorf("m.Unmarshal(&got) failed with %v; want success; data=%q", err, data) + } + + want := examplepb.ABitOfEverything{ + Uuid: "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", + Nested: []*examplepb.ABitOfEverything_Nested{ + { + Name: "foo", + Amount: 12345, + }, + }, + Uint64Value: 0xFFFFFFFFFFFFFFFF, + EnumValue: examplepb.NumericEnum_ONE, + OneofValue: &examplepb.ABitOfEverything_OneofString{ + OneofString: "bar", + }, + MapValue: map[string]examplepb.NumericEnum{ + "a": examplepb.NumericEnum_ONE, + "b": examplepb.NumericEnum_ZERO, + }, + } + if !reflect.DeepEqual(got, want) { + t.Errorf("got = %v; want = %v; data = %v", &got, &want, data) + } + } +} + +func TestJSONPbDecoderFields(t *testing.T) { + var m runtime.JSONPb + for _, fixt := range fieldFixtures { + if fixt.skipUnmarshal { + continue + } + + dest := reflect.New(reflect.TypeOf(fixt.data)) + dec := m.NewDecoder(strings.NewReader(fixt.json)) + if err := dec.Decode(dest.Interface()); err != nil { + t.Errorf("dec.Decode(%T) failed with %v; want success; input = %q", dest.Interface(), err, fixt.json) + } + if got, want := dest.Elem().Interface(), fixt.data; !reflect.DeepEqual(got, want) { + t.Errorf("dest = %#v; want %#v; input = %v", got, want, fixt.json) + } + } +} + +func TestJSONPbDecoderUnknownField(t *testing.T) { + var ( + m runtime.JSONPb + got examplepb.ABitOfEverything + ) + data := `{ + "uuid": "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", + "unknownField": "111" + }` + + runtime.DisallowUnknownFields() + + r := strings.NewReader(data) + dec := m.NewDecoder(r) + if err := dec.Decode(&got); err == nil { + t.Errorf("m.Unmarshal(&got) not failed; want `unknown field` error; data=%q", data) + } +} + +var ( + fieldFixtures = []struct { + data interface{} + json string + skipUnmarshal bool + }{ + {data: int32(1), json: "1"}, + {data: proto.Int32(1), json: "1"}, + {data: int64(1), json: "1"}, + {data: proto.Int64(1), json: "1"}, + {data: uint32(1), json: "1"}, + {data: proto.Uint32(1), json: "1"}, + {data: uint64(1), json: "1"}, + {data: proto.Uint64(1), json: "1"}, + {data: "abc", json: `"abc"`}, + {data: proto.String("abc"), json: `"abc"`}, + {data: float32(1.5), json: "1.5"}, + {data: proto.Float32(1.5), json: "1.5"}, + {data: float64(1.5), json: "1.5"}, + {data: proto.Float64(1.5), json: "1.5"}, + {data: true, json: "true"}, + {data: false, json: "false"}, + {data: (*string)(nil), json: "null"}, + { + data: examplepb.NumericEnum_ONE, + json: `"ONE"`, + // TODO(yugui) support unmarshaling of symbolic enum + skipUnmarshal: true, + }, + { + data: (*examplepb.NumericEnum)(proto.Int32(int32(examplepb.NumericEnum_ONE))), + json: `"ONE"`, + // TODO(yugui) support unmarshaling of symbolic enum + skipUnmarshal: true, + }, + + { + data: map[string]int32{ + "foo": 1, + }, + json: `{"foo":1}`, + }, + { + data: map[string]*examplepb.SimpleMessage{ + "foo": {Id: "bar"}, + }, + json: `{"foo":{"id":"bar"}}`, + }, + { + data: map[int32]*examplepb.SimpleMessage{ + 1: {Id: "foo"}, + }, + json: `{"1":{"id":"foo"}}`, + }, + { + data: map[bool]*examplepb.SimpleMessage{ + true: {Id: "foo"}, + }, + json: `{"true":{"id":"foo"}}`, + }, + { + data: &duration.Duration{ + Seconds: 123, + Nanos: 456000000, + }, + json: `"123.456s"`, + }, + { + data: ×tamp.Timestamp{ + Seconds: 1462875553, + Nanos: 123000000, + }, + json: `"2016-05-10T10:19:13.123Z"`, + }, + { + data: new(empty.Empty), + json: "{}", + }, + + // TODO(yugui) Enable unmarshaling of the following examples + // once jsonpb supports them. + { + data: &structpb.Value{ + Kind: new(structpb.Value_NullValue), + }, + json: "null", + skipUnmarshal: true, + }, + { + data: &structpb.Value{ + Kind: &structpb.Value_NumberValue{ + NumberValue: 123.4, + }, + }, + json: "123.4", + skipUnmarshal: true, + }, + { + data: &structpb.Value{ + Kind: &structpb.Value_StringValue{ + StringValue: "abc", + }, + }, + json: `"abc"`, + skipUnmarshal: true, + }, + { + data: &structpb.Value{ + Kind: &structpb.Value_BoolValue{ + BoolValue: true, + }, + }, + json: "true", + skipUnmarshal: true, + }, + { + data: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "foo_bar": { + Kind: &structpb.Value_BoolValue{ + BoolValue: true, + }, + }, + }, + }, + json: `{"foo_bar":true}`, + skipUnmarshal: true, + }, + + { + data: &wrappers.BoolValue{Value: true}, + json: "true", + }, + { + data: &wrappers.DoubleValue{Value: 123.456}, + json: "123.456", + }, + { + data: &wrappers.FloatValue{Value: 123.456}, + json: "123.456", + }, + { + data: &wrappers.Int32Value{Value: -123}, + json: "-123", + }, + { + data: &wrappers.Int64Value{Value: -123}, + json: `"-123"`, + }, + { + data: &wrappers.UInt32Value{Value: 123}, + json: "123", + }, + { + data: &wrappers.UInt64Value{Value: 123}, + json: `"123"`, + }, + // TODO(yugui) Add other well-known types once jsonpb supports them + } +) + +func TestJSONPbMarshalResponseBodies(t *testing.T) { + for i, spec := range []struct { + input interface{} + emitDefaults bool + verifier func(json string) + }{ + { + input: &examplepb.ResponseBodyOut{ + Response: &examplepb.ResponseBodyOut_Response{Data: "abcdef"}, + }, + verifier: func(json string) { + expected := `{"response":{"data":"abcdef"}}` + if json != expected { + t.Errorf("json not equal (%q, %q)", json, expected) + } + }, + }, + { + emitDefaults: true, + input: &examplepb.ResponseBodyOut{}, + verifier: func(json string) { + expected := `{"response":null}` + if json != expected { + t.Errorf("json not equal (%q, %q)", json, expected) + } + }, + }, + { + input: &examplepb.RepeatedResponseBodyOut_Response{}, + verifier: func(json string) { + expected := `{}` + if json != expected { + t.Errorf("json not equal (%q, %q)", json, expected) + } + }, + }, + { + emitDefaults: true, + input: &examplepb.RepeatedResponseBodyOut_Response{}, + verifier: func(json string) { + expected := `{"data":"","type":"UNKNOWN"}` + if json != expected { + t.Errorf("json not equal (%q, %q)", json, expected) + } + }, + }, + { + input: ([]*examplepb.RepeatedResponseBodyOut_Response)(nil), + verifier: func(json string) { + expected := `null` + if json != expected { + t.Errorf("json not equal (%q, %q)", json, expected) + } + }, + }, + { + emitDefaults: true, + input: ([]*examplepb.RepeatedResponseBodyOut_Response)(nil), + verifier: func(json string) { + expected := `[]` + if json != expected { + t.Errorf("json not equal (%q, %q)", json, expected) + } + }, + }, + { + input: []*examplepb.RepeatedResponseBodyOut_Response{}, + verifier: func(json string) { + expected := `[]` + if json != expected { + t.Errorf("json not equal (%q, %q)", json, expected) + } + }, + }, + { + input: []string{"something"}, + verifier: func(json string) { + expected := `["something"]` + if json != expected { + t.Errorf("json not equal (%q, %q)", json, expected) + } + }, + }, + { + input: []string{}, + verifier: func(json string) { + expected := `[]` + if json != expected { + t.Errorf("json not equal (%q, %q)", json, expected) + } + }, + }, + { + input: ([]string)(nil), + verifier: func(json string) { + expected := `null` + if json != expected { + t.Errorf("json not equal (%q, %q)", json, expected) + } + }, + }, + { + emitDefaults: true, + input: ([]string)(nil), + verifier: func(json string) { + expected := `[]` + if json != expected { + t.Errorf("json not equal (%q, %q)", json, expected) + } + }, + }, + { + input: []*examplepb.RepeatedResponseBodyOut_Response{ + &examplepb.RepeatedResponseBodyOut_Response{}, + &examplepb.RepeatedResponseBodyOut_Response{ + Data: "abc", + Type: examplepb.RepeatedResponseBodyOut_Response_A, + }, + }, + verifier: func(json string) { + expected := `[{},{"data":"abc","type":"A"}]` + if json != expected { + t.Errorf("json not equal (%q, %q)", json, expected) + } + }, + }, + { + emitDefaults: true, + input: []*examplepb.RepeatedResponseBodyOut_Response{ + &examplepb.RepeatedResponseBodyOut_Response{}, + &examplepb.RepeatedResponseBodyOut_Response{ + Data: "abc", + Type: examplepb.RepeatedResponseBodyOut_Response_B, + }, + }, + verifier: func(json string) { + expected := `[{"data":"","type":"UNKNOWN"},{"data":"abc","type":"B"}]` + if json != expected { + t.Errorf("json not equal (%q, %q)", json, expected) + } + }, + }, + } { + + t.Run(strconv.Itoa(i), func(t *testing.T) { + m := runtime.JSONPb{ + EmitDefaults: spec.emitDefaults, + } + val := spec.input + buf, err := m.Marshal(val) + if err != nil { + t.Errorf("m.Marshal(%v) failed with %v; want success; spec=%v", val, err, spec) + } + if spec.verifier != nil { + spec.verifier(string(buf)) + } + }) + } +} diff --git a/gateway/runtime/marshal_proto_test.go b/gateway/runtime/marshal_proto_test.go new file mode 100644 index 0000000..d653aca --- /dev/null +++ b/gateway/runtime/marshal_proto_test.go @@ -0,0 +1,91 @@ +package runtime_test + +import ( + "bytes" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes/timestamp" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb" +) + +var message = &examplepb.ABitOfEverything{ + SingleNested: &examplepb.ABitOfEverything_Nested{}, + RepeatedStringValue: nil, + MappedStringValue: nil, + MappedNestedValue: nil, + RepeatedEnumValue: nil, + TimestampValue: ×tamp.Timestamp{}, + Uuid: "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", + Nested: []*examplepb.ABitOfEverything_Nested{ + { + Name: "foo", + Amount: 12345, + }, + }, + Uint64Value: 0xFFFFFFFFFFFFFFFF, + EnumValue: examplepb.NumericEnum_ONE, + OneofValue: &examplepb.ABitOfEverything_OneofString{ + OneofString: "bar", + }, + MapValue: map[string]examplepb.NumericEnum{ + "a": examplepb.NumericEnum_ONE, + "b": examplepb.NumericEnum_ZERO, + }, +} + +func TestProtoMarshalUnmarshal(t *testing.T) { + marshaller := runtime.ProtoMarshaller{} + + // Marshal + buffer, err := marshaller.Marshal(message) + if err != nil { + t.Fatalf("Marshalling returned error: %s", err.Error()) + } + + // Unmarshal + unmarshalled := &examplepb.ABitOfEverything{} + err = marshaller.Unmarshal(buffer, unmarshalled) + if err != nil { + t.Fatalf("Unmarshalling returned error: %s", err.Error()) + } + + if !proto.Equal(unmarshalled, message) { + t.Errorf( + "Unmarshalled didn't match original message: (original = %v) != (unmarshalled = %v)", + unmarshalled, + message, + ) + } +} + +func TestProtoEncoderDecodert(t *testing.T) { + marshaller := runtime.ProtoMarshaller{} + + var buf bytes.Buffer + + encoder := marshaller.NewEncoder(&buf) + decoder := marshaller.NewDecoder(&buf) + + // Encode + err := encoder.Encode(message) + if err != nil { + t.Fatalf("Encoding returned error: %s", err.Error()) + } + + // Decode + unencoded := &examplepb.ABitOfEverything{} + err = decoder.Decode(unencoded) + if err != nil { + t.Fatalf("Unmarshalling returned error: %s", err.Error()) + } + + if !proto.Equal(unencoded, message) { + t.Errorf( + "Unencoded didn't match original message: (original = %v) != (unencoded = %v)", + unencoded, + message, + ) + } +} diff --git a/gateway/runtime/marshaler.go b/gateway/runtime/marshaler.go index 98fe6e8..4615329 100644 --- a/gateway/runtime/marshaler.go +++ b/gateway/runtime/marshaler.go @@ -19,6 +19,13 @@ type Marshaler interface { ContentType() string } +// Marshalers that implement contentTypeMarshaler will have their ContentTypeFromMessage method called +// to set the Content-Type header on the response +type contentTypeMarshaler interface { + // ContentTypeFromMessage returns the Content-Type this marshaler produces from the provided message + ContentTypeFromMessage(v interface{}) string +} + // Decoder decodes a byte sequence type Decoder interface { Decode(v interface{}) error @@ -43,6 +50,6 @@ func (f EncoderFunc) Encode(v interface{}) error { return f(v) } // Delimited defines the streaming delimiter. type Delimited interface { - // Delimiter returns the record seperator for the stream. + // Delimiter returns the record separator for the stream. Delimiter() []byte } diff --git a/gateway/runtime/marshaler_registry.go b/gateway/runtime/marshaler_registry.go index 42e9d15..8dd5c24 100644 --- a/gateway/runtime/marshaler_registry.go +++ b/gateway/runtime/marshaler_registry.go @@ -2,7 +2,10 @@ package runtime import ( "errors" + "mime" "net/http" + + "google.golang.org/grpc/grpclog" ) // MIMEWildcard is the fallback MIME type used for requests which do not match @@ -13,10 +16,7 @@ var ( acceptHeader = http.CanonicalHeaderKey("Accept") contentTypeHeader = http.CanonicalHeaderKey("Content-Type") - defaultMarshaler = &JSONPb{ - OrigName: true, - EnumsAsInts: true, - } + defaultMarshaler = &JSONPb{OrigName: true} ) // MarshalerForRequest returns the inbound/outbound marshalers for this request. @@ -34,7 +34,12 @@ func MarshalerForRequest(mux *ServeMux, r *http.Request) (inbound Marshaler, out } for _, contentTypeVal := range r.Header[contentTypeHeader] { - if m, ok := mux.marshalers.mimeMap[contentTypeVal]; ok { + contentType, _, err := mime.ParseMediaType(contentTypeVal) + if err != nil { + grpclog.Infof("Failed to parse Content-Type %s: %v", contentTypeVal, err) + continue + } + if m, ok := mux.marshalers.mimeMap[contentType]; ok { inbound = m break } diff --git a/gateway/runtime/marshaler_registry_test.go b/gateway/runtime/marshaler_registry_test.go index dfe2269..70bbea5 100644 --- a/gateway/runtime/marshaler_registry_test.go +++ b/gateway/runtime/marshaler_registry_test.go @@ -2,6 +2,7 @@ package runtime_test import ( "errors" + "fmt" "io" "net/http" "testing" @@ -14,11 +15,11 @@ func TestMarshalerForRequest(t *testing.T) { if err != nil { t.Fatalf(`http.NewRequest("GET", "http://example.com", nil) failed with %v; want success`, err) } - r.Header.Set("Accept", "application/x-out") - r.Header.Set("Content-Type", "application/x-in") mux := runtime.NewServeMux() + r.Header.Set("Accept", "application/x-out") + r.Header.Set("Content-Type", "application/x-in") in, out := runtime.MarshalerForRequest(mux, r) if _, ok := in.(*runtime.JSONPb); !ok { t.Errorf("in = %#v; want a runtime.JSONPb", in) @@ -27,23 +28,27 @@ func TestMarshalerForRequest(t *testing.T) { t.Errorf("out = %#v; want a runtime.JSONPb", in) } - var marshalers [3]dummyMarshaler + marshalers := []dummyMarshaler{0, 1, 2} specs := []struct { opt runtime.ServeMuxOption wantIn runtime.Marshaler wantOut runtime.Marshaler }{ + // The option with wildcard overwrites the default configuration { opt: runtime.WithMarshalerOption(runtime.MIMEWildcard, &marshalers[0]), wantIn: &marshalers[0], wantOut: &marshalers[0], }, + // You can specify a marshaler for a specific MIME type. + // The output marshaler follows the input one unless specified. { opt: runtime.WithMarshalerOption("application/x-in", &marshalers[1]), wantIn: &marshalers[1], - wantOut: &marshalers[0], + wantOut: &marshalers[1], }, + // You can also separately specify an output marshaler { opt: runtime.WithMarshalerOption("application/x-out", &marshalers[2]), wantIn: &marshalers[1], @@ -66,17 +71,27 @@ func TestMarshalerForRequest(t *testing.T) { } } - r.Header.Set("Content-Type", "application/x-another") + r.Header.Set("Content-Type", "application/x-in; charset=UTF-8") in, out = runtime.MarshalerForRequest(mux, r) if got, want := in, &marshalers[1]; got != want { t.Errorf("in = %#v; want %#v", got, want) } + if got, want := out, &marshalers[2]; got != want { + t.Errorf("out = %#v; want %#v", got, want) + } + + r.Header.Set("Content-Type", "application/x-another") + r.Header.Set("Accept", "application/x-another") + in, out = runtime.MarshalerForRequest(mux, r) + if got, want := in, &marshalers[0]; got != want { + t.Errorf("in = %#v; want %#v", got, want) + } if got, want := out, &marshalers[0]; got != want { t.Errorf("out = %#v; want %#v", got, want) } } -type dummyMarshaler struct{} +type dummyMarshaler int func (dummyMarshaler) ContentType() string { return "" } func (dummyMarshaler) Marshal(interface{}) ([]byte, error) { @@ -94,6 +109,10 @@ func (dummyMarshaler) NewEncoder(w io.Writer) runtime.Encoder { return dummyEncoder{} } +func (m dummyMarshaler) GoString() string { + return fmt.Sprintf("dummyMarshaler(%d)", m) +} + type dummyDecoder struct{} func (dummyDecoder) Decode(interface{}) error { diff --git a/gateway/runtime/proto_errors.go b/gateway/runtime/proto_errors.go index ca76324..3fd30da 100644 --- a/gateway/runtime/proto_errors.go +++ b/gateway/runtime/proto_errors.go @@ -44,12 +44,12 @@ func DefaultHTTPProtoErrorHandler(ctx context.Context, mux *ServeMux, marshaler w.Header().Del("Trailer") contentType := marshaler.ContentType() - // Check marshaler on run time in order to keep backwards compatability + // Check marshaler on run time in order to keep backwards compatibility // An interface param needs to be added to the ContentType() function on // the Marshal interface to be able to remove this check - if httpBodyMarshaler, ok := marshaler.(*HTTPBodyMarshaler); ok { + if typeMarshaler, ok := marshaler.(contentTypeMarshaler); ok { pb := s.Proto() - contentType = httpBodyMarshaler.ContentTypeFromMessage(pb) + contentType = typeMarshaler.ContentTypeFromMessage(pb) } w.Header().Set("Content-Type", contentType) diff --git a/gateway/runtime/query.go b/gateway/runtime/query.go index 4b9ef0f..ba66842 100644 --- a/gateway/runtime/query.go +++ b/gateway/runtime/query.go @@ -132,14 +132,16 @@ func fieldByProtoName(m reflect.Value, name string) (reflect.Value, *proto.Prope props := proto.GetProperties(m.Type()) // look up field name in oneof map - if op, ok := props.OneofTypes[name]; ok { - v := reflect.New(op.Type.Elem()) - field := m.Field(op.Field) - if !field.IsNil() { - return reflect.Value{}, nil, fmt.Errorf("field already set for %s oneof", props.Prop[op.Field].OrigName) + for _, op := range props.OneofTypes { + if name == op.Prop.OrigName || name == op.Prop.JSONName { + v := reflect.New(op.Type.Elem()) + field := m.Field(op.Field) + if !field.IsNil() { + return reflect.Value{}, nil, fmt.Errorf("field already set for %s oneof", props.Prop[op.Field].OrigName) + } + field.Set(v) + return v.Elem().Field(0), op.Prop, nil } - field.Set(v) - return v.Elem().Field(0), op.Prop, nil } for _, p := range props.Prop { From ed85ea21e7a0683a0a68cc64986d502de11f1877 Mon Sep 17 00:00:00 2001 From: binchen Date: Fri, 10 Jul 2020 17:34:21 +0800 Subject: [PATCH 07/56] Delete github.com/binchencoder/ease-gateway/gateway/protoc-gen-grpc-gateway/httprule, use github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/httprule --- gateway/README.md | 14 - .../descriptor/BUILD.bazel | 4 +- .../descriptor/services.go | 3 +- .../descriptor/services_test.go | 3 +- .../descriptor/types.go | 3 +- .../httprule/BUILD.bazel | 32 -- .../httprule/compile.go | 117 ------ .../httprule/compile_test.go | 122 ------ .../protoc-gen-grpc-gateway/httprule/fuzz.go | 11 - .../protoc-gen-grpc-gateway/httprule/parse.go | 351 ------------------ .../httprule/parse_test.go | 319 ---------------- .../protoc-gen-grpc-gateway/httprule/types.go | 60 --- .../httprule/types_test.go | 91 ----- .../internal/gengateway/BUILD.bazel | 2 +- .../internal/gengateway/template_test.go | 4 +- .../protoc-gen-swagger/genswagger/BUILD.bazel | 2 +- .../genswagger/template_test.go | 4 +- 17 files changed, 11 insertions(+), 1131 deletions(-) delete mode 100644 gateway/protoc-gen-grpc-gateway/httprule/BUILD.bazel delete mode 100644 gateway/protoc-gen-grpc-gateway/httprule/compile.go delete mode 100644 gateway/protoc-gen-grpc-gateway/httprule/compile_test.go delete mode 100644 gateway/protoc-gen-grpc-gateway/httprule/fuzz.go delete mode 100644 gateway/protoc-gen-grpc-gateway/httprule/parse.go delete mode 100644 gateway/protoc-gen-grpc-gateway/httprule/parse_test.go delete mode 100644 gateway/protoc-gen-grpc-gateway/httprule/types.go delete mode 100644 gateway/protoc-gen-grpc-gateway/httprule/types_test.go diff --git a/gateway/README.md b/gateway/README.md index 5a457bd..3dc5aad 100644 --- a/gateway/README.md +++ b/gateway/README.md @@ -72,20 +72,6 @@ protoc -I/usr/local/include -I. \ - template_test.go - template.go -### httprule - -Link [grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/httprule](https://github.com/grpc-ecosystem/grpc-gateway/tree/master/protoc-gen-grpc-gateway/httprule) - -该目录下没有修改代码,直接拷贝的。原因是 grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/httprule package visibility 只能在本项目内依赖 - -``` -package(default_visibility = ["//:generators"]) -``` - -修改文件: - -- BUILD.bazel - ## protoc-gen-swagger Link [grpc-ecosystem/grpc-gateway/protoc-gen-swagger](https://github.com/grpc-ecosystem/grpc-gateway/tree/master/protoc-gen-swagger) diff --git a/gateway/protoc-gen-grpc-gateway/descriptor/BUILD.bazel b/gateway/protoc-gen-grpc-gateway/descriptor/BUILD.bazel index 011317f..4299efb 100644 --- a/gateway/protoc-gen-grpc-gateway/descriptor/BUILD.bazel +++ b/gateway/protoc-gen-grpc-gateway/descriptor/BUILD.bazel @@ -14,13 +14,13 @@ go_library( importpath = "github.com/binchencoder/ease-gateway/gateway/protoc-gen-grpc-gateway/descriptor", deps = [ "//httpoptions:go_default_library", - "//gateway/protoc-gen-grpc-gateway/httprule:go_default_library", "@com_github_binchencoder_gateway_proto//data:go_default_library", "@com_github_ghodss_yaml//:go_default_library", "@com_github_golang_glog//:go_default_library", "@com_github_golang_protobuf//jsonpb:go_default_library_gen", "@com_github_golang_protobuf//proto:go_default_library", "@com_github_golang_protobuf//protoc-gen-go/generator:go_default_library_gen", + "@com_github_grpc_ecosystem_grpc_gateway//protoc-gen-grpc-gateway/httprule:go_default_library", "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", "@io_bazel_rules_go//proto/wkt:descriptor_go_proto", ], @@ -37,8 +37,8 @@ go_test( ], embed = [":go_default_library"], deps = [ - "//gateway/protoc-gen-grpc-gateway/httprule:go_default_library", "@com_github_golang_protobuf//proto:go_default_library", + "@com_github_grpc_ecosystem_grpc_gateway//protoc-gen-grpc-gateway/httprule:go_default_library", "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", "@io_bazel_rules_go//proto/wkt:descriptor_go_proto", ], diff --git a/gateway/protoc-gen-grpc-gateway/descriptor/services.go b/gateway/protoc-gen-grpc-gateway/descriptor/services.go index 1f8acea..41e82f0 100644 --- a/gateway/protoc-gen-grpc-gateway/descriptor/services.go +++ b/gateway/protoc-gen-grpc-gateway/descriptor/services.go @@ -9,8 +9,7 @@ import ( "github.com/golang/protobuf/proto" descriptor "github.com/golang/protobuf/protoc-gen-go/descriptor" - // "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/httprule" - "github.com/binchencoder/ease-gateway/gateway/protoc-gen-grpc-gateway/httprule" + "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/httprule" // options "google.golang.org/genproto/googleapis/api/annotations" options "github.com/binchencoder/ease-gateway/httpoptions" diff --git a/gateway/protoc-gen-grpc-gateway/descriptor/services_test.go b/gateway/protoc-gen-grpc-gateway/descriptor/services_test.go index 1fa2693..8018b0f 100644 --- a/gateway/protoc-gen-grpc-gateway/descriptor/services_test.go +++ b/gateway/protoc-gen-grpc-gateway/descriptor/services_test.go @@ -6,8 +6,7 @@ import ( "github.com/golang/protobuf/proto" descriptor "github.com/golang/protobuf/protoc-gen-go/descriptor" - // "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/httprule" - "github.com/binchencoder/ease-gateway/gateway/protoc-gen-grpc-gateway/httprule" + "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/httprule" ) func compilePath(t *testing.T, path string) httprule.Template { diff --git a/gateway/protoc-gen-grpc-gateway/descriptor/types.go b/gateway/protoc-gen-grpc-gateway/descriptor/types.go index 1001ecb..d796153 100644 --- a/gateway/protoc-gen-grpc-gateway/descriptor/types.go +++ b/gateway/protoc-gen-grpc-gateway/descriptor/types.go @@ -8,8 +8,7 @@ import ( "github.com/golang/protobuf/protoc-gen-go/descriptor" gogen "github.com/golang/protobuf/protoc-gen-go/generator" - // "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/httprule" - "github.com/binchencoder/ease-gateway/gateway/protoc-gen-grpc-gateway/httprule" + "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/httprule" options "github.com/binchencoder/ease-gateway/httpoptions" "github.com/binchencoder/gateway-proto/data" diff --git a/gateway/protoc-gen-grpc-gateway/httprule/BUILD.bazel b/gateway/protoc-gen-grpc-gateway/httprule/BUILD.bazel deleted file mode 100644 index 957db8f..0000000 --- a/gateway/protoc-gen-grpc-gateway/httprule/BUILD.bazel +++ /dev/null @@ -1,32 +0,0 @@ -load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") - -package(default_visibility = ["//visibility:public"]) - -go_library( - name = "go_default_library", - srcs = [ - "compile.go", - "parse.go", - "types.go", - ], - importpath = "github.com/binchencoder/ease-gateway/gateway/protoc-gen-grpc-gateway/httprule", - deps = [ - "@com_github_golang_glog//:go_default_library", - "@com_github_grpc_ecosystem_grpc_gateway//utilities:go_default_library", - ], -) - -go_test( - name = "go_default_test", - size = "small", - srcs = [ - "compile_test.go", - "parse_test.go", - "types_test.go", - ], - embed = [":go_default_library"], - deps = [ - "@com_github_golang_glog//:go_default_library", - "@com_github_grpc_ecosystem_grpc_gateway//utilities:go_default_library", - ], -) diff --git a/gateway/protoc-gen-grpc-gateway/httprule/compile.go b/gateway/protoc-gen-grpc-gateway/httprule/compile.go deleted file mode 100644 index 437039a..0000000 --- a/gateway/protoc-gen-grpc-gateway/httprule/compile.go +++ /dev/null @@ -1,117 +0,0 @@ -package httprule - -import ( - "github.com/grpc-ecosystem/grpc-gateway/utilities" -) - -const ( - opcodeVersion = 1 -) - -// Template is a compiled representation of path templates. -type Template struct { - // Version is the version number of the format. - Version int - // OpCodes is a sequence of operations. - OpCodes []int - // Pool is a constant pool - Pool []string - // Verb is a VERB part in the template. - Verb string - // Fields is a list of field paths bound in this template. - Fields []string - // Original template (example: /v1/a_bit_of_everything) - Template string -} - -// Compiler compiles utilities representation of path templates into marshallable operations. -// They can be unmarshalled by runtime.NewPattern. -type Compiler interface { - Compile() Template -} - -type op struct { - // code is the opcode of the operation - code utilities.OpCode - - // str is a string operand of the code. - // num is ignored if str is not empty. - str string - - // num is a numeric operand of the code. - num int -} - -func (w wildcard) compile() []op { - return []op{ - {code: utilities.OpPush}, - } -} - -func (w deepWildcard) compile() []op { - return []op{ - {code: utilities.OpPushM}, - } -} - -func (l literal) compile() []op { - return []op{ - { - code: utilities.OpLitPush, - str: string(l), - }, - } -} - -func (v variable) compile() []op { - var ops []op - for _, s := range v.segments { - ops = append(ops, s.compile()...) - } - ops = append(ops, op{ - code: utilities.OpConcatN, - num: len(v.segments), - }, op{ - code: utilities.OpCapture, - str: v.path, - }) - - return ops -} - -func (t template) Compile() Template { - var rawOps []op - for _, s := range t.segments { - rawOps = append(rawOps, s.compile()...) - } - - var ( - ops []int - pool []string - fields []string - ) - consts := make(map[string]int) - for _, op := range rawOps { - ops = append(ops, int(op.code)) - if op.str == "" { - ops = append(ops, op.num) - } else { - if _, ok := consts[op.str]; !ok { - consts[op.str] = len(pool) - pool = append(pool, op.str) - } - ops = append(ops, consts[op.str]) - } - if op.code == utilities.OpCapture { - fields = append(fields, op.str) - } - } - return Template{ - Version: opcodeVersion, - OpCodes: ops, - Pool: pool, - Verb: t.verb, - Fields: fields, - Template: t.template, - } -} diff --git a/gateway/protoc-gen-grpc-gateway/httprule/compile_test.go b/gateway/protoc-gen-grpc-gateway/httprule/compile_test.go deleted file mode 100644 index 9ef2975..0000000 --- a/gateway/protoc-gen-grpc-gateway/httprule/compile_test.go +++ /dev/null @@ -1,122 +0,0 @@ -package httprule - -import ( - "reflect" - "testing" - - "github.com/grpc-ecosystem/grpc-gateway/utilities" -) - -const ( - operandFiller = 0 -) - -func TestCompile(t *testing.T) { - for _, spec := range []struct { - segs []segment - verb string - - ops []int - pool []string - fields []string - }{ - {}, - { - segs: []segment{ - wildcard{}, - }, - ops: []int{int(utilities.OpPush), operandFiller}, - }, - { - segs: []segment{ - deepWildcard{}, - }, - ops: []int{int(utilities.OpPushM), operandFiller}, - }, - { - segs: []segment{ - literal("v1"), - }, - ops: []int{int(utilities.OpLitPush), 0}, - pool: []string{"v1"}, - }, - { - segs: []segment{ - literal("v1"), - }, - verb: "LOCK", - ops: []int{int(utilities.OpLitPush), 0}, - pool: []string{"v1"}, - }, - { - segs: []segment{ - variable{ - path: "name.nested", - segments: []segment{ - wildcard{}, - }, - }, - }, - ops: []int{ - int(utilities.OpPush), operandFiller, - int(utilities.OpConcatN), 1, - int(utilities.OpCapture), 0, - }, - pool: []string{"name.nested"}, - fields: []string{"name.nested"}, - }, - { - segs: []segment{ - literal("obj"), - variable{ - path: "name.nested", - segments: []segment{ - literal("a"), - wildcard{}, - literal("b"), - }, - }, - variable{ - path: "obj", - segments: []segment{ - deepWildcard{}, - }, - }, - }, - ops: []int{ - int(utilities.OpLitPush), 0, - int(utilities.OpLitPush), 1, - int(utilities.OpPush), operandFiller, - int(utilities.OpLitPush), 2, - int(utilities.OpConcatN), 3, - int(utilities.OpCapture), 3, - int(utilities.OpPushM), operandFiller, - int(utilities.OpConcatN), 1, - int(utilities.OpCapture), 0, - }, - pool: []string{"obj", "a", "b", "name.nested"}, - fields: []string{"name.nested", "obj"}, - }, - } { - tmpl := template{ - segments: spec.segs, - verb: spec.verb, - } - compiled := tmpl.Compile() - if got, want := compiled.Version, opcodeVersion; got != want { - t.Errorf("tmpl.Compile().Version = %d; want %d; segs=%#v, verb=%q", got, want, spec.segs, spec.verb) - } - if got, want := compiled.OpCodes, spec.ops; !reflect.DeepEqual(got, want) { - t.Errorf("tmpl.Compile().OpCodes = %v; want %v; segs=%#v, verb=%q", got, want, spec.segs, spec.verb) - } - if got, want := compiled.Pool, spec.pool; !reflect.DeepEqual(got, want) { - t.Errorf("tmpl.Compile().Pool = %q; want %q; segs=%#v, verb=%q", got, want, spec.segs, spec.verb) - } - if got, want := compiled.Verb, spec.verb; got != want { - t.Errorf("tmpl.Compile().Verb = %q; want %q; segs=%#v, verb=%q", got, want, spec.segs, spec.verb) - } - if got, want := compiled.Fields, spec.fields; !reflect.DeepEqual(got, want) { - t.Errorf("tmpl.Compile().Fields = %q; want %q; segs=%#v, verb=%q", got, want, spec.segs, spec.verb) - } - } -} diff --git a/gateway/protoc-gen-grpc-gateway/httprule/fuzz.go b/gateway/protoc-gen-grpc-gateway/httprule/fuzz.go deleted file mode 100644 index 138f7c1..0000000 --- a/gateway/protoc-gen-grpc-gateway/httprule/fuzz.go +++ /dev/null @@ -1,11 +0,0 @@ -// +build gofuzz - -package httprule - -func Fuzz(data []byte) int { - _, err := Parse(string(data)) - if err != nil { - return 0 - } - return 0 -} diff --git a/gateway/protoc-gen-grpc-gateway/httprule/parse.go b/gateway/protoc-gen-grpc-gateway/httprule/parse.go deleted file mode 100644 index f933cd8..0000000 --- a/gateway/protoc-gen-grpc-gateway/httprule/parse.go +++ /dev/null @@ -1,351 +0,0 @@ -package httprule - -import ( - "fmt" - "strings" - - "github.com/golang/glog" -) - -// InvalidTemplateError indicates that the path template is not valid. -type InvalidTemplateError struct { - tmpl string - msg string -} - -func (e InvalidTemplateError) Error() string { - return fmt.Sprintf("%s: %s", e.msg, e.tmpl) -} - -// Parse parses the string representation of path template -func Parse(tmpl string) (Compiler, error) { - if !strings.HasPrefix(tmpl, "/") { - return template{}, InvalidTemplateError{tmpl: tmpl, msg: "no leading /"} - } - tokens, verb := tokenize(tmpl[1:]) - - p := parser{tokens: tokens} - segs, err := p.topLevelSegments() - if err != nil { - return template{}, InvalidTemplateError{tmpl: tmpl, msg: err.Error()} - } - - return template{ - segments: segs, - verb: verb, - template: tmpl, - }, nil -} - -func tokenize(path string) (tokens []string, verb string) { - if path == "" { - return []string{eof}, "" - } - - const ( - init = iota - field - nested - ) - var ( - st = init - ) - for path != "" { - var idx int - switch st { - case init: - idx = strings.IndexAny(path, "/{") - case field: - idx = strings.IndexAny(path, ".=}") - case nested: - idx = strings.IndexAny(path, "/}") - } - if idx < 0 { - tokens = append(tokens, path) - break - } - switch r := path[idx]; r { - case '/', '.': - case '{': - st = field - case '=': - st = nested - case '}': - st = init - } - if idx == 0 { - tokens = append(tokens, path[idx:idx+1]) - } else { - tokens = append(tokens, path[:idx], path[idx:idx+1]) - } - path = path[idx+1:] - } - - l := len(tokens) - t := tokens[l-1] - if idx := strings.LastIndex(t, ":"); idx == 0 { - tokens, verb = tokens[:l-1], t[1:] - } else if idx > 0 { - tokens[l-1], verb = t[:idx], t[idx+1:] - } - tokens = append(tokens, eof) - return tokens, verb -} - -// parser is a parser of the template syntax defined in github.com/googleapis/googleapis/google/api/http.proto. -type parser struct { - tokens []string - accepted []string -} - -// topLevelSegments is the target of this parser. -func (p *parser) topLevelSegments() ([]segment, error) { - glog.V(1).Infof("Parsing %q", p.tokens) - segs, err := p.segments() - if err != nil { - return nil, err - } - glog.V(2).Infof("accept segments: %q; %q", p.accepted, p.tokens) - if _, err := p.accept(typeEOF); err != nil { - return nil, fmt.Errorf("unexpected token %q after segments %q", p.tokens[0], strings.Join(p.accepted, "")) - } - glog.V(2).Infof("accept eof: %q; %q", p.accepted, p.tokens) - return segs, nil -} - -func (p *parser) segments() ([]segment, error) { - s, err := p.segment() - if err != nil { - return nil, err - } - glog.V(2).Infof("accept segment: %q; %q", p.accepted, p.tokens) - - segs := []segment{s} - for { - if _, err := p.accept("/"); err != nil { - return segs, nil - } - s, err := p.segment() - if err != nil { - return segs, err - } - segs = append(segs, s) - glog.V(2).Infof("accept segment: %q; %q", p.accepted, p.tokens) - } -} - -func (p *parser) segment() (segment, error) { - if _, err := p.accept("*"); err == nil { - return wildcard{}, nil - } - if _, err := p.accept("**"); err == nil { - return deepWildcard{}, nil - } - if l, err := p.literal(); err == nil { - return l, nil - } - - v, err := p.variable() - if err != nil { - return nil, fmt.Errorf("segment neither wildcards, literal or variable: %v", err) - } - return v, err -} - -func (p *parser) literal() (segment, error) { - lit, err := p.accept(typeLiteral) - if err != nil { - return nil, err - } - return literal(lit), nil -} - -func (p *parser) variable() (segment, error) { - if _, err := p.accept("{"); err != nil { - return nil, err - } - - path, err := p.fieldPath() - if err != nil { - return nil, err - } - - var segs []segment - if _, err := p.accept("="); err == nil { - segs, err = p.segments() - if err != nil { - return nil, fmt.Errorf("invalid segment in variable %q: %v", path, err) - } - } else { - segs = []segment{wildcard{}} - } - - if _, err := p.accept("}"); err != nil { - return nil, fmt.Errorf("unterminated variable segment: %s", path) - } - return variable{ - path: path, - segments: segs, - }, nil -} - -func (p *parser) fieldPath() (string, error) { - c, err := p.accept(typeIdent) - if err != nil { - return "", err - } - components := []string{c} - for { - if _, err = p.accept("."); err != nil { - return strings.Join(components, "."), nil - } - c, err := p.accept(typeIdent) - if err != nil { - return "", fmt.Errorf("invalid field path component: %v", err) - } - components = append(components, c) - } -} - -// A termType is a type of terminal symbols. -type termType string - -// These constants define some of valid values of termType. -// They improve readability of parse functions. -// -// You can also use "/", "*", "**", "." or "=" as valid values. -const ( - typeIdent = termType("ident") - typeLiteral = termType("literal") - typeEOF = termType("$") -) - -const ( - // eof is the terminal symbol which always appears at the end of token sequence. - eof = "\u0000" -) - -// accept tries to accept a token in "p". -// This function consumes a token and returns it if it matches to the specified "term". -// If it doesn't match, the function does not consume any tokens and return an error. -func (p *parser) accept(term termType) (string, error) { - t := p.tokens[0] - switch term { - case "/", "*", "**", ".", "=", "{", "}": - if t != string(term) && t != "/" { - return "", fmt.Errorf("expected %q but got %q", term, t) - } - case typeEOF: - if t != eof { - return "", fmt.Errorf("expected EOF but got %q", t) - } - case typeIdent: - if err := expectIdent(t); err != nil { - return "", err - } - case typeLiteral: - if err := expectPChars(t); err != nil { - return "", err - } - default: - return "", fmt.Errorf("unknown termType %q", term) - } - p.tokens = p.tokens[1:] - p.accepted = append(p.accepted, t) - return t, nil -} - -// expectPChars determines if "t" consists of only pchars defined in RFC3986. -// -// https://www.ietf.org/rfc/rfc3986.txt, P.49 -// pchar = unreserved / pct-encoded / sub-delims / ":" / "@" -// unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" -// sub-delims = "!" / "$" / "&" / "'" / "(" / ")" -// / "*" / "+" / "," / ";" / "=" -// pct-encoded = "%" HEXDIG HEXDIG -func expectPChars(t string) error { - const ( - init = iota - pct1 - pct2 - ) - st := init - for _, r := range t { - if st != init { - if !isHexDigit(r) { - return fmt.Errorf("invalid hexdigit: %c(%U)", r, r) - } - switch st { - case pct1: - st = pct2 - case pct2: - st = init - } - continue - } - - // unreserved - switch { - case 'A' <= r && r <= 'Z': - continue - case 'a' <= r && r <= 'z': - continue - case '0' <= r && r <= '9': - continue - } - switch r { - case '-', '.', '_', '~': - // unreserved - case '!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=': - // sub-delims - case ':', '@': - // rest of pchar - case '%': - // pct-encoded - st = pct1 - default: - return fmt.Errorf("invalid character in path segment: %q(%U)", r, r) - } - } - if st != init { - return fmt.Errorf("invalid percent-encoding in %q", t) - } - return nil -} - -// expectIdent determines if "ident" is a valid identifier in .proto schema ([[:alpha:]_][[:alphanum:]_]*). -func expectIdent(ident string) error { - if ident == "" { - return fmt.Errorf("empty identifier") - } - for pos, r := range ident { - switch { - case '0' <= r && r <= '9': - if pos == 0 { - return fmt.Errorf("identifier starting with digit: %s", ident) - } - continue - case 'A' <= r && r <= 'Z': - continue - case 'a' <= r && r <= 'z': - continue - case r == '_': - continue - default: - return fmt.Errorf("invalid character %q(%U) in identifier: %s", r, r, ident) - } - } - return nil -} - -func isHexDigit(r rune) bool { - switch { - case '0' <= r && r <= '9': - return true - case 'A' <= r && r <= 'F': - return true - case 'a' <= r && r <= 'f': - return true - } - return false -} diff --git a/gateway/protoc-gen-grpc-gateway/httprule/parse_test.go b/gateway/protoc-gen-grpc-gateway/httprule/parse_test.go deleted file mode 100644 index 6508e82..0000000 --- a/gateway/protoc-gen-grpc-gateway/httprule/parse_test.go +++ /dev/null @@ -1,319 +0,0 @@ -package httprule - -import ( - "flag" - "fmt" - "reflect" - "testing" - - "github.com/golang/glog" -) - -func TestTokenize(t *testing.T) { - for _, spec := range []struct { - src string - tokens []string - }{ - { - src: "", - tokens: []string{eof}, - }, - { - src: "v1", - tokens: []string{"v1", eof}, - }, - { - src: "v1/b", - tokens: []string{"v1", "/", "b", eof}, - }, - { - src: "v1/endpoint/*", - tokens: []string{"v1", "/", "endpoint", "/", "*", eof}, - }, - { - src: "v1/endpoint/**", - tokens: []string{"v1", "/", "endpoint", "/", "**", eof}, - }, - { - src: "v1/b/{bucket_name=*}", - tokens: []string{ - "v1", "/", - "b", "/", - "{", "bucket_name", "=", "*", "}", - eof, - }, - }, - { - src: "v1/b/{bucket_name=buckets/*}", - tokens: []string{ - "v1", "/", - "b", "/", - "{", "bucket_name", "=", "buckets", "/", "*", "}", - eof, - }, - }, - { - src: "v1/b/{bucket_name=buckets/*}/o", - tokens: []string{ - "v1", "/", - "b", "/", - "{", "bucket_name", "=", "buckets", "/", "*", "}", "/", - "o", - eof, - }, - }, - { - src: "v1/b/{bucket_name=buckets/*}/o/{name}", - tokens: []string{ - "v1", "/", - "b", "/", - "{", "bucket_name", "=", "buckets", "/", "*", "}", "/", - "o", "/", "{", "name", "}", - eof, - }, - }, - { - src: "v1/a=b&c=d;e=f:g/endpoint.rdf", - tokens: []string{ - "v1", "/", - "a=b&c=d;e=f:g", "/", - "endpoint.rdf", - eof, - }, - }, - } { - tokens, verb := tokenize(spec.src) - if got, want := tokens, spec.tokens; !reflect.DeepEqual(got, want) { - t.Errorf("tokenize(%q) = %q, _; want %q, _", spec.src, got, want) - } - if got, want := verb, ""; got != want { - t.Errorf("tokenize(%q) = _, %q; want _, %q", spec.src, got, want) - } - - src := fmt.Sprintf("%s:%s", spec.src, "LOCK") - tokens, verb = tokenize(src) - if got, want := tokens, spec.tokens; !reflect.DeepEqual(got, want) { - t.Errorf("tokenize(%q) = %q, _; want %q, _", src, got, want) - } - if got, want := verb, "LOCK"; got != want { - t.Errorf("tokenize(%q) = _, %q; want _, %q", src, got, want) - } - } -} - -func TestParseSegments(t *testing.T) { - flag.Set("v", "3") - for _, spec := range []struct { - tokens []string - want []segment - }{ - { - tokens: []string{"v1", eof}, - want: []segment{ - literal("v1"), - }, - }, - { - tokens: []string{"/", eof}, - want: []segment{ - wildcard{}, - }, - }, - { - tokens: []string{"-._~!$&'()*+,;=:@", eof}, - want: []segment{ - literal("-._~!$&'()*+,;=:@"), - }, - }, - { - tokens: []string{"%e7%ac%ac%e4%b8%80%e7%89%88", eof}, - want: []segment{ - literal("%e7%ac%ac%e4%b8%80%e7%89%88"), - }, - }, - { - tokens: []string{"v1", "/", "*", eof}, - want: []segment{ - literal("v1"), - wildcard{}, - }, - }, - { - tokens: []string{"v1", "/", "**", eof}, - want: []segment{ - literal("v1"), - deepWildcard{}, - }, - }, - { - tokens: []string{"{", "name", "}", eof}, - want: []segment{ - variable{ - path: "name", - segments: []segment{ - wildcard{}, - }, - }, - }, - }, - { - tokens: []string{"{", "name", "=", "*", "}", eof}, - want: []segment{ - variable{ - path: "name", - segments: []segment{ - wildcard{}, - }, - }, - }, - }, - { - tokens: []string{"{", "field", ".", "nested", ".", "nested2", "=", "*", "}", eof}, - want: []segment{ - variable{ - path: "field.nested.nested2", - segments: []segment{ - wildcard{}, - }, - }, - }, - }, - { - tokens: []string{"{", "name", "=", "a", "/", "b", "/", "*", "}", eof}, - want: []segment{ - variable{ - path: "name", - segments: []segment{ - literal("a"), - literal("b"), - wildcard{}, - }, - }, - }, - }, - { - tokens: []string{ - "v1", "/", - "{", - "name", ".", "nested", ".", "nested2", - "=", - "a", "/", "b", "/", "*", - "}", "/", - "o", "/", - "{", - "another_name", - "=", - "a", "/", "b", "/", "*", "/", "c", - "}", "/", - "**", - eof}, - want: []segment{ - literal("v1"), - variable{ - path: "name.nested.nested2", - segments: []segment{ - literal("a"), - literal("b"), - wildcard{}, - }, - }, - literal("o"), - variable{ - path: "another_name", - segments: []segment{ - literal("a"), - literal("b"), - wildcard{}, - literal("c"), - }, - }, - deepWildcard{}, - }, - }, - } { - p := parser{tokens: spec.tokens} - segs, err := p.topLevelSegments() - if err != nil { - t.Errorf("parser{%q}.segments() failed with %v; want success", spec.tokens, err) - continue - } - if got, want := segs, spec.want; !reflect.DeepEqual(got, want) { - t.Errorf("parser{%q}.segments() = %#v; want %#v", spec.tokens, got, want) - } - if got := p.tokens; len(got) > 0 { - t.Errorf("p.tokens = %q; want []; spec.tokens=%q", got, spec.tokens) - } - } -} - -func TestParseSegmentsWithErrors(t *testing.T) { - flag.Set("v", "3") - for _, spec := range []struct { - tokens []string - }{ - { - // double slash - tokens: []string{"//", eof}, - }, - { - // invalid literal - tokens: []string{"a?b", eof}, - }, - { - // invalid percent-encoding - tokens: []string{"%", eof}, - }, - { - // invalid percent-encoding - tokens: []string{"%2", eof}, - }, - { - // invalid percent-encoding - tokens: []string{"a%2z", eof}, - }, - { - // empty segments - tokens: []string{eof}, - }, - { - // unterminated variable - tokens: []string{"{", "name", eof}, - }, - { - // unterminated variable - tokens: []string{"{", "name", "=", eof}, - }, - { - // unterminated variable - tokens: []string{"{", "name", "=", "*", eof}, - }, - { - // empty component in field path - tokens: []string{"{", "name", ".", "}", eof}, - }, - { - // empty component in field path - tokens: []string{"{", "name", ".", ".", "nested", "}", eof}, - }, - { - // invalid character in identifier - tokens: []string{"{", "field-name", "}", eof}, - }, - { - // no slash between segments - tokens: []string{"v1", "endpoint", eof}, - }, - { - // no slash between segments - tokens: []string{"v1", "{", "name", "}", eof}, - }, - } { - p := parser{tokens: spec.tokens} - segs, err := p.topLevelSegments() - if err == nil { - t.Errorf("parser{%q}.segments() succeeded; want InvalidTemplateError; accepted %#v", spec.tokens, segs) - continue - } - glog.V(1).Info(err) - } -} diff --git a/gateway/protoc-gen-grpc-gateway/httprule/types.go b/gateway/protoc-gen-grpc-gateway/httprule/types.go deleted file mode 100644 index 5a814a0..0000000 --- a/gateway/protoc-gen-grpc-gateway/httprule/types.go +++ /dev/null @@ -1,60 +0,0 @@ -package httprule - -import ( - "fmt" - "strings" -) - -type template struct { - segments []segment - verb string - template string -} - -type segment interface { - fmt.Stringer - compile() (ops []op) -} - -type wildcard struct{} - -type deepWildcard struct{} - -type literal string - -type variable struct { - path string - segments []segment -} - -func (wildcard) String() string { - return "*" -} - -func (deepWildcard) String() string { - return "**" -} - -func (l literal) String() string { - return string(l) -} - -func (v variable) String() string { - var segs []string - for _, s := range v.segments { - segs = append(segs, s.String()) - } - return fmt.Sprintf("{%s=%s}", v.path, strings.Join(segs, "/")) -} - -func (t template) String() string { - var segs []string - for _, s := range t.segments { - segs = append(segs, s.String()) - } - str := strings.Join(segs, "/") - if t.verb != "" { - str = fmt.Sprintf("%s:%s", str, t.verb) - } - return "/" + str -} diff --git a/gateway/protoc-gen-grpc-gateway/httprule/types_test.go b/gateway/protoc-gen-grpc-gateway/httprule/types_test.go deleted file mode 100644 index 7ed0c5c..0000000 --- a/gateway/protoc-gen-grpc-gateway/httprule/types_test.go +++ /dev/null @@ -1,91 +0,0 @@ -package httprule - -import ( - "fmt" - "testing" -) - -func TestTemplateStringer(t *testing.T) { - for _, spec := range []struct { - segs []segment - want string - }{ - { - segs: []segment{ - literal("v1"), - }, - want: "/v1", - }, - { - segs: []segment{ - wildcard{}, - }, - want: "/*", - }, - { - segs: []segment{ - deepWildcard{}, - }, - want: "/**", - }, - { - segs: []segment{ - variable{ - path: "name", - segments: []segment{ - literal("a"), - }, - }, - }, - want: "/{name=a}", - }, - { - segs: []segment{ - variable{ - path: "name", - segments: []segment{ - literal("a"), - wildcard{}, - literal("b"), - }, - }, - }, - want: "/{name=a/*/b}", - }, - { - segs: []segment{ - literal("v1"), - variable{ - path: "name", - segments: []segment{ - literal("a"), - wildcard{}, - literal("b"), - }, - }, - literal("c"), - variable{ - path: "field.nested", - segments: []segment{ - wildcard{}, - literal("d"), - }, - }, - wildcard{}, - literal("e"), - deepWildcard{}, - }, - want: "/v1/{name=a/*/b}/c/{field.nested=*/d}/*/e/**", - }, - } { - tmpl := template{segments: spec.segs} - if got, want := tmpl.String(), spec.want; got != want { - t.Errorf("%#v.String() = %q; want %q", tmpl, got, want) - } - - tmpl.verb = "LOCK" - if got, want := tmpl.String(), fmt.Sprintf("%s:LOCK", spec.want); got != want { - t.Errorf("%#v.String() = %q; want %q", tmpl, got, want) - } - } -} diff --git a/gateway/protoc-gen-grpc-gateway/internal/gengateway/BUILD.bazel b/gateway/protoc-gen-grpc-gateway/internal/gengateway/BUILD.bazel index 0124921..ce5a0df 100644 --- a/gateway/protoc-gen-grpc-gateway/internal/gengateway/BUILD.bazel +++ b/gateway/protoc-gen-grpc-gateway/internal/gengateway/BUILD.bazel @@ -33,8 +33,8 @@ go_test( embed = [":go_default_library"], deps = [ "//gateway/protoc-gen-grpc-gateway/descriptor:go_default_library", - "//gateway/protoc-gen-grpc-gateway/httprule:go_default_library", "@com_github_golang_protobuf//proto:go_default_library", + "@com_github_grpc_ecosystem_grpc_gateway//protoc-gen-grpc-gateway/httprule:go_default_library", "@io_bazel_rules_go//proto/wkt:descriptor_go_proto", ], ) diff --git a/gateway/protoc-gen-grpc-gateway/internal/gengateway/template_test.go b/gateway/protoc-gen-grpc-gateway/internal/gengateway/template_test.go index e500b3e..92e1a01 100644 --- a/gateway/protoc-gen-grpc-gateway/internal/gengateway/template_test.go +++ b/gateway/protoc-gen-grpc-gateway/internal/gengateway/template_test.go @@ -6,10 +6,10 @@ import ( "github.com/golang/protobuf/proto" protodescriptor "github.com/golang/protobuf/protoc-gen-go/descriptor" + // "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/descriptor" "github.com/binchencoder/ease-gateway/gateway/protoc-gen-grpc-gateway/descriptor" - // "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/httprule" - "github.com/binchencoder/ease-gateway/gateway/protoc-gen-grpc-gateway/httprule" + "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/httprule" ) func crossLinkFixture(f *descriptor.File) *descriptor.File { diff --git a/gateway/protoc-gen-swagger/genswagger/BUILD.bazel b/gateway/protoc-gen-swagger/genswagger/BUILD.bazel index ee9f347..ab7a3f8 100644 --- a/gateway/protoc-gen-swagger/genswagger/BUILD.bazel +++ b/gateway/protoc-gen-swagger/genswagger/BUILD.bazel @@ -38,9 +38,9 @@ go_test( embed = [":go_default_library"], deps = [ "//gateway/protoc-gen-grpc-gateway/descriptor:go_default_library", - "//gateway/protoc-gen-grpc-gateway/httprule:go_default_library", "//gateway/protoc-gen-swagger/options:go_default_library", "@com_github_golang_protobuf//proto:go_default_library", + "@com_github_grpc_ecosystem_grpc_gateway//protoc-gen-grpc-gateway/httprule:go_default_library", "@io_bazel_rules_go//proto/wkt:any_go_proto", "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", "@io_bazel_rules_go//proto/wkt:descriptor_go_proto", diff --git a/gateway/protoc-gen-swagger/genswagger/template_test.go b/gateway/protoc-gen-swagger/genswagger/template_test.go index 2571d87..ac6cf0e 100644 --- a/gateway/protoc-gen-swagger/genswagger/template_test.go +++ b/gateway/protoc-gen-swagger/genswagger/template_test.go @@ -12,11 +12,11 @@ import ( plugin "github.com/golang/protobuf/protoc-gen-go/plugin" "github.com/golang/protobuf/ptypes/any" structpb "github.com/golang/protobuf/ptypes/struct" + // "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/descriptor" "github.com/binchencoder/ease-gateway/gateway/protoc-gen-grpc-gateway/descriptor" - // "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/httprule" - "github.com/binchencoder/ease-gateway/gateway/protoc-gen-grpc-gateway/httprule" + "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/httprule" // swagger_options "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger/options" swagger_options "github.com/binchencoder/ease-gateway/gateway/protoc-gen-swagger/options" From 935167ffc8949926c19dc1a37167db1d1771e4f6 Mon Sep 17 00:00:00 2001 From: binchen Date: Fri, 10 Jul 2020 17:48:47 +0800 Subject: [PATCH 08/56] Update README.md --- README.md | 32 +++++--------------------------- 1 file changed, 5 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index 1e03d24..2e2a0c8 100644 --- a/README.md +++ b/README.md @@ -17,39 +17,17 @@ Gateway service based on [grpc-ecosystem/grpc-gateway](https://github.com/grpc-e ## Prepared -**ease-gateway** 在编译时需要依赖其他的repo, 为了编译时方便, 在WORKSPACE中定义的是依赖本地的repository, 这样在`bazel build` 时就不会再次从远程仓库下载代码. 因此在编译ease-gateway 之前需要将依赖的repositories下载到本地, 并放在与ease-gateway的同级目录 +**ease-gateway** 使用GO MOD来管理Dependencies,clone代码之后直接在本地使用bazel构建 -目前依赖本地的repo有: +### Build tools -- gateway-proto [https://github.com/binchencoder/gateway-proto] -- letsgo [https://github.com/binchencoder/letsgo.git] -- skylb-api [https://github.com/binchencoder/skylb-api.git] - -``` -git clone https://github.com/binchencoder/gateway-proto.git -git clone https://github.com/binchencoder/letsgo.git -git clone https://github.com/binchencoder/skylb-api.git -``` +- Bazel 3.1.0+ +- Go 1.13.12+ ## Clone code -``` +```shell git clone https://github.com/binchencoder/ease-gateway.git - -git clone https://github.com/binchencoder/gateway-proto.git -git clone https://github.com/binchencoder/letsgo.git -git clone https://github.com/binchencoder/skylb-api.git -``` -> 也可以连同submodules一起clone到本地 -``` -git clone --recurse-submodules https://github.com/binchencoder/ease-gateway.git -``` - -## Sync submodule - -``` -git submodule init -git submodule update ``` ## Bazel build gateway From d29e845f40749262e05cf02690d740e4cd0a5583 Mon Sep 17 00:00:00 2001 From: chenbin1314 Date: Sat, 11 Jul 2020 11:43:58 +0800 Subject: [PATCH 09/56] Synchronization with github.com/grpc-ecosystem/grpc-gateway //gateway code in the directory --- .../internal/gengateway/generator.go | 60 +++++++++++++------ .../internal/gengateway/template.go | 43 ++++++++----- gateway/protoc-gen-grpc-gateway/main.go | 3 +- 3 files changed, 71 insertions(+), 35 deletions(-) diff --git a/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator.go b/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator.go index f229696..9c94b23 100644 --- a/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator.go +++ b/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator.go @@ -38,11 +38,12 @@ type generator struct { useRequestContext bool registerFuncSuffix string pathType pathType + modulePath string allowPatchFeature bool } // New returns a new generator which generates grpc gateway files. -func New(reg *descriptor.Registry, useRequestContext bool, registerFuncSuffix, pathTypeString string, allowPatchFeature bool) gen.Generator { +func New(reg *descriptor.Registry, useRequestContext bool, registerFuncSuffix, pathTypeString, modulePathString string, allowPatchFeature bool) gen.Generator { var imports []descriptor.GoPackage for pkgpath, alias := range map[string]string{ "context": "", @@ -52,20 +53,20 @@ func New(reg *descriptor.Registry, useRequestContext bool, registerFuncSuffix, p "strings": "", "sync": "", "unicode/utf8": "", - "github.com/binchencoder/ease-gateway/gateway/runtime": "", - "github.com/grpc-ecosystem/grpc-gateway/utilities": "", - "github.com/golang/protobuf/proto": "", - "github.com/binchencoder/gateway-proto/data": "vexpb", - "github.com/binchencoder/gateway-proto/frontend": "fpb", - "github.com/binchencoder/letsgo/grpc": "lgr", - "github.com/binchencoder/skylb-api/balancer": "", - "github.com/binchencoder/skylb-api/client": "", - "github.com/binchencoder/skylb-api/client/option": "", - "github.com/binchencoder/skylb-api/proto": "skypb", - "google.golang.org/grpc": "", - "google.golang.org/grpc/codes": "", - "google.golang.org/grpc/naming": "", - // "google.golang.org/grpc/grpclog": "", + "github.com/binchencoder/ease-gateway/gateway/runtime": "", + "github.com/grpc-ecosystem/grpc-gateway/utilities": "", + "github.com/golang/protobuf/proto": "", + "github.com/binchencoder/gateway-proto/data": "vexpb", + "github.com/binchencoder/gateway-proto/frontend": "fpb", + "github.com/binchencoder/letsgo/grpc": "lgr", + "github.com/binchencoder/skylb-api/balancer": "", + "github.com/binchencoder/skylb-api/client": "", + "github.com/binchencoder/skylb-api/client/option": "", + "github.com/binchencoder/skylb-api/proto": "skypb", + "google.golang.org/grpc": "", + "google.golang.org/grpc/codes": "", + "google.golang.org/grpc/naming": "", + // "google.golang.org/grpc/grpclog": "", "google.golang.org/grpc/status": "", } { pkg := descriptor.GoPackage{ @@ -104,6 +105,7 @@ func New(reg *descriptor.Registry, useRequestContext bool, registerFuncSuffix, p useRequestContext: useRequestContext, registerFuncSuffix: registerFuncSuffix, pathType: pathType, + modulePath: modulePathString, allowPatchFeature: allowPatchFeature, } } @@ -125,9 +127,10 @@ func (g *generator) Generate(targets []*descriptor.File) ([]*plugin.CodeGenerato glog.Errorf("%v: %s", err, code) return nil, err } - name := file.GetName() - if g.pathType == pathTypeImport && file.GoPkg.Path != "" { - name = fmt.Sprintf("%s/%s", file.GoPkg.Path, filepath.Base(name)) + name, err := g.getFilePath(file) + if err != nil { + glog.Errorf("%v: %s", err, code) + return nil, err } ext := filepath.Ext(name) base := strings.TrimSuffix(name, ext) @@ -141,6 +144,27 @@ func (g *generator) Generate(targets []*descriptor.File) ([]*plugin.CodeGenerato return files, nil } +func (g *generator) getFilePath(file *descriptor.File) (string, error) { + name := file.GetName() + switch { + case g.modulePath != "" && g.pathType != pathTypeImport: + return "", errors.New("cannot use module= with paths=") + + case g.modulePath != "": + trimPath, pkgPath := g.modulePath+"/", file.GoPkg.Path+"/" + if !strings.HasPrefix(pkgPath, trimPath) { + return "", fmt.Errorf("%v: file go path does not match module prefix: %v", file.GoPkg.Path, trimPath) + } + return filepath.Join(strings.TrimPrefix(pkgPath, trimPath), filepath.Base(name)), nil + + case g.pathType == pathTypeImport && file.GoPkg.Path != "": + return fmt.Sprintf("%s/%s", file.GoPkg.Path, filepath.Base(name)), nil + + default: + return name, nil + } +} + func (g *generator) generate(file *descriptor.File) (string, error) { pkgSeen := make(map[string]bool) var imports []descriptor.GoPackage diff --git a/gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go b/gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go index b7b5883..7ab69e1 100644 --- a/gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go +++ b/gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go @@ -231,9 +231,9 @@ func applyTemplate(p param, reg *descriptor.Registry) (string, error) { AssumeColonVerb: assumeColonVerb, } // Local - // if err := localTrailerTemplate.Execute(w, tp); err != nil { - // return "", err - // } + if err := localTrailerTemplate.Execute(w, tp); err != nil { + return "", err + } if err := trailerTemplate.Execute(w, tp); err != nil { return "", err @@ -558,10 +558,10 @@ var ( {{if $param.IsNestedProto3}} err = runtime.PopulateFieldFromPath(&protoReq, {{$param | printf "%q"}}, val) {{if $enum}} - e{{if $param.IsRepeated}}s{{end}}, err = {{$param.ConvertFuncExpr}}(val{{if $param.IsRepeated}}, {{$binding.Registry.GetRepeatedPathParamSeparator | printf "%c" | printf "%q"}}{{end}}, {{$enum.GoType $param.Target.Message.File.GoPkg.Path}}_value) + 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) {{end}} {{else if $enum}} - e{{if $param.IsRepeated}}s{{end}}, err = {{$param.ConvertFuncExpr}}(val{{if $param.IsRepeated}}, {{$binding.Registry.GetRepeatedPathParamSeparator | printf "%c" | printf "%q"}}{{end}}, {{$enum.GoType $param.Target.Message.File.GoPkg.Path}}_value) + 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) {{else}} {{$param.AssignableExpr "protoReq"}}, err = {{$param.ConvertFuncExpr}}(val{{if $param.IsRepeated}}, {{$binding.Registry.GetRepeatedPathParamSeparator | printf "%c" | printf "%q"}}{{end}}) {{end}} @@ -569,13 +569,13 @@ var ( return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", {{$param | printf "%q"}}, err) } {{if and $enum $param.IsRepeated}} - s := make([]{{$enum.GoType $param.Target.Message.File.GoPkg.Path}}, len(es)) + s := make([]{{$enum.GoType $param.Method.Service.File.GoPkg.Path}}, len(es)) for i, v := range es { - s[i] = {{$enum.GoType $param.Target.Message.File.GoPkg.Path}}(v) + s[i] = {{$enum.GoType $param.Method.Service.File.GoPkg.Path}}(v) } {{$param.AssignableExpr "protoReq"}} = s {{else if $enum}} - {{$param.AssignableExpr "protoReq"}} = {{$enum.GoType $param.Target.Message.File.GoPkg.Path}}(e) + {{$param.AssignableExpr "protoReq"}} = {{$enum.GoType $param.Method.Service.File.GoPkg.Path}}(e) {{end}} {{end}} {{end}} @@ -736,10 +736,10 @@ func local_request_{{.Method.Service.GetName}}_{{.Method.GetName}}_{{.Index}}(ct {{if $param.IsNestedProto3}} err = runtime.PopulateFieldFromPath(&protoReq, {{$param | printf "%q"}}, val) {{if $enum}} - e{{if $param.IsRepeated}}s{{end}}, err = {{$param.ConvertFuncExpr}}(val{{if $param.IsRepeated}}, {{$binding.Registry.GetRepeatedPathParamSeparator | printf "%c" | printf "%q"}}{{end}}, {{$enum.GoType $param.Target.Message.File.GoPkg.Path}}_value) + 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) {{end}} {{else if $enum}} - e{{if $param.IsRepeated}}s{{end}}, err = {{$param.ConvertFuncExpr}}(val{{if $param.IsRepeated}}, {{$binding.Registry.GetRepeatedPathParamSeparator | printf "%c" | printf "%q"}}{{end}}, {{$enum.GoType $param.Target.Message.File.GoPkg.Path}}_value) + 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) {{else}} {{$param.AssignableExpr "protoReq"}}, err = {{$param.ConvertFuncExpr}}(val{{if $param.IsRepeated}}, {{$binding.Registry.GetRepeatedPathParamSeparator | printf "%c" | printf "%q"}}{{end}}) {{end}} @@ -747,18 +747,21 @@ func local_request_{{.Method.Service.GetName}}_{{.Method.GetName}}_{{.Index}}(ct return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", {{$param | printf "%q"}}, err) } {{if and $enum $param.IsRepeated}} - s := make([]{{$enum.GoType $param.Target.Message.File.GoPkg.Path}}, len(es)) + s := make([]{{$enum.GoType $param.Method.Service.File.GoPkg.Path}}, len(es)) for i, v := range es { - s[i] = {{$enum.GoType $param.Target.Message.File.GoPkg.Path}}(v) + s[i] = {{$enum.GoType $param.Method.Service.File.GoPkg.Path}}(v) } {{$param.AssignableExpr "protoReq"}} = s {{else if $enum}} - {{$param.AssignableExpr "protoReq"}} = {{$enum.GoType $param.Target.Message.File.GoPkg.Path}}(e) + {{$param.AssignableExpr "protoReq"}} = {{$enum.GoType $param.Method.Service.File.GoPkg.Path}}(e) {{end}} {{end}} {{end}} {{if .HasQueryParam}} - if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_{{.Method.Service.GetName}}_{{.Method.GetName}}_{{.Index}}); err != nil { + 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 { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } {{end}} @@ -776,18 +779,19 @@ func local_request_{{.Method.Service.GetName}}_{{.Method.GetName}}_{{.Index}}(ct // 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. +// Note that using this registration option will cause many gRPC library features (such as grpc.SendHeader, etc) to stop working. Consider using Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}FromEndpoint instead. 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) { + mux.Handle({{$b.HTTPMethod | printf "%q"}}, pattern_{{$svc.GetName}}_{{$m.GetName}}_{{$b.Index}}, vexpb.ServiceId_{{$svc.ServiceId}}, func(inctx context.Context, 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) { + mux.Handle({{$b.HTTPMethod | printf "%q"}}, pattern_{{$svc.GetName}}_{{$m.GetName}}_{{$b.Index}}, vexpb.ServiceId_{{$svc.ServiceId}}, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { {{- if $UseRequestContext }} ctx, cancel := context.WithCancel(req.Context()) {{- else -}} @@ -927,7 +931,14 @@ func Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}Client(ctx context.Context, return } {{if $m.GetServerStreaming}} + {{ 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 }} forward_{{$svc.GetName}}_{{$m.GetName}}_{{$b.Index}}(ctx, mux, outboundMarshaler, w, req, func() (proto.Message, error) { return resp.Recv() }, mux.GetForwardResponseOptions()...) + {{end}} {{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()...) diff --git a/gateway/protoc-gen-grpc-gateway/main.go b/gateway/protoc-gen-grpc-gateway/main.go index 5913b0e..3ebe467 100644 --- a/gateway/protoc-gen-grpc-gateway/main.go +++ b/gateway/protoc-gen-grpc-gateway/main.go @@ -35,6 +35,7 @@ var ( allowDeleteBody = flag.Bool("allow_delete_body", false, "unless set, HTTP DELETE methods may not have a body") grpcAPIConfiguration = flag.String("grpc_api_configuration", "", "path to gRPC API Configuration in YAML format") pathType = flag.String("paths", "", "specifies how the paths of generated files are structured") + modulePath = flag.String("module", "", "specifies a module prefix that will be stripped from the go package to determine the output directory") allowRepeatedFieldsInBody = flag.Bool("allow_repeated_fields_in_body", false, "allows to use repeated field in `body` and `response_body` field of `google.api.http` annotation option") repeatedPathParamSeparator = flag.String("repeated_path_param_separator", "csv", "configures how repeated fields should be split. Allowed values are `csv`, `pipes`, `ssv` and `tsv`.") allowPatchFeature = flag.Bool("allow_patch_feature", true, "determines whether to use PATCH feature involving update masks (using google.protobuf.FieldMask).") @@ -87,7 +88,7 @@ func main() { } } - g := gengateway.New(reg, *useRequestContext, *registerFuncSuffix, *pathType, *allowPatchFeature) + g := gengateway.New(reg, *useRequestContext, *registerFuncSuffix, *pathType, *modulePath, *allowPatchFeature) if *grpcAPIConfiguration != "" { if err := reg.LoadGrpcAPIServiceFromYAML(*grpcAPIConfiguration); err != nil { From 1a69a2c8b04d58fcb6662471610b070b85c6a8da Mon Sep 17 00:00:00 2001 From: chenbin1314 Date: Sat, 11 Jul 2020 18:55:48 +0800 Subject: [PATCH 10/56] Use grpc-gateway/internal/errors --- gateway/internal/BUILD.bazel | 32 ++ gateway/internal/casing/BUILD.bazel | 8 + gateway/internal/casing/LICENSE.md | 28 + gateway/internal/casing/README.md | 5 + gateway/internal/casing/camel.go | 63 +++ gateway/internal/errors.pb.go | 292 ++++++++++ gateway/internal/errors.proto | 27 + .../descriptor/BUILD.bazel | 1 + .../descriptor/types.go | 13 +- .../internal/gengateway/BUILD.bazel | 3 +- .../internal/gengateway/generator.go | 4 +- .../internal/gengateway/template.go | 14 +- gateway/runtime/BUILD.bazel | 6 +- gateway/runtime/errors.go | 25 +- gateway/runtime/handler.go | 3 +- gateway/runtime/handler_test.go | 3 +- gateway/runtime/proto_errors.go | 3 +- go.mod | 1 + integrate/hook.go | 2 +- proto/examples/BUILD.bazel | 2 +- proto/examples/echo_service.pb.go | 497 +++++++++++------- proto/examples/echo_service.pb.gw.go | 321 +++++++---- proto/examples/echo_service.proto | 58 +- 23 files changed, 1042 insertions(+), 369 deletions(-) create mode 100644 gateway/internal/BUILD.bazel create mode 100644 gateway/internal/casing/BUILD.bazel create mode 100644 gateway/internal/casing/LICENSE.md create mode 100644 gateway/internal/casing/README.md create mode 100644 gateway/internal/casing/camel.go create mode 100755 gateway/internal/errors.pb.go create mode 100644 gateway/internal/errors.proto diff --git a/gateway/internal/BUILD.bazel b/gateway/internal/BUILD.bazel new file mode 100644 index 0000000..d1917c5 --- /dev/null +++ b/gateway/internal/BUILD.bazel @@ -0,0 +1,32 @@ +load("@rules_proto//proto:defs.bzl", "proto_library") +load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") + +package(default_visibility = ["//visibility:public"]) + +proto_library( + name = "internal_proto", + srcs = ["errors.proto"], + deps = [ + "@com_github_binchencoder_gateway_proto//frontend:error_proto", + "@com_google_protobuf//:any_proto", + ], +) + +go_proto_library( + name = "internal_go_proto", + importpath = "github.com/binchencoder/ease-gateway/gateway/internal", + proto = ":internal_proto", + deps = [ + "@com_github_binchencoder_gateway_proto//frontend:error_go_proto", + ] +) + +go_library( + name = "go_default_library", + embed = [":internal_go_proto"], + importpath = "github.com/binchencoder/ease-gateway/gateway/internal", + deps = [ + "@com_github_binchencoder_gateway_proto//frontend:go_default_library", + ] +) diff --git a/gateway/internal/casing/BUILD.bazel b/gateway/internal/casing/BUILD.bazel new file mode 100644 index 0000000..94c3fc4 --- /dev/null +++ b/gateway/internal/casing/BUILD.bazel @@ -0,0 +1,8 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = ["camel.go"], + importpath = "github.com/binchencoder/ease-gateway/gateway/internal/casing", + visibility = ["//:__subpackages__"], +) diff --git a/gateway/internal/casing/LICENSE.md b/gateway/internal/casing/LICENSE.md new file mode 100644 index 0000000..0f64693 --- /dev/null +++ b/gateway/internal/casing/LICENSE.md @@ -0,0 +1,28 @@ +Copyright 2010 The Go Authors. All rights reserved. + +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. + diff --git a/gateway/internal/casing/README.md b/gateway/internal/casing/README.md new file mode 100644 index 0000000..8811446 --- /dev/null +++ b/gateway/internal/casing/README.md @@ -0,0 +1,5 @@ +# Case conversion + +This package contains a single function, copied from the +`github.com/golang/protobuf/protoc-gen-go/generator` package. That +modules LICENSE is referenced in its entirety in this package. diff --git a/gateway/internal/casing/camel.go b/gateway/internal/casing/camel.go new file mode 100644 index 0000000..8cfef4b --- /dev/null +++ b/gateway/internal/casing/camel.go @@ -0,0 +1,63 @@ +package casing + +// Camel returns the CamelCased name. +// +// This was moved from the now deprecated github.com/golang/protobuf/protoc-gen-go/generator package +// +// If there is an interior underscore followed by a lower case letter, +// drop the underscore and convert the letter to upper case. +// There is a remote possibility of this rewrite causing a name collision, +// but it's so remote we're prepared to pretend it's nonexistent - since the +// C++ generator lowercases names, it's extremely unlikely to have two fields +// with different capitalizations. +// In short, _my_field_name_2 becomes XMyFieldName_2. +func Camel(s string) string { + if s == "" { + return "" + } + t := make([]byte, 0, 32) + i := 0 + if s[0] == '_' { + // Need a capital letter; drop the '_'. + t = append(t, 'X') + i++ + } + // Invariant: if the next letter is lower case, it must be converted + // to upper case. + // That is, we process a word at a time, where words are marked by _ or + // upper case letter. Digits are treated as words. + for ; i < len(s); i++ { + c := s[i] + if c == '_' && i+1 < len(s) && isASCIILower(s[i+1]) { + continue // Skip the underscore in s. + } + if isASCIIDigit(c) { + t = append(t, c) + continue + } + // Assume we have a letter now - if not, it's a bogus identifier. + // The next word is a sequence of characters that must start upper case. + if isASCIILower(c) { + c ^= ' ' // Make it a capital letter. + } + t = append(t, c) // Guaranteed not lower case. + // Accept lower case sequence that follows. + for i+1 < len(s) && isASCIILower(s[i+1]) { + i++ + t = append(t, s[i]) + } + } + return string(t) +} + +// And now lots of helper functions. + +// Is c an ASCII lower-case letter? +func isASCIILower(c byte) bool { + return 'a' <= c && c <= 'z' +} + +// Is c an ASCII digit? +func isASCIIDigit(c byte) bool { + return '0' <= c && c <= '9' +} diff --git a/gateway/internal/errors.pb.go b/gateway/internal/errors.pb.go new file mode 100755 index 0000000..0a1147d --- /dev/null +++ b/gateway/internal/errors.pb.go @@ -0,0 +1,292 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.22.0 +// protoc v3.9.0 +// source: gateway/internal/errors.proto + +package internal + +import ( + frontend "github.com/binchencoder/gateway-proto/frontend" + proto "github.com/golang/protobuf/proto" + any "github.com/golang/protobuf/ptypes/any" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// This is a compile-time assertion that a sufficiently up-to-date version +// of the legacy proto package is being used. +const _ = proto.ProtoPackageIsVersion4 + +type Error struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Error *frontend.Error `protobuf:"bytes,1,opt,name=error,proto3" json:"error,omitempty"` + Code int32 `protobuf:"varint,2,opt,name=code,proto3" json:"code,omitempty"` + Message string `protobuf:"bytes,3,opt,name=message,proto3" json:"message,omitempty"` + Details []*any.Any `protobuf:"bytes,4,rep,name=details,proto3" json:"details,omitempty"` +} + +func (x *Error) Reset() { + *x = Error{} + if protoimpl.UnsafeEnabled { + mi := &file_gateway_internal_errors_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Error) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Error) ProtoMessage() {} + +func (x *Error) ProtoReflect() protoreflect.Message { + mi := &file_gateway_internal_errors_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Error.ProtoReflect.Descriptor instead. +func (*Error) Descriptor() ([]byte, []int) { + return file_gateway_internal_errors_proto_rawDescGZIP(), []int{0} +} + +func (x *Error) GetError() *frontend.Error { + if x != nil { + return x.Error + } + return nil +} + +func (x *Error) GetCode() int32 { + if x != nil { + return x.Code + } + return 0 +} + +func (x *Error) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +func (x *Error) GetDetails() []*any.Any { + if x != nil { + return x.Details + } + return nil +} + +type StreamError struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + GrpcCode int32 `protobuf:"varint,1,opt,name=grpc_code,json=grpcCode,proto3" json:"grpc_code,omitempty"` + HttpCode int32 `protobuf:"varint,2,opt,name=http_code,json=httpCode,proto3" json:"http_code,omitempty"` + Message string `protobuf:"bytes,3,opt,name=message,proto3" json:"message,omitempty"` + HttpStatus string `protobuf:"bytes,4,opt,name=http_status,json=httpStatus,proto3" json:"http_status,omitempty"` + Details []*any.Any `protobuf:"bytes,5,rep,name=details,proto3" json:"details,omitempty"` +} + +func (x *StreamError) Reset() { + *x = StreamError{} + if protoimpl.UnsafeEnabled { + mi := &file_gateway_internal_errors_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StreamError) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StreamError) ProtoMessage() {} + +func (x *StreamError) ProtoReflect() protoreflect.Message { + mi := &file_gateway_internal_errors_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StreamError.ProtoReflect.Descriptor instead. +func (*StreamError) Descriptor() ([]byte, []int) { + return file_gateway_internal_errors_proto_rawDescGZIP(), []int{1} +} + +func (x *StreamError) GetGrpcCode() int32 { + if x != nil { + return x.GrpcCode + } + return 0 +} + +func (x *StreamError) GetHttpCode() int32 { + if x != nil { + return x.HttpCode + } + return 0 +} + +func (x *StreamError) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +func (x *StreamError) GetHttpStatus() string { + if x != nil { + return x.HttpStatus + } + return "" +} + +func (x *StreamError) GetDetails() []*any.Any { + if x != nil { + return x.Details + } + return nil +} + +var File_gateway_internal_errors_proto protoreflect.FileDescriptor + +var file_gateway_internal_errors_proto_rawDesc = []byte{ + 0x0a, 0x1d, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, + 0x61, 0x6c, 0x2f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, + 0x14, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, + 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x1a, 0x14, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x2f, 0x65, 0x72, 0x72, 0x6f, 0x72, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x8c, 0x01, 0x0a, 0x05, 0x45, 0x72, 0x72, 0x6f, 0x72, + 0x12, 0x25, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x0f, 0x2e, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, + 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2e, 0x0a, 0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, + 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x07, 0x64, 0x65, + 0x74, 0x61, 0x69, 0x6c, 0x73, 0x22, 0xb2, 0x01, 0x0a, 0x0b, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, + 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x67, 0x72, 0x70, 0x63, 0x5f, 0x63, 0x6f, + 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x67, 0x72, 0x70, 0x63, 0x43, 0x6f, + 0x64, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x68, 0x74, 0x74, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x12, + 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x68, 0x74, 0x74, + 0x70, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, + 0x68, 0x74, 0x74, 0x70, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x2e, 0x0a, 0x07, 0x64, 0x65, + 0x74, 0x61, 0x69, 0x6c, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, + 0x79, 0x52, 0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x42, 0x0a, 0x5a, 0x08, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_gateway_internal_errors_proto_rawDescOnce sync.Once + file_gateway_internal_errors_proto_rawDescData = file_gateway_internal_errors_proto_rawDesc +) + +func file_gateway_internal_errors_proto_rawDescGZIP() []byte { + file_gateway_internal_errors_proto_rawDescOnce.Do(func() { + file_gateway_internal_errors_proto_rawDescData = protoimpl.X.CompressGZIP(file_gateway_internal_errors_proto_rawDescData) + }) + return file_gateway_internal_errors_proto_rawDescData +} + +var file_gateway_internal_errors_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_gateway_internal_errors_proto_goTypes = []interface{}{ + (*Error)(nil), // 0: grpc.gateway.runtime.Error + (*StreamError)(nil), // 1: grpc.gateway.runtime.StreamError + (*frontend.Error)(nil), // 2: frontend.Error + (*any.Any)(nil), // 3: google.protobuf.Any +} +var file_gateway_internal_errors_proto_depIdxs = []int32{ + 2, // 0: grpc.gateway.runtime.Error.error:type_name -> frontend.Error + 3, // 1: grpc.gateway.runtime.Error.details:type_name -> google.protobuf.Any + 3, // 2: grpc.gateway.runtime.StreamError.details:type_name -> google.protobuf.Any + 3, // [3:3] is the sub-list for method output_type + 3, // [3:3] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name +} + +func init() { file_gateway_internal_errors_proto_init() } +func file_gateway_internal_errors_proto_init() { + if File_gateway_internal_errors_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_gateway_internal_errors_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Error); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_gateway_internal_errors_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StreamError); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_gateway_internal_errors_proto_rawDesc, + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_gateway_internal_errors_proto_goTypes, + DependencyIndexes: file_gateway_internal_errors_proto_depIdxs, + MessageInfos: file_gateway_internal_errors_proto_msgTypes, + }.Build() + File_gateway_internal_errors_proto = out.File + file_gateway_internal_errors_proto_rawDesc = nil + file_gateway_internal_errors_proto_goTypes = nil + file_gateway_internal_errors_proto_depIdxs = nil +} diff --git a/gateway/internal/errors.proto b/gateway/internal/errors.proto new file mode 100644 index 0000000..b0a0022 --- /dev/null +++ b/gateway/internal/errors.proto @@ -0,0 +1,27 @@ +syntax = "proto3"; +package grpc.gateway.runtime; +option go_package = "internal"; + +import "google/protobuf/any.proto"; +import "frontend/error.proto"; + +// Error is the generic error returned from unary RPCs. +message Error { + frontend.Error error = 1; + // This is to make the error more compatible with users that expect errors to be Status objects: + // https://github.com/grpc/grpc/blob/master/src/proto/grpc/status/status.proto + // It should be the exact same message as the Error field. + int32 code = 2; + string message = 3; + repeated google.protobuf.Any details = 4; +} + +// StreamError is a response type which is returned when +// streaming rpc returns an error. +message StreamError { + int32 grpc_code = 1; + int32 http_code = 2; + string message = 3; + string http_status = 4; + repeated google.protobuf.Any details = 5; +} diff --git a/gateway/protoc-gen-grpc-gateway/descriptor/BUILD.bazel b/gateway/protoc-gen-grpc-gateway/descriptor/BUILD.bazel index 4299efb..661c734 100644 --- a/gateway/protoc-gen-grpc-gateway/descriptor/BUILD.bazel +++ b/gateway/protoc-gen-grpc-gateway/descriptor/BUILD.bazel @@ -13,6 +13,7 @@ go_library( ], importpath = "github.com/binchencoder/ease-gateway/gateway/protoc-gen-grpc-gateway/descriptor", deps = [ + "//gateway/internal/casing:go_default_library", "//httpoptions:go_default_library", "@com_github_binchencoder_gateway_proto//data:go_default_library", "@com_github_ghodss_yaml//:go_default_library", diff --git a/gateway/protoc-gen-grpc-gateway/descriptor/types.go b/gateway/protoc-gen-grpc-gateway/descriptor/types.go index d796153..5355c8e 100644 --- a/gateway/protoc-gen-grpc-gateway/descriptor/types.go +++ b/gateway/protoc-gen-grpc-gateway/descriptor/types.go @@ -5,9 +5,8 @@ import ( "strings" "unicode" + "github.com/binchencoder/ease-gateway/gateway/internal/casing" "github.com/golang/protobuf/protoc-gen-go/descriptor" - gogen "github.com/golang/protobuf/protoc-gen-go/generator" - "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/httprule" options "github.com/binchencoder/ease-gateway/httpoptions" @@ -545,14 +544,14 @@ func (p FieldPath) AssignableExpr(msgExpr string) string { if c.Target.OneofIndex != nil { index := c.Target.OneofIndex msg := c.Target.Message - oneOfName := gogen.CamelCase(msg.GetOneofDecl()[*index].GetName()) + oneOfName := casing.Camel(msg.GetOneofDecl()[*index].GetName()) oneofFieldName := msg.GetName() + "_" + c.AssignableExpr() components = components + "." + oneOfName s := `if %s == nil { %s =&%s{} } else if _, ok := %s.(*%s); !ok { - return nil, metadata, grpc.Errorf(codes.InvalidArgument, "expect type: *%s, but: %%t\n",%s) + return nil, metadata, status.Errorf(codes.InvalidArgument, "expect type: *%s, but: %%t\n",%s) }` preparations = append(preparations, fmt.Sprintf(s, components, components, oneofFieldName, components, oneofFieldName, oneofFieldName, components)) @@ -581,15 +580,15 @@ type FieldPathComponent struct { // AssignableExpr returns an assignable expression in go for this field. func (c FieldPathComponent) AssignableExpr() string { - return gogen.CamelCase(c.Name) + return casing.Camel(c.Name) } // ValueExpr returns an expression in go for this field. func (c FieldPathComponent) ValueExpr() string { if c.Target.Message.File.proto2() { - return fmt.Sprintf("Get%s()", gogen.CamelCase(c.Name)) + return fmt.Sprintf("Get%s()", casing.Camel(c.Name)) } - return gogen.CamelCase(c.Name) + return casing.Camel(c.Name) } var ( diff --git a/gateway/protoc-gen-grpc-gateway/internal/gengateway/BUILD.bazel b/gateway/protoc-gen-grpc-gateway/internal/gengateway/BUILD.bazel index ce5a0df..85b9987 100644 --- a/gateway/protoc-gen-grpc-gateway/internal/gengateway/BUILD.bazel +++ b/gateway/protoc-gen-grpc-gateway/internal/gengateway/BUILD.bazel @@ -12,10 +12,11 @@ go_library( importpath = "github.com/binchencoder/ease-gateway/gateway/protoc-gen-grpc-gateway/internal/gengateway", deps = [ "//httpoptions:go_default_library", + "//gateway/internal/casing:go_default_library", "//gateway/runtime:go_default_library", "//gateway/protoc-gen-grpc-gateway/descriptor:go_default_library", "//gateway/protoc-gen-grpc-gateway/generator:go_default_library", - "@com_github_grpc_ecosystem_grpc_gateway//utilities:go_default_library", + "@com_github_grpc_ecosystem_grpc_gateway//utilities:go_default_library", "@com_github_golang_glog//:go_default_library", "@com_github_golang_protobuf//proto:go_default_library", "@com_github_golang_protobuf//protoc-gen-go/generator:go_default_library_gen", diff --git a/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator.go b/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator.go index 9c94b23..df96d3b 100644 --- a/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator.go +++ b/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator.go @@ -66,8 +66,8 @@ func New(reg *descriptor.Registry, useRequestContext bool, registerFuncSuffix, p "google.golang.org/grpc": "", "google.golang.org/grpc/codes": "", "google.golang.org/grpc/naming": "", - // "google.golang.org/grpc/grpclog": "", - "google.golang.org/grpc/status": "", + "google.golang.org/grpc/grpclog": "", + "google.golang.org/grpc/status": "", } { pkg := descriptor.GoPackage{ Path: pkgpath, diff --git a/gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go b/gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go index 7ab69e1..7c24e5b 100644 --- a/gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go +++ b/gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go @@ -8,8 +8,8 @@ import ( "text/template" "unicode" + "github.com/binchencoder/ease-gateway/gateway/internal/casing" "github.com/golang/glog" - generator2 "github.com/golang/protobuf/protoc-gen-go/generator" // "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/descriptor" "github.com/binchencoder/ease-gateway/gateway/protoc-gen-grpc-gateway/descriptor" @@ -41,7 +41,7 @@ func (b binding) GetBodyFieldPath() string { // GetBodyFieldPath returns the binding body's struct field name. func (b binding) GetBodyFieldStructName() (string, error) { if b.Body != nil && len(b.Body.FieldPath) != 0 { - return generator2.CamelCase(b.Body.FieldPath.String()), nil + return casing.Camel(b.Body.FieldPath.String()), nil } return "", errors.New("No body field found") } @@ -142,7 +142,7 @@ func (b binding) FieldMaskField() string { } } if fieldMaskField != nil { - return generator2.CamelCase(fieldMaskField.GetName()) + return casing.Camel(fieldMaskField.GetName()) } return "" } @@ -181,16 +181,16 @@ func applyTemplate(p param, reg *descriptor.Registry) (string, error) { var targetServices []*descriptor.Service for _, msg := range p.Messages { - msgName := generator2.CamelCase(*msg.Name) + msgName := casing.Camel(*msg.Name) msg.Name = &msgName } for _, svc := range p.Services { var methodWithBindingsSeen bool - svcName := generator2.CamelCase(*svc.Name) + svcName := casing.Camel(*svc.Name) svc.Name = &svcName for _, meth := range svc.Methods { glog.V(2).Infof("Processing %s.%s", svc.GetName(), meth.GetName()) - methName := generator2.CamelCase(*meth.Name) + methName := casing.Camel(*meth.Name) meth.Name = &methName for _, b := range meth.Bindings { methodWithBindingsSeen = true @@ -907,7 +907,7 @@ func Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}Client(ctx context.Context, ctx, err := runtime.RequestAccepted(inctx, internal_{{$svc.GetName}}_{{$svc.ServiceId}}_spec, "{{$svc.GetName}}", "{{$m.GetName}}", w, req) if err != nil { - // grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) + grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) runtime.HTTPError(ctx, nil, &runtime.JSONBuiltin{}, w, req, err) return } diff --git a/gateway/runtime/BUILD.bazel b/gateway/runtime/BUILD.bazel index 3d8cdae..94bead7 100644 --- a/gateway/runtime/BUILD.bazel +++ b/gateway/runtime/BUILD.bazel @@ -10,6 +10,7 @@ go_library( ), importpath = "github.com/binchencoder/ease-gateway/gateway/runtime", deps = [ + "//gateway/internal:go_default_library", "//httpoptions:go_default_library", "@com_github_binchencoder_gateway_proto//data:go_default_library", "@com_github_binchencoder_gateway_proto//frontend:go_default_library", @@ -19,7 +20,7 @@ go_library( "@com_github_golang_protobuf//descriptor:go_default_library_gen", "@com_github_golang_protobuf//jsonpb:go_default_library_gen", "@com_github_golang_protobuf//proto:go_default_library", - "@com_github_grpc_ecosystem_grpc_gateway//internal:go_default_library", + # "@com_github_grpc_ecosystem_grpc_gateway//internal:go_default_library", "@com_github_grpc_ecosystem_grpc_gateway//utilities:go_default_library", "@com_github_pborman_uuid//:go_default_library", "@go_googleapis//google/api:httpbody_go_proto", @@ -57,12 +58,13 @@ go_test( embed = [":go_default_library"], deps = [ "//examples/proto:go_default_library", + "//gateway/internal:go_default_library", "//httpoptions:go_default_library", "@com_github_binchencoder_letsgo//hashring:go_default_library", "@com_github_binchencoder_skylb_api//proto:go_default_library", "@com_github_golang_protobuf//proto:go_default_library", "@com_github_golang_protobuf//ptypes:go_default_library_gen", - "@com_github_grpc_ecosystem_grpc_gateway//internal:go_default_library", + # "@com_github_grpc_ecosystem_grpc_gateway//internal:go_default_library", "@com_github_grpc_ecosystem_grpc_gateway//utilities:go_default_library", "@go_googleapis//google/api:httpbody_go_proto", "@go_googleapis//google/rpc:errdetails_go_proto", diff --git a/gateway/runtime/errors.go b/gateway/runtime/errors.go index cf2cc85..e02824e 100644 --- a/gateway/runtime/errors.go +++ b/gateway/runtime/errors.go @@ -2,18 +2,18 @@ package runtime import ( "context" + "fmt" "io" "net/http" "strings" "github.com/golang/protobuf/jsonpb" - "github.com/golang/protobuf/proto" - "github.com/golang/protobuf/ptypes/any" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/grpclog" "google.golang.org/grpc/status" + "github.com/binchencoder/ease-gateway/gateway/internal" fpb "github.com/binchencoder/gateway-proto/frontend" ) @@ -79,7 +79,7 @@ var ( // option, set GlobalHTTPErrorHandler to a custom function. // // Setting this variable directly to customize error format is deprecated. - HTTPError = DefaultHTTPError + HTTPError = MuxOrGlobalHTTPError // GlobalHTTPErrorHandler is the HTTPError handler for all ServeMux instances not using the // WithProtoErrorHandler serve option. @@ -109,21 +109,6 @@ func MuxOrGlobalHTTPError(ctx context.Context, mux *ServeMux, marshaler Marshale } } -type errorBody struct { - Error *fpb.Error `protobuf:"bytes,1,name=error" json:"error"` - // This is to make the error more compatible with users that expect errors to be Status objects: - // https://github.com/grpc/grpc/blob/master/src/proto/grpc/status/status.proto - // It should be the exact same message as the Error field. - Code int32 `protobuf:"varint,1,name=code" json:"code"` - Message string `protobuf:"bytes,2,name=message" json:"message"` - Details []*any.Any `protobuf:"bytes,3,rep,name=details" json:"details,omitempty"` -} - -// Make this also conform to proto.Message for builtin JSONPb Marshaler -func (e *errorBody) Reset() { *e = errorBody{} } -func (e *errorBody) String() string { return proto.CompactTextString(e) } -func (*errorBody) ProtoMessage() {} - // DefaultHTTPError is the default implementation of HTTPError. // If "err" is an error from gRPC system, the function replies with the status code mapped by HTTPStatusFromCode. // If otherwise, it replies with http.StatusInternalServerError. @@ -157,13 +142,15 @@ func DefaultHTTPError(ctx context.Context, mux *ServeMux, marshaler Marshaler, w e.Code = fpb.ErrorCode_UNDEFINED e.Params = []string{desc} } - body := &errorBody{ + body := &internal.Error{ Error: &e, Message: s.Message(), Code: int32(s.Code()), Details: s.Proto().GetDetails(), } + fmt.Printf("Marshal error %v\n", body) + buf, merr := marshaler.Marshal(body) if merr != nil { grpclog.Infof("Failed to marshal error message %q: %v", body, merr) diff --git a/gateway/runtime/handler.go b/gateway/runtime/handler.go index e6e8f28..7c0f67c 100644 --- a/gateway/runtime/handler.go +++ b/gateway/runtime/handler.go @@ -8,8 +8,9 @@ import ( "net/http" "net/textproto" + // "github.com/grpc-ecosystem/grpc-gateway/internal" + "github.com/binchencoder/ease-gateway/gateway/internal" "github.com/golang/protobuf/proto" - "github.com/grpc-ecosystem/grpc-gateway/internal" "google.golang.org/grpc/grpclog" ) diff --git a/gateway/runtime/handler_test.go b/gateway/runtime/handler_test.go index 0d3fe80..c9edcfd 100644 --- a/gateway/runtime/handler_test.go +++ b/gateway/runtime/handler_test.go @@ -9,9 +9,10 @@ import ( "testing" pb "github.com/binchencoder/ease-gateway/examples/proto" + // "github.com/grpc-ecosystem/grpc-gateway/internal" + "github.com/binchencoder/ease-gateway/gateway/internal" "github.com/binchencoder/ease-gateway/gateway/runtime" "github.com/golang/protobuf/proto" - "github.com/grpc-ecosystem/grpc-gateway/internal" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) diff --git a/gateway/runtime/proto_errors.go b/gateway/runtime/proto_errors.go index 3fd30da..96fa398 100644 --- a/gateway/runtime/proto_errors.go +++ b/gateway/runtime/proto_errors.go @@ -5,8 +5,9 @@ import ( "io" "net/http" + // "github.com/grpc-ecosystem/grpc-gateway/internal" + "github.com/binchencoder/ease-gateway/gateway/internal" "github.com/golang/protobuf/ptypes/any" - "github.com/grpc-ecosystem/grpc-gateway/internal" "google.golang.org/grpc/codes" "google.golang.org/grpc/grpclog" "google.golang.org/grpc/status" diff --git a/go.mod b/go.mod index a0b15c5..e9dda22 100644 --- a/go.mod +++ b/go.mod @@ -17,6 +17,7 @@ require ( golang.org/x/net v0.0.0-20200625001655-4c5254603344 google.golang.org/genproto v0.0.0-20200702021140-07506425bd67 google.golang.org/grpc v1.30.0 + google.golang.org/protobuf v1.24.0 ) replace ( diff --git a/integrate/hook.go b/integrate/hook.go index 6618fdd..c204713 100755 --- a/integrate/hook.go +++ b/integrate/hook.go @@ -13,8 +13,8 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" - options "github.com/binchencoder/ease-gateway/httpoptions" "github.com/binchencoder/ease-gateway/gateway/runtime" + options "github.com/binchencoder/ease-gateway/httpoptions" "github.com/binchencoder/ease-gateway/integrate/metrics" "github.com/binchencoder/ease-gateway/util" "github.com/binchencoder/letsgo/grpc" diff --git a/proto/examples/BUILD.bazel b/proto/examples/BUILD.bazel index a0099ed..ae9069f 100644 --- a/proto/examples/BUILD.bazel +++ b/proto/examples/BUILD.bazel @@ -57,7 +57,7 @@ go_library( ) protoc_gen_swagger( - name = "expamplepb_protoc_gen_swagger", + name = "examplepb_protoc_gen_swagger", proto = ":examplepb_proto", single_output = False, # Outputs a single swagger.json file. ) \ No newline at end of file diff --git a/proto/examples/echo_service.pb.go b/proto/examples/echo_service.pb.go index 6848915..3e67030 100755 --- a/proto/examples/echo_service.pb.go +++ b/proto/examples/echo_service.pb.go @@ -1,79 +1,78 @@ // Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.22.0 +// protoc v3.9.0 // source: proto/examples/echo_service.proto package proto import ( - _ "github.com/binchencoder/ease-gateway/httpoptions" context "context" - fmt "fmt" + _ "github.com/binchencoder/ease-gateway/httpoptions" proto "github.com/golang/protobuf/proto" grpc "google.golang.org/grpc" - math "math" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" ) -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) -// 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.ProtoPackageIsVersion3 // please upgrade the proto package +// This is a compile-time assertion that a sufficiently up-to-date version +// of the legacy proto package is being used. +const _ = proto.ProtoPackageIsVersion4 type Embedded struct { - // Types that are valid to be assigned to Mark: + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Mark: // *Embedded_Progress // *Embedded_Note - Mark isEmbedded_Mark `protobuf_oneof:"mark"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + Mark isEmbedded_Mark `protobuf_oneof:"mark"` } -func (m *Embedded) Reset() { *m = Embedded{} } -func (m *Embedded) String() string { return proto.CompactTextString(m) } -func (*Embedded) ProtoMessage() {} -func (*Embedded) Descriptor() ([]byte, []int) { - return fileDescriptor_50dd28de91ad0693, []int{0} +func (x *Embedded) Reset() { + *x = Embedded{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_examples_echo_service_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *Embedded) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Embedded.Unmarshal(m, b) -} -func (m *Embedded) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Embedded.Marshal(b, m, deterministic) +func (x *Embedded) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *Embedded) XXX_Merge(src proto.Message) { - xxx_messageInfo_Embedded.Merge(m, src) -} -func (m *Embedded) XXX_Size() int { - return xxx_messageInfo_Embedded.Size(m) -} -func (m *Embedded) XXX_DiscardUnknown() { - xxx_messageInfo_Embedded.DiscardUnknown(m) -} - -var xxx_messageInfo_Embedded proto.InternalMessageInfo -type isEmbedded_Mark interface { - isEmbedded_Mark() -} +func (*Embedded) ProtoMessage() {} -type Embedded_Progress struct { - Progress int64 `protobuf:"varint,1,opt,name=progress,proto3,oneof"` +func (x *Embedded) ProtoReflect() protoreflect.Message { + mi := &file_proto_examples_echo_service_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -type Embedded_Note struct { - Note string `protobuf:"bytes,2,opt,name=note,proto3,oneof"` +// Deprecated: Use Embedded.ProtoReflect.Descriptor instead. +func (*Embedded) Descriptor() ([]byte, []int) { + return file_proto_examples_echo_service_proto_rawDescGZIP(), []int{0} } -func (*Embedded_Progress) isEmbedded_Mark() {} - -func (*Embedded_Note) isEmbedded_Mark() {} - func (m *Embedded) GetMark() isEmbedded_Mark { if m != nil { return m.Mark @@ -81,100 +80,100 @@ func (m *Embedded) GetMark() isEmbedded_Mark { return nil } -func (m *Embedded) GetProgress() int64 { - if x, ok := m.GetMark().(*Embedded_Progress); ok { +func (x *Embedded) GetProgress() int64 { + if x, ok := x.GetMark().(*Embedded_Progress); ok { return x.Progress } return 0 } -func (m *Embedded) GetNote() string { - if x, ok := m.GetMark().(*Embedded_Note); ok { +func (x *Embedded) GetNote() string { + if x, ok := x.GetMark().(*Embedded_Note); ok { return x.Note } return "" } -// XXX_OneofWrappers is for the internal use of the proto package. -func (*Embedded) XXX_OneofWrappers() []interface{} { - return []interface{}{ - (*Embedded_Progress)(nil), - (*Embedded_Note)(nil), - } +type isEmbedded_Mark interface { + isEmbedded_Mark() +} + +type Embedded_Progress struct { + Progress int64 `protobuf:"varint,1,opt,name=progress,proto3,oneof"` } +type Embedded_Note struct { + Note string `protobuf:"bytes,2,opt,name=note,proto3,oneof"` +} + +func (*Embedded_Progress) isEmbedded_Mark() {} + +func (*Embedded_Note) isEmbedded_Mark() {} + type SimpleMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` Num int64 `protobuf:"varint,2,opt,name=num,proto3" json:"num,omitempty"` - // Types that are valid to be assigned to Code: + // Types that are assignable to Code: // *SimpleMessage_LineNum // *SimpleMessage_Lang Code isSimpleMessage_Code `protobuf_oneof:"code"` Status *Embedded `protobuf:"bytes,5,opt,name=status,proto3" json:"status,omitempty"` - // Types that are valid to be assigned to Ext: + // Types that are assignable to Ext: // *SimpleMessage_En // *SimpleMessage_No - Ext isSimpleMessage_Ext `protobuf_oneof:"ext"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + Ext isSimpleMessage_Ext `protobuf_oneof:"ext"` } -func (m *SimpleMessage) Reset() { *m = SimpleMessage{} } -func (m *SimpleMessage) String() string { return proto.CompactTextString(m) } -func (*SimpleMessage) ProtoMessage() {} -func (*SimpleMessage) Descriptor() ([]byte, []int) { - return fileDescriptor_50dd28de91ad0693, []int{1} +func (x *SimpleMessage) Reset() { + *x = SimpleMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_examples_echo_service_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *SimpleMessage) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SimpleMessage.Unmarshal(m, b) -} -func (m *SimpleMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SimpleMessage.Marshal(b, m, deterministic) -} -func (m *SimpleMessage) XXX_Merge(src proto.Message) { - xxx_messageInfo_SimpleMessage.Merge(m, src) -} -func (m *SimpleMessage) XXX_Size() int { - return xxx_messageInfo_SimpleMessage.Size(m) -} -func (m *SimpleMessage) XXX_DiscardUnknown() { - xxx_messageInfo_SimpleMessage.DiscardUnknown(m) +func (x *SimpleMessage) String() string { + return protoimpl.X.MessageStringOf(x) } -var xxx_messageInfo_SimpleMessage proto.InternalMessageInfo +func (*SimpleMessage) ProtoMessage() {} -func (m *SimpleMessage) GetId() string { - if m != nil { - return m.Id - } - return "" -} - -func (m *SimpleMessage) GetNum() int64 { - if m != nil { - return m.Num +func (x *SimpleMessage) ProtoReflect() protoreflect.Message { + mi := &file_proto_examples_echo_service_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms } - return 0 + return mi.MessageOf(x) } -type isSimpleMessage_Code interface { - isSimpleMessage_Code() +// Deprecated: Use SimpleMessage.ProtoReflect.Descriptor instead. +func (*SimpleMessage) Descriptor() ([]byte, []int) { + return file_proto_examples_echo_service_proto_rawDescGZIP(), []int{1} } -type SimpleMessage_LineNum struct { - LineNum int64 `protobuf:"varint,3,opt,name=line_num,json=lineNum,proto3,oneof"` +func (x *SimpleMessage) GetId() string { + if x != nil { + return x.Id + } + return "" } -type SimpleMessage_Lang struct { - Lang string `protobuf:"bytes,4,opt,name=lang,proto3,oneof"` +func (x *SimpleMessage) GetNum() int64 { + if x != nil { + return x.Num + } + return 0 } -func (*SimpleMessage_LineNum) isSimpleMessage_Code() {} - -func (*SimpleMessage_Lang) isSimpleMessage_Code() {} - func (m *SimpleMessage) GetCode() isSimpleMessage_Code { if m != nil { return m.Code @@ -182,27 +181,64 @@ func (m *SimpleMessage) GetCode() isSimpleMessage_Code { return nil } -func (m *SimpleMessage) GetLineNum() int64 { - if x, ok := m.GetCode().(*SimpleMessage_LineNum); ok { +func (x *SimpleMessage) GetLineNum() int64 { + if x, ok := x.GetCode().(*SimpleMessage_LineNum); ok { return x.LineNum } return 0 } -func (m *SimpleMessage) GetLang() string { - if x, ok := m.GetCode().(*SimpleMessage_Lang); ok { +func (x *SimpleMessage) GetLang() string { + if x, ok := x.GetCode().(*SimpleMessage_Lang); ok { return x.Lang } return "" } -func (m *SimpleMessage) GetStatus() *Embedded { +func (x *SimpleMessage) GetStatus() *Embedded { + if x != nil { + return x.Status + } + return nil +} + +func (m *SimpleMessage) GetExt() isSimpleMessage_Ext { if m != nil { - return m.Status + return m.Ext } return nil } +func (x *SimpleMessage) GetEn() int64 { + if x, ok := x.GetExt().(*SimpleMessage_En); ok { + return x.En + } + return 0 +} + +func (x *SimpleMessage) GetNo() *Embedded { + if x, ok := x.GetExt().(*SimpleMessage_No); ok { + return x.No + } + return nil +} + +type isSimpleMessage_Code interface { + isSimpleMessage_Code() +} + +type SimpleMessage_LineNum struct { + LineNum int64 `protobuf:"varint,3,opt,name=line_num,json=lineNum,proto3,oneof"` +} + +type SimpleMessage_Lang struct { + Lang string `protobuf:"bytes,4,opt,name=lang,proto3,oneof"` +} + +func (*SimpleMessage_LineNum) isSimpleMessage_Code() {} + +func (*SimpleMessage_Lang) isSimpleMessage_Code() {} + type isSimpleMessage_Ext interface { isSimpleMessage_Ext() } @@ -219,89 +255,172 @@ func (*SimpleMessage_En) isSimpleMessage_Ext() {} func (*SimpleMessage_No) isSimpleMessage_Ext() {} -func (m *SimpleMessage) GetExt() isSimpleMessage_Ext { - if m != nil { - return m.Ext - } - return nil -} +var File_proto_examples_echo_service_proto protoreflect.FileDescriptor + +var file_proto_examples_echo_service_proto_rawDesc = []byte{ + 0x0a, 0x21, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, + 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x1a, 0x1d, 0x68, + 0x74, 0x74, 0x70, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x46, 0x0a, 0x08, + 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x12, 0x1c, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x67, + 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x08, 0x70, 0x72, + 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x14, 0x0a, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x42, 0x06, 0x0a, 0x04, + 0x6d, 0x61, 0x72, 0x6b, 0x22, 0x89, 0x02, 0x0a, 0x0d, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x31, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x42, 0x21, 0xb2, 0xe4, 0x34, 0x1d, 0x0a, 0x04, 0x08, 0x05, 0x10, 0x02, 0x0a, 0x09, + 0x08, 0x06, 0x10, 0x02, 0x1a, 0x01, 0x32, 0x20, 0x01, 0x0a, 0x0a, 0x08, 0x07, 0x10, 0x02, 0x1a, + 0x02, 0x36, 0x31, 0x20, 0x01, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1f, 0x0a, 0x03, 0x6e, 0x75, 0x6d, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x42, 0x0d, 0xb2, 0xe4, 0x34, 0x09, 0x0a, 0x07, 0x08, 0x01, + 0x10, 0x01, 0x1a, 0x01, 0x30, 0x52, 0x03, 0x6e, 0x75, 0x6d, 0x12, 0x1b, 0x0a, 0x08, 0x6c, 0x69, + 0x6e, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x07, + 0x6c, 0x69, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x12, 0x14, 0x0a, 0x04, 0x6c, 0x61, 0x6e, 0x67, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x6c, 0x61, 0x6e, 0x67, 0x12, 0x2a, 0x0a, + 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, + 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, + 0x64, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x10, 0x0a, 0x02, 0x65, 0x6e, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x03, 0x48, 0x01, 0x52, 0x02, 0x65, 0x6e, 0x12, 0x24, 0x0a, 0x02, 0x6e, + 0x6f, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, + 0x65, 0x73, 0x2e, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x48, 0x01, 0x52, 0x02, 0x6e, + 0x6f, 0x42, 0x06, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x42, 0x05, 0x0a, 0x03, 0x65, 0x78, 0x74, + 0x32, 0xd8, 0x03, 0x0a, 0x0b, 0x45, 0x63, 0x68, 0x6f, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x12, 0xee, 0x01, 0x0a, 0x04, 0x45, 0x63, 0x68, 0x6f, 0x12, 0x17, 0x2e, 0x65, 0x78, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x1a, 0x17, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x53, 0x69, + 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xb3, 0x01, 0xca, 0xf3, + 0x34, 0xae, 0x01, 0x22, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, + 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x5a, 0x1d, 0x12, 0x1b, 0x2f, 0x76, + 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x2f, 0x7b, + 0x69, 0x64, 0x7d, 0x2f, 0x7b, 0x6e, 0x75, 0x6d, 0x7d, 0x5a, 0x24, 0x12, 0x22, 0x2f, 0x76, 0x31, + 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x2f, 0x7b, 0x69, + 0x64, 0x7d, 0x2f, 0x7b, 0x6e, 0x75, 0x6d, 0x7d, 0x2f, 0x7b, 0x6c, 0x61, 0x6e, 0x67, 0x7d, 0x5a, + 0x31, 0x12, 0x2f, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, + 0x63, 0x68, 0x6f, 0x31, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x2f, 0x7b, 0x6c, 0x69, 0x6e, 0x65, 0x5f, + 0x6e, 0x75, 0x6d, 0x7d, 0x2f, 0x7b, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x6e, 0x6f, 0x74, + 0x65, 0x7d, 0x5a, 0x1d, 0x12, 0x1b, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, + 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x32, 0x2f, 0x7b, 0x6e, 0x6f, 0x2e, 0x6e, 0x6f, 0x74, 0x65, + 0x7d, 0x12, 0x5c, 0x0a, 0x08, 0x45, 0x63, 0x68, 0x6f, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x17, 0x2e, + 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x17, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, + 0x73, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, + 0x1e, 0xca, 0xf3, 0x34, 0x1a, 0x22, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, + 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x62, 0x6f, 0x64, 0x79, 0x3a, 0x01, 0x2a, 0x12, + 0x5d, 0x0a, 0x0a, 0x45, 0x63, 0x68, 0x6f, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x17, 0x2e, + 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x17, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, + 0x73, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, + 0x1d, 0xca, 0xf3, 0x34, 0x19, 0x2a, 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, + 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x1a, 0x1b, + 0xea, 0xf3, 0x34, 0x17, 0x08, 0xb6, 0x95, 0xff, 0xff, 0x07, 0x12, 0x04, 0x67, 0x72, 0x70, 0x63, + 0x1a, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x01, 0x42, 0x38, 0x0a, 0x20, 0x63, + 0x6f, 0x6d, 0x2e, 0x62, 0x69, 0x6e, 0x63, 0x68, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, + 0x65, 0x61, 0x73, 0x65, 0x67, 0x77, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x42, + 0x0d, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x5a, 0x05, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_proto_examples_echo_service_proto_rawDescOnce sync.Once + file_proto_examples_echo_service_proto_rawDescData = file_proto_examples_echo_service_proto_rawDesc +) -func (m *SimpleMessage) GetEn() int64 { - if x, ok := m.GetExt().(*SimpleMessage_En); ok { - return x.En +func file_proto_examples_echo_service_proto_rawDescGZIP() []byte { + file_proto_examples_echo_service_proto_rawDescOnce.Do(func() { + file_proto_examples_echo_service_proto_rawDescData = protoimpl.X.CompressGZIP(file_proto_examples_echo_service_proto_rawDescData) + }) + return file_proto_examples_echo_service_proto_rawDescData +} + +var file_proto_examples_echo_service_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_proto_examples_echo_service_proto_goTypes = []interface{}{ + (*Embedded)(nil), // 0: examples.Embedded + (*SimpleMessage)(nil), // 1: examples.SimpleMessage +} +var file_proto_examples_echo_service_proto_depIdxs = []int32{ + 0, // 0: examples.SimpleMessage.status:type_name -> examples.Embedded + 0, // 1: examples.SimpleMessage.no:type_name -> examples.Embedded + 1, // 2: examples.EchoService.Echo:input_type -> examples.SimpleMessage + 1, // 3: examples.EchoService.EchoBody:input_type -> examples.SimpleMessage + 1, // 4: examples.EchoService.EchoDelete:input_type -> examples.SimpleMessage + 1, // 5: examples.EchoService.Echo:output_type -> examples.SimpleMessage + 1, // 6: examples.EchoService.EchoBody:output_type -> examples.SimpleMessage + 1, // 7: examples.EchoService.EchoDelete:output_type -> examples.SimpleMessage + 5, // [5:8] is the sub-list for method output_type + 2, // [2:5] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name +} + +func init() { file_proto_examples_echo_service_proto_init() } +func file_proto_examples_echo_service_proto_init() { + if File_proto_examples_echo_service_proto != nil { + return } - return 0 -} - -func (m *SimpleMessage) GetNo() *Embedded { - if x, ok := m.GetExt().(*SimpleMessage_No); ok { - return x.No + if !protoimpl.UnsafeEnabled { + file_proto_examples_echo_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Embedded); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_examples_echo_service_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SimpleMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } - return nil -} - -// XXX_OneofWrappers is for the internal use of the proto package. -func (*SimpleMessage) XXX_OneofWrappers() []interface{} { - return []interface{}{ + file_proto_examples_echo_service_proto_msgTypes[0].OneofWrappers = []interface{}{ + (*Embedded_Progress)(nil), + (*Embedded_Note)(nil), + } + file_proto_examples_echo_service_proto_msgTypes[1].OneofWrappers = []interface{}{ (*SimpleMessage_LineNum)(nil), (*SimpleMessage_Lang)(nil), (*SimpleMessage_En)(nil), (*SimpleMessage_No)(nil), } -} - -func init() { - proto.RegisterType((*Embedded)(nil), "examples.Embedded") - proto.RegisterType((*SimpleMessage)(nil), "examples.SimpleMessage") -} - -func init() { proto.RegisterFile("proto/examples/echo_service.proto", fileDescriptor_50dd28de91ad0693) } - -var fileDescriptor_50dd28de91ad0693 = []byte{ - // 544 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x53, 0x41, 0x6e, 0xd3, 0x40, - 0x14, 0xed, 0xd8, 0x4e, 0xec, 0xfc, 0x2a, 0x52, 0x34, 0x02, 0xc5, 0x38, 0x04, 0xdc, 0xa8, 0x8b, - 0x28, 0x0b, 0x9b, 0x04, 0x0b, 0x21, 0x96, 0x16, 0x41, 0xdd, 0x80, 0x90, 0xbb, 0x8b, 0x40, 0x91, - 0x63, 0x7f, 0x12, 0x8b, 0x78, 0xc6, 0xb2, 0x9d, 0xd2, 0x2a, 0xca, 0x01, 0x38, 0x00, 0xd7, 0x60, - 0x51, 0x24, 0x0e, 0x91, 0x13, 0x70, 0x80, 0xae, 0x58, 0xb0, 0xc9, 0x01, 0x8a, 0xc6, 0x89, 0x8b, - 0xa0, 0x2d, 0x8b, 0xae, 0x3c, 0x7f, 0xde, 0xf3, 0xfb, 0xff, 0xbf, 0xa7, 0x81, 0x83, 0x24, 0xe5, - 0x39, 0xb7, 0xf1, 0xd4, 0x8f, 0x93, 0x39, 0x66, 0x36, 0x06, 0x33, 0x3e, 0xce, 0x30, 0x3d, 0x89, - 0x02, 0xb4, 0x0a, 0x8c, 0x6a, 0x25, 0x68, 0xb4, 0x67, 0x79, 0x9e, 0xf0, 0x24, 0x8f, 0x38, 0xcb, - 0x6c, 0x9f, 0x31, 0x9e, 0xfb, 0xc5, 0x79, 0x4b, 0xec, 0xbc, 0x02, 0x6d, 0x18, 0x4f, 0x30, 0x0c, - 0x31, 0xa4, 0x0f, 0x41, 0x4b, 0x52, 0x3e, 0x4d, 0x31, 0xcb, 0x74, 0x62, 0x92, 0xae, 0x7c, 0xb4, - 0xe7, 0x5d, 0xdd, 0xd0, 0x7b, 0xa0, 0x30, 0x9e, 0xa3, 0x2e, 0x99, 0xa4, 0x5b, 0x3b, 0xda, 0xf3, - 0x8a, 0xca, 0xad, 0x82, 0x12, 0xfb, 0xe9, 0xc7, 0xce, 0x67, 0x09, 0xea, 0xc7, 0x91, 0x68, 0xf9, - 0x1a, 0xb3, 0xcc, 0x9f, 0x22, 0xed, 0x83, 0x14, 0x85, 0x85, 0x4e, 0xcd, 0x3d, 0x38, 0xbf, 0x70, - 0xda, 0xa0, 0x68, 0x95, 0x86, 0x04, 0x35, 0xad, 0xda, 0x90, 0x0c, 0x32, 0x30, 0x09, 0x80, 0xa6, - 0x36, 0x24, 0x43, 0x7a, 0xd6, 0x37, 0x89, 0x27, 0x45, 0x21, 0x7d, 0x0c, 0x32, 0x5b, 0xc4, 0x45, - 0x07, 0xd9, 0xad, 0x9f, 0x5f, 0x38, 0x35, 0x50, 0x35, 0xd2, 0x20, 0x06, 0x79, 0xe2, 0x09, 0x84, - 0xb6, 0x40, 0x9b, 0x47, 0x0c, 0xc7, 0x82, 0x25, 0xef, 0x26, 0x54, 0xc5, 0xcd, 0x9b, 0x45, 0x2c, - 0x06, 0x9c, 0xfb, 0x6c, 0xaa, 0x2b, 0xe5, 0x80, 0xa2, 0xa2, 0x3d, 0xa8, 0x66, 0xb9, 0x9f, 0x2f, - 0x32, 0xbd, 0x62, 0x92, 0xee, 0xfe, 0x80, 0x5a, 0xa5, 0x35, 0x56, 0xb9, 0xb8, 0xb7, 0x63, 0xd0, - 0x06, 0x48, 0xc8, 0xf4, 0x6a, 0x21, 0x4c, 0x3c, 0x09, 0x19, 0x3d, 0x04, 0x89, 0x71, 0x5d, 0xbd, - 0xed, 0x4f, 0xc1, 0x62, 0x5c, 0x98, 0x10, 0xf0, 0x10, 0xdd, 0x0a, 0xc8, 0x78, 0x9a, 0x0f, 0x7e, - 0xc8, 0xb0, 0x3f, 0x0c, 0x66, 0xfc, 0x78, 0x1b, 0x09, 0xfd, 0x45, 0x40, 0x11, 0x35, 0x6d, 0xfe, - 0x51, 0xf8, 0xcb, 0x2b, 0xe3, 0x36, 0xa0, 0xf3, 0x8d, 0xac, 0x37, 0xce, 0x57, 0xd2, 0xb9, 0x6f, - 0x9f, 0xf4, 0xcb, 0xc0, 0x8b, 0xbc, 0xed, 0x65, 0x14, 0xae, 0x46, 0x6d, 0xda, 0xba, 0x11, 0xb0, - 0x97, 0x6c, 0x11, 0xaf, 0x46, 0x87, 0xb4, 0xf3, 0x1f, 0xd8, 0x5e, 0x0a, 0x83, 0x56, 0xa3, 0x3e, - 0xb5, 0xff, 0x65, 0xf5, 0x77, 0xb4, 0xd2, 0xec, 0x95, 0xbd, 0xdc, 0x5a, 0x64, 0x89, 0xd0, 0x6f, - 0xec, 0x3b, 0xb0, 0x97, 0x8c, 0x6f, 0x61, 0xfa, 0x0e, 0x34, 0xb1, 0xaf, 0xcb, 0xc3, 0xb3, 0x3b, - 0xec, 0xfc, 0x68, 0xbd, 0x71, 0x8c, 0xeb, 0x1b, 0x8f, 0x27, 0x3c, 0x3c, 0x7b, 0x41, 0x7a, 0xf4, - 0x3d, 0x80, 0x50, 0x7f, 0x89, 0x73, 0xcc, 0xf1, 0x0e, 0xfa, 0xed, 0xf5, 0xc6, 0x79, 0xd0, 0x6b, - 0x5e, 0xd3, 0x0f, 0x0b, 0x41, 0xa3, 0xf5, 0x73, 0xe3, 0x34, 0xb5, 0xef, 0x5f, 0x2e, 0x2f, 0x55, - 0xaa, 0x4c, 0xd3, 0x24, 0x30, 0xd4, 0x10, 0x3f, 0xf8, 0x8b, 0x79, 0x6e, 0x12, 0xf7, 0x39, 0x98, - 0x01, 0x8f, 0xad, 0x49, 0xc4, 0x82, 0x19, 0x32, 0x11, 0x7a, 0x6a, 0xa1, 0x9f, 0xe1, 0xf4, 0xd3, - 0x55, 0x37, 0xb7, 0x3e, 0xdc, 0x9d, 0xde, 0x8a, 0x17, 0x36, 0xaa, 0x14, 0x0f, 0x6d, 0x52, 0x2d, - 0x3e, 0x4f, 0x7f, 0x07, 0x00, 0x00, 0xff, 0xff, 0x50, 0x55, 0xf3, 0xae, 0xbd, 0x03, 0x00, 0x00, + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_proto_examples_echo_service_proto_rawDesc, + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_proto_examples_echo_service_proto_goTypes, + DependencyIndexes: file_proto_examples_echo_service_proto_depIdxs, + MessageInfos: file_proto_examples_echo_service_proto_msgTypes, + }.Build() + File_proto_examples_echo_service_proto = out.File + file_proto_examples_echo_service_proto_rawDesc = nil + file_proto_examples_echo_service_proto_goTypes = nil + file_proto_examples_echo_service_proto_depIdxs = nil } // Reference imports to suppress errors if they are not otherwise used. var _ context.Context -var _ grpc.ClientConn +var _ grpc.ClientConnInterface // 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 +const _ = grpc.SupportPackageIsVersion6 // EchoServiceClient is the client API for EchoService service. // @@ -313,10 +432,10 @@ type EchoServiceClient interface { } type echoServiceClient struct { - cc *grpc.ClientConn + cc grpc.ClientConnInterface } -func NewEchoServiceClient(cc *grpc.ClientConn) EchoServiceClient { +func NewEchoServiceClient(cc grpc.ClientConnInterface) EchoServiceClient { return &echoServiceClient{cc} } @@ -354,6 +473,20 @@ type EchoServiceServer interface { EchoDelete(context.Context, *SimpleMessage) (*SimpleMessage, error) } +// UnimplementedEchoServiceServer can be embedded to have forward compatible implementations. +type UnimplementedEchoServiceServer struct { +} + +func (*UnimplementedEchoServiceServer) Echo(context.Context, *SimpleMessage) (*SimpleMessage, error) { + return nil, status.Errorf(codes.Unimplemented, "method Echo not implemented") +} +func (*UnimplementedEchoServiceServer) EchoBody(context.Context, *SimpleMessage) (*SimpleMessage, error) { + return nil, status.Errorf(codes.Unimplemented, "method EchoBody not implemented") +} +func (*UnimplementedEchoServiceServer) EchoDelete(context.Context, *SimpleMessage) (*SimpleMessage, error) { + return nil, status.Errorf(codes.Unimplemented, "method EchoDelete not implemented") +} + func RegisterEchoServiceServer(s *grpc.Server, srv EchoServiceServer) { s.RegisterService(&_EchoService_serviceDesc, srv) } diff --git a/proto/examples/echo_service.pb.gw.go b/proto/examples/echo_service.pb.gw.go index d17576d..512d4d4 100755 --- a/proto/examples/echo_service.pb.gw.go +++ b/proto/examples/echo_service.pb.gw.go @@ -29,6 +29,7 @@ import ( "github.com/grpc-ecosystem/grpc-gateway/utilities" "google.golang.org/grpc" "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" "google.golang.org/grpc/naming" "google.golang.org/grpc/status" ) @@ -187,7 +188,10 @@ func local_request_EchoService_Echo_0(ctx context.Context, marshaler runtime.Mar return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } - if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_EchoService_Echo_0); err != nil { + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EchoService_Echo_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -296,7 +300,10 @@ func local_request_EchoService_Echo_1(ctx context.Context, marshaler runtime.Mar return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "num", err) } - if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_EchoService_Echo_1); err != nil { + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EchoService_Echo_1); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -354,7 +361,7 @@ func request_EchoService_Echo_2(ctx context.Context, marshaler runtime.Marshaler if protoReq.Code == nil { protoReq.Code = &SimpleMessage_Lang{} } else if _, ok := protoReq.Code.(*SimpleMessage_Lang); !ok { - return nil, metadata, grpc.Errorf(codes.InvalidArgument, "expect type: *SimpleMessage_Lang, but: %t\n", protoReq.Code) + return nil, metadata, status.Errorf(codes.InvalidArgument, "expect type: *SimpleMessage_Lang, but: %t\n", protoReq.Code) } protoReq.Code.(*SimpleMessage_Lang).Lang, err = runtime.String(val) @@ -430,7 +437,7 @@ func local_request_EchoService_Echo_2(ctx context.Context, marshaler runtime.Mar if protoReq.Code == nil { protoReq.Code = &SimpleMessage_Lang{} } else if _, ok := protoReq.Code.(*SimpleMessage_Lang); !ok { - return nil, metadata, grpc.Errorf(codes.InvalidArgument, "expect type: *SimpleMessage_Lang, but: %t\n", protoReq.Code) + return nil, metadata, status.Errorf(codes.InvalidArgument, "expect type: *SimpleMessage_Lang, but: %t\n", protoReq.Code) } protoReq.Code.(*SimpleMessage_Lang).Lang, err = runtime.String(val) @@ -438,7 +445,10 @@ func local_request_EchoService_Echo_2(ctx context.Context, marshaler runtime.Mar return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "lang", err) } - if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_EchoService_Echo_2); err != nil { + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EchoService_Echo_2); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -484,7 +494,7 @@ func request_EchoService_Echo_3(ctx context.Context, marshaler runtime.Marshaler if protoReq.Code == nil { protoReq.Code = &SimpleMessage_LineNum{} } else if _, ok := protoReq.Code.(*SimpleMessage_LineNum); !ok { - return nil, metadata, grpc.Errorf(codes.InvalidArgument, "expect type: *SimpleMessage_LineNum, but: %t\n", protoReq.Code) + return nil, metadata, status.Errorf(codes.InvalidArgument, "expect type: *SimpleMessage_LineNum, but: %t\n", protoReq.Code) } protoReq.Code.(*SimpleMessage_LineNum).LineNum, err = runtime.Int64(val) @@ -561,7 +571,7 @@ func local_request_EchoService_Echo_3(ctx context.Context, marshaler runtime.Mar if protoReq.Code == nil { protoReq.Code = &SimpleMessage_LineNum{} } else if _, ok := protoReq.Code.(*SimpleMessage_LineNum); !ok { - return nil, metadata, grpc.Errorf(codes.InvalidArgument, "expect type: *SimpleMessage_LineNum, but: %t\n", protoReq.Code) + return nil, metadata, status.Errorf(codes.InvalidArgument, "expect type: *SimpleMessage_LineNum, but: %t\n", protoReq.Code) } protoReq.Code.(*SimpleMessage_LineNum).LineNum, err = runtime.Int64(val) @@ -580,7 +590,10 @@ func local_request_EchoService_Echo_3(ctx context.Context, marshaler runtime.Mar return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "status.note", err) } - if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_EchoService_Echo_3); err != nil { + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EchoService_Echo_3); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -666,7 +679,10 @@ func local_request_EchoService_Echo_4(ctx context.Context, marshaler runtime.Mar return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "no.note", err) } - if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_EchoService_Echo_4); err != nil { + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EchoService_Echo_4); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -766,7 +782,10 @@ func local_request_EchoService_EchoDelete_0(ctx context.Context, marshaler runti var protoReq SimpleMessage var metadata runtime.ServerMetadata - if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_EchoService_EchoDelete_0); err != nil { + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EchoService_EchoDelete_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -775,6 +794,155 @@ func local_request_EchoService_EchoDelete_0(ctx context.Context, marshaler runti } +// RegisterEchoServiceHandlerServer registers the http handlers for service EchoService to "mux". +// UnaryRPC :call EchoServiceServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +// Note that using this registration option will cause many gRPC library features (such as grpc.SendHeader, etc) to stop working. Consider using RegisterEchoServiceHandlerFromEndpoint instead. +func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server EchoServiceServer) error { + + mux.Handle("POST", pattern_EchoService_Echo_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + 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_EchoService_Echo_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_EchoService_Echo_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_EchoService_Echo_1, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + 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_EchoService_Echo_1(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_EchoService_Echo_1(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_EchoService_Echo_2, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + 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_EchoService_Echo_2(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_EchoService_Echo_2(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_EchoService_Echo_3, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + 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_EchoService_Echo_3(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_EchoService_Echo_3(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_EchoService_Echo_4, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + 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_EchoService_Echo_4(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_EchoService_Echo_4(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("POST", pattern_EchoService_EchoBody_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + 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_EchoService_EchoBody_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_EchoService_EchoBody_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("DELETE", pattern_EchoService_EchoDelete_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + 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_EchoService_EchoDelete_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_EchoService_EchoDelete_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + // Register itself to runtime. func init() { var s *runtime.Service @@ -841,40 +1009,29 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux // TODO(mojz): review all locking/unlocking logic. // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() - cli := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client - if cli == nil { + client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client + if client == nil { runtime.DefaultOtherErrorHandler(w, req, "service disabled", http.StatusInternalServerError) return } ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) if err != nil { - // grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) + grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) runtime.HTTPError(ctx, nil, &runtime.JSONBuiltin{}, w, req, err) return } ctx, cancel := context.WithCancel(req.Context()) defer cancel() - if cn, ok := w.(http.CloseNotifier); ok { - go func(done <-chan struct{}, closed <-chan bool) { - select { - case <-done: - case <-closed: - cancel() - } - }(ctx.Done(), cn.CloseNotify()) - } inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) rctx, err := runtime.AnnotateContext(ctx, mux, req) if err != nil { - // grpclog.Errorf("runtime.AnnotateContext returns error: %v", err) runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_EchoService_Echo_0(rctx, inboundMarshaler, cli, req, pathParams) + resp, md, err := request_EchoService_Echo_0(rctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { - // grpclog.Errorf("request_%s_%s_%s returns error: %v", "EchoService", "Echo", "0", err) runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } @@ -888,40 +1045,29 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux // TODO(mojz): review all locking/unlocking logic. // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() - cli := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client - if cli == nil { + client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client + if client == nil { runtime.DefaultOtherErrorHandler(w, req, "service disabled", http.StatusInternalServerError) return } ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) if err != nil { - // grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) + grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) runtime.HTTPError(ctx, nil, &runtime.JSONBuiltin{}, w, req, err) return } ctx, cancel := context.WithCancel(req.Context()) defer cancel() - if cn, ok := w.(http.CloseNotifier); ok { - go func(done <-chan struct{}, closed <-chan bool) { - select { - case <-done: - case <-closed: - cancel() - } - }(ctx.Done(), cn.CloseNotify()) - } inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) rctx, err := runtime.AnnotateContext(ctx, mux, req) if err != nil { - // grpclog.Errorf("runtime.AnnotateContext returns error: %v", err) runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_EchoService_Echo_1(rctx, inboundMarshaler, cli, req, pathParams) + resp, md, err := request_EchoService_Echo_1(rctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { - // grpclog.Errorf("request_%s_%s_%s returns error: %v", "EchoService", "Echo", "1", err) runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } @@ -935,40 +1081,29 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux // TODO(mojz): review all locking/unlocking logic. // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() - cli := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client - if cli == nil { + client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client + if client == nil { runtime.DefaultOtherErrorHandler(w, req, "service disabled", http.StatusInternalServerError) return } ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) if err != nil { - // grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) + grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) runtime.HTTPError(ctx, nil, &runtime.JSONBuiltin{}, w, req, err) return } ctx, cancel := context.WithCancel(req.Context()) defer cancel() - if cn, ok := w.(http.CloseNotifier); ok { - go func(done <-chan struct{}, closed <-chan bool) { - select { - case <-done: - case <-closed: - cancel() - } - }(ctx.Done(), cn.CloseNotify()) - } inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) rctx, err := runtime.AnnotateContext(ctx, mux, req) if err != nil { - // grpclog.Errorf("runtime.AnnotateContext returns error: %v", err) runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_EchoService_Echo_2(rctx, inboundMarshaler, cli, req, pathParams) + resp, md, err := request_EchoService_Echo_2(rctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { - // grpclog.Errorf("request_%s_%s_%s returns error: %v", "EchoService", "Echo", "2", err) runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } @@ -982,40 +1117,29 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux // TODO(mojz): review all locking/unlocking logic. // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() - cli := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client - if cli == nil { + client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client + if client == nil { runtime.DefaultOtherErrorHandler(w, req, "service disabled", http.StatusInternalServerError) return } ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) if err != nil { - // grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) + grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) runtime.HTTPError(ctx, nil, &runtime.JSONBuiltin{}, w, req, err) return } ctx, cancel := context.WithCancel(req.Context()) defer cancel() - if cn, ok := w.(http.CloseNotifier); ok { - go func(done <-chan struct{}, closed <-chan bool) { - select { - case <-done: - case <-closed: - cancel() - } - }(ctx.Done(), cn.CloseNotify()) - } inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) rctx, err := runtime.AnnotateContext(ctx, mux, req) if err != nil { - // grpclog.Errorf("runtime.AnnotateContext returns error: %v", err) runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_EchoService_Echo_3(rctx, inboundMarshaler, cli, req, pathParams) + resp, md, err := request_EchoService_Echo_3(rctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { - // grpclog.Errorf("request_%s_%s_%s returns error: %v", "EchoService", "Echo", "3", err) runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } @@ -1029,40 +1153,29 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux // TODO(mojz): review all locking/unlocking logic. // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() - cli := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client - if cli == nil { + client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client + if client == nil { runtime.DefaultOtherErrorHandler(w, req, "service disabled", http.StatusInternalServerError) return } ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) if err != nil { - // grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) + grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) runtime.HTTPError(ctx, nil, &runtime.JSONBuiltin{}, w, req, err) return } ctx, cancel := context.WithCancel(req.Context()) defer cancel() - if cn, ok := w.(http.CloseNotifier); ok { - go func(done <-chan struct{}, closed <-chan bool) { - select { - case <-done: - case <-closed: - cancel() - } - }(ctx.Done(), cn.CloseNotify()) - } inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) rctx, err := runtime.AnnotateContext(ctx, mux, req) if err != nil { - // grpclog.Errorf("runtime.AnnotateContext returns error: %v", err) runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_EchoService_Echo_4(rctx, inboundMarshaler, cli, req, pathParams) + resp, md, err := request_EchoService_Echo_4(rctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { - // grpclog.Errorf("request_%s_%s_%s returns error: %v", "EchoService", "Echo", "4", err) runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } @@ -1076,40 +1189,29 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux // TODO(mojz): review all locking/unlocking logic. // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() - cli := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client - if cli == nil { + client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client + if client == nil { runtime.DefaultOtherErrorHandler(w, req, "service disabled", http.StatusInternalServerError) return } ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "EchoBody", w, req) if err != nil { - // grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) + grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) runtime.HTTPError(ctx, nil, &runtime.JSONBuiltin{}, w, req, err) return } ctx, cancel := context.WithCancel(req.Context()) defer cancel() - if cn, ok := w.(http.CloseNotifier); ok { - go func(done <-chan struct{}, closed <-chan bool) { - select { - case <-done: - case <-closed: - cancel() - } - }(ctx.Done(), cn.CloseNotify()) - } inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) rctx, err := runtime.AnnotateContext(ctx, mux, req) if err != nil { - // grpclog.Errorf("runtime.AnnotateContext returns error: %v", err) runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_EchoService_EchoBody_0(rctx, inboundMarshaler, cli, req, pathParams) + resp, md, err := request_EchoService_EchoBody_0(rctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { - // grpclog.Errorf("request_%s_%s_%s returns error: %v", "EchoService", "EchoBody", "0", err) runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } @@ -1123,40 +1225,29 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux // TODO(mojz): review all locking/unlocking logic. // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() - cli := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client - if cli == nil { + client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client + if client == nil { runtime.DefaultOtherErrorHandler(w, req, "service disabled", http.StatusInternalServerError) return } ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "EchoDelete", w, req) if err != nil { - // grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) + grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) runtime.HTTPError(ctx, nil, &runtime.JSONBuiltin{}, w, req, err) return } ctx, cancel := context.WithCancel(req.Context()) defer cancel() - if cn, ok := w.(http.CloseNotifier); ok { - go func(done <-chan struct{}, closed <-chan bool) { - select { - case <-done: - case <-closed: - cancel() - } - }(ctx.Done(), cn.CloseNotify()) - } inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) rctx, err := runtime.AnnotateContext(ctx, mux, req) if err != nil { - // grpclog.Errorf("runtime.AnnotateContext returns error: %v", err) runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_EchoService_EchoDelete_0(rctx, inboundMarshaler, cli, req, pathParams) + resp, md, err := request_EchoService_EchoDelete_0(rctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { - // grpclog.Errorf("request_%s_%s_%s returns error: %v", "EchoService", "EchoDelete", "0", err) runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } diff --git a/proto/examples/echo_service.proto b/proto/examples/echo_service.proto index 8331929..96b28b6 100644 --- a/proto/examples/echo_service.proto +++ b/proto/examples/echo_service.proto @@ -25,37 +25,37 @@ message Embedded { message SimpleMessage { // Id represents the message identifier. string id = 1 -// [ -// (ease.api.rules) = { -// rules: { -// type: STRING, -// operator: NON_NIL, -// }, -// rules: { -// type: STRING, -// function: TRIM, -// operator: LEN_GT, -// value: "2", -// }, -// rules: { -// type: STRING, -// function: TRIM, -// operator: LEN_LT, -// value: "61", -// } -// } -// ] + [ + (ease.api.rules) = { + rules: { + type: STRING, + operator: NON_NIL, + }, + rules: { + type: STRING, + function: TRIM, + operator: LEN_GT, + value: "2", + }, + rules: { + type: STRING, + function: TRIM, + operator: LEN_LT, + value: "61", + } + } + ] ; int64 num = 2 -// [ -// (ease.api.rules) = { -// rules: { -// type: NUMBER, -// operator: GT, -// value: "0", -// } -// } -// ] + [ + (ease.api.rules) = { + rules: { + type: NUMBER, + operator: GT, + value: "0", + } + } + ] ; oneof code { int64 line_num = 3; From 1d8c0f36c467731ca7039e174c3090cce6a1fdb4 Mon Sep 17 00:00:00 2001 From: chenbin1314 Date: Sat, 11 Jul 2020 22:34:36 +0800 Subject: [PATCH 11/56] =?UTF-8?q?=E8=A7=A3=E5=86=B3Response=E8=BE=93?= =?UTF-8?q?=E5=87=BAerror.code=E4=B8=BA=E5=AD=97=E7=AC=A6=E4=B8=B2?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gateway/README.md | 44 ++++++++++++++++++++++++++- gateway/runtime/errors.go | 3 -- gateway/runtime/marshaler_registry.go | 5 ++- 3 files changed, 47 insertions(+), 5 deletions(-) diff --git a/gateway/README.md b/gateway/README.md index 3dc5aad..6f6ad2c 100644 --- a/gateway/README.md +++ b/gateway/README.md @@ -10,7 +10,7 @@ grpc-gateway 是一款非常优秀的网关服务器,负责转化和代理转 为了支持这些新feature,我不得不将grpc-gateway的源码拷贝到ease-gateway中并进行大量的修改,```//gateway``` 目录下就是从grpc-gateway中拷贝的部分源码 -# 修改内容 +# Changed History 以下详细说明了我基于grpc-gateway修改了哪些目录下的代码 @@ -134,6 +134,48 @@ Link [grpc-ecosystem/grpc-gateway/runtime](https://github.com/grpc-ecosystem/g - mux.go - query_test.go +## Upgrade issues + +#### 输出error.code 为字符串 + +``` +{ + "error": { + "code": "BAD_REQUEST", + "params": [ + "Validation error" + ] + }, + "code": 3, + "message": "{\"code\":100006,\"params\":[\"Validation error\"]}" +} +``` +> 升级之后response body中 error.code为字符串, 期望是Integer +``` +{ + "error": { + "code": 100006, + "params": [ + "Validation error" + ] + }, + "code": 3, + "message": "{\"code\":100006,\"params\":[\"Validation error\"]}" +} +``` +问题出在 //gateway/runtime/marshaler_registry.go 文件中, EnumsAsInts应该设置为true +``` +var ( + acceptHeader = http.CanonicalHeaderKey("Accept") + contentTypeHeader = http.CanonicalHeaderKey("Content-Type") + + defaultMarshaler = &JSONPb{ + OrigName: true, + EnumsAsInts: true, + } +) +``` + ## grpc-ecosystem/grpc-gateway grpc-ecosystem/grpc-gateway: grpc-gateway is a plugin of protoc. It reads diff --git a/gateway/runtime/errors.go b/gateway/runtime/errors.go index e02824e..704128d 100644 --- a/gateway/runtime/errors.go +++ b/gateway/runtime/errors.go @@ -2,7 +2,6 @@ package runtime import ( "context" - "fmt" "io" "net/http" "strings" @@ -149,8 +148,6 @@ func DefaultHTTPError(ctx context.Context, mux *ServeMux, marshaler Marshaler, w Details: s.Proto().GetDetails(), } - fmt.Printf("Marshal error %v\n", body) - buf, merr := marshaler.Marshal(body) if merr != nil { grpclog.Infof("Failed to marshal error message %q: %v", body, merr) diff --git a/gateway/runtime/marshaler_registry.go b/gateway/runtime/marshaler_registry.go index 8dd5c24..ae673e3 100644 --- a/gateway/runtime/marshaler_registry.go +++ b/gateway/runtime/marshaler_registry.go @@ -16,7 +16,10 @@ var ( acceptHeader = http.CanonicalHeaderKey("Accept") contentTypeHeader = http.CanonicalHeaderKey("Content-Type") - defaultMarshaler = &JSONPb{OrigName: true} + defaultMarshaler = &JSONPb{ + OrigName: true, + EnumsAsInts: true, + } ) // MarshalerForRequest returns the inbound/outbound marshalers for this request. From 11d1c59c847f11d1f67cfa49fb94be89fd5e151f Mon Sep 17 00:00:00 2001 From: chenbin1314 Date: Sat, 11 Jul 2020 23:58:09 +0800 Subject: [PATCH 12/56] Synchronization with github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger //gateway/protoc-gen-swagger code in the directory --- examples/proto/echo_service.pb.go | 497 +++++--- examples/proto/echo_service.pb.gw.go | 579 +++++++-- examples/proto/echo_service.swagger.json | 18 +- gateway/README.md | 13 + gateway/internal/errors.proto | 2 +- .../protoc-gen-swagger/genswagger/BUILD.bazel | 5 +- .../genswagger/generator.go | 9 +- .../protoc-gen-swagger/genswagger/template.go | 447 +++++-- .../genswagger/template_test.go | 1083 +++++++++++++++-- .../protoc-gen-swagger/genswagger/types.go | 23 +- .../options/openapiv2.proto | 122 +- proto/examples/echo_service.swagger.json | 30 +- 12 files changed, 2275 insertions(+), 553 deletions(-) diff --git a/examples/proto/echo_service.pb.go b/examples/proto/echo_service.pb.go index 18a3f20..3c34e78 100755 --- a/examples/proto/echo_service.pb.go +++ b/examples/proto/echo_service.pb.go @@ -1,79 +1,78 @@ // Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.22.0 +// protoc v3.9.0 // source: examples/proto/echo_service.proto package proto import ( context "context" - fmt "fmt" _ "github.com/binchencoder/ease-gateway/httpoptions" proto "github.com/golang/protobuf/proto" grpc "google.golang.org/grpc" - math "math" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" ) -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) -// 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.ProtoPackageIsVersion3 // please upgrade the proto package +// This is a compile-time assertion that a sufficiently up-to-date version +// of the legacy proto package is being used. +const _ = proto.ProtoPackageIsVersion4 type Embedded struct { - // Types that are valid to be assigned to Mark: + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Mark: // *Embedded_Progress // *Embedded_Note - Mark isEmbedded_Mark `protobuf_oneof:"mark"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + Mark isEmbedded_Mark `protobuf_oneof:"mark"` } -func (m *Embedded) Reset() { *m = Embedded{} } -func (m *Embedded) String() string { return proto.CompactTextString(m) } -func (*Embedded) ProtoMessage() {} -func (*Embedded) Descriptor() ([]byte, []int) { - return fileDescriptor_4b4d3f52be8fcd98, []int{0} +func (x *Embedded) Reset() { + *x = Embedded{} + if protoimpl.UnsafeEnabled { + mi := &file_examples_proto_echo_service_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *Embedded) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Embedded.Unmarshal(m, b) -} -func (m *Embedded) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Embedded.Marshal(b, m, deterministic) -} -func (m *Embedded) XXX_Merge(src proto.Message) { - xxx_messageInfo_Embedded.Merge(m, src) -} -func (m *Embedded) XXX_Size() int { - return xxx_messageInfo_Embedded.Size(m) +func (x *Embedded) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *Embedded) XXX_DiscardUnknown() { - xxx_messageInfo_Embedded.DiscardUnknown(m) -} - -var xxx_messageInfo_Embedded proto.InternalMessageInfo -type isEmbedded_Mark interface { - isEmbedded_Mark() -} +func (*Embedded) ProtoMessage() {} -type Embedded_Progress struct { - Progress int64 `protobuf:"varint,1,opt,name=progress,proto3,oneof"` +func (x *Embedded) ProtoReflect() protoreflect.Message { + mi := &file_examples_proto_echo_service_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -type Embedded_Note struct { - Note string `protobuf:"bytes,2,opt,name=note,proto3,oneof"` +// Deprecated: Use Embedded.ProtoReflect.Descriptor instead. +func (*Embedded) Descriptor() ([]byte, []int) { + return file_examples_proto_echo_service_proto_rawDescGZIP(), []int{0} } -func (*Embedded_Progress) isEmbedded_Mark() {} - -func (*Embedded_Note) isEmbedded_Mark() {} - func (m *Embedded) GetMark() isEmbedded_Mark { if m != nil { return m.Mark @@ -81,100 +80,100 @@ func (m *Embedded) GetMark() isEmbedded_Mark { return nil } -func (m *Embedded) GetProgress() int64 { - if x, ok := m.GetMark().(*Embedded_Progress); ok { +func (x *Embedded) GetProgress() int64 { + if x, ok := x.GetMark().(*Embedded_Progress); ok { return x.Progress } return 0 } -func (m *Embedded) GetNote() string { - if x, ok := m.GetMark().(*Embedded_Note); ok { +func (x *Embedded) GetNote() string { + if x, ok := x.GetMark().(*Embedded_Note); ok { return x.Note } return "" } -// XXX_OneofWrappers is for the internal use of the proto package. -func (*Embedded) XXX_OneofWrappers() []interface{} { - return []interface{}{ - (*Embedded_Progress)(nil), - (*Embedded_Note)(nil), - } +type isEmbedded_Mark interface { + isEmbedded_Mark() +} + +type Embedded_Progress struct { + Progress int64 `protobuf:"varint,1,opt,name=progress,proto3,oneof"` } +type Embedded_Note struct { + Note string `protobuf:"bytes,2,opt,name=note,proto3,oneof"` +} + +func (*Embedded_Progress) isEmbedded_Mark() {} + +func (*Embedded_Note) isEmbedded_Mark() {} + type SimpleMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` Num int64 `protobuf:"varint,2,opt,name=num,proto3" json:"num,omitempty"` - // Types that are valid to be assigned to Code: + // Types that are assignable to Code: // *SimpleMessage_LineNum // *SimpleMessage_Lang Code isSimpleMessage_Code `protobuf_oneof:"code"` Status *Embedded `protobuf:"bytes,5,opt,name=status,proto3" json:"status,omitempty"` - // Types that are valid to be assigned to Ext: + // Types that are assignable to Ext: // *SimpleMessage_En // *SimpleMessage_No - Ext isSimpleMessage_Ext `protobuf_oneof:"ext"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + Ext isSimpleMessage_Ext `protobuf_oneof:"ext"` } -func (m *SimpleMessage) Reset() { *m = SimpleMessage{} } -func (m *SimpleMessage) String() string { return proto.CompactTextString(m) } -func (*SimpleMessage) ProtoMessage() {} -func (*SimpleMessage) Descriptor() ([]byte, []int) { - return fileDescriptor_4b4d3f52be8fcd98, []int{1} +func (x *SimpleMessage) Reset() { + *x = SimpleMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_examples_proto_echo_service_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *SimpleMessage) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SimpleMessage.Unmarshal(m, b) -} -func (m *SimpleMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SimpleMessage.Marshal(b, m, deterministic) +func (x *SimpleMessage) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *SimpleMessage) XXX_Merge(src proto.Message) { - xxx_messageInfo_SimpleMessage.Merge(m, src) -} -func (m *SimpleMessage) XXX_Size() int { - return xxx_messageInfo_SimpleMessage.Size(m) -} -func (m *SimpleMessage) XXX_DiscardUnknown() { - xxx_messageInfo_SimpleMessage.DiscardUnknown(m) -} - -var xxx_messageInfo_SimpleMessage proto.InternalMessageInfo -func (m *SimpleMessage) GetId() string { - if m != nil { - return m.Id - } - return "" -} +func (*SimpleMessage) ProtoMessage() {} -func (m *SimpleMessage) GetNum() int64 { - if m != nil { - return m.Num +func (x *SimpleMessage) ProtoReflect() protoreflect.Message { + mi := &file_examples_proto_echo_service_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms } - return 0 + return mi.MessageOf(x) } -type isSimpleMessage_Code interface { - isSimpleMessage_Code() +// Deprecated: Use SimpleMessage.ProtoReflect.Descriptor instead. +func (*SimpleMessage) Descriptor() ([]byte, []int) { + return file_examples_proto_echo_service_proto_rawDescGZIP(), []int{1} } -type SimpleMessage_LineNum struct { - LineNum int64 `protobuf:"varint,3,opt,name=line_num,json=lineNum,proto3,oneof"` +func (x *SimpleMessage) GetId() string { + if x != nil { + return x.Id + } + return "" } -type SimpleMessage_Lang struct { - Lang string `protobuf:"bytes,4,opt,name=lang,proto3,oneof"` +func (x *SimpleMessage) GetNum() int64 { + if x != nil { + return x.Num + } + return 0 } -func (*SimpleMessage_LineNum) isSimpleMessage_Code() {} - -func (*SimpleMessage_Lang) isSimpleMessage_Code() {} - func (m *SimpleMessage) GetCode() isSimpleMessage_Code { if m != nil { return m.Code @@ -182,27 +181,64 @@ func (m *SimpleMessage) GetCode() isSimpleMessage_Code { return nil } -func (m *SimpleMessage) GetLineNum() int64 { - if x, ok := m.GetCode().(*SimpleMessage_LineNum); ok { +func (x *SimpleMessage) GetLineNum() int64 { + if x, ok := x.GetCode().(*SimpleMessage_LineNum); ok { return x.LineNum } return 0 } -func (m *SimpleMessage) GetLang() string { - if x, ok := m.GetCode().(*SimpleMessage_Lang); ok { +func (x *SimpleMessage) GetLang() string { + if x, ok := x.GetCode().(*SimpleMessage_Lang); ok { return x.Lang } return "" } -func (m *SimpleMessage) GetStatus() *Embedded { +func (x *SimpleMessage) GetStatus() *Embedded { + if x != nil { + return x.Status + } + return nil +} + +func (m *SimpleMessage) GetExt() isSimpleMessage_Ext { if m != nil { - return m.Status + return m.Ext + } + return nil +} + +func (x *SimpleMessage) GetEn() int64 { + if x, ok := x.GetExt().(*SimpleMessage_En); ok { + return x.En + } + return 0 +} + +func (x *SimpleMessage) GetNo() *Embedded { + if x, ok := x.GetExt().(*SimpleMessage_No); ok { + return x.No } return nil } +type isSimpleMessage_Code interface { + isSimpleMessage_Code() +} + +type SimpleMessage_LineNum struct { + LineNum int64 `protobuf:"varint,3,opt,name=line_num,json=lineNum,proto3,oneof"` +} + +type SimpleMessage_Lang struct { + Lang string `protobuf:"bytes,4,opt,name=lang,proto3,oneof"` +} + +func (*SimpleMessage_LineNum) isSimpleMessage_Code() {} + +func (*SimpleMessage_Lang) isSimpleMessage_Code() {} + type isSimpleMessage_Ext interface { isSimpleMessage_Ext() } @@ -219,86 +255,177 @@ func (*SimpleMessage_En) isSimpleMessage_Ext() {} func (*SimpleMessage_No) isSimpleMessage_Ext() {} -func (m *SimpleMessage) GetExt() isSimpleMessage_Ext { - if m != nil { - return m.Ext - } - return nil -} +var File_examples_proto_echo_service_proto protoreflect.FileDescriptor + +var file_examples_proto_echo_service_proto_rawDesc = []byte{ + 0x0a, 0x21, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x12, 0x1b, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, + 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x1a, 0x1d, 0x68, 0x74, 0x74, 0x70, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x61, 0x6e, + 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, + 0x46, 0x0a, 0x08, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x12, 0x1c, 0x0a, 0x08, 0x70, + 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, + 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x14, 0x0a, 0x04, 0x6e, 0x6f, 0x74, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x42, + 0x06, 0x0a, 0x04, 0x6d, 0x61, 0x72, 0x6b, 0x22, 0xfd, 0x01, 0x0a, 0x0d, 0x53, 0x69, 0x6d, 0x70, + 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x6e, 0x75, 0x6d, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x6e, 0x75, 0x6d, 0x12, 0x1b, 0x0a, 0x08, 0x6c, + 0x69, 0x6e, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, + 0x07, 0x6c, 0x69, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x12, 0x14, 0x0a, 0x04, 0x6c, 0x61, 0x6e, 0x67, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x6c, 0x61, 0x6e, 0x67, 0x12, 0x3d, + 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, + 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, + 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x6d, 0x62, + 0x65, 0x64, 0x64, 0x65, 0x64, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x10, 0x0a, + 0x02, 0x65, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x48, 0x01, 0x52, 0x02, 0x65, 0x6e, 0x12, + 0x37, 0x0a, 0x02, 0x6e, 0x6f, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x65, 0x61, + 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, + 0x6c, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, + 0x65, 0x64, 0x48, 0x01, 0x52, 0x02, 0x6e, 0x6f, 0x42, 0x06, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, + 0x42, 0x05, 0x0a, 0x03, 0x65, 0x78, 0x74, 0x32, 0xcc, 0x04, 0x0a, 0x0b, 0x45, 0x63, 0x68, 0x6f, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x94, 0x02, 0x0a, 0x04, 0x45, 0x63, 0x68, 0x6f, + 0x12, 0x2a, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, + 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, + 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x2a, 0x2e, 0x65, + 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, + 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xb3, 0x01, 0xca, 0xf3, 0x34, 0xae, 0x01, + 0x22, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, + 0x68, 0x6f, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x5a, 0x1d, 0x12, 0x1b, 0x2f, 0x76, 0x31, 0x2f, 0x65, + 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x2f, 0x7b, 0x69, 0x64, 0x7d, + 0x2f, 0x7b, 0x6e, 0x75, 0x6d, 0x7d, 0x5a, 0x24, 0x12, 0x22, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, + 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x2f, + 0x7b, 0x6e, 0x75, 0x6d, 0x7d, 0x2f, 0x7b, 0x6c, 0x61, 0x6e, 0x67, 0x7d, 0x5a, 0x31, 0x12, 0x2f, + 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, + 0x31, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x2f, 0x7b, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x6e, 0x75, 0x6d, + 0x7d, 0x2f, 0x7b, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x6e, 0x6f, 0x74, 0x65, 0x7d, 0x5a, + 0x1d, 0x12, 0x1b, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, + 0x63, 0x68, 0x6f, 0x32, 0x2f, 0x7b, 0x6e, 0x6f, 0x2e, 0x6e, 0x6f, 0x74, 0x65, 0x7d, 0x12, 0x82, + 0x01, 0x0a, 0x08, 0x45, 0x63, 0x68, 0x6f, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x2a, 0x2e, 0x65, 0x61, + 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, + 0x6c, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x2a, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, + 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x22, 0x1e, 0xca, 0xf3, 0x34, 0x1a, 0x22, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x65, + 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x62, 0x6f, 0x64, 0x79, + 0x3a, 0x01, 0x2a, 0x12, 0x83, 0x01, 0x0a, 0x0a, 0x45, 0x63, 0x68, 0x6f, 0x44, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x12, 0x2a, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, + 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x2a, + 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, + 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x69, 0x6d, + 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x1d, 0xca, 0xf3, 0x34, 0x19, + 0x2a, 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, + 0x68, 0x6f, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x1a, 0x1b, 0xea, 0xf3, 0x34, 0x17, 0x08, + 0xb6, 0x95, 0xff, 0xff, 0x07, 0x12, 0x04, 0x67, 0x72, 0x70, 0x63, 0x1a, 0x07, 0x64, 0x65, 0x66, + 0x61, 0x75, 0x6c, 0x74, 0x20, 0x01, 0x42, 0x07, 0x5a, 0x05, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_examples_proto_echo_service_proto_rawDescOnce sync.Once + file_examples_proto_echo_service_proto_rawDescData = file_examples_proto_echo_service_proto_rawDesc +) -func (m *SimpleMessage) GetEn() int64 { - if x, ok := m.GetExt().(*SimpleMessage_En); ok { - return x.En +func file_examples_proto_echo_service_proto_rawDescGZIP() []byte { + file_examples_proto_echo_service_proto_rawDescOnce.Do(func() { + file_examples_proto_echo_service_proto_rawDescData = protoimpl.X.CompressGZIP(file_examples_proto_echo_service_proto_rawDescData) + }) + return file_examples_proto_echo_service_proto_rawDescData +} + +var file_examples_proto_echo_service_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_examples_proto_echo_service_proto_goTypes = []interface{}{ + (*Embedded)(nil), // 0: ease.gateway.examples.proto.Embedded + (*SimpleMessage)(nil), // 1: ease.gateway.examples.proto.SimpleMessage +} +var file_examples_proto_echo_service_proto_depIdxs = []int32{ + 0, // 0: ease.gateway.examples.proto.SimpleMessage.status:type_name -> ease.gateway.examples.proto.Embedded + 0, // 1: ease.gateway.examples.proto.SimpleMessage.no:type_name -> ease.gateway.examples.proto.Embedded + 1, // 2: ease.gateway.examples.proto.EchoService.Echo:input_type -> ease.gateway.examples.proto.SimpleMessage + 1, // 3: ease.gateway.examples.proto.EchoService.EchoBody:input_type -> ease.gateway.examples.proto.SimpleMessage + 1, // 4: ease.gateway.examples.proto.EchoService.EchoDelete:input_type -> ease.gateway.examples.proto.SimpleMessage + 1, // 5: ease.gateway.examples.proto.EchoService.Echo:output_type -> ease.gateway.examples.proto.SimpleMessage + 1, // 6: ease.gateway.examples.proto.EchoService.EchoBody:output_type -> ease.gateway.examples.proto.SimpleMessage + 1, // 7: ease.gateway.examples.proto.EchoService.EchoDelete:output_type -> ease.gateway.examples.proto.SimpleMessage + 5, // [5:8] is the sub-list for method output_type + 2, // [2:5] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name +} + +func init() { file_examples_proto_echo_service_proto_init() } +func file_examples_proto_echo_service_proto_init() { + if File_examples_proto_echo_service_proto != nil { + return } - return 0 -} - -func (m *SimpleMessage) GetNo() *Embedded { - if x, ok := m.GetExt().(*SimpleMessage_No); ok { - return x.No + if !protoimpl.UnsafeEnabled { + file_examples_proto_echo_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Embedded); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_examples_proto_echo_service_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SimpleMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } - return nil -} - -// XXX_OneofWrappers is for the internal use of the proto package. -func (*SimpleMessage) XXX_OneofWrappers() []interface{} { - return []interface{}{ + file_examples_proto_echo_service_proto_msgTypes[0].OneofWrappers = []interface{}{ + (*Embedded_Progress)(nil), + (*Embedded_Note)(nil), + } + file_examples_proto_echo_service_proto_msgTypes[1].OneofWrappers = []interface{}{ (*SimpleMessage_LineNum)(nil), (*SimpleMessage_Lang)(nil), (*SimpleMessage_En)(nil), (*SimpleMessage_No)(nil), } -} - -func init() { - proto.RegisterType((*Embedded)(nil), "ease.gateway.examples.proto.Embedded") - proto.RegisterType((*SimpleMessage)(nil), "ease.gateway.examples.proto.SimpleMessage") -} - -func init() { proto.RegisterFile("examples/proto/echo_service.proto", fileDescriptor_4b4d3f52be8fcd98) } - -var fileDescriptor_4b4d3f52be8fcd98 = []byte{ - // 489 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x52, 0x41, 0x6b, 0x13, 0x41, - 0x14, 0xee, 0x6c, 0xb6, 0x49, 0x3a, 0x45, 0x29, 0x83, 0xd2, 0x35, 0xb1, 0x92, 0x06, 0x85, 0x90, - 0xc3, 0x0e, 0x89, 0x01, 0x41, 0xf0, 0x12, 0xac, 0xf4, 0xa2, 0x87, 0xed, 0x2d, 0x97, 0x30, 0xc9, - 0x3c, 0xb7, 0x8b, 0xbb, 0x33, 0xcb, 0xce, 0x6c, 0x6d, 0x58, 0x72, 0xd1, 0xbf, 0xa0, 0x7f, 0xc3, - 0x8b, 0xe0, 0x8f, 0x08, 0xfe, 0x12, 0xaf, 0x39, 0x4b, 0x65, 0x66, 0x37, 0x82, 0xb6, 0x04, 0x7a, - 0xe8, 0x69, 0xe6, 0x7d, 0xef, 0x7b, 0xef, 0x7b, 0xef, 0x9b, 0xc1, 0xc7, 0x70, 0xc9, 0x92, 0x34, - 0x06, 0x45, 0xd3, 0x4c, 0x6a, 0x49, 0x61, 0x7e, 0x2e, 0xa7, 0x0a, 0xb2, 0x8b, 0x68, 0x0e, 0xbe, - 0x85, 0x48, 0x1b, 0x98, 0x02, 0x3f, 0x64, 0x1a, 0x3e, 0xb2, 0x85, 0xbf, 0xe1, 0x97, 0xc9, 0xd6, - 0x71, 0x85, 0x53, 0x99, 0xea, 0x48, 0x0a, 0x45, 0x99, 0x10, 0x52, 0x33, 0x7b, 0x2f, 0x29, 0xdd, - 0x37, 0xb8, 0x79, 0x92, 0xcc, 0x80, 0x73, 0xe0, 0xe4, 0x31, 0x6e, 0xa6, 0x99, 0x0c, 0x33, 0x50, - 0xca, 0x43, 0x1d, 0xd4, 0xab, 0x9d, 0xee, 0x04, 0x7f, 0x11, 0xf2, 0x00, 0xbb, 0x42, 0x6a, 0xf0, - 0x9c, 0x0e, 0xea, 0xed, 0x9d, 0xee, 0x04, 0x36, 0x1a, 0xd7, 0xb1, 0x9b, 0xb0, 0xec, 0x43, 0xf7, - 0x37, 0xc2, 0xf7, 0xce, 0x22, 0x23, 0xfe, 0x16, 0x94, 0x62, 0x21, 0x90, 0xfb, 0xd8, 0x89, 0xb8, - 0xed, 0xb3, 0x17, 0x38, 0x11, 0x27, 0x07, 0xb8, 0x26, 0xf2, 0xc4, 0x96, 0xd7, 0x02, 0x73, 0x25, - 0x6d, 0xdc, 0x8c, 0x23, 0x01, 0x53, 0x03, 0xd7, 0x2a, 0xbd, 0x86, 0x41, 0xde, 0xe5, 0x89, 0x91, - 0x8b, 0x99, 0x08, 0x3d, 0x77, 0x23, 0x67, 0x22, 0xf2, 0x0a, 0xd7, 0x95, 0x66, 0x3a, 0x57, 0xde, - 0x6e, 0x07, 0xf5, 0xf6, 0x87, 0xcf, 0xfc, 0x2d, 0xfb, 0xfb, 0x9b, 0xcd, 0x82, 0xaa, 0x88, 0x1c, - 0x60, 0x07, 0x84, 0x57, 0xb7, 0x5a, 0x28, 0x70, 0x40, 0x90, 0x17, 0xd8, 0x11, 0xd2, 0x6b, 0xdc, - 0xa2, 0x99, 0x29, 0x14, 0xd2, 0x2c, 0x3e, 0x97, 0x1c, 0xc6, 0xbb, 0xb8, 0x06, 0x97, 0x7a, 0xf8, - 0xd3, 0xc5, 0xfb, 0x27, 0xf3, 0x73, 0x79, 0x56, 0xbe, 0x0e, 0xf9, 0xe2, 0x60, 0xd7, 0xc4, 0xa4, - 0xbf, 0xb5, 0xe9, 0x3f, 0x96, 0xb5, 0x6e, 0xc1, 0xed, 0x7e, 0x47, 0xab, 0xf5, 0xe8, 0x1b, 0xea, - 0x3e, 0xa4, 0x17, 0x03, 0x5a, 0x31, 0xed, 0x07, 0xa1, 0x45, 0xc4, 0x97, 0x93, 0x23, 0xd2, 0xbe, - 0x31, 0x41, 0x0b, 0x91, 0x27, 0xcb, 0xc9, 0x53, 0xd2, 0xdd, 0x92, 0xa6, 0x85, 0x31, 0x7b, 0x39, - 0x19, 0x10, 0xfa, 0x3f, 0x6b, 0x50, 0xd1, 0x36, 0x0f, 0xb7, 0xa4, 0x45, 0xe9, 0xad, 0x6f, 0xbe, - 0xc3, 0x8d, 0xba, 0x43, 0x5a, 0x08, 0x59, 0xa6, 0xc9, 0x27, 0x84, 0x9b, 0xc6, 0x96, 0xb1, 0xe4, - 0x8b, 0x3b, 0xb3, 0xe6, 0xc9, 0x6a, 0x3d, 0x6a, 0x5d, 0x37, 0x66, 0x3a, 0x93, 0x7c, 0xf1, 0x12, - 0xf5, 0xc9, 0x67, 0x84, 0xb1, 0x19, 0xe2, 0x35, 0xc4, 0xa0, 0xe1, 0xce, 0xc6, 0x38, 0x5a, 0xad, - 0x47, 0x8f, 0xfa, 0x87, 0xd7, 0xc6, 0xe0, 0x56, 0xb6, 0xd5, 0xfe, 0xb5, 0x1e, 0x1d, 0x36, 0x7f, - 0x7c, 0xbd, 0xba, 0x6a, 0x10, 0x37, 0xcc, 0xd2, 0x79, 0xab, 0xc1, 0xe1, 0x3d, 0xcb, 0x63, 0xdd, - 0x41, 0xe3, 0xc6, 0x64, 0xd7, 0xb6, 0x9c, 0xd5, 0xed, 0xf1, 0xfc, 0x4f, 0x00, 0x00, 0x00, 0xff, - 0xff, 0x35, 0x06, 0x8b, 0xf6, 0x0b, 0x04, 0x00, 0x00, + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_examples_proto_echo_service_proto_rawDesc, + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_examples_proto_echo_service_proto_goTypes, + DependencyIndexes: file_examples_proto_echo_service_proto_depIdxs, + MessageInfos: file_examples_proto_echo_service_proto_msgTypes, + }.Build() + File_examples_proto_echo_service_proto = out.File + file_examples_proto_echo_service_proto_rawDesc = nil + file_examples_proto_echo_service_proto_goTypes = nil + file_examples_proto_echo_service_proto_depIdxs = nil } // Reference imports to suppress errors if they are not otherwise used. var _ context.Context -var _ grpc.ClientConn +var _ grpc.ClientConnInterface // 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 +const _ = grpc.SupportPackageIsVersion6 // EchoServiceClient is the client API for EchoService service. // @@ -310,10 +437,10 @@ type EchoServiceClient interface { } type echoServiceClient struct { - cc *grpc.ClientConn + cc grpc.ClientConnInterface } -func NewEchoServiceClient(cc *grpc.ClientConn) EchoServiceClient { +func NewEchoServiceClient(cc grpc.ClientConnInterface) EchoServiceClient { return &echoServiceClient{cc} } @@ -351,6 +478,20 @@ type EchoServiceServer interface { EchoDelete(context.Context, *SimpleMessage) (*SimpleMessage, error) } +// UnimplementedEchoServiceServer can be embedded to have forward compatible implementations. +type UnimplementedEchoServiceServer struct { +} + +func (*UnimplementedEchoServiceServer) Echo(context.Context, *SimpleMessage) (*SimpleMessage, error) { + return nil, status.Errorf(codes.Unimplemented, "method Echo not implemented") +} +func (*UnimplementedEchoServiceServer) EchoBody(context.Context, *SimpleMessage) (*SimpleMessage, error) { + return nil, status.Errorf(codes.Unimplemented, "method EchoBody not implemented") +} +func (*UnimplementedEchoServiceServer) EchoDelete(context.Context, *SimpleMessage) (*SimpleMessage, error) { + return nil, status.Errorf(codes.Unimplemented, "method EchoDelete not implemented") +} + func RegisterEchoServiceServer(s *grpc.Server, srv EchoServiceServer) { s.RegisterService(&_EchoService_serviceDesc, srv) } diff --git a/examples/proto/echo_service.pb.gw.go b/examples/proto/echo_service.pb.gw.go index 15fa4c1..0a340a2 100755 --- a/examples/proto/echo_service.pb.gw.go +++ b/examples/proto/echo_service.pb.gw.go @@ -29,15 +29,19 @@ import ( "github.com/grpc-ecosystem/grpc-gateway/utilities" "google.golang.org/grpc" "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" "google.golang.org/grpc/naming" "google.golang.org/grpc/status" ) +// Suppress "imported and not used" errors var _ codes.Code var _ io.Reader var _ status.Status var _ = runtime.String var _ = utilities.NewDoubleArray + +// var _ = descriptor.ForMessage var _ sync.RWMutex var _ proto.Message var _ context.Context @@ -99,11 +103,48 @@ func request_EchoService_Echo_0(ctx context.Context, marshaler runtime.Marshaler runtime.RequestParsed(ctx, spec, "EchoService", "Echo", &protoReq, &metadata) ctx = runtime.PreLoadBalance(ctx, "ROUND_ROBIN", "", &protoReq) msg, err := client.Echo(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + // if err != nil { + // grpclog.Errorf("client.%s returns error: %v", "Echo", err) + // } runtime.RequestHandled(ctx, spec, "EchoService", "Echo", msg, &metadata, err) return msg, metadata, err } +func local_request_EchoService_Echo_0(ctx context.Context, marshaler runtime.Marshaler, server EchoServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq SimpleMessage + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") + } + + protoReq.Id, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EchoService_Echo_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.Echo(ctx, &protoReq) + return msg, metadata, err + +} + var ( filter_EchoService_Echo_1 = &utilities.DoubleArray{Encoding: map[string]int{"id": 0, "num": 1}, Base: []int{1, 1, 2, 0, 0}, Check: []int{0, 1, 1, 2, 3}} ) @@ -156,11 +197,59 @@ func request_EchoService_Echo_1(ctx context.Context, marshaler runtime.Marshaler runtime.RequestParsed(ctx, spec, "EchoService", "Echo", &protoReq, &metadata) ctx = runtime.PreLoadBalance(ctx, "ROUND_ROBIN", "", &protoReq) msg, err := client.Echo(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + // if err != nil { + // grpclog.Errorf("client.%s returns error: %v", "Echo", err) + // } runtime.RequestHandled(ctx, spec, "EchoService", "Echo", msg, &metadata, err) return msg, metadata, err } +func local_request_EchoService_Echo_1(ctx context.Context, marshaler runtime.Marshaler, server EchoServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq SimpleMessage + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") + } + + protoReq.Id, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) + } + + val, ok = pathParams["num"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "num") + } + + protoReq.Num, err = runtime.Int64(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "num", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EchoService_Echo_1); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.Echo(ctx, &protoReq) + return msg, metadata, err + +} + var ( filter_EchoService_Echo_2 = &utilities.DoubleArray{Encoding: map[string]int{"id": 0, "num": 1, "lang": 2}, Base: []int{1, 1, 2, 3, 0, 0, 0}, Check: []int{0, 1, 1, 1, 2, 3, 4}} ) @@ -210,7 +299,7 @@ func request_EchoService_Echo_2(ctx context.Context, marshaler runtime.Marshaler if protoReq.Code == nil { protoReq.Code = &SimpleMessage_Lang{} } else if _, ok := protoReq.Code.(*SimpleMessage_Lang); !ok { - return nil, metadata, grpc.Errorf(codes.InvalidArgument, "expect type: *SimpleMessage_Lang, but: %t\n", protoReq.Code) + return nil, metadata, status.Errorf(codes.InvalidArgument, "expect type: *SimpleMessage_Lang, but: %t\n", protoReq.Code) } protoReq.Code.(*SimpleMessage_Lang).Lang, err = runtime.String(val) @@ -230,11 +319,75 @@ func request_EchoService_Echo_2(ctx context.Context, marshaler runtime.Marshaler runtime.RequestParsed(ctx, spec, "EchoService", "Echo", &protoReq, &metadata) ctx = runtime.PreLoadBalance(ctx, "ROUND_ROBIN", "", &protoReq) msg, err := client.Echo(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + // if err != nil { + // grpclog.Errorf("client.%s returns error: %v", "Echo", err) + // } runtime.RequestHandled(ctx, spec, "EchoService", "Echo", msg, &metadata, err) return msg, metadata, err } +func local_request_EchoService_Echo_2(ctx context.Context, marshaler runtime.Marshaler, server EchoServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq SimpleMessage + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") + } + + protoReq.Id, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) + } + + val, ok = pathParams["num"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "num") + } + + protoReq.Num, err = runtime.Int64(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "num", err) + } + + val, ok = pathParams["lang"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "lang") + } + + if protoReq.Code == nil { + protoReq.Code = &SimpleMessage_Lang{} + } else if _, ok := protoReq.Code.(*SimpleMessage_Lang); !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "expect type: *SimpleMessage_Lang, but: %t\n", protoReq.Code) + } + protoReq.Code.(*SimpleMessage_Lang).Lang, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "lang", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EchoService_Echo_2); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.Echo(ctx, &protoReq) + return msg, metadata, err + +} + var ( filter_EchoService_Echo_3 = &utilities.DoubleArray{Encoding: map[string]int{"id": 0, "line_num": 1, "status": 2, "note": 3}, Base: []int{1, 1, 2, 1, 3, 0, 0, 0}, Check: []int{0, 1, 1, 1, 4, 2, 3, 5}} ) @@ -272,7 +425,7 @@ func request_EchoService_Echo_3(ctx context.Context, marshaler runtime.Marshaler if protoReq.Code == nil { protoReq.Code = &SimpleMessage_LineNum{} } else if _, ok := protoReq.Code.(*SimpleMessage_LineNum); !ok { - return nil, metadata, grpc.Errorf(codes.InvalidArgument, "expect type: *SimpleMessage_LineNum, but: %t\n", protoReq.Code) + return nil, metadata, status.Errorf(codes.InvalidArgument, "expect type: *SimpleMessage_LineNum, but: %t\n", protoReq.Code) } protoReq.Code.(*SimpleMessage_LineNum).LineNum, err = runtime.Int64(val) @@ -304,11 +457,75 @@ func request_EchoService_Echo_3(ctx context.Context, marshaler runtime.Marshaler runtime.RequestParsed(ctx, spec, "EchoService", "Echo", &protoReq, &metadata) ctx = runtime.PreLoadBalance(ctx, "ROUND_ROBIN", "", &protoReq) msg, err := client.Echo(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + // if err != nil { + // grpclog.Errorf("client.%s returns error: %v", "Echo", err) + // } runtime.RequestHandled(ctx, spec, "EchoService", "Echo", msg, &metadata, err) return msg, metadata, err } +func local_request_EchoService_Echo_3(ctx context.Context, marshaler runtime.Marshaler, server EchoServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq SimpleMessage + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") + } + + protoReq.Id, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) + } + + val, ok = pathParams["line_num"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "line_num") + } + + if protoReq.Code == nil { + protoReq.Code = &SimpleMessage_LineNum{} + } else if _, ok := protoReq.Code.(*SimpleMessage_LineNum); !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "expect type: *SimpleMessage_LineNum, but: %t\n", protoReq.Code) + } + protoReq.Code.(*SimpleMessage_LineNum).LineNum, err = runtime.Int64(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "line_num", err) + } + + val, ok = pathParams["status.note"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "status.note") + } + + err = runtime.PopulateFieldFromPath(&protoReq, "status.note", val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "status.note", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EchoService_Echo_3); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.Echo(ctx, &protoReq) + return msg, metadata, err + +} + var ( filter_EchoService_Echo_4 = &utilities.DoubleArray{Encoding: map[string]int{"no": 0, "note": 1}, Base: []int{1, 1, 1, 0}, Check: []int{0, 1, 2, 3}} ) @@ -349,11 +566,48 @@ func request_EchoService_Echo_4(ctx context.Context, marshaler runtime.Marshaler runtime.RequestParsed(ctx, spec, "EchoService", "Echo", &protoReq, &metadata) ctx = runtime.PreLoadBalance(ctx, "ROUND_ROBIN", "", &protoReq) msg, err := client.Echo(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + // if err != nil { + // grpclog.Errorf("client.%s returns error: %v", "Echo", err) + // } runtime.RequestHandled(ctx, spec, "EchoService", "Echo", msg, &metadata, err) return msg, metadata, err } +func local_request_EchoService_Echo_4(ctx context.Context, marshaler runtime.Marshaler, server EchoServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq SimpleMessage + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["no.note"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "no.note") + } + + err = runtime.PopulateFieldFromPath(&protoReq, "no.note", val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "no.note", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EchoService_Echo_4); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.Echo(ctx, &protoReq) + return msg, metadata, err + +} + func request_EchoService_EchoBody_0(ctx context.Context, marshaler runtime.Marshaler, client EchoServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq SimpleMessage var metadata runtime.ServerMetadata @@ -373,11 +627,31 @@ func request_EchoService_EchoBody_0(ctx context.Context, marshaler runtime.Marsh runtime.RequestParsed(ctx, spec, "EchoService", "EchoBody", &protoReq, &metadata) ctx = runtime.PreLoadBalance(ctx, "ROUND_ROBIN", "", &protoReq) msg, err := client.EchoBody(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + // if err != nil { + // grpclog.Errorf("client.%s returns error: %v", "EchoBody", err) + // } runtime.RequestHandled(ctx, spec, "EchoService", "EchoBody", msg, &metadata, err) return msg, metadata, err } +func local_request_EchoService_EchoBody_0(ctx context.Context, marshaler runtime.Marshaler, server EchoServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq SimpleMessage + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.EchoBody(ctx, &protoReq) + return msg, metadata, err + +} + var ( filter_EchoService_EchoDelete_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} ) @@ -399,11 +673,179 @@ func request_EchoService_EchoDelete_0(ctx context.Context, marshaler runtime.Mar runtime.RequestParsed(ctx, spec, "EchoService", "EchoDelete", &protoReq, &metadata) ctx = runtime.PreLoadBalance(ctx, "ROUND_ROBIN", "", &protoReq) msg, err := client.EchoDelete(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + // if err != nil { + // grpclog.Errorf("client.%s returns error: %v", "EchoDelete", err) + // } runtime.RequestHandled(ctx, spec, "EchoService", "EchoDelete", msg, &metadata, err) return msg, metadata, err } +func local_request_EchoService_EchoDelete_0(ctx context.Context, marshaler runtime.Marshaler, server EchoServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq SimpleMessage + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EchoService_EchoDelete_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.EchoDelete(ctx, &protoReq) + return msg, metadata, err + +} + +// RegisterEchoServiceHandlerServer registers the http handlers for service EchoService to "mux". +// UnaryRPC :call EchoServiceServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +// Note that using this registration option will cause many gRPC library features (such as grpc.SendHeader, etc) to stop working. Consider using RegisterEchoServiceHandlerFromEndpoint instead. +func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server EchoServiceServer) error { + + mux.Handle("POST", pattern_EchoService_Echo_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + 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_EchoService_Echo_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_EchoService_Echo_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_EchoService_Echo_1, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + 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_EchoService_Echo_1(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_EchoService_Echo_1(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_EchoService_Echo_2, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + 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_EchoService_Echo_2(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_EchoService_Echo_2(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_EchoService_Echo_3, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + 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_EchoService_Echo_3(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_EchoService_Echo_3(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_EchoService_Echo_4, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + 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_EchoService_Echo_4(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_EchoService_Echo_4(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("POST", pattern_EchoService_EchoBody_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + 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_EchoService_EchoBody_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_EchoService_EchoBody_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("DELETE", pattern_EchoService_EchoDelete_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + 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_EchoService_EchoDelete_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_EchoService_EchoDelete_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + // Register itself to runtime. func init() { var s *runtime.Service @@ -470,36 +912,27 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux // TODO(mojz): review all locking/unlocking logic. // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() - cli := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client - if cli == nil { + client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client + if client == nil { runtime.DefaultOtherErrorHandler(w, req, "service disabled", http.StatusInternalServerError) return } ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) if err != nil { - runtime.DefaultHTTPError(ctx, nil, &runtime.JSONBuiltin{}, w, req, err) + grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) + runtime.HTTPError(ctx, nil, &runtime.JSONBuiltin{}, w, req, err) return } - ctx, cancel := context.WithCancel(req.Context()) defer cancel() - if cn, ok := w.(http.CloseNotifier); ok { - go func(done <-chan struct{}, closed <-chan bool) { - select { - case <-done: - case <-closed: - cancel() - } - }(ctx.Done(), cn.CloseNotify()) - } 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_EchoService_Echo_0(rctx, inboundMarshaler, cli, req, pathParams) + resp, md, err := request_EchoService_Echo_0(rctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) @@ -515,36 +948,27 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux // TODO(mojz): review all locking/unlocking logic. // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() - cli := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client - if cli == nil { + client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client + if client == nil { runtime.DefaultOtherErrorHandler(w, req, "service disabled", http.StatusInternalServerError) return } ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) if err != nil { - runtime.DefaultHTTPError(ctx, nil, &runtime.JSONBuiltin{}, w, req, err) + grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) + runtime.HTTPError(ctx, nil, &runtime.JSONBuiltin{}, w, req, err) return } - ctx, cancel := context.WithCancel(req.Context()) defer cancel() - if cn, ok := w.(http.CloseNotifier); ok { - go func(done <-chan struct{}, closed <-chan bool) { - select { - case <-done: - case <-closed: - cancel() - } - }(ctx.Done(), cn.CloseNotify()) - } 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_EchoService_Echo_1(rctx, inboundMarshaler, cli, req, pathParams) + resp, md, err := request_EchoService_Echo_1(rctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) @@ -560,36 +984,27 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux // TODO(mojz): review all locking/unlocking logic. // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() - cli := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client - if cli == nil { + client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client + if client == nil { runtime.DefaultOtherErrorHandler(w, req, "service disabled", http.StatusInternalServerError) return } ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) if err != nil { - runtime.DefaultHTTPError(ctx, nil, &runtime.JSONBuiltin{}, w, req, err) + grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) + runtime.HTTPError(ctx, nil, &runtime.JSONBuiltin{}, w, req, err) return } - ctx, cancel := context.WithCancel(req.Context()) defer cancel() - if cn, ok := w.(http.CloseNotifier); ok { - go func(done <-chan struct{}, closed <-chan bool) { - select { - case <-done: - case <-closed: - cancel() - } - }(ctx.Done(), cn.CloseNotify()) - } 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_EchoService_Echo_2(rctx, inboundMarshaler, cli, req, pathParams) + resp, md, err := request_EchoService_Echo_2(rctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) @@ -605,36 +1020,27 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux // TODO(mojz): review all locking/unlocking logic. // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() - cli := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client - if cli == nil { + client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client + if client == nil { runtime.DefaultOtherErrorHandler(w, req, "service disabled", http.StatusInternalServerError) return } ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) if err != nil { - runtime.DefaultHTTPError(ctx, nil, &runtime.JSONBuiltin{}, w, req, err) + grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) + runtime.HTTPError(ctx, nil, &runtime.JSONBuiltin{}, w, req, err) return } - ctx, cancel := context.WithCancel(req.Context()) defer cancel() - if cn, ok := w.(http.CloseNotifier); ok { - go func(done <-chan struct{}, closed <-chan bool) { - select { - case <-done: - case <-closed: - cancel() - } - }(ctx.Done(), cn.CloseNotify()) - } 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_EchoService_Echo_3(rctx, inboundMarshaler, cli, req, pathParams) + resp, md, err := request_EchoService_Echo_3(rctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) @@ -650,36 +1056,27 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux // TODO(mojz): review all locking/unlocking logic. // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() - cli := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client - if cli == nil { + client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client + if client == nil { runtime.DefaultOtherErrorHandler(w, req, "service disabled", http.StatusInternalServerError) return } ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) if err != nil { - runtime.DefaultHTTPError(ctx, nil, &runtime.JSONBuiltin{}, w, req, err) + grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) + runtime.HTTPError(ctx, nil, &runtime.JSONBuiltin{}, w, req, err) return } - ctx, cancel := context.WithCancel(req.Context()) defer cancel() - if cn, ok := w.(http.CloseNotifier); ok { - go func(done <-chan struct{}, closed <-chan bool) { - select { - case <-done: - case <-closed: - cancel() - } - }(ctx.Done(), cn.CloseNotify()) - } 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_EchoService_Echo_4(rctx, inboundMarshaler, cli, req, pathParams) + resp, md, err := request_EchoService_Echo_4(rctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) @@ -695,36 +1092,27 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux // TODO(mojz): review all locking/unlocking logic. // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() - cli := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client - if cli == nil { + client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client + if client == nil { runtime.DefaultOtherErrorHandler(w, req, "service disabled", http.StatusInternalServerError) return } ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "EchoBody", w, req) if err != nil { - runtime.DefaultHTTPError(ctx, nil, &runtime.JSONBuiltin{}, w, req, err) + grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) + runtime.HTTPError(ctx, nil, &runtime.JSONBuiltin{}, w, req, err) return } - ctx, cancel := context.WithCancel(req.Context()) defer cancel() - if cn, ok := w.(http.CloseNotifier); ok { - go func(done <-chan struct{}, closed <-chan bool) { - select { - case <-done: - case <-closed: - cancel() - } - }(ctx.Done(), cn.CloseNotify()) - } 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_EchoService_EchoBody_0(rctx, inboundMarshaler, cli, req, pathParams) + resp, md, err := request_EchoService_EchoBody_0(rctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) @@ -740,36 +1128,27 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux // TODO(mojz): review all locking/unlocking logic. // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() - cli := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client - if cli == nil { + client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client + if client == nil { runtime.DefaultOtherErrorHandler(w, req, "service disabled", http.StatusInternalServerError) return } ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "EchoDelete", w, req) if err != nil { - runtime.DefaultHTTPError(ctx, nil, &runtime.JSONBuiltin{}, w, req, err) + grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) + runtime.HTTPError(ctx, nil, &runtime.JSONBuiltin{}, w, req, err) return } - ctx, cancel := context.WithCancel(req.Context()) defer cancel() - if cn, ok := w.(http.CloseNotifier); ok { - go func(done <-chan struct{}, closed <-chan bool) { - select { - case <-done: - case <-closed: - cancel() - } - }(ctx.Done(), cn.CloseNotify()) - } 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_EchoService_EchoDelete_0(rctx, inboundMarshaler, cli, req, pathParams) + resp, md, err := request_EchoService_EchoDelete_0(rctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) diff --git a/examples/proto/echo_service.swagger.json b/examples/proto/echo_service.swagger.json index 384818e..31a4aec 100755 --- a/examples/proto/echo_service.swagger.json +++ b/examples/proto/echo_service.swagger.json @@ -5,10 +5,6 @@ "description": "Echo Service API consists of a single service which returns\na message.", "version": "version not set" }, - "schemes": [ - "http", - "https" - ], "consumes": [ "application/json" ], @@ -20,7 +16,7 @@ "post": { "summary": "Echo method receives a simple message and returns it.", "description": "The message posted as the id parameter will also be\nreturned.", - "operationId": "Echo", + "operationId": "EchoService_Echo", "responses": { "200": { "description": "A successful response.", @@ -47,7 +43,7 @@ "get": { "summary": "Echo method receives a simple message and returns it.", "description": "The message posted as the id parameter will also be\nreturned.", - "operationId": "Echo2", + "operationId": "EchoService_Echo2", "responses": { "200": { "description": "A successful response.", @@ -127,7 +123,7 @@ "get": { "summary": "Echo method receives a simple message and returns it.", "description": "The message posted as the id parameter will also be\nreturned.", - "operationId": "Echo3", + "operationId": "EchoService_Echo3", "responses": { "200": { "description": "A successful response.", @@ -207,7 +203,7 @@ "get": { "summary": "Echo method receives a simple message and returns it.", "description": "The message posted as the id parameter will also be\nreturned.", - "operationId": "Echo4", + "operationId": "EchoService_Echo4", "responses": { "200": { "description": "A successful response.", @@ -281,7 +277,7 @@ "get": { "summary": "Echo method receives a simple message and returns it.", "description": "The message posted as the id parameter will also be\nreturned.", - "operationId": "Echo5", + "operationId": "EchoService_Echo5", "responses": { "200": { "description": "A successful response.", @@ -354,7 +350,7 @@ "/v1/example/echo_body": { "post": { "summary": "EchoBody method receives a simple message and returns it.", - "operationId": "EchoBody", + "operationId": "EchoService_EchoBody", "responses": { "200": { "description": "A successful response.", @@ -381,7 +377,7 @@ "/v1/example/echo_delete": { "delete": { "summary": "EchoDelete method receives a simple message and returns it.", - "operationId": "EchoDelete", + "operationId": "EchoService_EchoDelete", "responses": { "200": { "description": "A successful response.", diff --git a/gateway/README.md b/gateway/README.md index 6f6ad2c..84b17d1 100644 --- a/gateway/README.md +++ b/gateway/README.md @@ -176,6 +176,19 @@ var ( ) ``` +### panic: can't resolve swagger ref from typename '.frontend.Error' + +运行一下命令就会出现panic +``` +bazel build proto/... +``` + +问题出在以下代码 +``` +runtimeError, swgRef, err := lookupMsgAndSwaggerName(".grpc.gateway.runtime", "Error", p.reg) +``` +如果有package name定义为 grpc.gateway.runtime的就有可能会出现这种错误 + ## grpc-ecosystem/grpc-gateway grpc-ecosystem/grpc-gateway: grpc-gateway is a plugin of protoc. It reads diff --git a/gateway/internal/errors.proto b/gateway/internal/errors.proto index b0a0022..64f81d2 100644 --- a/gateway/internal/errors.proto +++ b/gateway/internal/errors.proto @@ -1,5 +1,5 @@ syntax = "proto3"; -package grpc.gateway.runtime; +package ease.gateway.runtime; option go_package = "internal"; import "google/protobuf/any.proto"; diff --git a/gateway/protoc-gen-swagger/genswagger/BUILD.bazel b/gateway/protoc-gen-swagger/genswagger/BUILD.bazel index ab7a3f8..a2b19ab 100644 --- a/gateway/protoc-gen-swagger/genswagger/BUILD.bazel +++ b/gateway/protoc-gen-swagger/genswagger/BUILD.bazel @@ -14,16 +14,17 @@ go_library( ], importpath = "github.com/binchencoder/ease-gateway/gateway/protoc-gen-swagger/genswagger", deps = [ - "//httpoptions:go_default_library", + "//gateway/internal:go_default_library", + "//gateway/internal/casing:go_default_library", "//gateway/protoc-gen-grpc-gateway/descriptor:go_default_library", "//gateway/protoc-gen-grpc-gateway/generator:go_default_library", "//gateway/protoc-gen-swagger/options:go_default_library", + "//httpoptions:go_default_library", "@com_github_golang_glog//:go_default_library", "@com_github_golang_protobuf//descriptor:go_default_library_gen", "@com_github_golang_protobuf//jsonpb:go_default_library_gen", "@com_github_golang_protobuf//proto:go_default_library", "@com_github_golang_protobuf//protoc-gen-go/generator:go_default_library_gen", - "@com_github_grpc_ecosystem_grpc_gateway//internal:go_default_library", "@io_bazel_rules_go//proto/wkt:any_go_proto", "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", "@io_bazel_rules_go//proto/wkt:descriptor_go_proto", diff --git a/gateway/protoc-gen-swagger/genswagger/generator.go b/gateway/protoc-gen-swagger/genswagger/generator.go index 122d834..0a9965e 100644 --- a/gateway/protoc-gen-swagger/genswagger/generator.go +++ b/gateway/protoc-gen-swagger/genswagger/generator.go @@ -15,7 +15,9 @@ import ( protocdescriptor "github.com/golang/protobuf/protoc-gen-go/descriptor" plugin "github.com/golang/protobuf/protoc-gen-go/plugin" "github.com/golang/protobuf/ptypes/any" - "github.com/grpc-ecosystem/grpc-gateway/internal" + + // "github.com/grpc-ecosystem/grpc-gateway/internal" + "github.com/binchencoder/ease-gateway/gateway/internal" // "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/descriptor" "github.com/binchencoder/ease-gateway/gateway/protoc-gen-grpc-gateway/descriptor" @@ -58,9 +60,6 @@ func mergeTargetFile(targets []*wrapper, mergeFileName string) *wrapper { for k, v := range f.swagger.Definitions { mergedTarget.swagger.Definitions[k] = v } - for k, v := range f.swagger.StreamDefinitions { - mergedTarget.swagger.StreamDefinitions[k] = v - } for k, v := range f.swagger.Paths { mergedTarget.swagger.Paths[k] = v } @@ -177,7 +176,7 @@ func (g *generator) Generate(targets []*descriptor.File) ([]*plugin.CodeGenerato for _, f := range targets { if mergedTarget == nil { mergedTarget = f - } else { + } else if mergedTarget != f { mergedTarget.Enums = append(mergedTarget.Enums, f.Enums...) mergedTarget.Messages = append(mergedTarget.Messages, f.Messages...) mergedTarget.Services = append(mergedTarget.Services, f.Services...) diff --git a/gateway/protoc-gen-swagger/genswagger/template.go b/gateway/protoc-gen-swagger/genswagger/template.go index 3d3b260..742aa9f 100644 --- a/gateway/protoc-gen-swagger/genswagger/template.go +++ b/gateway/protoc-gen-swagger/genswagger/template.go @@ -5,7 +5,6 @@ import ( "encoding/json" "fmt" "io/ioutil" - "net/url" "os" "reflect" "regexp" @@ -19,8 +18,9 @@ import ( "github.com/golang/protobuf/jsonpb" "github.com/golang/protobuf/proto" pbdescriptor "github.com/golang/protobuf/protoc-gen-go/descriptor" - gogen "github.com/golang/protobuf/protoc-gen-go/generator" structpb "github.com/golang/protobuf/ptypes/struct" + + "github.com/binchencoder/ease-gateway/gateway/internal/casing" // "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/descriptor" "github.com/binchencoder/ease-gateway/gateway/protoc-gen-grpc-gateway/descriptor" options "github.com/binchencoder/ease-gateway/httpoptions" @@ -70,7 +70,6 @@ var wktSchemas = map[string]schemaCore{ }, ".google.protobuf.BoolValue": schemaCore{ Type: "boolean", - Format: "boolean", }, ".google.protobuf.Empty": schemaCore{}, ".google.protobuf.Struct": schemaCore{ @@ -97,6 +96,13 @@ func listEnumNames(enum *descriptor.Enum) (names []string) { return names } +func listEnumNumbers(enum *descriptor.Enum) (numbers []string) { + for _, value := range enum.GetValue() { + numbers = append(numbers, strconv.Itoa(int(value.GetNumber()))) + } + return +} + func getEnumDefault(enum *descriptor.Enum) string { for _, value := range enum.GetValue() { if value.GetNumber() == 0 { @@ -118,8 +124,18 @@ func messageToQueryParameters(message *descriptor.Message, reg *descriptor.Regis return params, nil } -// queryParams converts a field to a list of swagger query parameters recursively. +// queryParams converts a field to a list of swagger query parameters recursively through the use of nestedQueryParams. func queryParams(message *descriptor.Message, field *descriptor.Field, prefix string, reg *descriptor.Registry, pathParams []descriptor.Parameter) (params []swaggerParameterObject, err error) { + return nestedQueryParams(message, field, prefix, reg, pathParams, map[string]bool{}) +} + +// nestedQueryParams converts a field to a list of swagger query parameters recursively. +// This function is a helper function for queryParams, that keeps track of cyclical message references +// through the use of +// touched map[string]bool +// If a cycle is discovered, an error is returned, as cyclical data structures aren't allowed +// in query parameters. +func nestedQueryParams(message *descriptor.Message, field *descriptor.Field, prefix string, reg *descriptor.Registry, pathParams []descriptor.Parameter, touchedIn map[string]bool) (params []swaggerParameterObject, err error) { // make sure the parameter is not already listed as a path parameter for _, pathParam := range pathParams { if pathParam.Target == field { @@ -187,10 +203,19 @@ func queryParams(message *descriptor.Message, field *descriptor.Field, prefix st Type: "string", Enum: listEnumNames(enum), } + if reg.GetEnumsAsInts() { + param.Items.Type = "integer" + param.Items.Enum = listEnumNumbers(enum) + } } else { param.Type = "string" param.Enum = listEnumNames(enum) param.Default = getEnumDefault(enum) + if reg.GetEnumsAsInts() { + param.Type = "integer" + param.Enum = listEnumNumbers(enum) + param.Default = "0" + } } valueComments := enumValueProtoComments(reg, enum) if valueComments != "" { @@ -205,8 +230,30 @@ func queryParams(message *descriptor.Message, field *descriptor.Field, prefix st if err != nil { return nil, fmt.Errorf("unknown message type %s", fieldType) } + + // Check for cyclical message reference: + isCycle := touchedIn[*msg.Name] + if isCycle { + return nil, fmt.Errorf("Recursive types are not allowed for query parameters, cycle found on %q", fieldType) + } + + // Construct a new map with the message name so a cycle further down the recursive path can be detected. + // Do not keep anything in the original touched reference and do not pass that reference along. This will + // prevent clobbering adjacent records while recursing. + touchedOut := make(map[string]bool) + for k, v := range touchedIn { + touchedOut[k] = v + } + touchedOut[*msg.Name] = true + for _, nestedField := range msg.Fields { - p, err := queryParams(msg, nestedField, prefix+field.GetName()+".", reg, pathParams) + var fieldName string + if reg.GetUseJSONNamesForFields() { + fieldName = field.GetJsonName() + } else { + fieldName = field.GetName() + } + p, err := nestedQueryParams(msg, nestedField, prefix+fieldName+".", reg, pathParams, touchedOut) if err != nil { return nil, err } @@ -220,28 +267,40 @@ func findServicesMessagesAndEnumerations(s []*descriptor.Service, reg *descripto for _, svc := range s { for _, meth := range svc.Methods { // Request may be fully included in query - if _, ok := refs[fmt.Sprintf("#/definitions/%s", fullyQualifiedNameToSwaggerName(meth.RequestType.FQMN(), reg))]; ok { - if !skipRenderingRef(meth.RequestType.FQMN()) { - m[fullyQualifiedNameToSwaggerName(meth.RequestType.FQMN(), reg)] = meth.RequestType + { + swgReqName, ok := fullyQualifiedNameToSwaggerName(meth.RequestType.FQMN(), reg) + if !ok { + glog.Errorf("couldn't resolve swagger name for FQMN '%v'", meth.RequestType.FQMN()) + continue + } + if _, ok := refs[fmt.Sprintf("#/definitions/%s", swgReqName)]; ok { + if !skipRenderingRef(meth.RequestType.FQMN()) { + m[swgReqName] = meth.RequestType + } } } + + swgRspName, ok := fullyQualifiedNameToSwaggerName(meth.ResponseType.FQMN(), reg) + if !ok && !skipRenderingRef(meth.ResponseType.FQMN()) { + glog.Errorf("couldn't resolve swagger name for FQMN '%v'", meth.ResponseType.FQMN()) + continue + } + findNestedMessagesAndEnumerations(meth.RequestType, reg, m, e) if !skipRenderingRef(meth.ResponseType.FQMN()) { - m[fullyQualifiedNameToSwaggerName(meth.ResponseType.FQMN(), reg)] = meth.ResponseType + m[swgRspName] = meth.ResponseType if meth.GetServerStreaming() { - runtimeStreamError := fullyQualifiedNameToSwaggerName(".grpc.gateway.runtime.StreamError", reg) - glog.V(1).Infof("StreamError FQMN: %s", runtimeStreamError) - streamError, err := reg.LookupMsg(".grpc.gateway.runtime", "StreamError") - if err == nil { + streamError, runtimeStreamError, err := lookupMsgAndSwaggerName(".grpc.gateway.runtime", "StreamError", reg) + if err != nil { + glog.Error(err) + } else { glog.V(1).Infof("StreamError: %v", streamError) + glog.V(1).Infof("StreamError FQMN: %s", runtimeStreamError) m[runtimeStreamError] = streamError findNestedMessagesAndEnumerations(streamError, reg, m, e) - } else { - //just in case there is an error looking up StreamError - glog.Error(err) } - ms[fullyQualifiedNameToSwaggerName(meth.ResponseType.FQMN(), reg)] = meth.ResponseType + ms[swgRspName] = meth.ResponseType } } findNestedMessagesAndEnumerations(meth.ResponseType, reg, m, e) @@ -280,6 +339,10 @@ func skipRenderingRef(refName string) bool { func renderMessagesAsDefinition(messages messageMap, d swaggerDefinitionsObject, reg *descriptor.Registry, customRefs refMap) { for name, msg := range messages { + swgName, ok := fullyQualifiedNameToSwaggerName(msg.FQMN(), reg) + if !ok { + panic(fmt.Sprintf("can't resolve swagger name from '%v'", msg.FQMN())) + } if skipRenderingRef(name) { continue } @@ -353,43 +416,7 @@ func renderMessagesAsDefinition(messages messageMap, d swaggerDefinitionsObject, } *schema.Properties = append(*schema.Properties, kv) } - d[fullyQualifiedNameToSwaggerName(msg.FQMN(), reg)] = schema - } -} - -func renderMessagesAsStreamDefinition(messages messageMap, d swaggerDefinitionsObject, reg *descriptor.Registry) { - for name, msg := range messages { - if skipRenderingRef(name) { - continue - } - - if opt := msg.GetOptions(); opt != nil && opt.MapEntry != nil && *opt.MapEntry { - continue - } - d[fullyQualifiedNameToSwaggerName(msg.FQMN(), reg)] = swaggerSchemaObject{ - schemaCore: schemaCore{ - Type: "object", - }, - Title: fmt.Sprintf("Stream result of %s", fullyQualifiedNameToSwaggerName(msg.FQMN(), reg)), - Properties: &swaggerSchemaObjectProperties{ - keyVal{ - Key: "result", - Value: swaggerSchemaObject{ - schemaCore: schemaCore{ - Ref: fmt.Sprintf("#/definitions/%s", fullyQualifiedNameToSwaggerName(msg.FQMN(), reg)), - }, - }, - }, - keyVal{ - Key: "error", - Value: swaggerSchemaObject{ - schemaCore: schemaCore{ - Ref: fmt.Sprintf("#/definitions/%s", fullyQualifiedNameToSwaggerName(".grpc.gateway.runtime.StreamError", reg)), - }, - }, - }, - }, - } + d[swgName] = schema } } @@ -427,12 +454,15 @@ func schemaOfField(f *descriptor.Field, reg *descriptor.Registry, refs refMap) s props = &swaggerSchemaObjectProperties{} } } else { + swgRef, ok := fullyQualifiedNameToSwaggerName(fd.GetTypeName(), reg) + if !ok { + panic(fmt.Sprintf("can't resolve swagger ref from typename '%v'", fd.GetTypeName())) + } core = schemaCore{ - Ref: "#/definitions/" + fullyQualifiedNameToSwaggerName(fd.GetTypeName(), reg), + Ref: "#/definitions/" + swgRef, } if refs != nil { refs[fd.GetTypeName()] = struct{}{} - } } default: @@ -540,6 +570,10 @@ func getRules(rules []*descriptor.Rule) []options.ValidationRule { // renderEnumerationsAsDefinition inserts enums into the definitions object. func renderEnumerationsAsDefinition(enums enumMap, d swaggerDefinitionsObject, reg *descriptor.Registry) { for _, enum := range enums { + swgName, ok := fullyQualifiedNameToSwaggerName(enum.FQEN(), reg) + if !ok { + panic(fmt.Sprintf("can't resolve swagger name from FQEN '%v'", enum.FQEN())) + } enumComments := protoComments(reg, enum.File, enum.Outers, "EnumType", int32(enum.Index)) // it may be necessary to sort the result of the GetValue function. @@ -556,24 +590,47 @@ func renderEnumerationsAsDefinition(enums enumMap, d swaggerDefinitionsObject, r Default: defaultValue, }, } + if reg.GetEnumsAsInts() { + enumSchemaObject.Type = "integer" + enumSchemaObject.Format = "int32" + enumSchemaObject.Default = "0" + enumSchemaObject.Enum = listEnumNumbers(enum) + } if err := updateSwaggerDataFromComments(reg, &enumSchemaObject, enum, enumComments, false); err != nil { panic(err) } - d[fullyQualifiedNameToSwaggerName(enum.FQEN(), reg)] = enumSchemaObject + d[swgName] = enumSchemaObject } } -// Take in a FQMN or FQEN and return a swagger safe version of the FQMN -func fullyQualifiedNameToSwaggerName(fqn string, reg *descriptor.Registry) string { +// Take in a FQMN or FQEN and return a swagger safe version of the FQMN and +// a boolean indicating if FQMN was properly resolved. +func fullyQualifiedNameToSwaggerName(fqn string, reg *descriptor.Registry) (string, bool) { registriesSeenMutex.Lock() defer registriesSeenMutex.Unlock() if mapping, present := registriesSeen[reg]; present { - return mapping[fqn] + ret, ok := mapping[fqn] + return ret, ok } mapping := resolveFullyQualifiedNameToSwaggerNames(append(reg.GetAllFQMNs(), reg.GetAllFQENs()...), reg.GetUseFQNForSwaggerName()) registriesSeen[reg] = mapping - return mapping[fqn] + ret, ok := mapping[fqn] + return ret, ok +} + +// Lookup message type by location.name and return a swagger-safe version +// of its FQMN. +func lookupMsgAndSwaggerName(location, name string, reg *descriptor.Registry) (*descriptor.Message, string, error) { + msg, err := reg.LookupMsg(location, name) + if err != nil { + return nil, "", err + } + swgName, ok := fullyQualifiedNameToSwaggerName(msg.FQMN(), reg) + if !ok { + return nil, "", fmt.Errorf("can't map swagger name from FQMN '%v'", msg.FQMN()) + } + return msg, swgName, nil } // registriesSeen is used to memoise calls to resolveFullyQualifiedNameToSwaggerNames so @@ -639,7 +696,7 @@ func resolveFullyQualifiedNameToSwaggerNames(messages []string, useFQNForSwagger var canRegexp = regexp.MustCompile("{([a-zA-Z][a-zA-Z0-9_.]*).*}") // Swagger expects paths of the form /path/{string_value} but grpc-gateway paths are expected to be of the form /path/{string_value=strprefix/*}. This should reformat it correctly. -func templateToSwaggerPath(path string, reg *descriptor.Registry) string { +func templateToSwaggerPath(path string, reg *descriptor.Registry, fields []*descriptor.Field, msgs []*descriptor.Message) string { // It seems like the right thing to do here is to just use // strings.Split(path, "/") but that breaks badly when you hit a url like // /{my_field=prefix/*}/ and end up with 2 sections representing my_field. @@ -668,7 +725,7 @@ func templateToSwaggerPath(path string, reg *descriptor.Registry) string { if reg.GetUseJSONNamesForFields() && len(jsonBuffer) > 1 { jsonSnakeCaseName := string(jsonBuffer[1:]) - jsonCamelCaseName := string(lowerCamelCase(jsonSnakeCaseName)) + jsonCamelCaseName := string(lowerCamelCase(jsonSnakeCaseName, fields, msgs)) prev := string(buffer[:len(buffer)-len(jsonSnakeCaseName)-2]) buffer = strings.Join([]string{prev, "{", jsonCamelCaseName, "}"}, "") jsonBuffer = "" @@ -696,18 +753,13 @@ func templateToSwaggerPath(path string, reg *descriptor.Registry) string { // Parts is now an array of segments of the path. Interestingly, since the // syntax for this subsection CAN be handled by a regexp since it has no // memory. - keyre := regexp.MustCompile("{(.*)}") for index, part := range parts { // If part is a resource name such as "parent", "name", "user.name", the format info must be retained. prefix := canRegexp.ReplaceAllString(part, "$1") if isResourceName(prefix) { - sm := keyre.FindStringSubmatch(part) - key := sm[1] - esckey := url.PathEscape(key) - parts[index] = keyre.ReplaceAllString(part, fmt.Sprintf("{%s}", esckey)) - } else { - parts[index] = canRegexp.ReplaceAllString(part, "{$1}") + continue } + parts[index] = canRegexp.ReplaceAllString(part, "{$1}") } return strings.Join(parts, "/") @@ -722,31 +774,17 @@ func isResourceName(prefix string) bool { return field == "parent" || field == "name" } -func extractResourceName(path string) map[string]string { - m := map[string]string{} - keyre := regexp.MustCompile("{(.*)}") - sm := keyre.FindStringSubmatch(path) - count := len(sm) - for i := 0; i < count; i++ { - key := sm[1] - parts := strings.Split(key, "=") - label := parts[0] - parts = strings.Split(label, ".") - l := len(parts) - field := parts[l-1] - if field == "parent" || field == "name" { - m[label] = key - } - } - return m -} - -func renderServices(services []*descriptor.Service, paths swaggerPathsObject, reg *descriptor.Registry, requestResponseRefs, customRefs refMap) error { +func renderServices(services []*descriptor.Service, paths swaggerPathsObject, reg *descriptor.Registry, requestResponseRefs, customRefs refMap, msgs []*descriptor.Message) error { // Correctness of svcIdx and methIdx depends on 'services' containing the services in the same order as the 'file.Service' array. + svcBaseIdx := 0 + var lastFile *descriptor.File = nil for svcIdx, svc := range services { + if svc.File != lastFile { + lastFile = svc.File + svcBaseIdx = svcIdx + } for methIdx, meth := range svc.Methods { for bIdx, b := range meth.Bindings { - pathParamMap := extractResourceName(templateToSwaggerPath(b.PathTmpl.Template, reg)) // Iterate over all the swagger parameters parameters := swaggerParametersObject{} for _, parameter := range b.PathParams { @@ -770,13 +808,18 @@ func renderServices(services []*descriptor.Service, paths swaggerPathsObject, re return fmt.Errorf("only primitive and well-known types are allowed in path parameters") } case pbdescriptor.FieldDescriptorProto_TYPE_ENUM: - paramType = "string" - paramFormat = "" enum, err := reg.LookupEnum("", parameter.Target.GetTypeName()) if err != nil { return err } + paramType = "string" + paramFormat = "" enumNames = listEnumNames(enum) + if reg.GetEnumsAsInts() { + paramType = "integer" + paramFormat = "" + enumNames = listEnumNumbers(enum) + } schema := schemaOfField(parameter.Target, reg, customRefs) desc = schema.Description defaultValue = schema.Default @@ -812,10 +855,7 @@ func renderServices(services []*descriptor.Service, paths swaggerPathsObject, re } parameterString := parameter.String() if reg.GetUseJSONNamesForFields() { - parameterString = lowerCamelCase(parameterString) - } - if esckey, ok := pathParamMap[parameterString]; ok { - parameterString = esckey + parameterString = lowerCamelCase(parameterString, meth.RequestType.Fields, msgs) } parameters = append(parameters, swaggerParameterObject{ Name: parameterString, @@ -844,7 +884,10 @@ func renderServices(services []*descriptor.Service, paths swaggerPathsObject, re wknSchemaCore, isWkn := wktSchemas[meth.RequestType.FQMN()] if !isWkn { - schema.Ref = fmt.Sprintf("#/definitions/%s", fullyQualifiedNameToSwaggerName(meth.RequestType.FQMN(), reg)) + err := schema.setRefFromFQN(meth.RequestType.FQMN(), reg) + if err != nil { + return err + } } else { schema.schemaCore = wknSchemaCore @@ -882,7 +925,7 @@ func renderServices(services []*descriptor.Service, paths swaggerPathsObject, re parameters = append(parameters, queryParams...) } - pathItemObject, ok := paths[templateToSwaggerPath(b.PathTmpl.Template, reg)] + pathItemObject, ok := paths[templateToSwaggerPath(b.PathTmpl.Template, reg, meth.RequestType.Fields, msgs)] if !ok { pathItemObject = swaggerPathItemObject{} } @@ -902,7 +945,10 @@ func renderServices(services []*descriptor.Service, paths swaggerPathsObject, re // well, without a definition wknSchemaCore, isWkn := wktSchemas[meth.ResponseType.FQMN()] if !isWkn { - responseSchema.Ref = fmt.Sprintf("#/definitions/%s", fullyQualifiedNameToSwaggerName(meth.ResponseType.FQMN(), reg)) + err := responseSchema.setRefFromFQN(meth.ResponseType.FQMN(), reg) + if err != nil { + return err + } } else { responseSchema.schemaCore = wknSchemaCore @@ -923,8 +969,32 @@ func renderServices(services []*descriptor.Service, paths swaggerPathsObject, re } if meth.GetServerStreaming() { desc += "(streaming responses)" - // Use the streamdefinition which wraps the message in a "result" - responseSchema.Ref = strings.Replace(responseSchema.Ref, `#/definitions/`, `#/x-stream-definitions/`, 1) + responseSchema.Type = "object" + swgRef, _ := fullyQualifiedNameToSwaggerName(meth.ResponseType.FQMN(), reg) + responseSchema.Title = "Stream result of " + swgRef + + props := swaggerSchemaObjectProperties{ + keyVal{ + Key: "result", + Value: swaggerSchemaObject{ + schemaCore: schemaCore{ + Ref: responseSchema.Ref, + }, + }, + }, + } + streamErrDef, hasStreamError := fullyQualifiedNameToSwaggerName(".grpc.gateway.runtime.StreamError", reg) + if hasStreamError { + props = append(props, keyVal{ + Key: "error", + Value: swaggerSchemaObject{ + schemaCore: schemaCore{ + Ref: fmt.Sprintf("#/definitions/%s", streamErrDef)}, + }, + }) + } + responseSchema.Properties = &props + responseSchema.Ref = "" } tag := svc.GetName() @@ -942,11 +1012,27 @@ func renderServices(services []*descriptor.Service, paths swaggerPathsObject, re }, }, } - if bIdx == 0 { + if !reg.GetDisableDefaultErrors() { + errDef, hasErrDef := fullyQualifiedNameToSwaggerName(".grpc.gateway.runtime.Error", reg) + if hasErrDef { + // https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#responses-object + operationObject.Responses["default"] = swaggerResponseObject{ + Description: "An unexpected error response", + Schema: swaggerSchemaObject{ + schemaCore: schemaCore{ + Ref: fmt.Sprintf("#/definitions/%s", errDef), + }, + }, + } + } + } + operationObject.OperationID = fmt.Sprintf("%s_%s", svc.GetName(), meth.GetName()) + if reg.GetSimpleOperationIDs() { operationObject.OperationID = fmt.Sprintf("%s", meth.GetName()) - } else { + } + if bIdx != 0 { // OperationID must be unique in an OpenAPI v2 definition. - operationObject.OperationID = fmt.Sprintf("%s%d", meth.GetName(), bIdx+1) + operationObject.OperationID += strconv.Itoa(bIdx + 1) } // Fill reference map with referenced request messages @@ -956,7 +1042,7 @@ func renderServices(services []*descriptor.Service, paths swaggerPathsObject, re } } - methComments := protoComments(reg, svc.File, nil, "Method", int32(svcIdx), methProtoPath, int32(methIdx)) + methComments := protoComments(reg, svc.File, nil, "Service", int32(svcIdx-svcBaseIdx), methProtoPath, int32(methIdx)) if err := updateSwaggerDataFromComments(reg, operationObject, meth, methComments, false); err != nil { panic(err) } @@ -980,6 +1066,9 @@ func renderServices(services []*descriptor.Service, paths swaggerPathsObject, re operationObject.Tags = make([]string, len(opts.Tags)) copy(operationObject.Tags, opts.Tags) } + if opts.OperationId != "" { + operationObject.OperationID = opts.OperationId + } if opts.Security != nil { newSecurity := []swaggerSecurityRequirementObject{} if operationObject.Security != nil { @@ -1005,9 +1094,16 @@ func renderServices(services []*descriptor.Service, paths swaggerPathsObject, re } if opts.Responses != nil { for name, resp := range opts.Responses { - respObj := swaggerResponseObject{ - Description: resp.Description, - Schema: swaggerSchemaFromProtoSchema(resp.Schema, reg, customRefs, meth), + // Merge response data into default response if available. + respObj := operationObject.Responses[name] + if resp.Description != "" { + respObj.Description = resp.Description + } + if resp.Schema != nil { + respObj.Schema = swaggerSchemaFromProtoSchema(resp.Schema, reg, customRefs, meth) + } + if resp.Examples != nil { + respObj.Examples = swaggerExamplesFromProtoExamples(resp.Examples) } if resp.Extensions != nil { exts, err := processExtensions(resp.Extensions) @@ -1028,6 +1124,11 @@ func renderServices(services []*descriptor.Service, paths swaggerPathsObject, re operationObject.extensions = exts } + if len(opts.Produces) > 0 { + operationObject.Produces = make([]string, len(opts.Produces)) + copy(operationObject.Produces, opts.Produces) + } + // TODO(ivucica): add remaining fields of operation object } @@ -1048,7 +1149,7 @@ func renderServices(services []*descriptor.Service, paths swaggerPathsObject, re pathItemObject.Patch = operationObject break } - paths[templateToSwaggerPath(b.PathTmpl.Template, reg)] = pathItemObject + paths[templateToSwaggerPath(b.PathTmpl.Template, reg, meth.RequestType.Fields, msgs)] = pathItemObject } } } @@ -1063,13 +1164,11 @@ func applyTemplate(p param) (*swaggerObject, error) { // defined off of. s := swaggerObject{ // Swagger 2.0 is the version of this document - Swagger: "2.0", - Schemes: []string{"http", "https"}, - Consumes: []string{"application/json"}, - Produces: []string{"application/json"}, - Paths: make(swaggerPathsObject), - Definitions: make(swaggerDefinitionsObject), - StreamDefinitions: make(swaggerDefinitionsObject), + Swagger: "2.0", + Consumes: []string{"application/json"}, + Produces: []string{"application/json"}, + Paths: make(swaggerPathsObject), + Definitions: make(swaggerDefinitionsObject), Info: swaggerInfoObject{ Title: *p.File.Name, Version: "version not set", @@ -1080,19 +1179,30 @@ func applyTemplate(p param) (*swaggerObject, error) { // and create entries for all of them. // Also adds custom user specified references to second map. requestResponseRefs, customRefs := refMap{}, refMap{} - if err := renderServices(p.Services, s.Paths, p.reg, requestResponseRefs, customRefs); err != nil { + if err := renderServices(p.Services, s.Paths, p.reg, requestResponseRefs, customRefs, p.Messages); err != nil { panic(err) } + messages := messageMap{} + streamingMessages := messageMap{} + enums := enumMap{} + + if !p.reg.GetDisableDefaultErrors() { + // Add the error type to the message map + runtimeError, swgRef, err := lookupMsgAndSwaggerName(".grpc.gateway.runtime", "Error", p.reg) + if err == nil { + messages[swgRef] = runtimeError + } else { + // just in case there is an error looking up runtimeError + glog.Error(err) + } + } + // Find all the service's messages and enumerations that are defined (recursively) // and write request, response and other custom (but referenced) types out as definition objects. - m := messageMap{} - ms := messageMap{} - e := enumMap{} - findServicesMessagesAndEnumerations(p.Services, p.reg, m, ms, e, requestResponseRefs) - renderMessagesAsDefinition(m, s.Definitions, p.reg, customRefs) - renderMessagesAsStreamDefinition(ms, s.StreamDefinitions, p.reg) - renderEnumerationsAsDefinition(e, s.Definitions, p.reg) + findServicesMessagesAndEnumerations(p.Services, p.reg, messages, streamingMessages, enums, requestResponseRefs) + renderMessagesAsDefinition(messages, s.Definitions, p.reg, customRefs) + renderEnumerationsAsDefinition(enums, s.Definitions, p.reg) // File itself might have some comments and metadata. packageProtoPath := protoPathIndex(reflect.TypeOf((*pbdescriptor.FileDescriptorProto)(nil)), "Package") @@ -1296,6 +1406,7 @@ func applyTemplate(p param) (*swaggerObject, error) { respMap[k] = swaggerResponseObject{ Description: v.Description, Schema: swaggerSchemaFromProtoSchema(v.Schema, p.reg, customRefs, nil), + Examples: swaggerExamplesFromProtoExamples(v.Examples), } } } @@ -1437,6 +1548,9 @@ func enumValueProtoComments(reg *descriptor.Registry, enum *descriptor.Enum) str var comments []string for idx, value := range enum.GetValue() { name := value.GetName() + if reg.GetEnumsAsInts() { + name = strconv.Itoa(int(value.GetNumber())) + } str := protoComments(reg, enum.File, enum.Outers, "EnumType", int32(enum.Index), protoPath, int32(idx)) if str != "" { comments = append(comments, name+": "+str) @@ -1589,7 +1703,7 @@ func isProtoPathMatches(paths []int32, outerPaths []int32, typeName string, type // For example, if we are trying to locate comments related to a field named // `Address` in a message named `Person`, the path will be: // -// [4, a, 2, b] +// [4, a, 2, b] // // While `a` gets determined by the order in which the messages appear in // the proto file, and `b` is the field index specified in the proto @@ -1705,8 +1819,8 @@ func protoJSONSchemaToSwaggerSchemaCore(j *swagger_options.JSONSchema, reg *desc ret := schemaCore{} if j.GetRef() != "" { - swaggerName := fullyQualifiedNameToSwaggerName(j.GetRef(), reg) - if swaggerName != "" { + swaggerName, ok := fullyQualifiedNameToSwaggerName(j.GetRef(), reg) + if ok { ret.Ref = "#/definitions/" + swaggerName if refs != nil { refs[j.GetRef()] = struct{}{} @@ -1767,6 +1881,24 @@ func swaggerSchemaFromProtoSchema(s *swagger_options.Schema, reg *descriptor.Reg return ret } +func swaggerExamplesFromProtoExamples(in map[string]string) map[string]interface{} { + if len(in) == 0 { + return nil + } + out := make(map[string]interface{}) + for mimeType, exampleStr := range in { + switch mimeType { + case "application/json": + // JSON example objects are rendered raw. + out[mimeType] = json.RawMessage(exampleStr) + default: + // All other mimetype examples are rendered as strings. + out[mimeType] = exampleStr + } + } + return out +} + func protoJSONSchemaTypeToFormat(in []swagger_options.JSONSchema_JSONSchemaSimpleTypes) (string, string) { if len(in) == 0 { return "", "" @@ -1824,19 +1956,24 @@ func addCustomRefs(d swaggerDefinitionsObject, reg *descriptor.Registry, refs re msgMap := make(messageMap) enumMap := make(enumMap) for ref := range refs { - if _, ok := d[fullyQualifiedNameToSwaggerName(ref, reg)]; ok { + swgName, swgOk := fullyQualifiedNameToSwaggerName(ref, reg) + if !swgOk { + glog.Errorf("can't resolve swagger name from CustomRef '%v'", ref) + continue + } + if _, ok := d[swgName]; ok { // Skip already existing definitions delete(refs, ref) continue } msg, err := reg.LookupMsg("", ref) if err == nil { - msgMap[fullyQualifiedNameToSwaggerName(ref, reg)] = msg + msgMap[swgName] = msg continue } enum, err := reg.LookupEnum("", ref) if err == nil { - enumMap[fullyQualifiedNameToSwaggerName(ref, reg)] = enum + enumMap[swgName] = enum continue } @@ -1849,10 +1986,54 @@ func addCustomRefs(d swaggerDefinitionsObject, reg *descriptor.Registry, refs re addCustomRefs(d, reg, refs) } -func lowerCamelCase(parameter string) string { - parameterString := gogen.CamelCase(parameter) +func lowerCamelCase(fieldName string, fields []*descriptor.Field, msgs []*descriptor.Message) string { + for _, oneField := range fields { + if oneField.GetName() == fieldName { + return oneField.GetJsonName() + } + } + messageNameToFieldsToJSONName := make(map[string]map[string]string, 0) + fieldNameToType := make(map[string]string, 0) + for _, msg := range msgs { + fieldNameToJSONName := make(map[string]string, 0) + for _, oneField := range msg.GetField() { + fieldNameToJSONName[oneField.GetName()] = oneField.GetJsonName() + fieldNameToType[oneField.GetName()] = oneField.GetTypeName() + } + messageNameToFieldsToJSONName[msg.GetName()] = fieldNameToJSONName + } + if strings.Contains(fieldName, ".") { + fieldNames := strings.Split(fieldName, ".") + fieldNamesWithCamelCase := make([]string, 0) + for i := 0; i < len(fieldNames)-1; i++ { + fieldNamesWithCamelCase = append(fieldNamesWithCamelCase, doCamelCase(string(fieldNames[i]))) + } + prefix := strings.Join(fieldNamesWithCamelCase, ".") + reservedJSONName := getReservedJSONName(fieldName, messageNameToFieldsToJSONName, fieldNameToType) + if reservedJSONName != "" { + return prefix + "." + reservedJSONName + } + } + return doCamelCase(fieldName) +} + +func doCamelCase(input string) string { + parameterString := casing.Camel(input) builder := &strings.Builder{} builder.WriteString(strings.ToLower(string(parameterString[0]))) builder.WriteString(parameterString[1:]) return builder.String() } + +func getReservedJSONName(fieldName string, messageNameToFieldsToJSONName map[string]map[string]string, fieldNameToType map[string]string) string { + if len(strings.Split(fieldName, ".")) == 2 { + fieldNames := strings.Split(fieldName, ".") + firstVariable := fieldNames[0] + firstType := fieldNameToType[firstVariable] + firstTypeShortNames := strings.Split(firstType, ".") + firstTypeShortName := firstTypeShortNames[len(firstTypeShortNames)-1] + return messageNameToFieldsToJSONName[firstTypeShortName][fieldNames[1]] + } + fieldNames := strings.Split(fieldName, ".") + return getReservedJSONName(strings.Join(fieldNames[1:], "."), messageNameToFieldsToJSONName, fieldNameToType) +} diff --git a/gateway/protoc-gen-swagger/genswagger/template_test.go b/gateway/protoc-gen-swagger/genswagger/template_test.go index ac6cf0e..9311399 100644 --- a/gateway/protoc-gen-swagger/genswagger/template_test.go +++ b/gateway/protoc-gen-swagger/genswagger/template_test.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "reflect" + "strings" "testing" "github.com/golang/protobuf/proto" @@ -41,6 +42,196 @@ func crossLinkFixture(f *descriptor.File) *descriptor.File { return f } +func reqFromFile(f *descriptor.File) *plugin.CodeGeneratorRequest { + return &plugin.CodeGeneratorRequest{ + ProtoFile: []*protodescriptor.FileDescriptorProto{ + f.FileDescriptorProto, + }, + FileToGenerate: []string{f.GetName()}, + } +} + +func TestMessageToQueryParametersWithEnumAsInt(t *testing.T) { + type test struct { + MsgDescs []*protodescriptor.DescriptorProto + Message string + Params []swaggerParameterObject + } + + tests := []test{ + { + MsgDescs: []*protodescriptor.DescriptorProto{ + &protodescriptor.DescriptorProto{ + Name: proto.String("ExampleMessage"), + Field: []*protodescriptor.FieldDescriptorProto{ + { + Name: proto.String("a"), + Type: protodescriptor.FieldDescriptorProto_TYPE_STRING.Enum(), + Number: proto.Int32(1), + }, + { + Name: proto.String("b"), + Type: protodescriptor.FieldDescriptorProto_TYPE_DOUBLE.Enum(), + Number: proto.Int32(2), + }, + { + Name: proto.String("c"), + Type: protodescriptor.FieldDescriptorProto_TYPE_STRING.Enum(), + Label: protodescriptor.FieldDescriptorProto_LABEL_REPEATED.Enum(), + Number: proto.Int32(3), + }, + }, + }, + }, + Message: "ExampleMessage", + Params: []swaggerParameterObject{ + swaggerParameterObject{ + Name: "a", + In: "query", + Required: false, + Type: "string", + }, + swaggerParameterObject{ + Name: "b", + In: "query", + Required: false, + Type: "number", + Format: "double", + }, + swaggerParameterObject{ + Name: "c", + In: "query", + Required: false, + Type: "array", + CollectionFormat: "multi", + }, + }, + }, + { + MsgDescs: []*protodescriptor.DescriptorProto{ + &protodescriptor.DescriptorProto{ + Name: proto.String("ExampleMessage"), + Field: []*protodescriptor.FieldDescriptorProto{ + { + Name: proto.String("nested"), + Type: protodescriptor.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + TypeName: proto.String(".example.Nested"), + Number: proto.Int32(1), + }, + }, + }, + &protodescriptor.DescriptorProto{ + Name: proto.String("Nested"), + Field: []*protodescriptor.FieldDescriptorProto{ + { + Name: proto.String("a"), + Type: protodescriptor.FieldDescriptorProto_TYPE_STRING.Enum(), + Number: proto.Int32(1), + }, + { + Name: proto.String("deep"), + Type: protodescriptor.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + TypeName: proto.String(".example.Nested.DeepNested"), + Number: proto.Int32(2), + }, + }, + NestedType: []*protodescriptor.DescriptorProto{{ + Name: proto.String("DeepNested"), + Field: []*protodescriptor.FieldDescriptorProto{ + { + Name: proto.String("b"), + Type: protodescriptor.FieldDescriptorProto_TYPE_STRING.Enum(), + Number: proto.Int32(1), + }, + { + Name: proto.String("c"), + Type: protodescriptor.FieldDescriptorProto_TYPE_ENUM.Enum(), + TypeName: proto.String(".example.Nested.DeepNested.DeepEnum"), + Number: proto.Int32(2), + }, + }, + EnumType: []*protodescriptor.EnumDescriptorProto{ + { + Name: proto.String("DeepEnum"), + Value: []*protodescriptor.EnumValueDescriptorProto{ + {Name: proto.String("FALSE"), Number: proto.Int32(0)}, + {Name: proto.String("TRUE"), Number: proto.Int32(1)}, + }, + }, + }, + }}, + }, + }, + Message: "ExampleMessage", + Params: []swaggerParameterObject{ + swaggerParameterObject{ + Name: "nested.a", + In: "query", + Required: false, + Type: "string", + }, + swaggerParameterObject{ + Name: "nested.deep.b", + In: "query", + Required: false, + Type: "string", + }, + swaggerParameterObject{ + Name: "nested.deep.c", + In: "query", + Required: false, + Type: "integer", + Enum: []string{"0", "1"}, + Default: "0", + }, + }, + }, + } + + for _, test := range tests { + reg := descriptor.NewRegistry() + reg.SetEnumsAsInts(true) + msgs := []*descriptor.Message{} + for _, msgdesc := range test.MsgDescs { + msgs = append(msgs, &descriptor.Message{DescriptorProto: msgdesc}) + } + file := descriptor.File{ + FileDescriptorProto: &protodescriptor.FileDescriptorProto{ + SourceCodeInfo: &protodescriptor.SourceCodeInfo{}, + Name: proto.String("example.proto"), + Package: proto.String("example"), + Dependency: []string{}, + MessageType: test.MsgDescs, + Service: []*protodescriptor.ServiceDescriptorProto{}, + }, + GoPkg: descriptor.GoPackage{ + Path: "example.com/path/to/example/example.pb", + Name: "example_pb", + }, + Messages: msgs, + } + reg.Load(&plugin.CodeGeneratorRequest{ + ProtoFile: []*protodescriptor.FileDescriptorProto{file.FileDescriptorProto}, + }) + + message, err := reg.LookupMsg("", ".example."+test.Message) + if err != nil { + t.Fatalf("failed to lookup message: %s", err) + } + params, err := messageToQueryParameters(message, reg, []descriptor.Parameter{}) + if err != nil { + t.Fatalf("failed to convert message to query parameters: %s", err) + } + // avoid checking Items for array types + for i := range params { + params[i].Items = nil + } + if !reflect.DeepEqual(params, test.Params) { + t.Errorf("expected %v, got %v", test.Params, params) + } + } +} + func TestMessageToQueryParameters(t *testing.T) { type test struct { MsgDescs []*protodescriptor.DescriptorProto @@ -221,81 +412,549 @@ func TestMessageToQueryParameters(t *testing.T) { } } -func TestMessageToQueryParametersWithJsonName(t *testing.T) { +// TestMessagetoQueryParametersNoRecursive, is a check that cyclical references between messages +// are not falsely detected given previous known edge-cases. +func TestMessageToQueryParametersNoRecursive(t *testing.T) { type test struct { MsgDescs []*protodescriptor.DescriptorProto Message string - Params []swaggerParameterObject } tests := []test{ + // First test: + // Here is a message that has two of another message adjacent to one another in a nested message. + // There is no loop but this was previouly falsely flagged as a cycle. + // Example proto: + // message NonRecursiveMessage { + // string field = 1; + // } + // message BaseMessage { + // NonRecursiveMessage first = 1; + // NonRecursiveMessage second = 2; + // } + // message QueryMessage { + // BaseMessage first = 1; + // string second = 2; + // } { MsgDescs: []*protodescriptor.DescriptorProto{ &protodescriptor.DescriptorProto{ - Name: proto.String("ExampleMessage"), + Name: proto.String("QueryMessage"), Field: []*protodescriptor.FieldDescriptorProto{ { - Name: proto.String("test_field_a"), - Type: protodescriptor.FieldDescriptorProto_TYPE_STRING.Enum(), + Name: proto.String("first"), + Type: protodescriptor.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + TypeName: proto.String(".example.BaseMessage"), Number: proto.Int32(1), - JsonName: proto.String("testFieldA"), + }, + { + Name: proto.String("second"), + Type: protodescriptor.FieldDescriptorProto_TYPE_STRING.Enum(), + Number: proto.Int32(2), + }, + }, + }, + &protodescriptor.DescriptorProto{ + Name: proto.String("BaseMessage"), + Field: []*protodescriptor.FieldDescriptorProto{ + { + Name: proto.String("first"), + Type: protodescriptor.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + TypeName: proto.String(".example.NonRecursiveMessage"), + Number: proto.Int32(1), + }, + { + Name: proto.String("second"), + Type: protodescriptor.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + TypeName: proto.String(".example.NonRecursiveMessage"), + Number: proto.Int32(2), + }, + }, + }, + // Note there is no recursive nature to this message + &protodescriptor.DescriptorProto{ + Name: proto.String("NonRecursiveMessage"), + Field: []*protodescriptor.FieldDescriptorProto{ + { + Name: proto.String("field"), + //Label: protodescriptor.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), + Type: protodescriptor.FieldDescriptorProto_TYPE_STRING.Enum(), + Number: proto.Int32(1), + }, + }, + }, + }, + Message: "QueryMessage", + }, + } + + for _, test := range tests { + reg := descriptor.NewRegistry() + msgs := []*descriptor.Message{} + for _, msgdesc := range test.MsgDescs { + msgs = append(msgs, &descriptor.Message{DescriptorProto: msgdesc}) + } + file := descriptor.File{ + FileDescriptorProto: &protodescriptor.FileDescriptorProto{ + SourceCodeInfo: &protodescriptor.SourceCodeInfo{}, + Name: proto.String("example.proto"), + Package: proto.String("example"), + Dependency: []string{}, + MessageType: test.MsgDescs, + Service: []*protodescriptor.ServiceDescriptorProto{}, + }, + GoPkg: descriptor.GoPackage{ + Path: "example.com/path/to/example/example.pb", + Name: "example_pb", + }, + Messages: msgs, + } + reg.Load(&plugin.CodeGeneratorRequest{ + ProtoFile: []*protodescriptor.FileDescriptorProto{file.FileDescriptorProto}, + }) + + message, err := reg.LookupMsg("", ".example."+test.Message) + if err != nil { + t.Fatalf("failed to lookup message: %s", err) + } + + _, err = messageToQueryParameters(message, reg, []descriptor.Parameter{}) + if err != nil { + t.Fatalf("No recursion error should be thrown: %s", err) + } + } +} + +// TestMessagetoQueryParametersRecursive, is a check that cyclical references between messages +// are handled gracefully. The goal is to insure that attempts to add messages with cyclical +// references to query-parameters returns an error message. +func TestMessageToQueryParametersRecursive(t *testing.T) { + type test struct { + MsgDescs []*protodescriptor.DescriptorProto + Message string + } + + tests := []test{ + // First test: + // Here we test that a message that references it self through a field will return an error. + // Example proto: + // message DirectRecursiveMessage { + // DirectRecursiveMessage nested = 1; + // } + { + MsgDescs: []*protodescriptor.DescriptorProto{ + &protodescriptor.DescriptorProto{ + Name: proto.String("DirectRecursiveMessage"), + Field: []*protodescriptor.FieldDescriptorProto{ + { + Name: proto.String("nested"), + Label: protodescriptor.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), + Type: protodescriptor.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + TypeName: proto.String(".example.DirectRecursiveMessage"), + Number: proto.Int32(1), + }, + }, + }, + }, + Message: "DirectRecursiveMessage", + }, + // Second test: + // Here we test that a cycle through multiple messages is detected and that an error is returned. + // Sample: + // message Root { NodeMessage nested = 1; } + // message NodeMessage { CycleMessage nested = 1; } + // message CycleMessage { Root nested = 1; } + { + MsgDescs: []*protodescriptor.DescriptorProto{ + &protodescriptor.DescriptorProto{ + Name: proto.String("RootMessage"), + Field: []*protodescriptor.FieldDescriptorProto{ + { + Name: proto.String("nested"), + Label: protodescriptor.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), + Type: protodescriptor.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + TypeName: proto.String(".example.NodeMessage"), + Number: proto.Int32(1), + }, + }, + }, + &protodescriptor.DescriptorProto{ + Name: proto.String("NodeMessage"), + Field: []*protodescriptor.FieldDescriptorProto{ + { + Name: proto.String("nested"), + Label: protodescriptor.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), + Type: protodescriptor.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + TypeName: proto.String(".example.CycleMessage"), + Number: proto.Int32(1), + }, + }, + }, + &protodescriptor.DescriptorProto{ + Name: proto.String("CycleMessage"), + Field: []*protodescriptor.FieldDescriptorProto{ + { + Name: proto.String("nested"), + Label: protodescriptor.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), + Type: protodescriptor.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + TypeName: proto.String(".example.RootMessage"), + Number: proto.Int32(1), + }, + }, + }, + }, + Message: "RootMessage", + }, + } + + for _, test := range tests { + reg := descriptor.NewRegistry() + msgs := []*descriptor.Message{} + for _, msgdesc := range test.MsgDescs { + msgs = append(msgs, &descriptor.Message{DescriptorProto: msgdesc}) + } + file := descriptor.File{ + FileDescriptorProto: &protodescriptor.FileDescriptorProto{ + SourceCodeInfo: &protodescriptor.SourceCodeInfo{}, + Name: proto.String("example.proto"), + Package: proto.String("example"), + Dependency: []string{}, + MessageType: test.MsgDescs, + Service: []*protodescriptor.ServiceDescriptorProto{}, + }, + GoPkg: descriptor.GoPackage{ + Path: "example.com/path/to/example/example.pb", + Name: "example_pb", + }, + Messages: msgs, + } + reg.Load(&plugin.CodeGeneratorRequest{ + ProtoFile: []*protodescriptor.FileDescriptorProto{file.FileDescriptorProto}, + }) + + message, err := reg.LookupMsg("", ".example."+test.Message) + if err != nil { + t.Fatalf("failed to lookup message: %s", err) + } + _, err = messageToQueryParameters(message, reg, []descriptor.Parameter{}) + if err == nil { + t.Fatalf("It should not be allowed to have recursive query parameters") + } + } +} + +func TestMessageToQueryParametersWithJsonName(t *testing.T) { + type test struct { + MsgDescs []*protodescriptor.DescriptorProto + Message string + Params []swaggerParameterObject + } + + tests := []test{ + { + MsgDescs: []*protodescriptor.DescriptorProto{ + &protodescriptor.DescriptorProto{ + Name: proto.String("ExampleMessage"), + Field: []*protodescriptor.FieldDescriptorProto{ + { + Name: proto.String("test_field_a"), + Type: protodescriptor.FieldDescriptorProto_TYPE_STRING.Enum(), + Number: proto.Int32(1), + JsonName: proto.String("testFieldA"), + }, + }, + }, + }, + Message: "ExampleMessage", + Params: []swaggerParameterObject{ + swaggerParameterObject{ + Name: "testFieldA", + In: "query", + Required: false, + Type: "string", + }, + }, + }, + { + MsgDescs: []*protodescriptor.DescriptorProto{ + &protodescriptor.DescriptorProto{ + Name: proto.String("SubMessage"), + Field: []*protodescriptor.FieldDescriptorProto{ + { + Name: proto.String("test_field_a"), + Type: protodescriptor.FieldDescriptorProto_TYPE_STRING.Enum(), + Number: proto.Int32(1), + JsonName: proto.String("testFieldA"), + }, + }, + }, + &protodescriptor.DescriptorProto{ + Name: proto.String("ExampleMessage"), + Field: []*protodescriptor.FieldDescriptorProto{ + { + Name: proto.String("sub_message"), + Type: protodescriptor.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + TypeName: proto.String(".example.SubMessage"), + Number: proto.Int32(1), + JsonName: proto.String("subMessage"), + }, + }, + }, + }, + Message: "ExampleMessage", + Params: []swaggerParameterObject{ + swaggerParameterObject{ + Name: "subMessage.testFieldA", + In: "query", + Required: false, + Type: "string", + }, + }, + }, + } + + for _, test := range tests { + reg := descriptor.NewRegistry() + reg.SetUseJSONNamesForFields(true) + msgs := []*descriptor.Message{} + for _, msgdesc := range test.MsgDescs { + msgs = append(msgs, &descriptor.Message{DescriptorProto: msgdesc}) + } + file := descriptor.File{ + FileDescriptorProto: &protodescriptor.FileDescriptorProto{ + SourceCodeInfo: &protodescriptor.SourceCodeInfo{}, + Name: proto.String("example.proto"), + Package: proto.String("example"), + Dependency: []string{}, + MessageType: test.MsgDescs, + Service: []*protodescriptor.ServiceDescriptorProto{}, + }, + GoPkg: descriptor.GoPackage{ + Path: "example.com/path/to/example/example.pb", + Name: "example_pb", + }, + Messages: msgs, + } + reg.Load(&plugin.CodeGeneratorRequest{ + ProtoFile: []*protodescriptor.FileDescriptorProto{file.FileDescriptorProto}, + }) + + message, err := reg.LookupMsg("", ".example."+test.Message) + if err != nil { + t.Fatalf("failed to lookup message: %s", err) + } + params, err := messageToQueryParameters(message, reg, []descriptor.Parameter{}) + if err != nil { + t.Fatalf("failed to convert message to query parameters: %s", err) + } + if !reflect.DeepEqual(params, test.Params) { + t.Errorf("expected %v, got %v", test.Params, params) + } + } +} + +func TestApplyTemplateSimple(t *testing.T) { + msgdesc := &protodescriptor.DescriptorProto{ + Name: proto.String("ExampleMessage"), + } + meth := &protodescriptor.MethodDescriptorProto{ + Name: proto.String("Example"), + InputType: proto.String("ExampleMessage"), + OutputType: proto.String("ExampleMessage"), + } + svc := &protodescriptor.ServiceDescriptorProto{ + Name: proto.String("ExampleService"), + Method: []*protodescriptor.MethodDescriptorProto{meth}, + } + msg := &descriptor.Message{ + DescriptorProto: msgdesc, + } + file := descriptor.File{ + FileDescriptorProto: &protodescriptor.FileDescriptorProto{ + SourceCodeInfo: &protodescriptor.SourceCodeInfo{}, + Name: proto.String("example.proto"), + Package: proto.String("example"), + Dependency: []string{"a.example/b/c.proto", "a.example/d/e.proto"}, + MessageType: []*protodescriptor.DescriptorProto{msgdesc}, + Service: []*protodescriptor.ServiceDescriptorProto{svc}, + }, + GoPkg: descriptor.GoPackage{ + Path: "example.com/path/to/example/example.pb", + Name: "example_pb", + }, + Messages: []*descriptor.Message{msg}, + Services: []*descriptor.Service{ + { + ServiceDescriptorProto: svc, + Methods: []*descriptor.Method{ + { + MethodDescriptorProto: meth, + RequestType: msg, + ResponseType: msg, + Bindings: []*descriptor.Binding{ + { + HTTPMethod: "GET", + Body: &descriptor.Body{FieldPath: nil}, + PathTmpl: httprule.Template{ + Version: 1, + OpCodes: []int{0, 0}, + Template: "/v1/echo", // TODO(achew22): Figure out what this should really be + }, + }, + }, + }, + }, + }, + }, + } + reg := descriptor.NewRegistry() + fileCL := crossLinkFixture(&file) + err := reg.Load(reqFromFile(fileCL)) + if err != nil { + t.Errorf("reg.Load(%#v) failed with %v; want success", file, err) + return + } + result, err := applyTemplate(param{File: fileCL, reg: reg}) + if err != nil { + t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err) + return + } + if want, is, name := "2.0", result.Swagger, "Swagger"; !reflect.DeepEqual(is, want) { + t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want) + } + if want, is, name := "", result.BasePath, "BasePath"; !reflect.DeepEqual(is, want) { + t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want) + } + if want, is, name := ([]string)(nil), result.Schemes, "Schemes"; !reflect.DeepEqual(is, want) { + t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want) + } + if want, is, name := []string{"application/json"}, result.Consumes, "Consumes"; !reflect.DeepEqual(is, want) { + t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want) + } + if want, is, name := []string{"application/json"}, result.Produces, "Produces"; !reflect.DeepEqual(is, want) { + t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want) + } + + // If there was a failure, print out the input and the json result for debugging. + if t.Failed() { + t.Errorf("had: %s", file) + t.Errorf("got: %s", fmt.Sprint(result)) + } +} + +func TestApplyTemplateMultiService(t *testing.T) { + msgdesc := &protodescriptor.DescriptorProto{ + Name: proto.String("ExampleMessage"), + } + meth := &protodescriptor.MethodDescriptorProto{ + Name: proto.String("Example"), + InputType: proto.String("ExampleMessage"), + OutputType: proto.String("ExampleMessage"), + } + + // Create two services that have the same method name. We will test that the + // operation IDs are different + svc := &protodescriptor.ServiceDescriptorProto{ + Name: proto.String("ExampleService"), + Method: []*protodescriptor.MethodDescriptorProto{meth}, + } + svc2 := &protodescriptor.ServiceDescriptorProto{ + Name: proto.String("OtherService"), + Method: []*protodescriptor.MethodDescriptorProto{meth}, + } + + msg := &descriptor.Message{ + DescriptorProto: msgdesc, + } + file := descriptor.File{ + FileDescriptorProto: &protodescriptor.FileDescriptorProto{ + SourceCodeInfo: &protodescriptor.SourceCodeInfo{}, + Name: proto.String("example.proto"), + Package: proto.String("example"), + Dependency: []string{"a.example/b/c.proto", "a.example/d/e.proto"}, + MessageType: []*protodescriptor.DescriptorProto{msgdesc}, + Service: []*protodescriptor.ServiceDescriptorProto{svc}, + }, + GoPkg: descriptor.GoPackage{ + Path: "example.com/path/to/example/example.pb", + Name: "example_pb", + }, + Messages: []*descriptor.Message{msg}, + Services: []*descriptor.Service{ + { + ServiceDescriptorProto: svc, + Methods: []*descriptor.Method{ + { + MethodDescriptorProto: meth, + RequestType: msg, + ResponseType: msg, + Bindings: []*descriptor.Binding{ + { + HTTPMethod: "GET", + Body: &descriptor.Body{FieldPath: nil}, + PathTmpl: httprule.Template{ + Version: 1, + OpCodes: []int{0, 0}, + Template: "/v1/echo", + }, + }, }, }, }, }, - Message: "ExampleMessage", - Params: []swaggerParameterObject{ - swaggerParameterObject{ - Name: "testFieldA", - In: "query", - Required: false, - Type: "string", + { + ServiceDescriptorProto: svc2, + Methods: []*descriptor.Method{ + { + MethodDescriptorProto: meth, + RequestType: msg, + ResponseType: msg, + Bindings: []*descriptor.Binding{ + { + HTTPMethod: "GET", + Body: &descriptor.Body{FieldPath: nil}, + PathTmpl: httprule.Template{ + Version: 1, + OpCodes: []int{0, 0}, + Template: "/v1/ping", + }, + }, + }, + }, }, }, }, } + reg := descriptor.NewRegistry() + fileCL := crossLinkFixture(&file) + err := reg.Load(reqFromFile(fileCL)) + if err != nil { + t.Errorf("reg.Load(%#v) failed with %v; want success", file, err) + return + } + result, err := applyTemplate(param{File: fileCL, reg: reg}) + if err != nil { + t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err) + return + } - for _, test := range tests { - reg := descriptor.NewRegistry() - reg.SetUseJSONNamesForFields(true) - msgs := []*descriptor.Message{} - for _, msgdesc := range test.MsgDescs { - msgs = append(msgs, &descriptor.Message{DescriptorProto: msgdesc}) - } - file := descriptor.File{ - FileDescriptorProto: &protodescriptor.FileDescriptorProto{ - SourceCodeInfo: &protodescriptor.SourceCodeInfo{}, - Name: proto.String("example.proto"), - Package: proto.String("example"), - Dependency: []string{}, - MessageType: test.MsgDescs, - Service: []*protodescriptor.ServiceDescriptorProto{}, - }, - GoPkg: descriptor.GoPackage{ - Path: "example.com/path/to/example/example.pb", - Name: "example_pb", - }, - Messages: msgs, - } - reg.Load(&plugin.CodeGeneratorRequest{ - ProtoFile: []*protodescriptor.FileDescriptorProto{file.FileDescriptorProto}, - }) + // Check that the two services have unique operation IDs even though they + // have the same method name. + if want, is := "ExampleService_Example", result.Paths["/v1/echo"].Get.OperationID; !reflect.DeepEqual(is, want) { + t.Errorf("applyTemplate(%#v).Paths[0].Get.OperationID = %s want to be %s", file, is, want) + } + if want, is := "OtherService_Example", result.Paths["/v1/ping"].Get.OperationID; !reflect.DeepEqual(is, want) { + t.Errorf("applyTemplate(%#v).Paths[0].Get.OperationID = %s want to be %s", file, is, want) + } - message, err := reg.LookupMsg("", ".example."+test.Message) - if err != nil { - t.Fatalf("failed to lookup message: %s", err) - } - params, err := messageToQueryParameters(message, reg, []descriptor.Parameter{}) - if err != nil { - t.Fatalf("failed to convert message to query parameters: %s", err) - } - if !reflect.DeepEqual(params, test.Params) { - t.Errorf("expected %v, got %v", test.Params, params) - } + // If there was a failure, print out the input and the json result for debugging. + if t.Failed() { + t.Errorf("had: %s", file) + t.Errorf("got: %s", fmt.Sprint(result)) } } -func TestApplyTemplateSimple(t *testing.T) { +func TestApplyTemplateOverrideOperationID(t *testing.T) { msgdesc := &protodescriptor.DescriptorProto{ Name: proto.String("ExampleMessage"), } @@ -303,7 +962,15 @@ func TestApplyTemplateSimple(t *testing.T) { Name: proto.String("Example"), InputType: proto.String("ExampleMessage"), OutputType: proto.String("ExampleMessage"), + Options: &protodescriptor.MethodOptions{}, + } + swaggerOperation := swagger_options.Operation{ + OperationId: "MyExample", + } + if err := proto.SetExtension(proto.Message(meth.Options), swagger_options.E_Openapiv2Operation, &swaggerOperation); err != nil { + t.Fatalf("proto.SetExtension(MethodDescriptorProto.Options) failed: %v", err) } + svc := &protodescriptor.ServiceDescriptorProto{ Name: proto.String("ExampleService"), Method: []*protodescriptor.MethodDescriptorProto{meth}, @@ -349,25 +1016,21 @@ func TestApplyTemplateSimple(t *testing.T) { }, }, } - result, err := applyTemplate(param{File: crossLinkFixture(&file), reg: descriptor.NewRegistry()}) + + reg := descriptor.NewRegistry() + fileCL := crossLinkFixture(&file) + err := reg.Load(reqFromFile(fileCL)) if err != nil { - t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err) + t.Errorf("reg.Load(%#v) failed with %v; want success", file, err) return } - if want, is, name := "2.0", result.Swagger, "Swagger"; !reflect.DeepEqual(is, want) { - t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want) - } - if want, is, name := "", result.BasePath, "BasePath"; !reflect.DeepEqual(is, want) { - t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want) - } - if want, is, name := []string{"http", "https"}, result.Schemes, "Schemes"; !reflect.DeepEqual(is, want) { - t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want) - } - if want, is, name := []string{"application/json"}, result.Consumes, "Consumes"; !reflect.DeepEqual(is, want) { - t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want) + result, err := applyTemplate(param{File: fileCL, reg: reg}) + if err != nil { + t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err) + return } - if want, is, name := []string{"application/json"}, result.Produces, "Produces"; !reflect.DeepEqual(is, want) { - t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want) + if want, is := "MyExample", result.Paths["/v1/echo"].Get.OperationID; !reflect.DeepEqual(is, want) { + t.Errorf("applyTemplate(%#v).Paths[0].Get.OperationID = %s want to be %s", file, is, want) } // If there was a failure, print out the input and the json result for debugging. @@ -475,7 +1138,14 @@ func TestApplyTemplateExtensions(t *testing.T) { if err := proto.SetExtension(proto.Message(meth.Options), swagger_options.E_Openapiv2Operation, &swaggerOperation); err != nil { t.Fatalf("proto.SetExtension(MethodDescriptorProto.Options) failed: %v", err) } - result, err := applyTemplate(param{File: crossLinkFixture(&file), reg: descriptor.NewRegistry()}) + reg := descriptor.NewRegistry() + fileCL := crossLinkFixture(&file) + err := reg.Load(reqFromFile(fileCL)) + if err != nil { + t.Errorf("reg.Load(%#v) failed with %v; want success", file, err) + return + } + result, err := applyTemplate(param{File: fileCL, reg: reg}) if err != nil { t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err) return @@ -662,7 +1332,7 @@ func TestApplyTemplateRequestWithoutClientStreaming(t *testing.T) { if want, got := "", result.BasePath; !reflect.DeepEqual(got, want) { t.Errorf("applyTemplate(%#v).BasePath = %s want to be %s", file, got, want) } - if want, got := []string{"http", "https"}, result.Schemes; !reflect.DeepEqual(got, want) { + if want, got := ([]string)(nil), result.Schemes; !reflect.DeepEqual(got, want) { t.Errorf("applyTemplate(%#v).Schemes = %s want to be %s", file, got, want) } if want, got := []string{"application/json"}, result.Consumes; !reflect.DeepEqual(got, want) { @@ -816,18 +1486,20 @@ func TestApplyTemplateRequestWithClientStreaming(t *testing.T) { } // Only ExampleMessage must be present, not NestedMessage - if want, got, name := 3, len(result.Definitions), "len(Definitions)"; !reflect.DeepEqual(got, want) { + if want, got, name := 4, len(result.Definitions), "len(Definitions)"; !reflect.DeepEqual(got, want) { t.Errorf("applyTemplate(%#v).%s = %d want to be %d", file, name, got, want) } - // stream ExampleMessage must be present - if want, got, name := 1, len(result.StreamDefinitions), "len(StreamDefinitions)"; !reflect.DeepEqual(got, want) { - t.Errorf("applyTemplate(%#v).%s = %d want to be %d", file, name, got, want) + if _, ok := result.Paths["/v1/echo"].Post.Responses["200"]; !ok { + t.Errorf("applyTemplate(%#v).%s = expected 200 response to be defined", file, `result.Paths["/v1/echo"].Post.Responses["200"]`) } else { - streamExampleExampleMessage := result.StreamDefinitions["exampleExampleMessage"] - if want, got, name := "object", streamExampleExampleMessage.Type, `StreamDefinitions["exampleExampleMessage"].Type`; !reflect.DeepEqual(got, want) { + if want, got, name := "A successful response.(streaming responses)", result.Paths["/v1/echo"].Post.Responses["200"].Description, `result.Paths["/v1/echo"].Post.Responses["200"].Description`; !reflect.DeepEqual(got, want) { + t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, got, want) + } + streamExampleExampleMessage := result.Paths["/v1/echo"].Post.Responses["200"].Schema + if want, got, name := "object", streamExampleExampleMessage.Type, `result.Paths["/v1/echo"].Post.Responses["200"].Schema.Type`; !reflect.DeepEqual(got, want) { t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, got, want) } - if want, got, name := "Stream result of exampleExampleMessage", streamExampleExampleMessage.Title, `StreamDefinitions["exampleExampleMessage"].Title`; !reflect.DeepEqual(got, want) { + if want, got, name := "Stream result of exampleExampleMessage", streamExampleExampleMessage.Title, `result.Paths["/v1/echo"].Post.Responses["200"].Schema.Title`; !reflect.DeepEqual(got, want) { t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, got, want) } streamExampleExampleMessageProperties := *(streamExampleExampleMessage.Properties) @@ -852,16 +1524,6 @@ func TestApplyTemplateRequestWithClientStreaming(t *testing.T) { } } } - if want, got, name := 1, len(result.Paths["/v1/echo"].Post.Responses), "len(Paths[/v1/echo].Post.Responses)"; !reflect.DeepEqual(got, want) { - t.Errorf("applyTemplate(%#v).%s = %d want to be %d", file, name, got, want) - } else { - if want, got, name := "A successful response.(streaming responses)", result.Paths["/v1/echo"].Post.Responses["200"].Description, `result.Paths["/v1/echo"].Post.Responses["200"].Description`; !reflect.DeepEqual(got, want) { - t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, got, want) - } - if want, got, name := "#/x-stream-definitions/exampleExampleMessage", result.Paths["/v1/echo"].Post.Responses["200"].Schema.Ref, `result.Paths["/v1/echo"].Post.Responses["200"].Description`; !reflect.DeepEqual(got, want) { - t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, got, want) - } - } // If there was a failure, print out the input and the json result for debugging. if t.Failed() { @@ -991,6 +1653,46 @@ func TestApplyTemplateRequestWithUnusedReferences(t *testing.T) { } } +func generateFieldsForJSONReservedName() []*descriptor.Field { + fields := make([]*descriptor.Field, 0) + fieldName := string("json_name") + fieldJSONName := string("jsonNAME") + fieldDescriptor := protodescriptor.FieldDescriptorProto{Name: &fieldName, JsonName: &fieldJSONName} + field := &descriptor.Field{FieldDescriptorProto: &fieldDescriptor} + return append(fields, field) +} + +func generateMsgsForJSONReservedName() []*descriptor.Message { + result := make([]*descriptor.Message, 0) + // The first message, its field is field_abc and its type is NewType + // NewType field_abc + fieldName := "field_abc" + fieldJSONName := "fieldAbc" + messageName1 := "message1" + messageType := "pkg.a.NewType" + pfd := protodescriptor.FieldDescriptorProto{Name: &fieldName, JsonName: &fieldJSONName, TypeName: &messageType} + result = append(result, + &descriptor.Message{ + DescriptorProto: &protodescriptor.DescriptorProto{ + Name: &messageName1, Field: []*protodescriptor.FieldDescriptorProto{&pfd}, + }, + }) + // The second message, its name is NewName, its type is string + // message NewType { + // string field_newName [json_name = RESERVEDJSONNAME] + // } + messageName := "NewType" + field := "field_newName" + fieldJSONName2 := "RESERVEDJSONNAME" + pfd2 := protodescriptor.FieldDescriptorProto{Name: &field, JsonName: &fieldJSONName2} + result = append(result, &descriptor.Message{ + DescriptorProto: &protodescriptor.DescriptorProto{ + Name: &messageName, Field: []*protodescriptor.FieldDescriptorProto{&pfd2}, + }, + }) + return result +} + func TestTemplateWithJsonCamelCase(t *testing.T) { var tests = []struct { input string @@ -1007,11 +1709,13 @@ func TestTemplateWithJsonCamelCase(t *testing.T) { {"test/{ab}", "test/{ab}"}, {"test/{a_a}", "test/{aA}"}, {"test/{ab_c}", "test/{abC}"}, + {"test/{json_name}", "test/{jsonNAME}"}, + {"test/{field_abc.field_newName}", "test/{fieldAbc.RESERVEDJSONNAME}"}, } reg := descriptor.NewRegistry() reg.SetUseJSONNamesForFields(true) for _, data := range tests { - actual := templateToSwaggerPath(data.input, reg) + actual := templateToSwaggerPath(data.input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName()) if data.expected != actual { t.Errorf("Expected templateToSwaggerPath(%v) = %v, actual: %v", data.input, data.expected, actual) } @@ -1033,11 +1737,13 @@ func TestTemplateWithoutJsonCamelCase(t *testing.T) { {"test/{a}", "test/{a}"}, {"test/{ab}", "test/{ab}"}, {"test/{a_a}", "test/{a_a}"}, + {"test/{json_name}", "test/{json_name}"}, + {"test/{field_abc.field_newName}", "test/{field_abc.field_newName}"}, } reg := descriptor.NewRegistry() reg.SetUseJSONNamesForFields(false) for _, data := range tests { - actual := templateToSwaggerPath(data.input, reg) + actual := templateToSwaggerPath(data.input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName()) if data.expected != actual { t.Errorf("Expected templateToSwaggerPath(%v) = %v, actual: %v", data.input, data.expected, actual) } @@ -1055,29 +1761,28 @@ func TestTemplateToSwaggerPath(t *testing.T) { {"/{test=prefix/that/has/multiple/parts/to/it/*}", "/{test}"}, {"/{test1}/{test2}", "/{test1}/{test2}"}, {"/{test1}/{test2}/", "/{test1}/{test2}/"}, - {"/{name=prefix/*}", "/{name=prefix%2F%2A}"}, - {"/{name=prefix1/*/prefix2/*}", "/{name=prefix1%2F%2A%2Fprefix2%2F%2A}"}, - {"/{parent=prefix1/*}/{name=prefix2/*}", "/{parent=prefix1%2F%2A}/{name=prefix2%2F%2A}"}, - {"/{user.name=prefix/*}", "/{user.name=prefix%2F%2A}"}, - {"/{user.name=prefix1/*/prefix2/*}", "/{user.name=prefix1%2F%2A%2Fprefix2%2F%2A}"}, - {"/{parent=prefix/*}/children", "/{parent=prefix%2F%2A}/children"}, - {"/{name=prefix/*}:customMethod", "/{name=prefix%2F%2A}:customMethod"}, - {"/{name=prefix1/*/prefix2/*}:customMethod", "/{name=prefix1%2F%2A%2Fprefix2%2F%2A}:customMethod"}, - {"/{user.name=prefix/*}:customMethod", "/{user.name=prefix%2F%2A}:customMethod"}, - {"/{user.name=prefix1/*/prefix2/*}:customMethod", "/{user.name=prefix1%2F%2A%2Fprefix2%2F%2A}:customMethod"}, - {"/{parent=prefix/*}/children:customMethod", "/{parent=prefix%2F%2A}/children:customMethod"}, + {"/{name=prefix/*}", "/{name=prefix/*}"}, + {"/{name=prefix1/*/prefix2/*}", "/{name=prefix1/*/prefix2/*}"}, + {"/{user.name=prefix/*}", "/{user.name=prefix/*}"}, + {"/{user.name=prefix1/*/prefix2/*}", "/{user.name=prefix1/*/prefix2/*}"}, + {"/{parent=prefix/*}/children", "/{parent=prefix/*}/children"}, + {"/{name=prefix/*}:customMethod", "/{name=prefix/*}:customMethod"}, + {"/{name=prefix1/*/prefix2/*}:customMethod", "/{name=prefix1/*/prefix2/*}:customMethod"}, + {"/{user.name=prefix/*}:customMethod", "/{user.name=prefix/*}:customMethod"}, + {"/{user.name=prefix1/*/prefix2/*}:customMethod", "/{user.name=prefix1/*/prefix2/*}:customMethod"}, + {"/{parent=prefix/*}/children:customMethod", "/{parent=prefix/*}/children:customMethod"}, } reg := descriptor.NewRegistry() reg.SetUseJSONNamesForFields(false) for _, data := range tests { - actual := templateToSwaggerPath(data.input, reg) + actual := templateToSwaggerPath(data.input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName()) if data.expected != actual { t.Errorf("Expected templateToSwaggerPath(%v) = %v, actual: %v", data.input, data.expected, actual) } } reg.SetUseJSONNamesForFields(true) for _, data := range tests { - actual := templateToSwaggerPath(data.input, reg) + actual := templateToSwaggerPath(data.input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName()) if data.expected != actual { t.Errorf("Expected templateToSwaggerPath(%v) = %v, actual: %v", data.input, data.expected, actual) } @@ -1092,7 +1797,7 @@ func BenchmarkTemplateToSwaggerPath(b *testing.B) { reg.SetUseJSONNamesForFields(false) for i := 0; i < b.N; i++ { - _ = templateToSwaggerPath(input, reg) + _ = templateToSwaggerPath(input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName()) } }) @@ -1101,7 +1806,7 @@ func BenchmarkTemplateToSwaggerPath(b *testing.B) { reg.SetUseJSONNamesForFields(true) for i := 0; i < b.N; i++ { - _ = templateToSwaggerPath(input, reg) + _ = templateToSwaggerPath(input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName()) } }) } @@ -1177,14 +1882,14 @@ func TestFQMNtoSwaggerName(t *testing.T) { reg := descriptor.NewRegistry() reg.SetUseJSONNamesForFields(false) for _, data := range tests { - actual := templateToSwaggerPath(data.input, reg) + actual := templateToSwaggerPath(data.input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName()) if data.expected != actual { t.Errorf("Expected templateToSwaggerPath(%v) = %v, actual: %v", data.input, data.expected, actual) } } reg.SetUseJSONNamesForFields(true) for _, data := range tests { - actual := templateToSwaggerPath(data.input, reg) + actual := templateToSwaggerPath(data.input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName()) if data.expected != actual { t.Errorf("Expected templateToSwaggerPath(%v) = %v, actual: %v", data.input, data.expected, actual) } @@ -1366,7 +2071,6 @@ func TestSchemaOfField(t *testing.T) { refs: make(refMap), expected: schemaCore{ Type: "boolean", - Format: "boolean", }, }, { @@ -1963,3 +2667,174 @@ func TestMessageOptionsWithGoTemplate(t *testing.T) { }) } } + +func TestTemplateWithoutErrorDefinition(t *testing.T) { + msgdesc := &protodescriptor.DescriptorProto{ + Name: proto.String("ExampleMessage"), + Field: []*protodescriptor.FieldDescriptorProto{}, + } + meth := &protodescriptor.MethodDescriptorProto{ + Name: proto.String("Echo"), + InputType: proto.String("ExampleMessage"), + OutputType: proto.String("ExampleMessage"), + } + svc := &protodescriptor.ServiceDescriptorProto{ + Name: proto.String("ExampleService"), + Method: []*protodescriptor.MethodDescriptorProto{meth}, + } + + msg := &descriptor.Message{ + DescriptorProto: msgdesc, + } + + file := descriptor.File{ + FileDescriptorProto: &protodescriptor.FileDescriptorProto{ + SourceCodeInfo: &protodescriptor.SourceCodeInfo{}, + Name: proto.String("example.proto"), + Package: proto.String("example"), + MessageType: []*protodescriptor.DescriptorProto{msgdesc, msgdesc}, + Service: []*protodescriptor.ServiceDescriptorProto{svc}, + }, + GoPkg: descriptor.GoPackage{ + Path: "example.com/path/to/example/example.pb", + Name: "example_pb", + }, + Messages: []*descriptor.Message{msg}, + Services: []*descriptor.Service{ + { + ServiceDescriptorProto: svc, + Methods: []*descriptor.Method{ + { + MethodDescriptorProto: meth, + RequestType: msg, + ResponseType: msg, + Bindings: []*descriptor.Binding{ + { + HTTPMethod: "POST", + PathTmpl: httprule.Template{ + Version: 1, + OpCodes: []int{0, 0}, + Template: "/v1/echo", + }, + Body: &descriptor.Body{ + FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{}), + }, + }, + }, + }, + }, + }, + }, + } + reg := descriptor.NewRegistry() + reg.Load(&plugin.CodeGeneratorRequest{ProtoFile: []*protodescriptor.FileDescriptorProto{file.FileDescriptorProto}}) + result, err := applyTemplate(param{File: crossLinkFixture(&file), reg: reg}) + if err != nil { + t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err) + return + } + + defRsp, ok := result.Paths["/v1/echo"].Post.Responses["default"] + if !ok { + return + } + + ref := defRsp.Schema.schemaCore.Ref + refName := strings.TrimPrefix(ref, "#/definitions/") + if refName == "" { + t.Fatal("created default Error response with empty reflink") + } + + if _, ok := result.Definitions[refName]; !ok { + t.Errorf("default Error response with reflink '%v', but its definition was not found", refName) + } +} + +func Test_getReservedJsonName(t *testing.T) { + type args struct { + fieldName string + messageNameToFieldsToJSONName map[string]map[string]string + fieldNameToType map[string]string + } + tests := []struct { + name string + args args + want string + }{ + { + "test case 1: single dot use case", + args{ + fieldName: "abc.a_1", + messageNameToFieldsToJSONName: map[string]map[string]string{ + "Msg": { + "a_1": "a1JSONNAME", + "b_1": "b1JSONNAME", + }, + }, + fieldNameToType: map[string]string{ + "abc": "pkg1.test.Msg", + "bcd": "pkg1.test.Msg", + }, + }, + "a1JSONNAME", + }, + { + "test case 2: single dot use case with no existing field", + args{ + fieldName: "abc.d_1", + messageNameToFieldsToJSONName: map[string]map[string]string{ + "Msg": { + "a_1": "a1JSONNAME", + "b_1": "b1JSONNAME", + }, + }, + fieldNameToType: map[string]string{ + "abc": "pkg1.test.Msg", + "bcd": "pkg1.test.Msg", + }, + }, + "", + }, + { + "test case 3: double dot use case", + args{ + fieldName: "pkg.abc.a_1", + messageNameToFieldsToJSONName: map[string]map[string]string{ + "Msg": { + "a_1": "a1JSONNAME", + "b_1": "b1JSONNAME", + }, + }, + fieldNameToType: map[string]string{ + "abc": "pkg1.test.Msg", + "bcd": "pkg1.test.Msg", + }, + }, + "a1JSONNAME", + }, + { + "test case 4: double dot use case with a not existed field", + args{ + fieldName: "pkg.abc.c_1", + messageNameToFieldsToJSONName: map[string]map[string]string{ + "Msg": { + "a_1": "a1JSONNAME", + "b_1": "b1JSONNAME", + }, + }, + fieldNameToType: map[string]string{ + "abc": "pkg1.test.Msg", + "bcd": "pkg1.test.Msg", + }, + }, + "", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := getReservedJSONName(tt.args.fieldName, tt.args.messageNameToFieldsToJSONName, tt.args.fieldNameToType); got != tt.want { + t.Errorf("getReservedJSONName() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/gateway/protoc-gen-swagger/genswagger/types.go b/gateway/protoc-gen-swagger/genswagger/types.go index 0406fce..2201972 100644 --- a/gateway/protoc-gen-swagger/genswagger/types.go +++ b/gateway/protoc-gen-swagger/genswagger/types.go @@ -3,6 +3,7 @@ package genswagger import ( "bytes" "encoding/json" + "fmt" // "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/descriptor" "github.com/binchencoder/ease-gateway/gateway/protoc-gen-grpc-gateway/descriptor" @@ -61,12 +62,11 @@ type swaggerObject struct { Info swaggerInfoObject `json:"info"` Host string `json:"host,omitempty"` BasePath string `json:"basePath,omitempty"` - Schemes []string `json:"schemes"` + Schemes []string `json:"schemes,omitempty"` Consumes []string `json:"consumes"` Produces []string `json:"produces"` Paths swaggerPathsObject `json:"paths"` Definitions swaggerDefinitionsObject `json:"definitions"` - StreamDefinitions swaggerDefinitionsObject `json:"x-stream-definitions,omitempty"` SecurityDefinitions swaggerSecurityDefinitionsObject `json:"securityDefinitions,omitempty"` Security []swaggerSecurityRequirementObject `json:"security,omitempty"` ExternalDocs *swaggerExternalDocumentationObject `json:"externalDocs,omitempty"` @@ -118,6 +118,7 @@ type swaggerOperationObject struct { Parameters swaggerParametersObject `json:"parameters,omitempty"` Tags []string `json:"tags,omitempty"` Deprecated bool `json:"deprecated,omitempty"` + Produces []string `json:"produces,omitempty"` Security *[]swaggerSecurityRequirementObject `json:"security,omitempty"` ExternalDocs *swaggerExternalDocumentationObject `json:"externalDocs,omitempty"` @@ -159,11 +160,20 @@ type schemaCore struct { // If the item is an enumeration include a list of all the *NAMES* of the // enum values. I'm not sure how well this will work but assuming all enums // start from 0 index it will be great. I don't think that is a good assumption. - Enum []string `json:"enum,omitempty"` - Default string `json:"default,omitempty"` + Enum []string `json:"enum,omitempty"` + Default string `json:"default,omitempty"` Rules []options.ValidationRule `json:"rules,omitempty"` } +func (s *schemaCore) setRefFromFQN(ref string, reg *descriptor.Registry) error { + name, ok := fullyQualifiedNameToSwaggerName(ref, reg) + if !ok { + return fmt.Errorf("setRefFromFQN: can't resolve swagger name from '%v'", ref) + } + s.Ref = fmt.Sprintf("#/definitions/%s", name) + return nil +} + type swaggerItemsObject schemaCore // http://swagger.io/specification/#responsesObject @@ -171,8 +181,9 @@ type swaggerResponsesObject map[string]swaggerResponseObject // http://swagger.io/specification/#responseObject type swaggerResponseObject struct { - Description string `json:"description"` - Schema swaggerSchemaObject `json:"schema"` + Description string `json:"description"` + Schema swaggerSchemaObject `json:"schema"` + Examples map[string]interface{} `json:"examples,omitempty"` extensions []extension } diff --git a/gateway/protoc-gen-swagger/options/openapiv2.proto b/gateway/protoc-gen-swagger/options/openapiv2.proto index 419aeef..b6d16c9 100644 --- a/gateway/protoc-gen-swagger/options/openapiv2.proto +++ b/gateway/protoc-gen-swagger/options/openapiv2.proto @@ -11,6 +11,28 @@ import "google/protobuf/struct.proto"; // // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#swaggerObject // +// Example: +// +// option (grpc.gateway.protoc_gen_swagger.options.openapiv2_swagger) = { +// info: { +// title: "Echo API"; +// version: "1.0"; +// description: "; +// contact: { +// name: "gRPC-Gateway project"; +// url: "https://github.com/grpc-ecosystem/grpc-gateway"; +// email: "none@example.com"; +// }; +// license: { +// name: "BSD 3-Clause License"; +// url: "https://github.com/grpc-ecosystem/grpc-gateway/blob/master/LICENSE.txt"; +// }; +// }; +// schemes: HTTPS; +// consumes: "application/json"; +// produces: "application/json"; +// }; +// message Swagger { // Specifies the Swagger Specification version being used. It can be // used by the Swagger UI and other clients to interpret the API listing. The @@ -81,6 +103,27 @@ message Swagger { // // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#operationObject // +// Example: +// +// service EchoService { +// rpc Echo(SimpleMessage) returns (SimpleMessage) { +// option (google.api.http) = { +// get: "/v1/example/echo/{id}" +// }; +// +// option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = { +// summary: "Get a message."; +// operation_id: "getMessage"; +// tags: "echo"; +// responses: { +// key: "200" +// value: { +// description: "OK"; +// } +// } +// }; +// } +// } message Operation { // A list of tags for API documentation control. Tags can be used for logical // grouping of operations by resources or any other qualifier. @@ -150,6 +193,26 @@ message Response { // // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#infoObject // +// Example: +// +// option (grpc.gateway.protoc_gen_swagger.options.openapiv2_swagger) = { +// info: { +// title: "Echo API"; +// version: "1.0"; +// description: "; +// contact: { +// name: "gRPC-Gateway project"; +// url: "https://github.com/grpc-ecosystem/grpc-gateway"; +// email: "none@example.com"; +// }; +// license: { +// name: "BSD 3-Clause License"; +// url: "https://github.com/grpc-ecosystem/grpc-gateway/blob/master/LICENSE.txt"; +// }; +// }; +// ... +// }; +// message Info { // The title of the application. string title = 1; @@ -172,6 +235,21 @@ message Info { // // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#contactObject // +// Example: +// +// option (grpc.gateway.protoc_gen_swagger.options.openapiv2_swagger) = { +// info: { +// ... +// contact: { +// name: "gRPC-Gateway project"; +// url: "https://github.com/grpc-ecosystem/grpc-gateway"; +// email: "none@example.com"; +// }; +// ... +// }; +// ... +// }; +// message Contact { // The identifying name of the contact person/organization. string name = 1; @@ -187,6 +265,20 @@ message Contact { // // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#licenseObject // +// Example: +// +// option (grpc.gateway.protoc_gen_swagger.options.openapiv2_swagger) = { +// info: { +// ... +// license: { +// name: "BSD 3-Clause License"; +// url: "https://github.com/grpc-ecosystem/grpc-gateway/blob/master/LICENSE.txt"; +// }; +// ... +// }; +// ... +// }; +// message License { // The license name used for the API. string name = 1; @@ -199,6 +291,17 @@ message License { // // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#externalDocumentationObject // +// Example: +// +// option (grpc.gateway.protoc_gen_swagger.options.openapiv2_swagger) = { +// ... +// external_docs: { +// description: "More about gRPC-Gateway"; +// url: "https://github.com/grpc-ecosystem/grpc-gateway"; +// } +// ... +// }; +// message ExternalDocumentation { // A short description of the target documentation. GFM syntax can be used for // rich text representation. @@ -244,7 +347,24 @@ message Schema { // See also: https://cswr.github.io/JsonSchema/spec/basic_types/, // https://github.com/json-schema-org/json-schema-spec/blob/master/schema.json // -// TODO(ivucica): document fields +// Example: +// +// message SimpleMessage { +// option (grpc.gateway.protoc_gen_swagger.options.openapiv2_schema) = { +// json_schema: { +// title: "SimpleMessage" +// description: "A simple message." +// required: ["id"] +// } +// }; +// +// // Id represents the message identifier. +// string id = 1; [ +// (grpc.gateway.protoc_gen_swagger.options.openapiv2_field) = { +// {description: "The unique identifier of the simple message." +// }]; +// } +// message JSONSchema { // field 1 is reserved for '$id', omitted from OpenAPI v2. reserved 1; diff --git a/proto/examples/echo_service.swagger.json b/proto/examples/echo_service.swagger.json index d6f97ac..07533ba 100755 --- a/proto/examples/echo_service.swagger.json +++ b/proto/examples/echo_service.swagger.json @@ -5,10 +5,6 @@ "description": "Echo Service API consists of a single service which returns\na message.", "version": "version not set" }, - "schemes": [ - "http", - "https" - ], "consumes": [ "application/json" ], @@ -20,7 +16,7 @@ "post": { "summary": "Echo method receives a simple message and returns it.", "description": "The message posted as the id parameter will also be\nreturned.", - "operationId": "Echo", + "operationId": "EchoService_Echo", "responses": { "200": { "description": "A successful response.", @@ -47,7 +43,7 @@ "get": { "summary": "Echo method receives a simple message and returns it.", "description": "The message posted as the id parameter will also be\nreturned.", - "operationId": "Echo2", + "operationId": "EchoService_Echo2", "responses": { "200": { "description": "A successful response.", @@ -127,7 +123,7 @@ "get": { "summary": "Echo method receives a simple message and returns it.", "description": "The message posted as the id parameter will also be\nreturned.", - "operationId": "Echo3", + "operationId": "EchoService_Echo3", "responses": { "200": { "description": "A successful response.", @@ -207,7 +203,7 @@ "get": { "summary": "Echo method receives a simple message and returns it.", "description": "The message posted as the id parameter will also be\nreturned.", - "operationId": "Echo4", + "operationId": "EchoService_Echo4", "responses": { "200": { "description": "A successful response.", @@ -281,7 +277,7 @@ "get": { "summary": "Echo method receives a simple message and returns it.", "description": "The message posted as the id parameter will also be\nreturned.", - "operationId": "Echo5", + "operationId": "EchoService_Echo5", "responses": { "200": { "description": "A successful response.", @@ -354,7 +350,7 @@ "/v1/example/echo_body": { "post": { "summary": "EchoBody method receives a simple message and returns it.", - "operationId": "EchoBody", + "operationId": "EchoService_EchoBody", "responses": { "200": { "description": "A successful response.", @@ -381,7 +377,7 @@ "/v1/example/echo_delete": { "delete": { "summary": "EchoDelete method receives a simple message and returns it.", - "operationId": "EchoDelete", + "operationId": "EchoService_EchoDelete", "responses": { "200": { "description": "A successful response.", @@ -479,10 +475,20 @@ "type": "string", "rules": [ { - "operator": 3, + "operator": 5, + "type": 2 + }, + { + "operator": 6, "type": 2, "value": "2", "function": 1 + }, + { + "operator": 7, + "type": 2, + "value": "61", + "function": 1 } ], "description": "Id represents the message identifier." From 21491d262fcbc149d15abfe5a2f384b484ad1291 Mon Sep 17 00:00:00 2001 From: chenbin1314 Date: Sun, 12 Jul 2020 00:10:28 +0800 Subject: [PATCH 13/56] Update: gateway/internal/errors.pb.go --- gateway/internal/errors.pb.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/gateway/internal/errors.pb.go b/gateway/internal/errors.pb.go index 0a1147d..8c7706b 100755 --- a/gateway/internal/errors.pb.go +++ b/gateway/internal/errors.pb.go @@ -182,7 +182,7 @@ var File_gateway_internal_errors_proto protoreflect.FileDescriptor var file_gateway_internal_errors_proto_rawDesc = []byte{ 0x0a, 0x1d, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, - 0x14, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, + 0x14, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x14, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x2f, 0x65, 0x72, 0x72, 0x6f, 0x72, @@ -224,15 +224,15 @@ func file_gateway_internal_errors_proto_rawDescGZIP() []byte { var file_gateway_internal_errors_proto_msgTypes = make([]protoimpl.MessageInfo, 2) var file_gateway_internal_errors_proto_goTypes = []interface{}{ - (*Error)(nil), // 0: grpc.gateway.runtime.Error - (*StreamError)(nil), // 1: grpc.gateway.runtime.StreamError + (*Error)(nil), // 0: ease.gateway.runtime.Error + (*StreamError)(nil), // 1: ease.gateway.runtime.StreamError (*frontend.Error)(nil), // 2: frontend.Error (*any.Any)(nil), // 3: google.protobuf.Any } var file_gateway_internal_errors_proto_depIdxs = []int32{ - 2, // 0: grpc.gateway.runtime.Error.error:type_name -> frontend.Error - 3, // 1: grpc.gateway.runtime.Error.details:type_name -> google.protobuf.Any - 3, // 2: grpc.gateway.runtime.StreamError.details:type_name -> google.protobuf.Any + 2, // 0: ease.gateway.runtime.Error.error:type_name -> frontend.Error + 3, // 1: ease.gateway.runtime.Error.details:type_name -> google.protobuf.Any + 3, // 2: ease.gateway.runtime.StreamError.details:type_name -> google.protobuf.Any 3, // [3:3] is the sub-list for method output_type 3, // [3:3] is the sub-list for method input_type 3, // [3:3] is the sub-list for extension type_name From b78b31751c59a9321b8b78291f7cccee11c346dc Mon Sep 17 00:00:00 2001 From: chenbin1314 Date: Sun, 12 Jul 2020 07:23:29 +0800 Subject: [PATCH 14/56] FIX: when verifyHeader failed, http: panic serving [::1]:60382: runtime error: invalid memory address or nil pointer dereference --- gateway/README.md | 4 +- gateway/internal/errors.pb.go | 353 +++++++----------- .../internal/gengateway/template.go | 4 +- 3 files changed, 131 insertions(+), 230 deletions(-) mode change 100755 => 100644 gateway/internal/errors.pb.go diff --git a/gateway/README.md b/gateway/README.md index 84b17d1..dc093f8 100644 --- a/gateway/README.md +++ b/gateway/README.md @@ -136,7 +136,7 @@ Link [grpc-ecosystem/grpc-gateway/runtime](https://github.com/grpc-ecosystem/g ## Upgrade issues -#### 输出error.code 为字符串 +### 输出error.code 为字符串 ``` { @@ -150,7 +150,9 @@ Link [grpc-ecosystem/grpc-gateway/runtime](https://github.com/grpc-ecosystem/g "message": "{\"code\":100006,\"params\":[\"Validation error\"]}" } ``` + > 升级之后response body中 error.code为字符串, 期望是Integer + ``` { "error": { diff --git a/gateway/internal/errors.pb.go b/gateway/internal/errors.pb.go old mode 100755 new mode 100644 index 8c7706b..e53f387 --- a/gateway/internal/errors.pb.go +++ b/gateway/internal/errors.pb.go @@ -1,292 +1,191 @@ // Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.22.0 -// protoc v3.9.0 -// source: gateway/internal/errors.proto +// source: internal/errors.proto package internal import ( + fmt "fmt" + math "math" + frontend "github.com/binchencoder/gateway-proto/frontend" proto "github.com/golang/protobuf/proto" any "github.com/golang/protobuf/ptypes/any" - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - reflect "reflect" - sync "sync" ) -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) +// 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 that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 +// 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.ProtoPackageIsVersion3 // please upgrade the proto package +// Error is the generic error returned from unary RPCs. type Error struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Error *frontend.Error `protobuf:"bytes,1,opt,name=error,proto3" json:"error,omitempty"` - Code int32 `protobuf:"varint,2,opt,name=code,proto3" json:"code,omitempty"` - Message string `protobuf:"bytes,3,opt,name=message,proto3" json:"message,omitempty"` - Details []*any.Any `protobuf:"bytes,4,rep,name=details,proto3" json:"details,omitempty"` + Error *frontend.Error `protobuf:"bytes,1,opt,name=error,proto3" json:"error,omitempty"` + // This is to make the error more compatible with users that expect errors to be Status objects: + // https://github.com/grpc/grpc/blob/master/src/proto/grpc/status/status.proto + // It should be the exact same message as the Error field. + Code int32 `protobuf:"varint,2,opt,name=code,proto3" json:"code,omitempty"` + Message string `protobuf:"bytes,3,opt,name=message,proto3" json:"message,omitempty"` + Details []*any.Any `protobuf:"bytes,4,rep,name=details,proto3" json:"details,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Error) Reset() { *m = Error{} } +func (m *Error) String() string { return proto.CompactTextString(m) } +func (*Error) ProtoMessage() {} +func (*Error) Descriptor() ([]byte, []int) { + return fileDescriptor_9b093362ca6d1e03, []int{0} } -func (x *Error) Reset() { - *x = Error{} - if protoimpl.UnsafeEnabled { - mi := &file_gateway_internal_errors_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } +func (m *Error) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Error.Unmarshal(m, b) } - -func (x *Error) String() string { - return protoimpl.X.MessageStringOf(x) +func (m *Error) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Error.Marshal(b, m, deterministic) } - -func (*Error) ProtoMessage() {} - -func (x *Error) ProtoReflect() protoreflect.Message { - mi := &file_gateway_internal_errors_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) +func (m *Error) XXX_Merge(src proto.Message) { + xxx_messageInfo_Error.Merge(m, src) } - -// Deprecated: Use Error.ProtoReflect.Descriptor instead. -func (*Error) Descriptor() ([]byte, []int) { - return file_gateway_internal_errors_proto_rawDescGZIP(), []int{0} +func (m *Error) XXX_Size() int { + return xxx_messageInfo_Error.Size(m) +} +func (m *Error) XXX_DiscardUnknown() { + xxx_messageInfo_Error.DiscardUnknown(m) } -func (x *Error) GetError() *frontend.Error { - if x != nil { - return x.Error +var xxx_messageInfo_Error proto.InternalMessageInfo + +func (m *Error) GetError() *frontend.Error { + if m != nil { + return m.Error } return nil } -func (x *Error) GetCode() int32 { - if x != nil { - return x.Code +func (m *Error) GetCode() int32 { + if m != nil { + return m.Code } return 0 } -func (x *Error) GetMessage() string { - if x != nil { - return x.Message +func (m *Error) GetMessage() string { + if m != nil { + return m.Message } return "" } -func (x *Error) GetDetails() []*any.Any { - if x != nil { - return x.Details +func (m *Error) GetDetails() []*any.Any { + if m != nil { + return m.Details } return nil } +// StreamError is a response type which is returned when +// streaming rpc returns an error. type StreamError struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - GrpcCode int32 `protobuf:"varint,1,opt,name=grpc_code,json=grpcCode,proto3" json:"grpc_code,omitempty"` - HttpCode int32 `protobuf:"varint,2,opt,name=http_code,json=httpCode,proto3" json:"http_code,omitempty"` - Message string `protobuf:"bytes,3,opt,name=message,proto3" json:"message,omitempty"` - HttpStatus string `protobuf:"bytes,4,opt,name=http_status,json=httpStatus,proto3" json:"http_status,omitempty"` - Details []*any.Any `protobuf:"bytes,5,rep,name=details,proto3" json:"details,omitempty"` + GrpcCode int32 `protobuf:"varint,1,opt,name=grpc_code,json=grpcCode,proto3" json:"grpc_code,omitempty"` + HttpCode int32 `protobuf:"varint,2,opt,name=http_code,json=httpCode,proto3" json:"http_code,omitempty"` + Message string `protobuf:"bytes,3,opt,name=message,proto3" json:"message,omitempty"` + HttpStatus string `protobuf:"bytes,4,opt,name=http_status,json=httpStatus,proto3" json:"http_status,omitempty"` + Details []*any.Any `protobuf:"bytes,5,rep,name=details,proto3" json:"details,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StreamError) Reset() { *m = StreamError{} } +func (m *StreamError) String() string { return proto.CompactTextString(m) } +func (*StreamError) ProtoMessage() {} +func (*StreamError) Descriptor() ([]byte, []int) { + return fileDescriptor_9b093362ca6d1e03, []int{1} } -func (x *StreamError) Reset() { - *x = StreamError{} - if protoimpl.UnsafeEnabled { - mi := &file_gateway_internal_errors_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } +func (m *StreamError) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_StreamError.Unmarshal(m, b) } - -func (x *StreamError) String() string { - return protoimpl.X.MessageStringOf(x) +func (m *StreamError) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_StreamError.Marshal(b, m, deterministic) } - -func (*StreamError) ProtoMessage() {} - -func (x *StreamError) ProtoReflect() protoreflect.Message { - mi := &file_gateway_internal_errors_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) +func (m *StreamError) XXX_Merge(src proto.Message) { + xxx_messageInfo_StreamError.Merge(m, src) } - -// Deprecated: Use StreamError.ProtoReflect.Descriptor instead. -func (*StreamError) Descriptor() ([]byte, []int) { - return file_gateway_internal_errors_proto_rawDescGZIP(), []int{1} +func (m *StreamError) XXX_Size() int { + return xxx_messageInfo_StreamError.Size(m) +} +func (m *StreamError) XXX_DiscardUnknown() { + xxx_messageInfo_StreamError.DiscardUnknown(m) } -func (x *StreamError) GetGrpcCode() int32 { - if x != nil { - return x.GrpcCode +var xxx_messageInfo_StreamError proto.InternalMessageInfo + +func (m *StreamError) GetGrpcCode() int32 { + if m != nil { + return m.GrpcCode } return 0 } -func (x *StreamError) GetHttpCode() int32 { - if x != nil { - return x.HttpCode +func (m *StreamError) GetHttpCode() int32 { + if m != nil { + return m.HttpCode } return 0 } -func (x *StreamError) GetMessage() string { - if x != nil { - return x.Message +func (m *StreamError) GetMessage() string { + if m != nil { + return m.Message } return "" } -func (x *StreamError) GetHttpStatus() string { - if x != nil { - return x.HttpStatus +func (m *StreamError) GetHttpStatus() string { + if m != nil { + return m.HttpStatus } return "" } -func (x *StreamError) GetDetails() []*any.Any { - if x != nil { - return x.Details +func (m *StreamError) GetDetails() []*any.Any { + if m != nil { + return m.Details } return nil } -var File_gateway_internal_errors_proto protoreflect.FileDescriptor - -var file_gateway_internal_errors_proto_rawDesc = []byte{ - 0x0a, 0x1d, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, - 0x61, 0x6c, 0x2f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, - 0x14, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, - 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x1a, 0x14, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x2f, 0x65, 0x72, 0x72, 0x6f, 0x72, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x8c, 0x01, 0x0a, 0x05, 0x45, 0x72, 0x72, 0x6f, 0x72, - 0x12, 0x25, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x0f, 0x2e, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, - 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2e, 0x0a, 0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, - 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x07, 0x64, 0x65, - 0x74, 0x61, 0x69, 0x6c, 0x73, 0x22, 0xb2, 0x01, 0x0a, 0x0b, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, - 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x67, 0x72, 0x70, 0x63, 0x5f, 0x63, 0x6f, - 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x67, 0x72, 0x70, 0x63, 0x43, 0x6f, - 0x64, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x68, 0x74, 0x74, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x12, - 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x68, 0x74, 0x74, - 0x70, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, - 0x68, 0x74, 0x74, 0x70, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x2e, 0x0a, 0x07, 0x64, 0x65, - 0x74, 0x61, 0x69, 0x6c, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, - 0x79, 0x52, 0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x42, 0x0a, 0x5a, 0x08, 0x69, 0x6e, - 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} - -var ( - file_gateway_internal_errors_proto_rawDescOnce sync.Once - file_gateway_internal_errors_proto_rawDescData = file_gateway_internal_errors_proto_rawDesc -) - -func file_gateway_internal_errors_proto_rawDescGZIP() []byte { - file_gateway_internal_errors_proto_rawDescOnce.Do(func() { - file_gateway_internal_errors_proto_rawDescData = protoimpl.X.CompressGZIP(file_gateway_internal_errors_proto_rawDescData) - }) - return file_gateway_internal_errors_proto_rawDescData -} - -var file_gateway_internal_errors_proto_msgTypes = make([]protoimpl.MessageInfo, 2) -var file_gateway_internal_errors_proto_goTypes = []interface{}{ - (*Error)(nil), // 0: ease.gateway.runtime.Error - (*StreamError)(nil), // 1: ease.gateway.runtime.StreamError - (*frontend.Error)(nil), // 2: frontend.Error - (*any.Any)(nil), // 3: google.protobuf.Any -} -var file_gateway_internal_errors_proto_depIdxs = []int32{ - 2, // 0: ease.gateway.runtime.Error.error:type_name -> frontend.Error - 3, // 1: ease.gateway.runtime.Error.details:type_name -> google.protobuf.Any - 3, // 2: ease.gateway.runtime.StreamError.details:type_name -> google.protobuf.Any - 3, // [3:3] is the sub-list for method output_type - 3, // [3:3] is the sub-list for method input_type - 3, // [3:3] is the sub-list for extension type_name - 3, // [3:3] is the sub-list for extension extendee - 0, // [0:3] is the sub-list for field type_name -} - -func init() { file_gateway_internal_errors_proto_init() } -func file_gateway_internal_errors_proto_init() { - if File_gateway_internal_errors_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_gateway_internal_errors_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Error); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_gateway_internal_errors_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StreamError); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_gateway_internal_errors_proto_rawDesc, - NumEnums: 0, - NumMessages: 2, - NumExtensions: 0, - NumServices: 0, - }, - GoTypes: file_gateway_internal_errors_proto_goTypes, - DependencyIndexes: file_gateway_internal_errors_proto_depIdxs, - MessageInfos: file_gateway_internal_errors_proto_msgTypes, - }.Build() - File_gateway_internal_errors_proto = out.File - file_gateway_internal_errors_proto_rawDesc = nil - file_gateway_internal_errors_proto_goTypes = nil - file_gateway_internal_errors_proto_depIdxs = nil +func init() { + proto.RegisterType((*Error)(nil), "grpc.gateway.runtime.Error") + proto.RegisterType((*StreamError)(nil), "grpc.gateway.runtime.StreamError") +} + +func init() { proto.RegisterFile("internal/errors.proto", fileDescriptor_9b093362ca6d1e03) } + +var fileDescriptor_9b093362ca6d1e03 = []byte{ + // 252 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x90, 0xc1, 0x4a, 0xc4, 0x30, + 0x10, 0x86, 0x89, 0xbb, 0x75, 0xdb, 0xe9, 0x2d, 0x54, 0x88, 0xee, 0xc1, 0xb2, 0xa7, 0x9e, 0x52, + 0xd0, 0x27, 0xd0, 0xc5, 0x17, 0xe8, 0xde, 0xbc, 0x2c, 0xd9, 0xdd, 0x31, 0x16, 0xda, 0xa4, 0x24, + 0x53, 0xa4, 0xf8, 0x56, 0x3e, 0xa1, 0x24, 0xa5, 0xb0, 0x27, 0xf1, 0xd6, 0xf9, 0xfb, 0xcf, 0x7c, + 0x1f, 0x81, 0xbb, 0xd6, 0x10, 0x3a, 0xa3, 0xba, 0x1a, 0x9d, 0xb3, 0xce, 0xcb, 0xc1, 0x59, 0xb2, + 0xbc, 0xd0, 0x6e, 0x38, 0x4b, 0xad, 0x08, 0xbf, 0xd4, 0x24, 0xdd, 0x68, 0xa8, 0xed, 0xf1, 0xe1, + 0x5e, 0x5b, 0xab, 0x3b, 0xac, 0x63, 0xe7, 0x34, 0x7e, 0xd4, 0xca, 0x4c, 0xf3, 0xc2, 0xee, 0x1b, + 0x92, 0xb7, 0x70, 0x80, 0x17, 0x90, 0xc4, 0x4b, 0x82, 0x95, 0xac, 0xca, 0x9a, 0x79, 0xe0, 0x1c, + 0xd6, 0x67, 0x7b, 0x41, 0x71, 0x53, 0xb2, 0x2a, 0x69, 0xe2, 0x37, 0x17, 0xb0, 0xe9, 0xd1, 0x7b, + 0xa5, 0x51, 0xac, 0x62, 0x77, 0x19, 0xb9, 0x84, 0xcd, 0x05, 0x49, 0xb5, 0x9d, 0x17, 0xeb, 0x72, + 0x55, 0xe5, 0x4f, 0x85, 0x9c, 0xc9, 0x72, 0x21, 0xcb, 0x17, 0x33, 0x35, 0x4b, 0x69, 0xf7, 0xc3, + 0x20, 0x3f, 0x90, 0x43, 0xd5, 0xcf, 0x0e, 0x5b, 0xc8, 0x82, 0xff, 0x31, 0x22, 0x59, 0x44, 0xa6, + 0x21, 0xd8, 0x07, 0xec, 0x16, 0xb2, 0x4f, 0xa2, 0xe1, 0x78, 0xe5, 0x93, 0x86, 0x60, 0xff, 0xb7, + 0xd3, 0x23, 0xe4, 0x71, 0xcd, 0x93, 0xa2, 0x31, 0x78, 0x85, 0xbf, 0x10, 0xa2, 0x43, 0x4c, 0xae, + 0xa5, 0x93, 0x7f, 0x48, 0xbf, 0xc2, 0x7b, 0xba, 0xbc, 0xfd, 0xe9, 0x36, 0x56, 0x9e, 0x7f, 0x03, + 0x00, 0x00, 0xff, 0xff, 0xde, 0x72, 0x6b, 0x83, 0x8e, 0x01, 0x00, 0x00, } diff --git a/gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go b/gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go index 7c24e5b..1a5edad 100644 --- a/gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go +++ b/gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go @@ -905,10 +905,11 @@ func Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}Client(ctx context.Context, return } + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) ctx, err := runtime.RequestAccepted(inctx, internal_{{$svc.GetName}}_{{$svc.ServiceId}}_spec, "{{$svc.GetName}}", "{{$m.GetName}}", w, req) if err != nil { grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) - runtime.HTTPError(ctx, nil, &runtime.JSONBuiltin{}, w, req, err) + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } @@ -918,7 +919,6 @@ func Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}Client(ctx context.Context, 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) From 5ef40b8641552d6555d5586fcd15128324332426 Mon Sep 17 00:00:00 2001 From: chenbin1314 Date: Sun, 12 Jul 2020 11:18:56 +0800 Subject: [PATCH 15/56] Resolve panic: can't resolve swagger ref from typename '.frontend.Error', rebuild proto *.pb.gw.go --- examples/proto/echo_service.pb.gw.go | 28 ++--- examples/proto/echo_service.swagger.json | 149 +++++++++++++++++++++++ gateway/internal/errors.proto | 2 +- httpoptions/BUILD.bazel | 3 + httpoptions/annotations.proto | 1 + proto/examples/echo_service.pb.gw.go | 28 ++--- proto/examples/echo_service.swagger.json | 149 +++++++++++++++++++++++ 7 files changed, 331 insertions(+), 29 deletions(-) diff --git a/examples/proto/echo_service.pb.gw.go b/examples/proto/echo_service.pb.gw.go index 0a340a2..b55bcff 100755 --- a/examples/proto/echo_service.pb.gw.go +++ b/examples/proto/echo_service.pb.gw.go @@ -918,15 +918,15 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux return } + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) if err != nil { grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) - runtime.HTTPError(ctx, nil, &runtime.JSONBuiltin{}, w, req, err) + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } ctx, cancel := context.WithCancel(req.Context()) 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) @@ -954,15 +954,15 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux return } + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) if err != nil { grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) - runtime.HTTPError(ctx, nil, &runtime.JSONBuiltin{}, w, req, err) + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } ctx, cancel := context.WithCancel(req.Context()) 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) @@ -990,15 +990,15 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux return } + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) if err != nil { grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) - runtime.HTTPError(ctx, nil, &runtime.JSONBuiltin{}, w, req, err) + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } ctx, cancel := context.WithCancel(req.Context()) 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) @@ -1026,15 +1026,15 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux return } + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) if err != nil { grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) - runtime.HTTPError(ctx, nil, &runtime.JSONBuiltin{}, w, req, err) + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } ctx, cancel := context.WithCancel(req.Context()) 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) @@ -1062,15 +1062,15 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux return } + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) if err != nil { grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) - runtime.HTTPError(ctx, nil, &runtime.JSONBuiltin{}, w, req, err) + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } ctx, cancel := context.WithCancel(req.Context()) 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) @@ -1098,15 +1098,15 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux return } + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "EchoBody", w, req) if err != nil { grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) - runtime.HTTPError(ctx, nil, &runtime.JSONBuiltin{}, w, req, err) + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } ctx, cancel := context.WithCancel(req.Context()) 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) @@ -1134,15 +1134,15 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux return } + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "EchoDelete", w, req) if err != nil { grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) - runtime.HTTPError(ctx, nil, &runtime.JSONBuiltin{}, w, req, err) + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } ctx, cancel := context.WithCancel(req.Context()) 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) diff --git a/examples/proto/echo_service.swagger.json b/examples/proto/echo_service.swagger.json index 31a4aec..6f9442f 100755 --- a/examples/proto/echo_service.swagger.json +++ b/examples/proto/echo_service.swagger.json @@ -23,6 +23,12 @@ "schema": { "$ref": "#/definitions/protoSimpleMessage" } + }, + "default": { + "description": "An unexpected error response", + "schema": { + "$ref": "#/definitions/gatewayruntimeError" + } } }, "parameters": [ @@ -50,6 +56,12 @@ "schema": { "$ref": "#/definitions/protoSimpleMessage" } + }, + "default": { + "description": "An unexpected error response", + "schema": { + "$ref": "#/definitions/gatewayruntimeError" + } } }, "parameters": [ @@ -130,6 +142,12 @@ "schema": { "$ref": "#/definitions/protoSimpleMessage" } + }, + "default": { + "description": "An unexpected error response", + "schema": { + "$ref": "#/definitions/gatewayruntimeError" + } } }, "parameters": [ @@ -210,6 +228,12 @@ "schema": { "$ref": "#/definitions/protoSimpleMessage" } + }, + "default": { + "description": "An unexpected error response", + "schema": { + "$ref": "#/definitions/gatewayruntimeError" + } } }, "parameters": [ @@ -284,6 +308,12 @@ "schema": { "$ref": "#/definitions/protoSimpleMessage" } + }, + "default": { + "description": "An unexpected error response", + "schema": { + "$ref": "#/definitions/gatewayruntimeError" + } } }, "parameters": [ @@ -357,6 +387,12 @@ "schema": { "$ref": "#/definitions/protoSimpleMessage" } + }, + "default": { + "description": "An unexpected error response", + "schema": { + "$ref": "#/definitions/gatewayruntimeError" + } } }, "parameters": [ @@ -384,6 +420,12 @@ "schema": { "$ref": "#/definitions/protoSimpleMessage" } + }, + "default": { + "description": "An unexpected error response", + "schema": { + "$ref": "#/definitions/gatewayruntimeError" + } } }, "parameters": [ @@ -455,6 +497,101 @@ } }, "definitions": { + "frontendError": { + "type": "object", + "properties": { + "code": { + "$ref": "#/definitions/frontendErrorCode", + "description": "The general error code." + }, + "params": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The general parameters with which to render a localized string." + }, + "debug": { + "type": "string", + "description": "The debug information. Only populated in DEV, TEST, and QA environment.\nIn PROD environment it will be stripped off before returning to the\nclient." + }, + "details": { + "type": "array", + "items": { + "$ref": "#/definitions/frontendErrorMessage" + }, + "description": "The detailed error messages." + } + }, + "description": "message GetMyMemosResponse {\n frontend.Error error = 1;\n\n int32 current_page = 2;\n int32 page_total = 3;\n string continue_token = 4;\n\n repeated MemoMsg memos = 5;\n }", + "title": "The error wrapper message. All frontend messages should contain exactly\none field with this message as the first field. Example:" + }, + "frontendErrorCode": { + "type": "string", + "enum": [ + "NONE", + "SERVICE_DOWN", + "SERVICE_INTERNAL_ERROR", + "SERVICE_INTERNAL_ACCIDENTAL_ERROR", + "SERVICE_BAD_PARAM_ERROR", + "SERVICE_UNREACHABLE_CODE", + "UNDEFINED", + "BADPARAM_ERROR", + "RESOURCE_NOT_FOUND", + "BAD_REQUEST", + "AUTHEN_ERROR", + "SERVER_ERROR", + "NORIGHT_ERROR", + "NODATA_ERROR", + "USER_ERROR", + "INVALID_SIGNATURE", + "IGOAL_DUPLICATE_TAG", + "IGOAL_NO_ONLINE_TMPL_MANAGE_PERMISSION", + "IGOAL_IMPORT_TEMPLATE_FILE_SIZE_EXCEEDED", + "IGOAL_VERSION_CONFLICT_ERROR", + "IGOAL_DOC_UPLOAD_FILE_NUMBER_EXCEEDED" + ], + "default": "NONE", + "description": "/### Enum for all error codes.\n/### Localization Guide for error codes. Error code which requires Localization\n/### need to provide a //@Trans chinese comment on the above line.\n\n - SERVICE_DOWN: /### 100000 - 120000 Common error\n@Trans 当前服务正在维护,请稍后再试.\n - SERVICE_INTERNAL_ERROR: @Trans 当前服务内部错误,请稍后再试.\n - SERVICE_INTERNAL_ACCIDENTAL_ERROR: @Trans 找不到意中的“它”,请稍后重试!\n - SERVICE_BAD_PARAM_ERROR: @Trans 程序参数错误.\n - SERVICE_UNREACHABLE_CODE: @Trans 程序编码错误.\n - UNDEFINED: @Trans Undefined error.\n - BADPARAM_ERROR: @Trans 参数不合法\n - RESOURCE_NOT_FOUND: @Trans 无法找到\n - BAD_REQUEST: @Trans 无效请求\n - AUTHEN_ERROR: /### 500500-500999: Common error codes.\n@Trans 用户认证失败,需重新登录\n - SERVER_ERROR: @Trans 服务器端错误\n - NORIGHT_ERROR: @Trans 权限不足\n - NODATA_ERROR: @Trans 数据不存在或已删除\n - USER_ERROR: @Trans 用户不存在或已停用\n - INVALID_SIGNATURE: @Trans 无效验签\n - IGOAL_DUPLICATE_TAG: @Trans 主线分类名称重复!\n - IGOAL_NO_ONLINE_TMPL_MANAGE_PERMISSION: @Trans 您无权限进行此操作!\n - IGOAL_IMPORT_TEMPLATE_FILE_SIZE_EXCEEDED: @Trans 模板文件大小超限!\n - IGOAL_VERSION_CONFLICT_ERROR: @Trans 系统开小差了,请稍后尝试!\n - IGOAL_DOC_UPLOAD_FILE_NUMBER_EXCEEDED: @Trans 上传文件数量超过上限!" + }, + "frontendErrorMessage": { + "type": "object", + "properties": { + "code": { + "$ref": "#/definitions/frontendErrorCode", + "description": "The error code." + }, + "params": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The parameters used to render a localized string." + } + }, + "description": "An error message including its error code and the parameters to render\na localized string." + }, + "gatewayruntimeError": { + "type": "object", + "properties": { + "error": { + "$ref": "#/definitions/frontendError" + }, + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "$ref": "#/definitions/protobufAny" + } + } + } + }, "protoEmbedded": { "type": "object", "properties": { @@ -498,6 +635,18 @@ } }, "description": "SimpleMessage represents a simple message sent to the Echo service." + }, + "protobufAny": { + "type": "object", + "properties": { + "type_url": { + "type": "string" + }, + "value": { + "type": "string", + "format": "byte" + } + } } } } diff --git a/gateway/internal/errors.proto b/gateway/internal/errors.proto index 64f81d2..b0a0022 100644 --- a/gateway/internal/errors.proto +++ b/gateway/internal/errors.proto @@ -1,5 +1,5 @@ syntax = "proto3"; -package ease.gateway.runtime; +package grpc.gateway.runtime; option go_package = "internal"; import "google/protobuf/any.proto"; diff --git a/httpoptions/BUILD.bazel b/httpoptions/BUILD.bazel index 9e28937..0bd1eba 100644 --- a/httpoptions/BUILD.bazel +++ b/httpoptions/BUILD.bazel @@ -27,6 +27,7 @@ proto_library( "@com_google_protobuf//:any_proto", "@com_google_protobuf//:descriptor_proto", "@com_github_binchencoder_gateway_proto//data:data_proto", + "@com_github_binchencoder_gateway_proto//frontend:error_proto", ], ) @@ -37,6 +38,7 @@ go_proto_library( proto = ":ease_api_proto", deps = [ "@com_github_binchencoder_gateway_proto//data:go_default_library", + "@com_github_binchencoder_gateway_proto//frontend:go_default_library", ], ) @@ -48,6 +50,7 @@ proto_library( ], deps = [ "@com_github_binchencoder_gateway_proto//data:data_proto", + "@com_github_binchencoder_gateway_proto//frontend:error_proto", "@com_google_protobuf//:descriptor_proto", ], ) diff --git a/httpoptions/annotations.proto b/httpoptions/annotations.proto index 1842ee6..873f98d 100644 --- a/httpoptions/annotations.proto +++ b/httpoptions/annotations.proto @@ -19,6 +19,7 @@ package ease.api; import "google/protobuf/descriptor.proto"; import "httpoptions/http.proto"; import "data/data.proto"; +import "frontend/error.proto"; option java_multiple_files = true; option java_outer_classname = "AnnotationsProto"; diff --git a/proto/examples/echo_service.pb.gw.go b/proto/examples/echo_service.pb.gw.go index 512d4d4..349464c 100755 --- a/proto/examples/echo_service.pb.gw.go +++ b/proto/examples/echo_service.pb.gw.go @@ -1015,15 +1015,15 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux return } + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) if err != nil { grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) - runtime.HTTPError(ctx, nil, &runtime.JSONBuiltin{}, w, req, err) + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } ctx, cancel := context.WithCancel(req.Context()) 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) @@ -1051,15 +1051,15 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux return } + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) if err != nil { grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) - runtime.HTTPError(ctx, nil, &runtime.JSONBuiltin{}, w, req, err) + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } ctx, cancel := context.WithCancel(req.Context()) 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) @@ -1087,15 +1087,15 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux return } + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) if err != nil { grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) - runtime.HTTPError(ctx, nil, &runtime.JSONBuiltin{}, w, req, err) + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } ctx, cancel := context.WithCancel(req.Context()) 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) @@ -1123,15 +1123,15 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux return } + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) if err != nil { grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) - runtime.HTTPError(ctx, nil, &runtime.JSONBuiltin{}, w, req, err) + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } ctx, cancel := context.WithCancel(req.Context()) 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) @@ -1159,15 +1159,15 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux return } + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) if err != nil { grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) - runtime.HTTPError(ctx, nil, &runtime.JSONBuiltin{}, w, req, err) + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } ctx, cancel := context.WithCancel(req.Context()) 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) @@ -1195,15 +1195,15 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux return } + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "EchoBody", w, req) if err != nil { grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) - runtime.HTTPError(ctx, nil, &runtime.JSONBuiltin{}, w, req, err) + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } ctx, cancel := context.WithCancel(req.Context()) 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) @@ -1231,15 +1231,15 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux return } + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "EchoDelete", w, req) if err != nil { grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) - runtime.HTTPError(ctx, nil, &runtime.JSONBuiltin{}, w, req, err) + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } ctx, cancel := context.WithCancel(req.Context()) 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) diff --git a/proto/examples/echo_service.swagger.json b/proto/examples/echo_service.swagger.json index 07533ba..4df8d71 100755 --- a/proto/examples/echo_service.swagger.json +++ b/proto/examples/echo_service.swagger.json @@ -23,6 +23,12 @@ "schema": { "$ref": "#/definitions/examplesSimpleMessage" } + }, + "default": { + "description": "An unexpected error response", + "schema": { + "$ref": "#/definitions/gatewayruntimeError" + } } }, "parameters": [ @@ -50,6 +56,12 @@ "schema": { "$ref": "#/definitions/examplesSimpleMessage" } + }, + "default": { + "description": "An unexpected error response", + "schema": { + "$ref": "#/definitions/gatewayruntimeError" + } } }, "parameters": [ @@ -130,6 +142,12 @@ "schema": { "$ref": "#/definitions/examplesSimpleMessage" } + }, + "default": { + "description": "An unexpected error response", + "schema": { + "$ref": "#/definitions/gatewayruntimeError" + } } }, "parameters": [ @@ -210,6 +228,12 @@ "schema": { "$ref": "#/definitions/examplesSimpleMessage" } + }, + "default": { + "description": "An unexpected error response", + "schema": { + "$ref": "#/definitions/gatewayruntimeError" + } } }, "parameters": [ @@ -284,6 +308,12 @@ "schema": { "$ref": "#/definitions/examplesSimpleMessage" } + }, + "default": { + "description": "An unexpected error response", + "schema": { + "$ref": "#/definitions/gatewayruntimeError" + } } }, "parameters": [ @@ -357,6 +387,12 @@ "schema": { "$ref": "#/definitions/examplesSimpleMessage" } + }, + "default": { + "description": "An unexpected error response", + "schema": { + "$ref": "#/definitions/gatewayruntimeError" + } } }, "parameters": [ @@ -384,6 +420,12 @@ "schema": { "$ref": "#/definitions/examplesSimpleMessage" } + }, + "default": { + "description": "An unexpected error response", + "schema": { + "$ref": "#/definitions/gatewayruntimeError" + } } }, "parameters": [ @@ -523,6 +565,113 @@ } }, "description": "SimpleMessage represents a simple message sent to the Echo service." + }, + "frontendError": { + "type": "object", + "properties": { + "code": { + "$ref": "#/definitions/frontendErrorCode", + "description": "The general error code." + }, + "params": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The general parameters with which to render a localized string." + }, + "debug": { + "type": "string", + "description": "The debug information. Only populated in DEV, TEST, and QA environment.\nIn PROD environment it will be stripped off before returning to the\nclient." + }, + "details": { + "type": "array", + "items": { + "$ref": "#/definitions/frontendErrorMessage" + }, + "description": "The detailed error messages." + } + }, + "description": "message GetMyMemosResponse {\n frontend.Error error = 1;\n\n int32 current_page = 2;\n int32 page_total = 3;\n string continue_token = 4;\n\n repeated MemoMsg memos = 5;\n }", + "title": "The error wrapper message. All frontend messages should contain exactly\none field with this message as the first field. Example:" + }, + "frontendErrorCode": { + "type": "string", + "enum": [ + "NONE", + "SERVICE_DOWN", + "SERVICE_INTERNAL_ERROR", + "SERVICE_INTERNAL_ACCIDENTAL_ERROR", + "SERVICE_BAD_PARAM_ERROR", + "SERVICE_UNREACHABLE_CODE", + "UNDEFINED", + "BADPARAM_ERROR", + "RESOURCE_NOT_FOUND", + "BAD_REQUEST", + "AUTHEN_ERROR", + "SERVER_ERROR", + "NORIGHT_ERROR", + "NODATA_ERROR", + "USER_ERROR", + "INVALID_SIGNATURE", + "IGOAL_DUPLICATE_TAG", + "IGOAL_NO_ONLINE_TMPL_MANAGE_PERMISSION", + "IGOAL_IMPORT_TEMPLATE_FILE_SIZE_EXCEEDED", + "IGOAL_VERSION_CONFLICT_ERROR", + "IGOAL_DOC_UPLOAD_FILE_NUMBER_EXCEEDED" + ], + "default": "NONE", + "description": "/### Enum for all error codes.\n/### Localization Guide for error codes. Error code which requires Localization\n/### need to provide a //@Trans chinese comment on the above line.\n\n - SERVICE_DOWN: /### 100000 - 120000 Common error\n@Trans 当前服务正在维护,请稍后再试.\n - SERVICE_INTERNAL_ERROR: @Trans 当前服务内部错误,请稍后再试.\n - SERVICE_INTERNAL_ACCIDENTAL_ERROR: @Trans 找不到意中的“它”,请稍后重试!\n - SERVICE_BAD_PARAM_ERROR: @Trans 程序参数错误.\n - SERVICE_UNREACHABLE_CODE: @Trans 程序编码错误.\n - UNDEFINED: @Trans Undefined error.\n - BADPARAM_ERROR: @Trans 参数不合法\n - RESOURCE_NOT_FOUND: @Trans 无法找到\n - BAD_REQUEST: @Trans 无效请求\n - AUTHEN_ERROR: /### 500500-500999: Common error codes.\n@Trans 用户认证失败,需重新登录\n - SERVER_ERROR: @Trans 服务器端错误\n - NORIGHT_ERROR: @Trans 权限不足\n - NODATA_ERROR: @Trans 数据不存在或已删除\n - USER_ERROR: @Trans 用户不存在或已停用\n - INVALID_SIGNATURE: @Trans 无效验签\n - IGOAL_DUPLICATE_TAG: @Trans 主线分类名称重复!\n - IGOAL_NO_ONLINE_TMPL_MANAGE_PERMISSION: @Trans 您无权限进行此操作!\n - IGOAL_IMPORT_TEMPLATE_FILE_SIZE_EXCEEDED: @Trans 模板文件大小超限!\n - IGOAL_VERSION_CONFLICT_ERROR: @Trans 系统开小差了,请稍后尝试!\n - IGOAL_DOC_UPLOAD_FILE_NUMBER_EXCEEDED: @Trans 上传文件数量超过上限!" + }, + "frontendErrorMessage": { + "type": "object", + "properties": { + "code": { + "$ref": "#/definitions/frontendErrorCode", + "description": "The error code." + }, + "params": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The parameters used to render a localized string." + } + }, + "description": "An error message including its error code and the parameters to render\na localized string." + }, + "gatewayruntimeError": { + "type": "object", + "properties": { + "error": { + "$ref": "#/definitions/frontendError" + }, + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "$ref": "#/definitions/protobufAny" + } + } + } + }, + "protobufAny": { + "type": "object", + "properties": { + "type_url": { + "type": "string" + }, + "value": { + "type": "string", + "format": "byte" + } + } } } } From 92a6426597250000aa982af8e20b1fe7420d36fa Mon Sep 17 00:00:00 2001 From: chenbin1314 Date: Sun, 12 Jul 2020 11:49:55 +0800 Subject: [PATCH 16/56] Update: examples/README.md --- examples/README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/README.md b/examples/README.md index 90edd8b..d46322b 100644 --- a/examples/README.md +++ b/examples/README.md @@ -18,27 +18,27 @@ bazel build ease-gateway/examples/cmd/example-grpc-server/... start gateway server ``` -ease-gateway/bazel-bin/examples/cmd/example-gateway-server/linux_amd64_stripped/example-gateway-server -skylb-endpoints="127.0.0.1:1900" -debug-svc-endpoint=custom-ease-gateway-test=localhost:9090 +ease-gateway/bazel-bin/examples/cmd/example-gateway-server/example-gateway-server_/example-gateway-server -skylb-endpoints="127.0.0.1:1900" -debug-svc-endpoint=custom-ease-gateway-test=localhost:9090 ``` start custom-gateway server ``` -ease-gateway/bazel-bin/cmd/custom-gateway/linux_amd64_stripped/custom-ease-gateway -skylb-endpoints="127.0.0.1:1900" -debug-service=custom-ease-gateway-test -debug-svc-endpoint=custom-ease-gateway-test=localhost:9090 +ease-gateway/bazel-bin/cmd/custom-gateway/custom-ease-gateway_/custom-ease-gateway -skylb-endpoints="127.0.0.1:1900" -debug-service=custom-ease-gateway-test -debug-svc-endpoint=custom-ease-gateway-test=localhost:9090 ``` start examples gRPC server for test //examples/cmd/example-gateway-server ``` -ease-gateway/bazel-bin/examples/cmd/example-grpc-server/linux_amd64_stripped/example-grpc-server +ease-gateway/bazel-bin/examples/cmd/example-grpc-server/example-grpc-server_/example-grpc-server ``` start gRPC server for test //cmd/gateway ``` -ease-gateway/bazel-bin/examples/cmd/grpc-server/linux_amd64_stripped/grpc-server -skylb-endpoints="127.0.0.1:1900" +ease-gateway/bazel-bin/examples/cmd/grpc-server/grpc-server_/grpc-server -skylb-endpoints="127.0.0.1:1900" ``` start //cmd/gateway ``` -ease-gateway/bazel-bin/cmd/gateway/linux_amd64_stripped/gateway -skylb-endpoints="127.0.0.1:1900" -v=2 -log_dir=. +ease-gateway/bazel-bin/cmd/gateway/gateway_/gateway -skylb-endpoints="127.0.0.1:1900" -v=2 -log_dir=. ``` # Usage From 271aea5b5636219570c7d63151f4ff6298769706 Mon Sep 17 00:00:00 2001 From: binchen Date: Mon, 13 Jul 2020 15:35:47 +0800 Subject: [PATCH 17/56] Add gateway-validation-rule.md, design.md --- README.md | 10 +- WORKSPACE | 8 +- docs/design.md | 224 +++++++++++++++++++++++++++ docs/gateway-validation-rule.md | 157 +++++++++++++++++++ docs/images/Arch.png | Bin 0 -> 32693 bytes docs/images/code-snippet.png | Bin 0 -> 28503 bytes docs/images/etcd.png | Bin 0 -> 19695 bytes docs/images/gateway-service-hook.png | Bin 0 -> 12538 bytes docs/images/mechanism.png | Bin 0 -> 33892 bytes docs/images/request-flow.png | Bin 0 -> 16670 bytes docs/spring-validation.md | 52 +++++++ repositories.bzl | 6 + 12 files changed, 452 insertions(+), 5 deletions(-) create mode 100644 docs/design.md create mode 100644 docs/gateway-validation-rule.md create mode 100644 docs/images/Arch.png create mode 100644 docs/images/code-snippet.png create mode 100644 docs/images/etcd.png create mode 100644 docs/images/gateway-service-hook.png create mode 100644 docs/images/mechanism.png create mode 100644 docs/images/request-flow.png create mode 100644 docs/spring-validation.md diff --git a/README.md b/README.md index 2e2a0c8..5f5e893 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# ease-gateway +# Ease-gateway Gateway service based on [grpc-ecosystem/grpc-gateway](https://github.com/grpc-ecosystem/grpc-gateway). This helps you provide your APIs in both gRPC and RESTful style at the same time. @@ -15,6 +15,14 @@ Gateway service based on [grpc-ecosystem/grpc-gateway](https://github.com/grpc-e - 支持网关层的Parameter Validation Rules - 支持自定义的Annotaion +## Design + +[design.md](https://github.com/binchencoder/ease-gateway/tree/master/docs/design.md) + +## Validation Rule + +[gateway-validation-rule.md](https://github.com/binchencoder/ease-gateway/tree/master/docs/gateway-validation-rule.md) + ## Prepared **ease-gateway** 使用GO MOD来管理Dependencies,clone代码之后直接在本地使用bazel构建 diff --git a/WORKSPACE b/WORKSPACE index e75fb52..c8c9d47 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -5,9 +5,9 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") # ----------从github下载扩展 io_bazel_rules_go ---------- http_archive( name = "io_bazel_rules_go", - sha256 = "87f0fb9747854cb76a0a82430adccb6269f7d394237104a4523b51061c469171", + sha256 = "7b9bbe3ea1fccb46dcfa6c3f3e29ba7ec740d8733370e21cdc8937467b4a4349", urls = [ - "https://github.com/bazelbuild/rules_go/releases/download/v0.23.1/rules_go-v0.23.1.tar.gz", + "https://github.com/bazelbuild/rules_go/releases/download/v0.22.4/rules_go-v0.22.4.tar.gz", ], ) @@ -53,8 +53,8 @@ go_repositories() go_repository( name = "com_google_protobuf", importpath = "github.com/protocolbuffers/protobuf", - sum = "h1:QbxPofk2041MRNYwie5F79xezBbVhMzoWy23+dKfgMY=", - version = "v3.9.0+incompatible", + sum = "h1:pNPOCD+Nm4NY0R6gdOpwOPpRGUjbPo9SO/UlD56lH+0=", + version = "v3.8.0+incompatible", ) load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps") diff --git a/docs/design.md b/docs/design.md new file mode 100644 index 0000000..56e2215 --- /dev/null +++ b/docs/design.md @@ -0,0 +1,224 @@ +# Ease-gatway - Enterprise Universal Gateway Service + +`ease-gateway` is a enterprise universal gateway service for mobile, native, and web apps. +It's based on `grpc-gateway` and mobile team's gateway development experience. + +## Overview + +`ease-gateway` is a thin gateway layer on top of all front-end or APIs services. It's the single entrance for all enterprise internal services except the connection services (such as EIM connection layer, SSO, etc.). All clients access the gateway (through the reverse proxy or load balancer) with RESTful APIs, the gateway translates the requests to gRPC calls to the target services. + +![Architecture](images/Arch.png) + +> SkyLB is an external load balancer for gRPC which is able to load balance on +> gRPC's long-lived connections. `ease-gateway` instances connect to SkyLB for endpoints +> of the target services, and load balance the end-users' requests to the target +> services. + +Based on this structure, `ease-gateway` provides foundamental functions to enterprise +infrastructure such as user identity verification, API management, monitoring, +and logging. + +## How does Ease-gateway Work? + +`ease-gateway` is based on the open-sourced `grpc-gateway` framework. The following +diagram shows how grpc-gateway works: + +![grpc-gateway](images/mechanism.png) + +> So the first step starts from a protocol buffer definition file (written by +> the target service's owner). For each gRPC service defined in the file, an +> annotation can be added to describe its RESTful properties: + +![code-snippet](images/code-snippet.png) + +The above code specifies that the client can call a RESTful API +"https://apis.xxx.com/v1/example/echo" which is a HTTP POST and the +request and response will be JSON objects. + +Once we have the proto file, grpc-gateway translates the RPC methods to both +gateway and gRPC service stubs in Golang. The generated code can be easily +hooked up with a HTTP server, and when HTTP requests arrive, it issues gRPC +calls to the target service. + +`ease-gateway` is the project to create such a HTTP server to meet enterprise business +needs. + +### Request Interception + +To make it easier to inject our business logic to the generated gateway stub, +we modified the `grpc-gateway` template with a GatewayServiceHook interface: + +![GatewayServiceHook](images/gateway-service-hook.png) + +Four request hook functions are put in the proper places of the generated +code: + +![RequestFlow](images/request-flow.png) + +- RequestReceived() + + The request just arrived at the gateway but the JSON payload has not + been unmarshaled. It's intended for operations like user identity + verification in which the information in the JSON payload is not needed. + +- RequestAccepted() + + The request has been verified with legal user identity, but the JSON + payload has not yet been unmarshaled. It's the good place for + extracting user/enterprise information and return them in a map. + +- RequestParsed() + + The JSON payload has been unmarshaled. + +- RequestHandled() + + The request has been handled, whether it failed or succeeded. Logging + can be done in this function. + +### Service Register/Discovery with SkyLB + +SkyLB is enterprise external load balancer for gRPC services. When `grpc-gateway` +translates the proto, it also generates a SkyLB client for each service. The +SkyLB clients talk to the SkyLB to fetch service endpoints, and get notified +when the service endpoints were changed so that it can do client side load +balance properly. A typical SkyLB client example can be found at +[ease-gateway demo](https://github.com/binchencoder/ease-gateway/tree/master/examples/gateway) (it also contains the `grpc-gateway` example). + +The GatewayServiceHook provides a Bootstrap() method for us to do +initialization work (triggered by calling runtime.SetGatewayServiceHook() of +`grpc-gateway`). In Bootstrap() we can create gRPC client for each service: + +```go +svc.Register(context.Background(), gh.mux, gh.host, opts) +if enabled_in_etcd { + svc.Enable() // Enable() creates a gRPC client. +} else { + svc.Disable() // Disable() destroies the gRPC client. +} +``` + +Thus we can enable/disable the APIs through ETCD. To keep fresh with service +configs in ETCD, Janus should maintain a watcher to ETCD instance. See next +section "Service Keeper" for more details. + +### Service Keeper + +Service information like enabled/disabled are configured as ETCD keys. Janus +UI provides a user friendly interface to manage these keys. In Bootstrap() +method we need to fetch service information from ETCD, and then create an ETCD +watcher to get notified when service config changes. + +![Etcd](images/etcd.png) + +The service hook should cache the services information in memory, and handle +requests according to the information. For those services which are not +yet exiting in ETCD, default values are returned (so that such services are +disabled by default). + +Note that ETCD v3 watcher itself is a gRPC stream call so it has ignorable +connection overhead (long-live connection) and very low latency. + +### Customized Annotations + +#### Service IDs/Names + +All enterprise gRPC services should be registered with distinct enums in +[gateway-proto/data/data.proto](https://github.com/binchencoder/gateway-proto/tree/master/data/data.proto). The enum value would be the service +ID. For a service enum MY_SERVICE, its service name would be +"my-service". + +> You can define a utility library to convert the service ID from/to service names. + +In gRPC service proto, engineers need to specify the service ID like this: + +```proto +import "options/extension.proto"; + +service Demo { + option (ease.api.service_spec) = { + service_id: EASE_GATEWAY_DEMO + namespace: "default" + port_name: "grpc" + } + // RPC definitions below. +} +``` + +The service spec is used by `grpc-gateway` to connect to SkyLB server and create +gRPC clients. + +#### Field Validation + +When `grpc-gateway` translates the proto, it also generates validation logic +for certain fields in request. If the validation failed, it returns HTTP 400 +(BAD REQUEST) directly to the caller. + +Engineers can annotate some fields as follows: + +```proto +import "httpoptions/annotations.proto"; + +// The request message for greeting. +message GreetingRequest { + string name = 1 [ + (ease.api.rules) = { + rules: { + type: STRING, + operator: NON_NIL, + }, + rules: { + type: STRING, + function: TRIM, + operator: LEN_GT, + value: "5", + }, + rules: { + type: STRING, + function: TRIM, + operator: LEN_LT, + value: "21", + } + } + ]; +} +``` + +The above option specifies that field "name" is a string with at least 5 chars +and at most 20. + +### Monitoring with Prometheus + +For commonly used monitoring metrics, we can rely on the existing +instrumentation in SkyLB client: QPS, latency, and error rate. + +We can add Janus customized instrumentation if needed. + +## Gateway Rollout Procedure + +When a new target service or service update is going to be added to `ease-gateway`, +it has to following the following steps: + +1. Add a service enum if it's a new service. + +2. Change the proto file and create gateway bazel build target. + +3. Implement the gRPC service and push to production. + +4. Link the service to gateway if it's a new service. This can be easily done + by adding an anonymous import in `//ease-gateway/cmd/gateway/registryprod.go ` : + + ```go + import ( + _ "github.com/binchencoder/ease-gateway/proto/examples" + ) + ``` + +5. Rebuild the `ease-gateway` binary and push to production. + + +## References + +https://github.com/grpc-ecosystem/grpc-gateway + +https://github.com/binchencoder/grpc-skylb \ No newline at end of file diff --git a/docs/gateway-validation-rule.md b/docs/gateway-validation-rule.md new file mode 100644 index 0000000..bf95cc2 --- /dev/null +++ b/docs/gateway-validation-rule.md @@ -0,0 +1,157 @@ +# Ease-gateway Validation Rule + +## Rules Defination + +Validation Rule定义可以在这里找到: + +> ease-gateway/httpoptions/annotations.proto + +```protobuf +// The opertaion type. +enum OperatorType { + OPERATOR_TYPE_UNKNOWN = 0; + + GT = 1; // Greater than + LT = 2; // Less than + EQ = 3; // Equals + MATCH = 4; // String pattern match. + NON_NIL = 5; // Not nil + LEN_GT = 6; // String length great than + LEN_LT = 7; // String length less than + LEN_EQ = 8; // String length equals +} + +// The supported function type list +enum FunctionType{ + FUNCTION_TYPE_UNKNOWN = 0; + + TRIM = 1; // String trim. +} + +// ValueType is the type of the field. +enum ValueType { + VALUE_TYPE_UNKNOWN = 0; + + NUMBER = 1; // Represent all number type like int,real + STRING = 2; // String + OBJ = 3; +} + +// ValidationRule defines the rule to validate the input value. +message ValidationRule { + OperatorType operator = 1; + ValueType type = 2; + string value = 3; + FunctionType function = 4; +} +``` + +> NOTE +> +> Validation Rule是作为Message's field的Extension Attribute。 + +每一条Rule包括: + +* 类型 +* 操作符 +* 期待值 +* 函数(可选) + +## Samples + +```protobuf +// The request message to be greeted. +message Payment { + message SubPayment { + PaymentType type = 1; + // 100 > paied_amount > 10 + int64 paied_amount = 2 [ + (jingoal.api.rules) = { + rules: { + type:NUMBER, + operator: GT, + value:"10", + }, + rules: { + type:NUMBER, + operator: LT, + value:"100", + }, + } + ]; + }; + + PaymentType type = 1; + // 长度=10 + string message_value_len_eq = 3 [ + (jingoal.api.rules) = { + rules: { + type:STRING, + operator: LEN_EQ, + value:"10", + }, + } + ]; + + // 长度Trim之后小于21 + string message_value_len_gt = 4 [ + (jingoal.api.rules) = { + rules: { + type:STRING, + operator: LEN_LT, + value:"21", + function: TRIM, + }, + } + ]; +} +``` + +更多例子可以以下目录找到: + +> ease-gateway/proto/examples/... + +## Implemention Details + +Validation Rule的定义会被编译到相呼应的xxx.gw.go文件中。每个类型会有一个Validation方法,如果这个类型包括任何Rule. 如果一个Field引用另外一个文件的类型(并且有Rule),那么生成的文件会引用相应的go package. + +这是一个生成代码的例子: + +```go + +func Validate__sharedproto_Payment(v *Payment) error { + if v == nil { + return nil + } + // Validation for each Fields + + // Validation Field: Type + + // Validation Field: Amount + + if v.Amount <= 10 { + return janus_demo_proto_sharedproto_shared_error + } + + if v.Amount >= 100 { + return janus_demo_proto_sharedproto_shared_error + } +... ... + return nil +} + +``` + +## Add Validation Rule + +加一个新的操作符或者函数是比较简单的。可以查阅有关的CR.代码在: + +### Defination + +> ease-gateway/httpoptions/annotations.proto + +### Implementation Validation Rule + +> ease-gateway/gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go + +所有Validation Rule的实现都在template.go 文件中, 搜索`validatorTemplate`, 参照现有实现Coding \ No newline at end of file diff --git a/docs/images/Arch.png b/docs/images/Arch.png new file mode 100644 index 0000000000000000000000000000000000000000..2ca913c689211c7d3f75fa3f7966e038b51f5035 GIT binary patch literal 32693 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

e8Y>!Qax6dNc& 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

kVmn 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 literal 0 HcmV?d00001 diff --git a/docs/images/code-snippet.png b/docs/images/code-snippet.png new file mode 100644 index 0000000000000000000000000000000000000000..9c8371889c2c1e8b3eb6f8c7e2ae5502fd0ee9bc GIT binary patch literal 28503 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 Uh&OEjzbpeTBP|eB25w3J0ekZ2L;wH) literal 0 HcmV?d00001 diff --git a/docs/images/gateway-service-hook.png b/docs/images/gateway-service-hook.png new file mode 100644 index 0000000000000000000000000000000000000000..cf2e646d966a02a8cd0d0eed004a868d1ba5c738 GIT binary patch literal 12538 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%0A351gxxPx08HTO=_&D5unEyYliUffB3`)b58 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 z%0D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 literal 0 HcmV?d00001 diff --git a/docs/spring-validation.md b/docs/spring-validation.md new file mode 100644 index 0000000..aa32d42 --- /dev/null +++ b/docs/spring-validation.md @@ -0,0 +1,52 @@ +# Common Validation Annotations by Spring + +## @NotNull + +The annotated element must not be null. Accepts any type. + +## @Min + +The annotated element must be a number whose value must be higher or equal +to the specified minimum. + +Supported types are: BigDecimal, BigInteger, byte, short, int, long, and their +respective wrappers. Note that double and float are not supported due to +rounding errors (some providers might provide some approximative support). + +null elements are considered valid. + +## @Max + +The annotated element must be a number whose value must be lower or equal +to the specified maximum. + +Supported types are: BigDecimal, BigInteger, byte, short, int, long, and their +respective wrappers. Note that double and float are not supported due to +rounding errors (some providers might provide some approximative support). + +null elements are considered valid. + +## @Size(min = 0, max = 100) + +The annotated element size must be between the specified boundaries (included). + +Supported types are: + +- String (string length is evaludated) +- Collection (collection size is evaluated) +- Map (map size is evaluated) +- Array (array length is evaluated) + +null elements are considered valid. + +## @Pattern(regex = "XXXX") + +The annotated String must match the following regular expression. +The regular expression follows the Java regular expression conventions +see Pattern. Accepts String. + +null elements are considered valid. + +## Reference: + +[Package javax.validation.constraints ](http://docs.oracle.com/javaee/6/api/javax/validation/constraints/package-summary.html) diff --git a/repositories.bzl b/repositories.bzl index f0805e5..5ba76ca 100644 --- a/repositories.bzl +++ b/repositories.bzl @@ -68,6 +68,12 @@ def go_repositories(): sum = "h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=", version = "v0.0.0-20160126235308-23def4e6c14b", ) + go_repository( + name = "com_github_golang_protobuf", + importpath = "github.com/golang/protobuf", + sum = "h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=", + version = "v1.3.3", + ) go_repository( name = "com_github_google_uuid", importpath = "github.com/google/uuid", From 5278cb98c82a1ade014968106c1e15680624d90b Mon Sep 17 00:00:00 2001 From: binchen Date: Mon, 13 Jul 2020 16:53:24 +0800 Subject: [PATCH 18/56] Update: docs/gateway-validation-rule.md --- docs/gateway-validation-rule.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/gateway-validation-rule.md b/docs/gateway-validation-rule.md index bf95cc2..914691e 100644 --- a/docs/gateway-validation-rule.md +++ b/docs/gateway-validation-rule.md @@ -66,7 +66,7 @@ message Payment { PaymentType type = 1; // 100 > paied_amount > 10 int64 paied_amount = 2 [ - (jingoal.api.rules) = { + (ease.api.rules) = { rules: { type:NUMBER, operator: GT, @@ -84,7 +84,7 @@ message Payment { PaymentType type = 1; // 长度=10 string message_value_len_eq = 3 [ - (jingoal.api.rules) = { + (ease.api.rules) = { rules: { type:STRING, operator: LEN_EQ, @@ -95,7 +95,7 @@ message Payment { // 长度Trim之后小于21 string message_value_len_gt = 4 [ - (jingoal.api.rules) = { + (ease.api.rules) = { rules: { type:STRING, operator: LEN_LT, From 9ff539b42ec5845b30fe807e4a89afb734896862 Mon Sep 17 00:00:00 2001 From: binchen Date: Tue, 14 Jul 2020 15:29:03 +0800 Subject: [PATCH 19/56] Add Architecture images --- README.md | 4 ++++ docs/images/Ease-Gateway.drawio | 1 + docs/images/Ease-Gateway.png | Bin 0 -> 100981 bytes 3 files changed, 5 insertions(+) create mode 100644 docs/images/Ease-Gateway.drawio create mode 100644 docs/images/Ease-Gateway.png diff --git a/README.md b/README.md index 5f5e893..c5236f9 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,10 @@ Gateway service based on [grpc-ecosystem/grpc-gateway](https://github.com/grpc-e - 支持网关层的Parameter Validation Rules - 支持自定义的Annotaion +## Architecture + +![](./docs/images/Ease-Gateway.png) + ## Design [design.md](https://github.com/binchencoder/ease-gateway/tree/master/docs/design.md) diff --git a/docs/images/Ease-Gateway.drawio b/docs/images/Ease-Gateway.drawio new file mode 100644 index 0000000..29fab66 --- /dev/null +++ b/docs/images/Ease-Gateway.drawio @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/docs/images/Ease-Gateway.png b/docs/images/Ease-Gateway.png new file mode 100644 index 0000000000000000000000000000000000000000..5ed3ac726390a24d3e02711dc4fb3c9955bc6aaa GIT binary patch literal 100981 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 z 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

Fksd2f!oO9<>(e2KMT@NU^xsQI1 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 z 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 Date: Fri, 17 Jul 2020 11:27:27 +0800 Subject: [PATCH 20/56] Update: docs/images/Ease-Gateway.png --- docs/images/Ease-Gateway.drawio | 2 +- docs/images/Ease-Gateway.png | Bin 100981 -> 117260 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/images/Ease-Gateway.drawio b/docs/images/Ease-Gateway.drawio index 29fab66..eb6fe35 100644 --- a/docs/images/Ease-Gateway.drawio +++ b/docs/images/Ease-Gateway.drawio @@ -1 +1 @@ -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 \ No newline at end of file +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 \ No newline at end of file diff --git a/docs/images/Ease-Gateway.png b/docs/images/Ease-Gateway.png index 5ed3ac726390a24d3e02711dc4fb3c9955bc6aaa..29674e2981c493388af6573d50a39486774a64a5 100644 GIT binary patch literal 117260 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 A@&Et; literal 100981 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 z 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

Fksd2f!oO9<>(e2KMT@NU^xsQI1 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 z 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 Date: Tue, 21 Jul 2020 17:17:44 +0800 Subject: [PATCH 21/56] Successful packaging probufers using Maven --- httpoptions/pom.xml | 158 +++++++++++++++++++++++++++++++++++++++++ proto/examples/pom.xml | 22 +++--- proto/pom.xml | 24 ++++--- 3 files changed, 185 insertions(+), 19 deletions(-) create mode 100755 httpoptions/pom.xml diff --git a/httpoptions/pom.xml b/httpoptions/pom.xml new file mode 100755 index 0000000..f91570c --- /dev/null +++ b/httpoptions/pom.xml @@ -0,0 +1,158 @@ + + + 4.0.0 + com.binchencoder.easegw + easegw-options-protos + jar + 1.0-SNAPSHOT + + + Binchencoder + https://www.github.com/binchencoder + + + + mvn-repo + https://raw.github.com/binchencoder/mvn-repo/master + + true + always + + + + + + + 1.18.0 + + 3.6.1 + + 0.0.3 + + github + + + + + io.grpc + grpc-protobuf + ${grpc.version} + provided + + + io.grpc + grpc-stub + ${grpc.version} + provided + + + + com.google.protobuf + protobuf-java + ${protobuf.version} + provided + + + com.google.api.grpc + googleapis-common-protos + ${googleapis.version} + provided + + + io.grpc + grpc-stub + + + + + + com.binchencoder.gateway + data-proto + 1.0-SNAPSHOT + + + com.binchencoder.gateway + frontend-proto + 1.0-SNAPSHOT + + + + + + + kr.motd.maven + os-maven-plugin + 1.4.1.Final + + + + + org.apache.maven.plugins + maven-source-plugin + + + org.apache.maven.plugins + maven-compiler-plugin + + + org.apache.maven.plugins + maven-deploy-plugin + 2.8.1 + + internal.repo::default::file://${project.build.directory}/mvn-repo + + + + com.github.github + site-maven-plugin + 0.12 + + Maven artifacts for ${project.version} + true + ${project.build.directory}/mvn-repo + refs/heads/master + true + + **/* + + mvn-repo + binchencoder + + + + + site + + deploy + + + + + org.xolstice.maven.plugins + protobuf-maven-plugin + 0.5.0 + + + com.google.protobuf:protoc:${protobuf.version}:exe:${os.detected.classifier} + grpc-java + io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier} + ../ + + httpoptions/*.proto + + + + + + compile + compile-custom + + + + + + + \ No newline at end of file diff --git a/proto/examples/pom.xml b/proto/examples/pom.xml index 9cd89ee..3eee815 100755 --- a/proto/examples/pom.xml +++ b/proto/examples/pom.xml @@ -15,6 +15,15 @@ + + com.binchencoder.easegw + easegw-options-protos + + + com.binchencoder.gateway + data-proto + + io.grpc grpc-protobuf @@ -32,11 +41,6 @@ com.google.api.grpc googleapis-common-protos - - - com.binchencoder.gateway - data-proto - @@ -49,12 +53,10 @@ org.xolstice.maven.plugins protobuf-maven-plugin - ../../../ + ../ - ease-gateway/proto/examples/*.proto - ease-gateway/proto/examples/*/*.proto - ease-gateway/gateway/options/http.proto - ease-gateway/gateway/options/annotations.proto + proto/examples/*.proto + proto/examples/*/*.proto diff --git a/proto/pom.xml b/proto/pom.xml index bd06821..8da16f4 100755 --- a/proto/pom.xml +++ b/proto/pom.xml @@ -39,6 +39,18 @@ + + com.binchencoder.gateway + data-proto + 1.0-SNAPSHOT + + + com.binchencoder.easegw + easegw-options-protos + 1.0-SNAPSHOT + provided + + io.grpc grpc-protobuf @@ -70,12 +82,6 @@ - - - com.binchencoder.gateway - data-proto - 1.0-SNAPSHOT - @@ -140,10 +146,10 @@ com.google.protobuf:protoc:${protobuf.version}:exe:${os.detected.classifier} grpc-java io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier} - ../../ + ../ - ease-gateway/proto/*/*.proto - ease-gateway/proto/*/*/*.proto + proto/*/*.proto + proto/*/*/*.proto From ba2df07f3e25ccee81fc2952373339862aa77a45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BD=AC=E8=87=A3?= Date: Tue, 8 Sep 2020 16:40:06 +0800 Subject: [PATCH 22/56] Create go.yml --- .github/workflows/go.yml | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 .github/workflows/go.yml diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml new file mode 100644 index 0000000..d31e87f --- /dev/null +++ b/.github/workflows/go.yml @@ -0,0 +1,37 @@ +name: Go + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + + build: + name: Build + runs-on: ubuntu-latest + steps: + + - name: Set up Go 1.x + uses: actions/setup-go@v2 + with: + go-version: ^1.13 + id: go + + - name: Check out code into the Go module directory + uses: actions/checkout@v2 + + - name: Get dependencies + run: | + go get -v -t -d ./... + if [ -f Gopkg.toml ]; then + curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh + dep ensure + fi + + - name: Build + run: go build -v . + + - name: Test + run: go test -v . From 7fd3eae56c5bd0274c00a4e09cb61b6e856115c7 Mon Sep 17 00:00:00 2001 From: binchen Date: Wed, 28 Oct 2020 16:10:29 +0800 Subject: [PATCH 23/56] Update based on master branch. grpc-gateway updated on 2020/10/27 --- .goreleaser.yml | 6 +- BUILD | 68 +- WORKSPACE | 38 +- examples/proto/BUILD.bazel | 9 +- examples/proto/echo_service.pb.go | 209 +- examples/proto/echo_service.pb.gw.go | 101 +- examples/proto/echo_service.proto | 9 +- examples/proto/echo_service.swagger.json | 166 +- examples/proto/echo_service_grpc.pb.go | 158 ++ gateway/HISTORY.md | 6 +- gateway/README.md | 6 +- gateway/internal/codegenerator/BUILD.bazel | 28 + gateway/internal/codegenerator/doc.go | 4 + gateway/internal/codegenerator/parse_req.go | 23 + .../internal/codegenerator/parse_req_test.go | 72 + .../descriptor/BUILD.bazel | 16 +- .../internal/descriptor/apiconfig/BUILD.bazel | 29 + .../descriptor/apiconfig/apiconfig.proto | 21 + .../descriptor/grpc_api_configuration.go | 31 +- .../descriptor/grpc_api_configuration_test.go | 313 ++- .../descriptor/registry.go | 90 +- .../descriptor/registry_test.go | 35 +- .../descriptor/services.go | 46 +- .../descriptor/services_test.go | 64 +- .../descriptor/types.go | 220 ++- .../descriptor/types_test.go | 79 +- gateway/internal/errors.pb.go | 2 +- .../generator/BUILD.bazel | 4 +- gateway/internal/generator/generator.go | 14 + gateway/protoc-gen-grpc-gateway/BUILD.bazel | 8 +- .../descriptor/grpc_api_service.go | 32 - .../generator/generator.go | 14 - .../internal/gengateway/BUILD.bazel | 13 +- .../internal/gengateway/generator.go | 33 +- .../internal/gengateway/generator_test.go | 103 +- .../internal/gengateway/template.go | 92 +- .../internal/gengateway/template_test.go | 169 +- gateway/protoc-gen-grpc-gateway/main.go | 28 +- .../BUILD.bazel | 12 +- .../defs.bzl | 62 +- .../internal/genopenapi}/BUILD.bazel | 24 +- .../internal/genopenapi/doc.go | 2 + .../internal/genopenapi}/generator.go | 130 +- .../internal/genopenapi}/helpers.go | 2 +- .../internal/genopenapi}/helpers_go111_old.go | 2 +- .../internal/genopenapi}/template.go | 511 +++-- .../internal/genopenapi}/template_test.go | 1088 ++++++----- .../internal/genopenapi}/types.go | 111 +- .../main.go | 51 +- .../main_test.go | 28 +- .../options/BUILD.bazel | 5 +- .../options/annotations.proto | 6 +- .../options/openapiv2.proto | 59 +- gateway/protoc-gen-swagger/genswagger/doc.go | 2 - .../options/annotations.pb.go | 105 - .../options/openapiv2.pb.go | 1721 ----------------- gateway/runtime/BUILD.bazel | 35 +- gateway/runtime/balancer.go | 75 +- gateway/runtime/balancer_test.go | 102 +- gateway/runtime/context.go | 31 +- gateway/runtime/context_test.go | 119 +- gateway/runtime/convert.go | 58 +- gateway/runtime/convert_test.go | 104 +- gateway/runtime/errors.go | 88 +- gateway/runtime/errors_test.go | 68 +- gateway/runtime/fieldmask.go | 85 +- gateway/runtime/fieldmask_test.go | 151 -- gateway/runtime/handler.go | 49 +- gateway/runtime/handler_test.go | 30 +- gateway/runtime/hook.go | 2 +- gateway/runtime/hook_test.go | 2 +- .../runtime/internal/examplepb/BUILD.bazel | 39 + .../runtime/internal/examplepb/proto3.pb.go | 886 +++++++++ .../runtime/internal/examplepb/proto3.proto | 64 + gateway/runtime/marshal_httpbodyproto.go | 21 +- gateway/runtime/marshal_httpbodyproto_test.go | 14 +- gateway/runtime/marshal_json.go | 2 +- gateway/runtime/marshal_json_test.go | 95 +- gateway/runtime/marshal_jsonpb.go | 121 +- gateway/runtime/marshal_jsonpb_test.go | 378 ++-- gateway/runtime/marshal_proto.go | 5 +- gateway/runtime/marshal_proto_test.go | 10 +- gateway/runtime/marshaler.go | 11 +- gateway/runtime/marshaler_registry.go | 13 +- gateway/runtime/marshaler_registry_test.go | 11 +- gateway/runtime/mux.go | 150 +- gateway/runtime/mux_test.go | 213 +- gateway/runtime/pattern.go | 49 +- gateway/runtime/pattern_test.go | 2 +- gateway/runtime/proto2_convert.go | 2 +- gateway/runtime/proto_errors.go | 107 - gateway/runtime/query.go | 511 +++-- gateway/runtime/query_test.go | 558 ++---- go.mod | 12 +- go.sum | 249 +++ httpoptions/annotations.pb.go | 1213 ++++++++---- httpoptions/annotations.proto | 2 + httpoptions/http.pb.go | 865 +++++++-- httpoptions/http.proto | 31 +- integrate/hook.go | 2 +- proto/examples/BUILD.bazel | 9 +- proto/examples/echo_service.pb.go | 308 +-- proto/examples/echo_service.pb.gw.go | 121 +- proto/examples/echo_service.proto | 13 +- proto/examples/echo_service.swagger.json | 166 +- proto/examples/echo_service_grpc.pb.go | 158 ++ repositories.bzl | 41 +- 107 files changed, 6756 insertions(+), 6975 deletions(-) create mode 100755 examples/proto/echo_service_grpc.pb.go create mode 100644 gateway/internal/codegenerator/BUILD.bazel create mode 100644 gateway/internal/codegenerator/doc.go create mode 100644 gateway/internal/codegenerator/parse_req.go create mode 100644 gateway/internal/codegenerator/parse_req_test.go rename gateway/{protoc-gen-grpc-gateway => internal}/descriptor/BUILD.bazel (64%) create mode 100644 gateway/internal/descriptor/apiconfig/BUILD.bazel create mode 100644 gateway/internal/descriptor/apiconfig/apiconfig.proto rename gateway/{protoc-gen-grpc-gateway => internal}/descriptor/grpc_api_configuration.go (64%) rename gateway/{protoc-gen-grpc-gateway => internal}/descriptor/grpc_api_configuration_test.go (84%) rename gateway/{protoc-gen-grpc-gateway => internal}/descriptor/registry.go (88%) rename gateway/{protoc-gen-grpc-gateway => internal}/descriptor/registry_test.go (94%) rename gateway/{protoc-gen-grpc-gateway => internal}/descriptor/services.go (87%) rename gateway/{protoc-gen-grpc-gateway => internal}/descriptor/services_test.go (93%) rename gateway/{protoc-gen-grpc-gateway => internal}/descriptor/types.go (72%) rename gateway/{protoc-gen-grpc-gateway => internal}/descriptor/types_test.go (68%) rename gateway/{protoc-gen-grpc-gateway => internal}/generator/BUILD.bazel (60%) create mode 100644 gateway/internal/generator/generator.go delete mode 100644 gateway/protoc-gen-grpc-gateway/descriptor/grpc_api_service.go delete mode 100644 gateway/protoc-gen-grpc-gateway/generator/generator.go rename gateway/{protoc-gen-swagger => protoc-gen-openapiv2}/BUILD.bazel (63%) rename gateway/{protoc-gen-swagger => protoc-gen-openapiv2}/defs.bzl (78%) rename gateway/{protoc-gen-swagger/genswagger => protoc-gen-openapiv2/internal/genopenapi}/BUILD.bazel (61%) create mode 100644 gateway/protoc-gen-openapiv2/internal/genopenapi/doc.go rename gateway/{protoc-gen-swagger/genswagger => protoc-gen-openapiv2/internal/genopenapi}/generator.go (59%) rename gateway/{protoc-gen-swagger/genswagger => protoc-gen-openapiv2/internal/genopenapi}/helpers.go (86%) rename gateway/{protoc-gen-swagger/genswagger => protoc-gen-openapiv2/internal/genopenapi}/helpers_go111_old.go (87%) rename gateway/{protoc-gen-swagger/genswagger => protoc-gen-openapiv2/internal/genopenapi}/template.go (77%) rename gateway/{protoc-gen-swagger/genswagger => protoc-gen-openapiv2/internal/genopenapi}/template_test.go (66%) rename gateway/{protoc-gen-swagger/genswagger => protoc-gen-openapiv2/internal/genopenapi}/types.go (70%) rename gateway/{protoc-gen-swagger => protoc-gen-openapiv2}/main.go (78%) rename gateway/{protoc-gen-swagger => protoc-gen-openapiv2}/main_test.go (89%) rename gateway/{protoc-gen-swagger => protoc-gen-openapiv2}/options/BUILD.bazel (90%) rename gateway/{protoc-gen-swagger => protoc-gen-openapiv2}/options/annotations.proto (91%) rename gateway/{protoc-gen-swagger => protoc-gen-openapiv2}/options/openapiv2.proto (93%) delete mode 100644 gateway/protoc-gen-swagger/genswagger/doc.go delete mode 100644 gateway/protoc-gen-swagger/options/annotations.pb.go delete mode 100644 gateway/protoc-gen-swagger/options/openapiv2.pb.go delete mode 100644 gateway/runtime/fieldmask_test.go create mode 100644 gateway/runtime/internal/examplepb/BUILD.bazel create mode 100644 gateway/runtime/internal/examplepb/proto3.pb.go create mode 100644 gateway/runtime/internal/examplepb/proto3.proto delete mode 100644 gateway/runtime/proto_errors.go mode change 100755 => 100644 httpoptions/annotations.pb.go mode change 100755 => 100644 httpoptions/http.pb.go create mode 100755 proto/examples/echo_service_grpc.pb.go diff --git a/.goreleaser.yml b/.goreleaser.yml index 9e1ee2a..7987166 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -1,5 +1,6 @@ builds: - main: ./gateway/protoc-gen-grpc-gateway/main.go + id: protoc-gen-grpc-gateway binary: protoc-gen-grpc-gateway env: - CGO_ENABLED=0 @@ -9,8 +10,9 @@ builds: - windows goarch: - amd64 - - main: ./gateway/protoc-gen-swagger/main.go - binary: protoc-gen-swagger + - main: ./gateway/protoc-gen-openapiv2/main.go + id: protoc-gen-openapiv2 + binary: protoc-gen-openapiv2 env: - CGO_ENABLED=0 goos: diff --git a/BUILD b/BUILD index f74a4eb..c76517b 100644 --- a/BUILD +++ b/BUILD @@ -1,5 +1,6 @@ load("@bazel_gazelle//:def.bzl", "gazelle") load("@com_github_bazelbuild_buildtools//buildifier:def.bzl", "buildifier") +load("@io_bazel_rules_go//proto:compiler.bzl", "go_proto_compiler") buildifier( name = "buildifier", @@ -11,8 +12,71 @@ buildifier( ) # gazelle:exclude third_party -# gazelle:exclude vendor # gazelle:exclude _output -# gazelle:prefix github.com/binchencoder/ease-gateway +# gazelle:prefix github.com/binchencoder/ease-gateway/gateway +# gazelle:go_proto_compilers //:go_apiv2 +# gazelle:go_grpc_compilers //:go_apiv2, //:go_grpc gazelle(name = "gazelle") + +package_group( + name = "generators", + packages = [ + "//gateway/protoc-gen-grpc-gateway/...", + "//gateway/protoc-gen-openapiv2/...", + ], +) + +go_proto_compiler( + name = "go_apiv2", + options = [ + "paths=source_relative", + ], + plugin = "@org_golang_google_protobuf//cmd/protoc-gen-go", + suffix = ".pb.go", + visibility = ["//visibility:public"], + deps = [ + "@com_github_golang_protobuf//proto:go_default_library", + "@io_bazel_rules_go//proto/wkt:any_go_proto", + "@io_bazel_rules_go//proto/wkt:api_go_proto", + "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", + "@io_bazel_rules_go//proto/wkt:descriptor_go_proto", + "@io_bazel_rules_go//proto/wkt:duration_go_proto", + "@io_bazel_rules_go//proto/wkt:empty_go_proto", + "@io_bazel_rules_go//proto/wkt:field_mask_go_proto", + "@io_bazel_rules_go//proto/wkt:source_context_go_proto", + "@io_bazel_rules_go//proto/wkt:struct_go_proto", + "@io_bazel_rules_go//proto/wkt:timestamp_go_proto", + "@io_bazel_rules_go//proto/wkt:type_go_proto", + "@io_bazel_rules_go//proto/wkt:wrappers_go_proto", + "@org_golang_google_protobuf//reflect/protoreflect:go_default_library", + "@org_golang_google_protobuf//runtime/protoimpl:go_default_library", + ], +) + +go_proto_compiler( + name = "go_grpc", + options = [ + "paths=source_relative", + ], + plugin = "@org_golang_google_grpc_cmd_protoc_gen_go_grpc//:protoc-gen-go-grpc", + suffix = "_grpc.pb.go", + visibility = ["//visibility:public"], + deps = [ + "@io_bazel_rules_go//proto/wkt:any_go_proto", + "@io_bazel_rules_go//proto/wkt:api_go_proto", + "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", + "@io_bazel_rules_go//proto/wkt:descriptor_go_proto", + "@io_bazel_rules_go//proto/wkt:duration_go_proto", + "@io_bazel_rules_go//proto/wkt:empty_go_proto", + "@io_bazel_rules_go//proto/wkt:field_mask_go_proto", + "@io_bazel_rules_go//proto/wkt:source_context_go_proto", + "@io_bazel_rules_go//proto/wkt:struct_go_proto", + "@io_bazel_rules_go//proto/wkt:timestamp_go_proto", + "@io_bazel_rules_go//proto/wkt:type_go_proto", + "@io_bazel_rules_go//proto/wkt:wrappers_go_proto", + "@org_golang_google_grpc//:go_default_library", + "@org_golang_google_grpc//codes:go_default_library", + "@org_golang_google_grpc//status:go_default_library", + ], +) diff --git a/WORKSPACE b/WORKSPACE index c8c9d47..9b82e53 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -5,9 +5,9 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") # ----------从github下载扩展 io_bazel_rules_go ---------- http_archive( name = "io_bazel_rules_go", - sha256 = "7b9bbe3ea1fccb46dcfa6c3f3e29ba7ec740d8733370e21cdc8937467b4a4349", + sha256 = "a8d6b1b354d371a646d2f7927319974e0f9e52f73a2452d2b3877118169eb6bb", urls = [ - "https://github.com/bazelbuild/rules_go/releases/download/v0.22.4/rules_go-v0.22.4.tar.gz", + "https://github.com/bazelbuild/rules_go/releases/download/v0.23.3/rules_go-v0.23.3.tar.gz", ], ) @@ -15,9 +15,9 @@ http_archive( # 一般来说都会使用gazelle工具来自动生成 BUILD 文件, 而不是手写. http_archive( name = "bazel_gazelle", - sha256 = "d8c45ee70ec39a57e7a05e5027c32b1576cc7f16d9dd37135b0eddde45cf1b10", + sha256 = "cdb02a887a7187ea4d5a27452311a75ed8637379a1287d8eeb952138ea485f7d", urls = [ - "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.20.0/bazel-gazelle-v0.20.0.tar.gz", + "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.21.1/bazel-gazelle-v0.21.1.tar.gz", ], ) @@ -41,22 +41,22 @@ load("//:repositories.bzl", "go_repositories") go_repositories() -# load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") +load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") -# git_repository( -# name = "com_google_protobuf", -# commit = "09745575a923640154bcf307fba8aedff47f240a", -# remote = "https://github.com/protocolbuffers/protobuf", -# shallow_since = "1558721209 -0700", -# ) - -go_repository( +git_repository( name = "com_google_protobuf", - importpath = "github.com/protocolbuffers/protobuf", - sum = "h1:pNPOCD+Nm4NY0R6gdOpwOPpRGUjbPo9SO/UlD56lH+0=", - version = "v3.8.0+incompatible", + commit = "09745575a923640154bcf307fba8aedff47f240a", + remote = "https://github.com/protocolbuffers/protobuf", + shallow_since = "1558721209 -0700", ) +# go_repository( +# name = "com_google_protobuf", +# importpath = "github.com/protocolbuffers/protobuf", +# sum = "h1:pNPOCD+Nm4NY0R6gdOpwOPpRGUjbPo9SO/UlD56lH+0=", +# version = "v3.8.0+incompatible", +# ) + load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps") protobuf_deps() @@ -64,9 +64,9 @@ protobuf_deps() # ---------- com_github_bazelbuild_buildtools ---------- http_archive( name = "com_github_bazelbuild_buildtools", - sha256 = "86592d703ecbe0c5cbb5139333a63268cf58d7efd2c459c8be8e69e77d135e29", - strip_prefix = "buildtools-0.26.0", - urls = ["https://github.com/bazelbuild/buildtools/archive/0.26.0.tar.gz"], + sha256 = "f11fc80da0681a6d64632a850346ed2d4e5cbb0908306d9a2a2915f707048a10", + strip_prefix = "buildtools-3.3.0", + urls = ["https://github.com/bazelbuild/buildtools/archive/3.3.0.tar.gz"], ) load("@com_github_bazelbuild_buildtools//buildifier:deps.bzl", "buildifier_dependencies") diff --git a/examples/proto/BUILD.bazel b/examples/proto/BUILD.bazel index 93aaf48..c5fc231 100644 --- a/examples/proto/BUILD.bazel +++ b/examples/proto/BUILD.bazel @@ -1,6 +1,6 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library") load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") -load("//gateway/protoc-gen-swagger:defs.bzl", "protoc_gen_swagger") +load("//gateway/protoc-gen-openapiv2:defs.bzl", "protoc_gen_openapiv2") package(default_visibility = ["//visibility:public"]) @@ -25,7 +25,8 @@ proto_library( go_proto_library( name = "examplepb_go_proto", compilers = [ - "@io_bazel_rules_go//proto:go_grpc", + "//:go_apiv2", + "//:go_grpc", "//gateway/protoc-gen-grpc-gateway:go_gen_grpc_gateway", # keep ], importpath = "github.com/binchencoder/ease-gateway/examples/proto", @@ -56,8 +57,8 @@ go_library( ], ) -protoc_gen_swagger( - name = "expamplepb_protoc_gen_swagger", +protoc_gen_openapiv2( + name = "expamplepb_protoc_gen_openapiv2", proto = ":examplepb_proto", single_output = False, # Outputs a single swagger.json file. ) \ No newline at end of file diff --git a/examples/proto/echo_service.pb.go b/examples/proto/echo_service.pb.go index 3c34e78..e78df51 100755 --- a/examples/proto/echo_service.pb.go +++ b/examples/proto/echo_service.pb.go @@ -1,18 +1,14 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.22.0 -// protoc v3.9.0 +// protoc v3.8.0 // source: examples/proto/echo_service.proto package proto import ( - context "context" _ "github.com/binchencoder/ease-gateway/httpoptions" proto "github.com/golang/protobuf/proto" - grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" @@ -260,7 +256,7 @@ var File_examples_proto_echo_service_proto protoreflect.FileDescriptor var file_examples_proto_echo_service_proto_rawDesc = []byte{ 0x0a, 0x21, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x12, 0x1b, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, + 0x6f, 0x74, 0x6f, 0x12, 0x1b, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1d, 0x68, 0x74, 0x74, 0x70, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, @@ -276,20 +272,20 @@ var file_examples_proto_echo_service_proto_rawDesc = []byte{ 0x07, 0x6c, 0x69, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x12, 0x14, 0x0a, 0x04, 0x6c, 0x61, 0x6e, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x6c, 0x61, 0x6e, 0x67, 0x12, 0x3d, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, - 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, + 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x10, 0x0a, 0x02, 0x65, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x48, 0x01, 0x52, 0x02, 0x65, 0x6e, 0x12, - 0x37, 0x0a, 0x02, 0x6e, 0x6f, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x65, 0x61, - 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, + 0x37, 0x0a, 0x02, 0x6e, 0x6f, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x67, 0x72, + 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x48, 0x01, 0x52, 0x02, 0x6e, 0x6f, 0x42, 0x06, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x42, 0x05, 0x0a, 0x03, 0x65, 0x78, 0x74, 0x32, 0xcc, 0x04, 0x0a, 0x0b, 0x45, 0x63, 0x68, 0x6f, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x94, 0x02, 0x0a, 0x04, 0x45, 0x63, 0x68, 0x6f, - 0x12, 0x2a, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, + 0x12, 0x2a, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, - 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x2a, 0x2e, 0x65, - 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, + 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x2a, 0x2e, 0x67, + 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xb3, 0x01, 0xca, 0xf3, 0x34, 0xae, 0x01, 0x22, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, @@ -303,26 +299,29 @@ var file_examples_proto_echo_service_proto_rawDesc = []byte{ 0x7d, 0x2f, 0x7b, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x6e, 0x6f, 0x74, 0x65, 0x7d, 0x5a, 0x1d, 0x12, 0x1b, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x32, 0x2f, 0x7b, 0x6e, 0x6f, 0x2e, 0x6e, 0x6f, 0x74, 0x65, 0x7d, 0x12, 0x82, - 0x01, 0x0a, 0x08, 0x45, 0x63, 0x68, 0x6f, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x2a, 0x2e, 0x65, 0x61, - 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, + 0x01, 0x0a, 0x08, 0x45, 0x63, 0x68, 0x6f, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x2a, 0x2e, 0x67, 0x72, + 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x2a, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x2a, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x1e, 0xca, 0xf3, 0x34, 0x1a, 0x22, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x62, 0x6f, 0x64, 0x79, 0x3a, 0x01, 0x2a, 0x12, 0x83, 0x01, 0x0a, 0x0a, 0x45, 0x63, 0x68, 0x6f, 0x44, 0x65, 0x6c, 0x65, - 0x74, 0x65, 0x12, 0x2a, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, + 0x74, 0x65, 0x12, 0x2a, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x2a, - 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, + 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x1d, 0xca, 0xf3, 0x34, 0x19, 0x2a, 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x1a, 0x1b, 0xea, 0xf3, 0x34, 0x17, 0x08, 0xb6, 0x95, 0xff, 0xff, 0x07, 0x12, 0x04, 0x67, 0x72, 0x70, 0x63, 0x1a, 0x07, 0x64, 0x65, 0x66, - 0x61, 0x75, 0x6c, 0x74, 0x20, 0x01, 0x42, 0x07, 0x5a, 0x05, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x61, 0x75, 0x6c, 0x74, 0x20, 0x01, 0x42, 0x35, 0x5a, 0x33, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x69, 0x6e, 0x63, 0x68, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, + 0x72, 0x2f, 0x65, 0x61, 0x73, 0x65, 0x2d, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2f, 0x65, + 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -339,18 +338,18 @@ func file_examples_proto_echo_service_proto_rawDescGZIP() []byte { var file_examples_proto_echo_service_proto_msgTypes = make([]protoimpl.MessageInfo, 2) var file_examples_proto_echo_service_proto_goTypes = []interface{}{ - (*Embedded)(nil), // 0: ease.gateway.examples.proto.Embedded - (*SimpleMessage)(nil), // 1: ease.gateway.examples.proto.SimpleMessage + (*Embedded)(nil), // 0: grpc.gateway.examples.proto.Embedded + (*SimpleMessage)(nil), // 1: grpc.gateway.examples.proto.SimpleMessage } var file_examples_proto_echo_service_proto_depIdxs = []int32{ - 0, // 0: ease.gateway.examples.proto.SimpleMessage.status:type_name -> ease.gateway.examples.proto.Embedded - 0, // 1: ease.gateway.examples.proto.SimpleMessage.no:type_name -> ease.gateway.examples.proto.Embedded - 1, // 2: ease.gateway.examples.proto.EchoService.Echo:input_type -> ease.gateway.examples.proto.SimpleMessage - 1, // 3: ease.gateway.examples.proto.EchoService.EchoBody:input_type -> ease.gateway.examples.proto.SimpleMessage - 1, // 4: ease.gateway.examples.proto.EchoService.EchoDelete:input_type -> ease.gateway.examples.proto.SimpleMessage - 1, // 5: ease.gateway.examples.proto.EchoService.Echo:output_type -> ease.gateway.examples.proto.SimpleMessage - 1, // 6: ease.gateway.examples.proto.EchoService.EchoBody:output_type -> ease.gateway.examples.proto.SimpleMessage - 1, // 7: ease.gateway.examples.proto.EchoService.EchoDelete:output_type -> ease.gateway.examples.proto.SimpleMessage + 0, // 0: grpc.gateway.examples.proto.SimpleMessage.status:type_name -> grpc.gateway.examples.proto.Embedded + 0, // 1: grpc.gateway.examples.proto.SimpleMessage.no:type_name -> grpc.gateway.examples.proto.Embedded + 1, // 2: grpc.gateway.examples.proto.EchoService.Echo:input_type -> grpc.gateway.examples.proto.SimpleMessage + 1, // 3: grpc.gateway.examples.proto.EchoService.EchoBody:input_type -> grpc.gateway.examples.proto.SimpleMessage + 1, // 4: grpc.gateway.examples.proto.EchoService.EchoDelete:input_type -> grpc.gateway.examples.proto.SimpleMessage + 1, // 5: grpc.gateway.examples.proto.EchoService.Echo:output_type -> grpc.gateway.examples.proto.SimpleMessage + 1, // 6: grpc.gateway.examples.proto.EchoService.EchoBody:output_type -> grpc.gateway.examples.proto.SimpleMessage + 1, // 7: grpc.gateway.examples.proto.EchoService.EchoDelete:output_type -> grpc.gateway.examples.proto.SimpleMessage 5, // [5:8] is the sub-list for method output_type 2, // [2:5] is the sub-list for method input_type 2, // [2:2] is the sub-list for extension type_name @@ -418,155 +417,3 @@ func file_examples_proto_echo_service_proto_init() { file_examples_proto_echo_service_proto_goTypes = nil file_examples_proto_echo_service_proto_depIdxs = nil } - -// Reference imports to suppress errors if they are not otherwise used. -var _ context.Context -var _ grpc.ClientConnInterface - -// 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.SupportPackageIsVersion6 - -// EchoServiceClient is the client API for EchoService service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. -type EchoServiceClient interface { - Echo(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) - EchoBody(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) - EchoDelete(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) -} - -type echoServiceClient struct { - cc grpc.ClientConnInterface -} - -func NewEchoServiceClient(cc grpc.ClientConnInterface) EchoServiceClient { - return &echoServiceClient{cc} -} - -func (c *echoServiceClient) Echo(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) { - out := new(SimpleMessage) - err := c.cc.Invoke(ctx, "/ease.gateway.examples.proto.EchoService/Echo", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *echoServiceClient) EchoBody(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) { - out := new(SimpleMessage) - err := c.cc.Invoke(ctx, "/ease.gateway.examples.proto.EchoService/EchoBody", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *echoServiceClient) EchoDelete(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) { - out := new(SimpleMessage) - err := c.cc.Invoke(ctx, "/ease.gateway.examples.proto.EchoService/EchoDelete", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -// EchoServiceServer is the server API for EchoService service. -type EchoServiceServer interface { - Echo(context.Context, *SimpleMessage) (*SimpleMessage, error) - EchoBody(context.Context, *SimpleMessage) (*SimpleMessage, error) - EchoDelete(context.Context, *SimpleMessage) (*SimpleMessage, error) -} - -// UnimplementedEchoServiceServer can be embedded to have forward compatible implementations. -type UnimplementedEchoServiceServer struct { -} - -func (*UnimplementedEchoServiceServer) Echo(context.Context, *SimpleMessage) (*SimpleMessage, error) { - return nil, status.Errorf(codes.Unimplemented, "method Echo not implemented") -} -func (*UnimplementedEchoServiceServer) EchoBody(context.Context, *SimpleMessage) (*SimpleMessage, error) { - return nil, status.Errorf(codes.Unimplemented, "method EchoBody not implemented") -} -func (*UnimplementedEchoServiceServer) EchoDelete(context.Context, *SimpleMessage) (*SimpleMessage, error) { - return nil, status.Errorf(codes.Unimplemented, "method EchoDelete not implemented") -} - -func RegisterEchoServiceServer(s *grpc.Server, srv EchoServiceServer) { - s.RegisterService(&_EchoService_serviceDesc, srv) -} - -func _EchoService_Echo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(SimpleMessage) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(EchoServiceServer).Echo(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/ease.gateway.examples.proto.EchoService/Echo", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(EchoServiceServer).Echo(ctx, req.(*SimpleMessage)) - } - return interceptor(ctx, in, info, handler) -} - -func _EchoService_EchoBody_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(SimpleMessage) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(EchoServiceServer).EchoBody(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/ease.gateway.examples.proto.EchoService/EchoBody", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(EchoServiceServer).EchoBody(ctx, req.(*SimpleMessage)) - } - return interceptor(ctx, in, info, handler) -} - -func _EchoService_EchoDelete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(SimpleMessage) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(EchoServiceServer).EchoDelete(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/ease.gateway.examples.proto.EchoService/EchoDelete", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(EchoServiceServer).EchoDelete(ctx, req.(*SimpleMessage)) - } - return interceptor(ctx, in, info, handler) -} - -var _EchoService_serviceDesc = grpc.ServiceDesc{ - ServiceName: "ease.gateway.examples.proto.EchoService", - HandlerType: (*EchoServiceServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "Echo", - Handler: _EchoService_Echo_Handler, - }, - { - MethodName: "EchoBody", - Handler: _EchoService_EchoBody_Handler, - }, - { - MethodName: "EchoDelete", - Handler: _EchoService_EchoDelete_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "examples/proto/echo_service.proto", -} diff --git a/examples/proto/echo_service.pb.gw.go b/examples/proto/echo_service.pb.gw.go index b55bcff..42bec24 100755 --- a/examples/proto/echo_service.pb.gw.go +++ b/examples/proto/echo_service.pb.gw.go @@ -25,13 +25,13 @@ import ( "github.com/binchencoder/skylb-api/client" "github.com/binchencoder/skylb-api/client/option" skypb "github.com/binchencoder/skylb-api/proto" - "github.com/golang/protobuf/proto" - "github.com/grpc-ecosystem/grpc-gateway/utilities" + "github.com/grpc-ecosystem/grpc-gateway/v2/utilities" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/grpclog" "google.golang.org/grpc/naming" "google.golang.org/grpc/status" + "google.golang.org/protobuf/proto" ) // Suppress "imported and not used" errors @@ -86,7 +86,6 @@ func request_EchoService_Echo_0(ctx context.Context, marshaler runtime.Marshaler } protoReq.Id, err = runtime.String(val) - if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } @@ -128,7 +127,6 @@ func local_request_EchoService_Echo_0(ctx context.Context, marshaler runtime.Mar } protoReq.Id, err = runtime.String(val) - if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } @@ -168,7 +166,6 @@ func request_EchoService_Echo_1(ctx context.Context, marshaler runtime.Marshaler } protoReq.Id, err = runtime.String(val) - if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } @@ -180,7 +177,6 @@ func request_EchoService_Echo_1(ctx context.Context, marshaler runtime.Marshaler } protoReq.Num, err = runtime.Int64(val) - if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "num", err) } @@ -222,7 +218,6 @@ func local_request_EchoService_Echo_1(ctx context.Context, marshaler runtime.Mar } protoReq.Id, err = runtime.String(val) - if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } @@ -233,7 +228,6 @@ func local_request_EchoService_Echo_1(ctx context.Context, marshaler runtime.Mar } protoReq.Num, err = runtime.Int64(val) - if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "num", err) } @@ -273,7 +267,6 @@ func request_EchoService_Echo_2(ctx context.Context, marshaler runtime.Marshaler } protoReq.Id, err = runtime.String(val) - if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } @@ -285,7 +278,6 @@ func request_EchoService_Echo_2(ctx context.Context, marshaler runtime.Marshaler } protoReq.Num, err = runtime.Int64(val) - if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "num", err) } @@ -302,7 +294,6 @@ func request_EchoService_Echo_2(ctx context.Context, marshaler runtime.Marshaler return nil, metadata, status.Errorf(codes.InvalidArgument, "expect type: *SimpleMessage_Lang, but: %t\n", protoReq.Code) } protoReq.Code.(*SimpleMessage_Lang).Lang, err = runtime.String(val) - if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "lang", err) } @@ -344,7 +335,6 @@ func local_request_EchoService_Echo_2(ctx context.Context, marshaler runtime.Mar } protoReq.Id, err = runtime.String(val) - if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } @@ -355,7 +345,6 @@ func local_request_EchoService_Echo_2(ctx context.Context, marshaler runtime.Mar } protoReq.Num, err = runtime.Int64(val) - if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "num", err) } @@ -371,7 +360,6 @@ func local_request_EchoService_Echo_2(ctx context.Context, marshaler runtime.Mar return nil, metadata, status.Errorf(codes.InvalidArgument, "expect type: *SimpleMessage_Lang, but: %t\n", protoReq.Code) } protoReq.Code.(*SimpleMessage_Lang).Lang, err = runtime.String(val) - if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "lang", err) } @@ -411,7 +399,6 @@ func request_EchoService_Echo_3(ctx context.Context, marshaler runtime.Marshaler } protoReq.Id, err = runtime.String(val) - if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } @@ -428,7 +415,6 @@ func request_EchoService_Echo_3(ctx context.Context, marshaler runtime.Marshaler return nil, metadata, status.Errorf(codes.InvalidArgument, "expect type: *SimpleMessage_LineNum, but: %t\n", protoReq.Code) } protoReq.Code.(*SimpleMessage_LineNum).LineNum, err = runtime.Int64(val) - if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "line_num", err) } @@ -440,7 +426,6 @@ func request_EchoService_Echo_3(ctx context.Context, marshaler runtime.Marshaler } err = runtime.PopulateFieldFromPath(&protoReq, "status.note", val) - if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "status.note", err) } @@ -482,7 +467,6 @@ func local_request_EchoService_Echo_3(ctx context.Context, marshaler runtime.Mar } protoReq.Id, err = runtime.String(val) - if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } @@ -498,7 +482,6 @@ func local_request_EchoService_Echo_3(ctx context.Context, marshaler runtime.Mar return nil, metadata, status.Errorf(codes.InvalidArgument, "expect type: *SimpleMessage_LineNum, but: %t\n", protoReq.Code) } protoReq.Code.(*SimpleMessage_LineNum).LineNum, err = runtime.Int64(val) - if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "line_num", err) } @@ -509,7 +492,6 @@ func local_request_EchoService_Echo_3(ctx context.Context, marshaler runtime.Mar } err = runtime.PopulateFieldFromPath(&protoReq, "status.note", val) - if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "status.note", err) } @@ -549,7 +531,6 @@ func request_EchoService_Echo_4(ctx context.Context, marshaler runtime.Marshaler } err = runtime.PopulateFieldFromPath(&protoReq, "no.note", val) - if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "no.note", err) } @@ -591,7 +572,6 @@ func local_request_EchoService_Echo_4(ctx context.Context, marshaler runtime.Mar } err = runtime.PopulateFieldFromPath(&protoReq, "no.note", val) - if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "no.note", err) } @@ -707,7 +687,7 @@ func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.proto.EchoService/Echo") if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -727,7 +707,7 @@ func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.proto.EchoService/Echo") if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -747,7 +727,7 @@ func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.proto.EchoService/Echo") if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -767,7 +747,7 @@ func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.proto.EchoService/Echo") if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -787,7 +767,7 @@ func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.proto.EchoService/Echo") if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -807,7 +787,7 @@ func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.proto.EchoService/EchoBody") if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -827,7 +807,7 @@ func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.proto.EchoService/EchoDelete") if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -913,12 +893,13 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) if client == nil { - runtime.DefaultOtherErrorHandler(w, req, "service disabled", http.StatusInternalServerError) + err := status.Error(codes.Internal, "service disabled") + runtime.HTTPError(inctx, mux, outboundMarshaler, w, req, err) return } - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) if err != nil { grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) @@ -927,7 +908,7 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux } ctx, cancel := context.WithCancel(req.Context()) defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.proto.EchoService/Echo") if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -949,12 +930,13 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) if client == nil { - runtime.DefaultOtherErrorHandler(w, req, "service disabled", http.StatusInternalServerError) + err := status.Error(codes.Internal, "service disabled") + runtime.HTTPError(inctx, mux, outboundMarshaler, w, req, err) return } - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) if err != nil { grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) @@ -963,7 +945,7 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux } ctx, cancel := context.WithCancel(req.Context()) defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.proto.EchoService/Echo") if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -985,12 +967,13 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) if client == nil { - runtime.DefaultOtherErrorHandler(w, req, "service disabled", http.StatusInternalServerError) + err := status.Error(codes.Internal, "service disabled") + runtime.HTTPError(inctx, mux, outboundMarshaler, w, req, err) return } - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) if err != nil { grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) @@ -999,7 +982,7 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux } ctx, cancel := context.WithCancel(req.Context()) defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.proto.EchoService/Echo") if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -1021,12 +1004,13 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) if client == nil { - runtime.DefaultOtherErrorHandler(w, req, "service disabled", http.StatusInternalServerError) + err := status.Error(codes.Internal, "service disabled") + runtime.HTTPError(inctx, mux, outboundMarshaler, w, req, err) return } - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) if err != nil { grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) @@ -1035,7 +1019,7 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux } ctx, cancel := context.WithCancel(req.Context()) defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.proto.EchoService/Echo") if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -1057,12 +1041,13 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) if client == nil { - runtime.DefaultOtherErrorHandler(w, req, "service disabled", http.StatusInternalServerError) + err := status.Error(codes.Internal, "service disabled") + runtime.HTTPError(inctx, mux, outboundMarshaler, w, req, err) return } - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) if err != nil { grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) @@ -1071,7 +1056,7 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux } ctx, cancel := context.WithCancel(req.Context()) defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.proto.EchoService/Echo") if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -1093,12 +1078,13 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) if client == nil { - runtime.DefaultOtherErrorHandler(w, req, "service disabled", http.StatusInternalServerError) + err := status.Error(codes.Internal, "service disabled") + runtime.HTTPError(inctx, mux, outboundMarshaler, w, req, err) return } - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "EchoBody", w, req) if err != nil { grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) @@ -1107,7 +1093,7 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux } ctx, cancel := context.WithCancel(req.Context()) defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.proto.EchoService/EchoBody") if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -1129,12 +1115,13 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) if client == nil { - runtime.DefaultOtherErrorHandler(w, req, "service disabled", http.StatusInternalServerError) + err := status.Error(codes.Internal, "service disabled") + runtime.HTTPError(inctx, mux, outboundMarshaler, w, req, err) return } - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "EchoDelete", w, req) if err != nil { grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) @@ -1143,7 +1130,7 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux } ctx, cancel := context.WithCancel(req.Context()) defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.proto.EchoService/EchoDelete") if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -1207,19 +1194,19 @@ func DisableEchoService_Service() { } var ( - pattern_EchoService_Echo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"v1", "example", "echo", "id"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_EchoService_Echo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"v1", "example", "echo", "id"}, "")) - pattern_EchoService_Echo_1 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 1, 0, 4, 1, 5, 4}, []string{"v1", "example", "echo", "id", "num"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_EchoService_Echo_1 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 1, 0, 4, 1, 5, 4}, []string{"v1", "example", "echo", "id", "num"}, "")) - pattern_EchoService_Echo_2 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5}, []string{"v1", "example", "echo", "id", "num", "lang"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_EchoService_Echo_2 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5}, []string{"v1", "example", "echo", "id", "num", "lang"}, "")) - pattern_EchoService_Echo_3 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5}, []string{"v1", "example", "echo1", "id", "line_num", "status.note"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_EchoService_Echo_3 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5}, []string{"v1", "example", "echo1", "id", "line_num", "status.note"}, "")) - pattern_EchoService_Echo_4 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"v1", "example", "echo2", "no.note"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_EchoService_Echo_4 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"v1", "example", "echo2", "no.note"}, "")) - pattern_EchoService_EchoBody_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "example", "echo_body"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_EchoService_EchoBody_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "example", "echo_body"}, "")) - pattern_EchoService_EchoDelete_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "example", "echo_delete"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_EchoService_EchoDelete_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "example", "echo_delete"}, "")) ) var ( diff --git a/examples/proto/echo_service.proto b/examples/proto/echo_service.proto index 75777b1..68c0edf 100644 --- a/examples/proto/echo_service.proto +++ b/examples/proto/echo_service.proto @@ -1,11 +1,8 @@ syntax = "proto3"; -option go_package = "proto"; -// Echo Service -// -// Echo Service API consists of a single service which returns -// a message. -package ease.gateway.examples.proto; +option go_package = "github.com/binchencoder/ease-gateway/examples/proto"; + +package grpc.gateway.examples.proto; // import "google/api/annotations.proto"; import "httpoptions/annotations.proto"; diff --git a/examples/proto/echo_service.swagger.json b/examples/proto/echo_service.swagger.json index 6f9442f..1e37053 100755 --- a/examples/proto/echo_service.swagger.json +++ b/examples/proto/echo_service.swagger.json @@ -1,8 +1,7 @@ { "swagger": "2.0", "info": { - "title": "Echo Service", - "description": "Echo Service API consists of a single service which returns\na message.", + "title": "examples/proto/echo_service.proto", "version": "version not set" }, "consumes": [ @@ -23,12 +22,6 @@ "schema": { "$ref": "#/definitions/protoSimpleMessage" } - }, - "default": { - "description": "An unexpected error response", - "schema": { - "$ref": "#/definitions/gatewayruntimeError" - } } }, "parameters": [ @@ -56,12 +49,6 @@ "schema": { "$ref": "#/definitions/protoSimpleMessage" } - }, - "default": { - "description": "An unexpected error response", - "schema": { - "$ref": "#/definitions/gatewayruntimeError" - } } }, "parameters": [ @@ -80,7 +67,7 @@ "format": "int64" }, { - "name": "line_num", + "name": "lineNum", "in": "query", "required": false, "type": "string", @@ -142,12 +129,6 @@ "schema": { "$ref": "#/definitions/protoSimpleMessage" } - }, - "default": { - "description": "An unexpected error response", - "schema": { - "$ref": "#/definitions/gatewayruntimeError" - } } }, "parameters": [ @@ -172,7 +153,7 @@ "type": "string" }, { - "name": "line_num", + "name": "lineNum", "in": "query", "required": false, "type": "string", @@ -217,7 +198,7 @@ ] } }, - "/v1/example/echo1/{id}/{line_num}/{status.note}": { + "/v1/example/echo1/{id}/{lineNum}/{status.note}": { "get": { "summary": "Echo method receives a simple message and returns it.", "description": "The message posted as the id parameter will also be\nreturned.", @@ -228,12 +209,6 @@ "schema": { "$ref": "#/definitions/protoSimpleMessage" } - }, - "default": { - "description": "An unexpected error response", - "schema": { - "$ref": "#/definitions/gatewayruntimeError" - } } }, "parameters": [ @@ -245,7 +220,7 @@ "type": "string" }, { - "name": "line_num", + "name": "lineNum", "in": "path", "required": true, "type": "string", @@ -308,12 +283,6 @@ "schema": { "$ref": "#/definitions/protoSimpleMessage" } - }, - "default": { - "description": "An unexpected error response", - "schema": { - "$ref": "#/definitions/gatewayruntimeError" - } } }, "parameters": [ @@ -338,7 +307,7 @@ "format": "int64" }, { - "name": "line_num", + "name": "lineNum", "in": "query", "required": false, "type": "string", @@ -387,12 +356,6 @@ "schema": { "$ref": "#/definitions/protoSimpleMessage" } - }, - "default": { - "description": "An unexpected error response", - "schema": { - "$ref": "#/definitions/gatewayruntimeError" - } } }, "parameters": [ @@ -420,12 +383,6 @@ "schema": { "$ref": "#/definitions/protoSimpleMessage" } - }, - "default": { - "description": "An unexpected error response", - "schema": { - "$ref": "#/definitions/gatewayruntimeError" - } } }, "parameters": [ @@ -444,7 +401,7 @@ "format": "int64" }, { - "name": "line_num", + "name": "lineNum", "in": "query", "required": false, "type": "string", @@ -497,101 +454,6 @@ } }, "definitions": { - "frontendError": { - "type": "object", - "properties": { - "code": { - "$ref": "#/definitions/frontendErrorCode", - "description": "The general error code." - }, - "params": { - "type": "array", - "items": { - "type": "string" - }, - "description": "The general parameters with which to render a localized string." - }, - "debug": { - "type": "string", - "description": "The debug information. Only populated in DEV, TEST, and QA environment.\nIn PROD environment it will be stripped off before returning to the\nclient." - }, - "details": { - "type": "array", - "items": { - "$ref": "#/definitions/frontendErrorMessage" - }, - "description": "The detailed error messages." - } - }, - "description": "message GetMyMemosResponse {\n frontend.Error error = 1;\n\n int32 current_page = 2;\n int32 page_total = 3;\n string continue_token = 4;\n\n repeated MemoMsg memos = 5;\n }", - "title": "The error wrapper message. All frontend messages should contain exactly\none field with this message as the first field. Example:" - }, - "frontendErrorCode": { - "type": "string", - "enum": [ - "NONE", - "SERVICE_DOWN", - "SERVICE_INTERNAL_ERROR", - "SERVICE_INTERNAL_ACCIDENTAL_ERROR", - "SERVICE_BAD_PARAM_ERROR", - "SERVICE_UNREACHABLE_CODE", - "UNDEFINED", - "BADPARAM_ERROR", - "RESOURCE_NOT_FOUND", - "BAD_REQUEST", - "AUTHEN_ERROR", - "SERVER_ERROR", - "NORIGHT_ERROR", - "NODATA_ERROR", - "USER_ERROR", - "INVALID_SIGNATURE", - "IGOAL_DUPLICATE_TAG", - "IGOAL_NO_ONLINE_TMPL_MANAGE_PERMISSION", - "IGOAL_IMPORT_TEMPLATE_FILE_SIZE_EXCEEDED", - "IGOAL_VERSION_CONFLICT_ERROR", - "IGOAL_DOC_UPLOAD_FILE_NUMBER_EXCEEDED" - ], - "default": "NONE", - "description": "/### Enum for all error codes.\n/### Localization Guide for error codes. Error code which requires Localization\n/### need to provide a //@Trans chinese comment on the above line.\n\n - SERVICE_DOWN: /### 100000 - 120000 Common error\n@Trans 当前服务正在维护,请稍后再试.\n - SERVICE_INTERNAL_ERROR: @Trans 当前服务内部错误,请稍后再试.\n - SERVICE_INTERNAL_ACCIDENTAL_ERROR: @Trans 找不到意中的“它”,请稍后重试!\n - SERVICE_BAD_PARAM_ERROR: @Trans 程序参数错误.\n - SERVICE_UNREACHABLE_CODE: @Trans 程序编码错误.\n - UNDEFINED: @Trans Undefined error.\n - BADPARAM_ERROR: @Trans 参数不合法\n - RESOURCE_NOT_FOUND: @Trans 无法找到\n - BAD_REQUEST: @Trans 无效请求\n - AUTHEN_ERROR: /### 500500-500999: Common error codes.\n@Trans 用户认证失败,需重新登录\n - SERVER_ERROR: @Trans 服务器端错误\n - NORIGHT_ERROR: @Trans 权限不足\n - NODATA_ERROR: @Trans 数据不存在或已删除\n - USER_ERROR: @Trans 用户不存在或已停用\n - INVALID_SIGNATURE: @Trans 无效验签\n - IGOAL_DUPLICATE_TAG: @Trans 主线分类名称重复!\n - IGOAL_NO_ONLINE_TMPL_MANAGE_PERMISSION: @Trans 您无权限进行此操作!\n - IGOAL_IMPORT_TEMPLATE_FILE_SIZE_EXCEEDED: @Trans 模板文件大小超限!\n - IGOAL_VERSION_CONFLICT_ERROR: @Trans 系统开小差了,请稍后尝试!\n - IGOAL_DOC_UPLOAD_FILE_NUMBER_EXCEEDED: @Trans 上传文件数量超过上限!" - }, - "frontendErrorMessage": { - "type": "object", - "properties": { - "code": { - "$ref": "#/definitions/frontendErrorCode", - "description": "The error code." - }, - "params": { - "type": "array", - "items": { - "type": "string" - }, - "description": "The parameters used to render a localized string." - } - }, - "description": "An error message including its error code and the parameters to render\na localized string." - }, - "gatewayruntimeError": { - "type": "object", - "properties": { - "error": { - "$ref": "#/definitions/frontendError" - }, - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "$ref": "#/definitions/protobufAny" - } - } - } - }, "protoEmbedded": { "type": "object", "properties": { @@ -616,7 +478,7 @@ "type": "string", "format": "int64" }, - "line_num": { + "lineNum": { "type": "string", "format": "int64" }, @@ -635,18 +497,6 @@ } }, "description": "SimpleMessage represents a simple message sent to the Echo service." - }, - "protobufAny": { - "type": "object", - "properties": { - "type_url": { - "type": "string" - }, - "value": { - "type": "string", - "format": "byte" - } - } } } } diff --git a/examples/proto/echo_service_grpc.pb.go b/examples/proto/echo_service_grpc.pb.go new file mode 100755 index 0000000..95e61da --- /dev/null +++ b/examples/proto/echo_service_grpc.pb.go @@ -0,0 +1,158 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. + +package proto + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// 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.SupportPackageIsVersion6 + +// EchoServiceClient is the client API for EchoService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type EchoServiceClient interface { + Echo(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) + EchoBody(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) + EchoDelete(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) +} + +type echoServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewEchoServiceClient(cc grpc.ClientConnInterface) EchoServiceClient { + return &echoServiceClient{cc} +} + +func (c *echoServiceClient) Echo(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) { + out := new(SimpleMessage) + err := c.cc.Invoke(ctx, "/grpc.gateway.examples.proto.EchoService/Echo", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *echoServiceClient) EchoBody(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) { + out := new(SimpleMessage) + err := c.cc.Invoke(ctx, "/grpc.gateway.examples.proto.EchoService/EchoBody", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *echoServiceClient) EchoDelete(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) { + out := new(SimpleMessage) + err := c.cc.Invoke(ctx, "/grpc.gateway.examples.proto.EchoService/EchoDelete", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// EchoServiceServer is the server API for EchoService service. +type EchoServiceServer interface { + Echo(context.Context, *SimpleMessage) (*SimpleMessage, error) + EchoBody(context.Context, *SimpleMessage) (*SimpleMessage, error) + EchoDelete(context.Context, *SimpleMessage) (*SimpleMessage, error) +} + +// UnimplementedEchoServiceServer can be embedded to have forward compatible implementations. +type UnimplementedEchoServiceServer struct { +} + +func (*UnimplementedEchoServiceServer) Echo(context.Context, *SimpleMessage) (*SimpleMessage, error) { + return nil, status.Errorf(codes.Unimplemented, "method Echo not implemented") +} +func (*UnimplementedEchoServiceServer) EchoBody(context.Context, *SimpleMessage) (*SimpleMessage, error) { + return nil, status.Errorf(codes.Unimplemented, "method EchoBody not implemented") +} +func (*UnimplementedEchoServiceServer) EchoDelete(context.Context, *SimpleMessage) (*SimpleMessage, error) { + return nil, status.Errorf(codes.Unimplemented, "method EchoDelete not implemented") +} + +func RegisterEchoServiceServer(s *grpc.Server, srv EchoServiceServer) { + s.RegisterService(&_EchoService_serviceDesc, srv) +} + +func _EchoService_Echo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SimpleMessage) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(EchoServiceServer).Echo(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/grpc.gateway.examples.proto.EchoService/Echo", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(EchoServiceServer).Echo(ctx, req.(*SimpleMessage)) + } + return interceptor(ctx, in, info, handler) +} + +func _EchoService_EchoBody_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SimpleMessage) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(EchoServiceServer).EchoBody(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/grpc.gateway.examples.proto.EchoService/EchoBody", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(EchoServiceServer).EchoBody(ctx, req.(*SimpleMessage)) + } + return interceptor(ctx, in, info, handler) +} + +func _EchoService_EchoDelete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SimpleMessage) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(EchoServiceServer).EchoDelete(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/grpc.gateway.examples.proto.EchoService/EchoDelete", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(EchoServiceServer).EchoDelete(ctx, req.(*SimpleMessage)) + } + return interceptor(ctx, in, info, handler) +} + +var _EchoService_serviceDesc = grpc.ServiceDesc{ + ServiceName: "grpc.gateway.examples.proto.EchoService", + HandlerType: (*EchoServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Echo", + Handler: _EchoService_Echo_Handler, + }, + { + MethodName: "EchoBody", + Handler: _EchoService_EchoBody_Handler, + }, + { + MethodName: "EchoDelete", + Handler: _EchoService_EchoDelete_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "examples/proto/echo_service.proto", +} diff --git a/gateway/HISTORY.md b/gateway/HISTORY.md index 69c9781..633565c 100644 --- a/gateway/HISTORY.md +++ b/gateway/HISTORY.md @@ -69,7 +69,7 @@ Pull message 更新 fdf0635..b6e6efb Fast-forward docs/_docs/customizingyourgateway.md | 22 ++++++++++++++++++++++ - protoc-gen-swagger/genswagger/BUILD.bazel | 1 + - protoc-gen-swagger/genswagger/template.go | 34 +++++++++++++++++++++++++++++----- - protoc-gen-swagger/genswagger/template_test.go | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- + protoc-gen-openapiv2/internal/genopenapi/BUILD.bazel | 1 + + protoc-gen-openapiv2/internal/genopenapi/template.go | 34 +++++++++++++++++++++++++++++----- + protoc-gen-openapiv2/internal/genopenapi/template_test.go | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- ``` \ No newline at end of file diff --git a/gateway/README.md b/gateway/README.md index dc093f8..961e4e2 100644 --- a/gateway/README.md +++ b/gateway/README.md @@ -72,11 +72,11 @@ protoc -I/usr/local/include -I. \ - template_test.go - template.go -## protoc-gen-swagger +## protoc-gen-openapiv2 -Link [grpc-ecosystem/grpc-gateway/protoc-gen-swagger](https://github.com/grpc-ecosystem/grpc-gateway/tree/master/protoc-gen-swagger) +Link [grpc-ecosystem/grpc-gateway/protoc-gen-openapiv2](https://github.com/grpc-ecosystem/grpc-gateway/tree/master/protoc-gen-openapiv2) -```protoc-gen-swagger``` 是生成swagger API定义的工具 +```protoc-gen-openapiv2``` 是生成swagger API定义的工具 修改文件: diff --git a/gateway/internal/codegenerator/BUILD.bazel b/gateway/internal/codegenerator/BUILD.bazel new file mode 100644 index 0000000..fd9ba63 --- /dev/null +++ b/gateway/internal/codegenerator/BUILD.bazel @@ -0,0 +1,28 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +package(default_visibility = ["//visibility:public"]) + +go_library( + name = "go_default_library", + srcs = [ + "doc.go", + "parse_req.go", + ], + importpath = "github.com/binchencoder/ease-gateway/gateway/internal/codegenerator", + deps = [ + "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", + "@org_golang_google_protobuf//proto:go_default_library", + ], +) + +go_test( + name = "go_default_test", + srcs = ["parse_req_test.go"], + embed = [":go_default_library"], + deps = [ + "@com_github_google_go_cmp//cmp:go_default_library", + "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", + "@org_golang_google_protobuf//proto:go_default_library", + "@org_golang_google_protobuf//testing/protocmp:go_default_library", + ], +) diff --git a/gateway/internal/codegenerator/doc.go b/gateway/internal/codegenerator/doc.go new file mode 100644 index 0000000..3645317 --- /dev/null +++ b/gateway/internal/codegenerator/doc.go @@ -0,0 +1,4 @@ +/* +Package codegenerator contains reusable functions used by the code generators. +*/ +package codegenerator diff --git a/gateway/internal/codegenerator/parse_req.go b/gateway/internal/codegenerator/parse_req.go new file mode 100644 index 0000000..dd489f0 --- /dev/null +++ b/gateway/internal/codegenerator/parse_req.go @@ -0,0 +1,23 @@ +package codegenerator + +import ( + "fmt" + "io" + "io/ioutil" + + pluginpb "github.com/golang/protobuf/protoc-gen-go/plugin" + "google.golang.org/protobuf/proto" +) + +// ParseRequest parses a code generator request from a proto Message. +func ParseRequest(r io.Reader) (*pluginpb.CodeGeneratorRequest, error) { + input, err := ioutil.ReadAll(r) + if err != nil { + return nil, fmt.Errorf("failed to read code generator request: %v", err) + } + req := new(pluginpb.CodeGeneratorRequest) + if err = proto.Unmarshal(input, req); err != nil { + return nil, fmt.Errorf("failed to unmarshal code generator request: %v", err) + } + return req, nil +} diff --git a/gateway/internal/codegenerator/parse_req_test.go b/gateway/internal/codegenerator/parse_req_test.go new file mode 100644 index 0000000..c4926eb --- /dev/null +++ b/gateway/internal/codegenerator/parse_req_test.go @@ -0,0 +1,72 @@ +package codegenerator_test + +import ( + "bytes" + "fmt" + "io" + "reflect" + "strings" + "testing" + + pluginpb "github.com/golang/protobuf/protoc-gen-go/plugin" + "github.com/google/go-cmp/cmp" + // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/codegenerator" + "github.com/binchencoder/ease-gateway/gateway/internal/codegenerator" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/testing/protocmp" +) + +var parseReqTests = []struct { + name string + in io.Reader + out *pluginpb.CodeGeneratorRequest + err error +}{ + { + "Empty input should produce empty output", + mustGetReader(&pluginpb.CodeGeneratorRequest{}), + &pluginpb.CodeGeneratorRequest{}, + nil, + }, + { + "Invalid reader should produce error", + &invalidReader{}, + nil, + fmt.Errorf("failed to read code generator request: invalid reader"), + }, + { + "Invalid proto message should produce error", + strings.NewReader("{}"), + nil, + fmt.Errorf("failed to unmarshal code generator request: unexpected EOF"), + }, +} + +func TestParseRequest(t *testing.T) { + for _, tt := range parseReqTests { + t.Run(tt.name, func(t *testing.T) { + out, err := codegenerator.ParseRequest(tt.in) + if !reflect.DeepEqual(err, tt.err) { + t.Errorf("got %v, want %v", err, tt.err) + } + if diff := cmp.Diff(out, tt.out, protocmp.Transform()); diff != "" { + t.Errorf(diff) + } + }) + } +} + +func mustGetReader(pb proto.Message) io.Reader { + b, err := proto.Marshal(pb) + if err != nil { + panic(err) + } + return bytes.NewBuffer(b) +} + +type invalidReader struct { +} + +func (*invalidReader) Read(p []byte) (int, error) { + return 0, fmt.Errorf("invalid reader") +} diff --git a/gateway/protoc-gen-grpc-gateway/descriptor/BUILD.bazel b/gateway/internal/descriptor/BUILD.bazel similarity index 64% rename from gateway/protoc-gen-grpc-gateway/descriptor/BUILD.bazel rename to gateway/internal/descriptor/BUILD.bazel index 661c734..2b846ca 100644 --- a/gateway/protoc-gen-grpc-gateway/descriptor/BUILD.bazel +++ b/gateway/internal/descriptor/BUILD.bazel @@ -6,24 +6,23 @@ go_library( name = "go_default_library", srcs = [ "grpc_api_configuration.go", - "grpc_api_service.go", "registry.go", "services.go", "types.go", ], - importpath = "github.com/binchencoder/ease-gateway/gateway/protoc-gen-grpc-gateway/descriptor", + importpath = "github.com/binchencoder/ease-gateway/gateway/internal/descriptor", deps = [ "//gateway/internal/casing:go_default_library", + "//gateway/internal/descriptor/apiconfig:go_default_library", "//httpoptions:go_default_library", "@com_github_binchencoder_gateway_proto//data:go_default_library", "@com_github_ghodss_yaml//:go_default_library", "@com_github_golang_glog//:go_default_library", - "@com_github_golang_protobuf//jsonpb:go_default_library_gen", - "@com_github_golang_protobuf//proto:go_default_library", - "@com_github_golang_protobuf//protoc-gen-go/generator:go_default_library_gen", - "@com_github_grpc_ecosystem_grpc_gateway//protoc-gen-grpc-gateway/httprule:go_default_library", + "@com_github_grpc_ecosystem_grpc_gateway//internal/httprule:go_default_library", "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", "@io_bazel_rules_go//proto/wkt:descriptor_go_proto", + "@org_golang_google_protobuf//encoding/protojson:go_default_library", + "@org_golang_google_protobuf//proto:go_default_library", ], ) @@ -38,9 +37,10 @@ go_test( ], embed = [":go_default_library"], deps = [ - "@com_github_golang_protobuf//proto:go_default_library", - "@com_github_grpc_ecosystem_grpc_gateway//protoc-gen-grpc-gateway/httprule:go_default_library", + "@com_github_grpc_ecosystem_grpc_gateway//internal/httprule:go_default_library", "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", "@io_bazel_rules_go//proto/wkt:descriptor_go_proto", + "@org_golang_google_protobuf//encoding/prototext:go_default_library", + "@org_golang_google_protobuf//proto:go_default_library", ], ) diff --git a/gateway/internal/descriptor/apiconfig/BUILD.bazel b/gateway/internal/descriptor/apiconfig/BUILD.bazel new file mode 100644 index 0000000..66a5dc1 --- /dev/null +++ b/gateway/internal/descriptor/apiconfig/BUILD.bazel @@ -0,0 +1,29 @@ +load("@rules_proto//proto:defs.bzl", "proto_library") +load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") + +package(default_visibility = ["//visibility:public"]) + +proto_library( + name = "apiconfig_proto", + srcs = [ + "apiconfig.proto", + ], + deps = [ + "//httpoptions:options_proto", + ], +) + +go_proto_library( + name = "apiconfig_go_proto", + compilers = ["//:go_apiv2"], + importpath = "github.com/binchencoder/ease-gateway/gateway/internal/descriptor/apiconfig", + proto = ":apiconfig_proto", + deps = ["//httpoptions:options_go_proto"], +) + +go_library( + name = "go_default_library", + embed = [":apiconfig_go_proto"], + importpath = "github.com/binchencoder/ease-gateway/gateway/internal/descriptor/apiconfig", +) diff --git a/gateway/internal/descriptor/apiconfig/apiconfig.proto b/gateway/internal/descriptor/apiconfig/apiconfig.proto new file mode 100644 index 0000000..ed897c2 --- /dev/null +++ b/gateway/internal/descriptor/apiconfig/apiconfig.proto @@ -0,0 +1,21 @@ +syntax = "proto3"; + +package grpc.gateway.internal.descriptor.apiconfig; + +option go_package = "github.com/binchencoder/ease-gateway/gatewayinternal/descriptor/apiconfig"; + +import "httpoptions/http.proto"; + +// GrpcAPIService represents a stripped down version of google.api.Service . +// Compare to https://github.com/googleapis/googleapis/blob/master/google/api/service.proto +// The original imports 23 other protobuf files we are not interested in. If a significant +// subset (>50%) of these start being reproduced in this file we should swap to using the +// full generated version instead. +// +// For the purposes of the gateway generator we only consider a small subset of all +// available features google supports in their service descriptions. Thanks to backwards +// compatibility guarantees by protobuf it is safe for us to remove the other fields. +message GrpcAPIService { + // Http Rule. + ease.api.Http http = 1; +} diff --git a/gateway/protoc-gen-grpc-gateway/descriptor/grpc_api_configuration.go b/gateway/internal/descriptor/grpc_api_configuration.go similarity index 64% rename from gateway/protoc-gen-grpc-gateway/descriptor/grpc_api_configuration.go rename to gateway/internal/descriptor/grpc_api_configuration.go index 0ebc7c8..3cbe319 100644 --- a/gateway/protoc-gen-grpc-gateway/descriptor/grpc_api_configuration.go +++ b/gateway/internal/descriptor/grpc_api_configuration.go @@ -1,44 +1,45 @@ package descriptor import ( - "bytes" "fmt" "io/ioutil" "strings" "github.com/ghodss/yaml" - "github.com/golang/protobuf/jsonpb" + // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor/apiconfig" + "github.com/binchencoder/ease-gateway/gateway/internal/descriptor/apiconfig" + "google.golang.org/protobuf/encoding/protojson" ) -func loadGrpcAPIServiceFromYAML(yamlFileContents []byte, yamlSourceLogName string) (*GrpcAPIService, error) { +func loadGrpcAPIServiceFromYAML(yamlFileContents []byte, yamlSourceLogName string) (*apiconfig.GrpcAPIService, error) { jsonContents, err := yaml.YAMLToJSON(yamlFileContents) if err != nil { - return nil, fmt.Errorf("Failed to convert gRPC API Configuration from YAML in '%v' to JSON: %v", yamlSourceLogName, err) + return nil, fmt.Errorf("failed to convert gRPC API Configuration from YAML in '%v' to JSON: %v", yamlSourceLogName, err) } - // As our GrpcAPIService is incomplete accept unknown fields. - unmarshaler := jsonpb.Unmarshaler{ - AllowUnknownFields: true, + // As our GrpcAPIService is incomplete, accept unknown fields. + unmarshaler := protojson.UnmarshalOptions{ + DiscardUnknown: true, } - serviceConfiguration := GrpcAPIService{} - if err := unmarshaler.Unmarshal(bytes.NewReader(jsonContents), &serviceConfiguration); err != nil { - return nil, fmt.Errorf("Failed to parse gRPC API Configuration from YAML in '%v': %v", yamlSourceLogName, err) + serviceConfiguration := apiconfig.GrpcAPIService{} + if err := unmarshaler.Unmarshal(jsonContents, &serviceConfiguration); err != nil { + return nil, fmt.Errorf("failed to parse gRPC API Configuration from YAML in '%v': %v", yamlSourceLogName, err) } return &serviceConfiguration, nil } -func registerHTTPRulesFromGrpcAPIService(registry *Registry, service *GrpcAPIService, sourceLogName string) error { - if service.HTTP == nil { +func registerHTTPRulesFromGrpcAPIService(registry *Registry, service *apiconfig.GrpcAPIService, sourceLogName string) error { + if service.Http == nil { // Nothing to do return nil } - for _, rule := range service.HTTP.GetRules() { + for _, rule := range service.Http.GetRules() { selector := "." + strings.Trim(rule.GetSelector(), " ") if strings.ContainsAny(selector, "*, ") { - return fmt.Errorf("Selector '%v' in %v must specify a single service method without wildcards", rule.GetSelector(), sourceLogName) + return fmt.Errorf("selector '%v' in %v must specify a single service method without wildcards", rule.GetSelector(), sourceLogName) } registry.AddExternalHTTPRule(selector, rule) @@ -59,7 +60,7 @@ func registerHTTPRulesFromGrpcAPIService(registry *Registry, service *GrpcAPISer func (r *Registry) LoadGrpcAPIServiceFromYAML(yamlFile string) error { yamlFileContents, err := ioutil.ReadFile(yamlFile) if err != nil { - return fmt.Errorf("Failed to read gRPC API Configuration description from '%v': %v", yamlFile, err) + return fmt.Errorf("failed to read gRPC API Configuration description from '%v': %v", yamlFile, err) } service, err := loadGrpcAPIServiceFromYAML(yamlFileContents, yamlFile) diff --git a/gateway/protoc-gen-grpc-gateway/descriptor/grpc_api_configuration_test.go b/gateway/internal/descriptor/grpc_api_configuration_test.go similarity index 84% rename from gateway/protoc-gen-grpc-gateway/descriptor/grpc_api_configuration_test.go rename to gateway/internal/descriptor/grpc_api_configuration_test.go index cc6cb44..09cf0a8 100644 --- a/gateway/protoc-gen-grpc-gateway/descriptor/grpc_api_configuration_test.go +++ b/gateway/internal/descriptor/grpc_api_configuration_test.go @@ -1,164 +1,149 @@ -package descriptor - -import ( - "strings" - "testing" -) - -func TestLoadGrpcAPIServiceFromYAMLEmpty(t *testing.T) { - service, err := loadGrpcAPIServiceFromYAML([]byte(``), "empty") - if err != nil { - t.Fatal(err) - } - - if service == nil { - t.Fatal("No service returned") - } - - if service.HTTP != nil { - t.Fatal("HTTP not empty") - } -} - -func TestLoadGrpcAPIServiceFromYAMLInvalidType(t *testing.T) { - // Ideally this would fail but for now this test documents that it doesn't - service, err := loadGrpcAPIServiceFromYAML([]byte(`type: not.the.right.type`), "invalidtype") - if err != nil { - t.Fatal(err) - } - - if service == nil { - t.Fatal("No service returned") - } -} - -func TestLoadGrpcAPIServiceFromYAMLSingleRule(t *testing.T) { - service, err := loadGrpcAPIServiceFromYAML([]byte(` -type: google.api.Service -config_version: 3 - -http: - rules: - - selector: grpctest.YourService.Echo - post: /v1/myecho - body: "*" -`), "example") - if err != nil { - t.Fatal(err) - } - - if service.HTTP == nil { - t.Fatal("HTTP is empty") - } - - if len(service.HTTP.GetRules()) != 1 { - t.Fatalf("Have %v rules instead of one. Got: %v", len(service.HTTP.GetRules()), service.HTTP.GetRules()) - } - - rule := service.HTTP.GetRules()[0] - if rule.GetSelector() != "grpctest.YourService.Echo" { - t.Errorf("Rule has unexpected selector '%v'", rule.GetSelector()) - } - if rule.GetPost() != "/v1/myecho" { - t.Errorf("Rule has unexpected post '%v'", rule.GetPost()) - } - if rule.GetBody() != "*" { - t.Errorf("Rule has unexpected body '%v'", rule.GetBody()) - } -} - -func TestLoadGrpcAPIServiceFromYAMLRejectInvalidYAML(t *testing.T) { - service, err := loadGrpcAPIServiceFromYAML([]byte(` -type: google.api.Service -config_version: 3 - -http: - rules: - - selector: grpctest.YourService.Echo - - post: thislinebreakstheselectorblockabovewiththeleadingdash - body: "*" -`), "invalidyaml") - if err == nil { - t.Fatal(err) - } - - if !strings.Contains(err.Error(), "line 7") { - t.Errorf("Expected yaml error to be detected in line 7. Got other error: %v", err) - } - - if service != nil { - t.Fatal("Service returned") - } -} - -func TestLoadGrpcAPIServiceFromYAMLMultipleWithAdditionalBindings(t *testing.T) { - service, err := loadGrpcAPIServiceFromYAML([]byte(` -type: google.api.Service -config_version: 3 - -http: - rules: - - selector: first.selector - post: /my/post/path - body: "*" - additional_bindings: - - post: /additional/post/path - - put: /additional/put/{value}/path - - delete: "{value}" - - patch: "/additional/patch/{value}" - - selector: some.other.service - delete: foo -`), "example") - if err != nil { - t.Fatalf("Failed to load service description from YAML: %v", err) - } - - if service == nil { - t.Fatal("No service returned") - } - - if service.HTTP == nil { - t.Fatal("HTTP is empty") - } - - if len(service.HTTP.GetRules()) != 2 { - t.Fatalf("%v service(s) returned when two were expected. Got: %v", len(service.HTTP.GetRules()), service.HTTP) - } - - first := service.HTTP.GetRules()[0] - if first.GetSelector() != "first.selector" { - t.Errorf("first.selector has unexpected selector '%v'", first.GetSelector()) - } - if first.GetBody() != "*" { - t.Errorf("first.selector has unexpected body '%v'", first.GetBody()) - } - if first.GetPost() != "/my/post/path" { - t.Errorf("first.selector has unexpected post '%v'", first.GetPost()) - } - if len(first.GetAdditionalBindings()) != 4 { - t.Fatalf("first.selector has unexpected number of bindings %v instead of four. Got: %v", len(first.GetAdditionalBindings()), first.GetAdditionalBindings()) - } - if first.GetAdditionalBindings()[0].GetPost() != "/additional/post/path" { - t.Errorf("first.selector additional binding 0 has unexpected post '%v'", first.GetAdditionalBindings()[0].GetPost()) - } - if first.GetAdditionalBindings()[1].GetPut() != "/additional/put/{value}/path" { - t.Errorf("first.selector additional binding 1 has unexpected put '%v'", first.GetAdditionalBindings()[0].GetPost()) - } - if first.GetAdditionalBindings()[2].GetDelete() != "{value}" { - t.Errorf("first.selector additional binding 2 has unexpected delete '%v'", first.GetAdditionalBindings()[0].GetPost()) - } - if first.GetAdditionalBindings()[3].GetPatch() != "/additional/patch/{value}" { - t.Errorf("first.selector additional binding 3 has unexpected patch '%v'", first.GetAdditionalBindings()[0].GetPost()) - } - - second := service.HTTP.GetRules()[1] - if second.GetSelector() != "some.other.service" { - t.Errorf("some.other.service has unexpected selector '%v'", second.GetSelector()) - } - if second.GetDelete() != "foo" { - t.Errorf("some.other.service has unexpected delete '%v'", second.GetDelete()) - } - if len(second.GetAdditionalBindings()) != 0 { - t.Errorf("some.other.service has %v additional bindings when it should not have any. Got: %v", len(second.GetAdditionalBindings()), second.GetAdditionalBindings()) - } -} +package descriptor + +import ( + "strings" + "testing" +) + +func TestLoadGrpcAPIServiceFromYAMLInvalidType(t *testing.T) { + // Ideally this would fail but for now this test documents that it doesn't + service, err := loadGrpcAPIServiceFromYAML([]byte(`type: not.the.right.type`), "invalidtype") + if err != nil { + t.Fatal(err) + } + + if service == nil { + t.Fatal("No service returned") + } +} + +func TestLoadGrpcAPIServiceFromYAMLSingleRule(t *testing.T) { + service, err := loadGrpcAPIServiceFromYAML([]byte(` +type: google.api.Service +config_version: 3 + +http: + rules: + - selector: grpctest.YourService.Echo + post: /v1/myecho + body: "*" +`), "example") + if err != nil { + t.Fatal(err) + } + + if service.Http == nil { + t.Fatal("HTTP is empty") + } + + if len(service.Http.GetRules()) != 1 { + t.Fatalf("Have %v rules instead of one. Got: %v", len(service.Http.GetRules()), service.Http.GetRules()) + } + + rule := service.Http.GetRules()[0] + if rule.GetSelector() != "grpctest.YourService.Echo" { + t.Errorf("Rule has unexpected selector '%v'", rule.GetSelector()) + } + if rule.GetPost() != "/v1/myecho" { + t.Errorf("Rule has unexpected post '%v'", rule.GetPost()) + } + if rule.GetBody() != "*" { + t.Errorf("Rule has unexpected body '%v'", rule.GetBody()) + } +} + +func TestLoadGrpcAPIServiceFromYAMLRejectInvalidYAML(t *testing.T) { + service, err := loadGrpcAPIServiceFromYAML([]byte(` +type: google.api.Service +config_version: 3 + +http: + rules: + - selector: grpctest.YourService.Echo + - post: thislinebreakstheselectorblockabovewiththeleadingdash + body: "*" +`), "invalidyaml") + if err == nil { + t.Fatal(err) + } + + if !strings.Contains(err.Error(), "line 7") { + t.Errorf("Expected yaml error to be detected in line 7. Got other error: %v", err) + } + + if service != nil { + t.Fatal("Service returned") + } +} + +func TestLoadGrpcAPIServiceFromYAMLMultipleWithAdditionalBindings(t *testing.T) { + service, err := loadGrpcAPIServiceFromYAML([]byte(` +type: google.api.Service +config_version: 3 + +http: + rules: + - selector: first.selector + post: /my/post/path + body: "*" + additional_bindings: + - post: /additional/post/path + - put: /additional/put/{value}/path + - delete: "{value}" + - patch: "/additional/patch/{value}" + - selector: some.other.service + delete: foo +`), "example") + if err != nil { + t.Fatalf("Failed to load service description from YAML: %v", err) + } + + if service == nil { + t.Fatal("No service returned") + } + + if service.Http == nil { + t.Fatal("HTTP is empty") + } + + if len(service.Http.GetRules()) != 2 { + t.Fatalf("%v service(s) returned when two were expected. Got: %v", len(service.Http.GetRules()), service.Http) + } + + first := service.Http.GetRules()[0] + if first.GetSelector() != "first.selector" { + t.Errorf("first.selector has unexpected selector '%v'", first.GetSelector()) + } + if first.GetBody() != "*" { + t.Errorf("first.selector has unexpected body '%v'", first.GetBody()) + } + if first.GetPost() != "/my/post/path" { + t.Errorf("first.selector has unexpected post '%v'", first.GetPost()) + } + if len(first.GetAdditionalBindings()) != 4 { + t.Fatalf("first.selector has unexpected number of bindings %v instead of four. Got: %v", len(first.GetAdditionalBindings()), first.GetAdditionalBindings()) + } + if first.GetAdditionalBindings()[0].GetPost() != "/additional/post/path" { + t.Errorf("first.selector additional binding 0 has unexpected post '%v'", first.GetAdditionalBindings()[0].GetPost()) + } + if first.GetAdditionalBindings()[1].GetPut() != "/additional/put/{value}/path" { + t.Errorf("first.selector additional binding 1 has unexpected put '%v'", first.GetAdditionalBindings()[0].GetPost()) + } + if first.GetAdditionalBindings()[2].GetDelete() != "{value}" { + t.Errorf("first.selector additional binding 2 has unexpected delete '%v'", first.GetAdditionalBindings()[0].GetPost()) + } + if first.GetAdditionalBindings()[3].GetPatch() != "/additional/patch/{value}" { + t.Errorf("first.selector additional binding 3 has unexpected patch '%v'", first.GetAdditionalBindings()[0].GetPost()) + } + + second := service.Http.GetRules()[1] + if second.GetSelector() != "some.other.service" { + t.Errorf("some.other.service has unexpected selector '%v'", second.GetSelector()) + } + if second.GetDelete() != "foo" { + t.Errorf("some.other.service has unexpected delete '%v'", second.GetDelete()) + } + if len(second.GetAdditionalBindings()) != 0 { + t.Errorf("some.other.service has %v additional bindings when it should not have any. Got: %v", len(second.GetAdditionalBindings()), second.GetAdditionalBindings()) + } +} diff --git a/gateway/protoc-gen-grpc-gateway/descriptor/registry.go b/gateway/internal/descriptor/registry.go similarity index 88% rename from gateway/protoc-gen-grpc-gateway/descriptor/registry.go rename to gateway/internal/descriptor/registry.go index b2b6b13..7d318c7 100644 --- a/gateway/protoc-gen-grpc-gateway/descriptor/registry.go +++ b/gateway/internal/descriptor/registry.go @@ -7,14 +7,14 @@ import ( "strings" "github.com/golang/glog" - descriptor "github.com/golang/protobuf/protoc-gen-go/descriptor" - plugin "github.com/golang/protobuf/protoc-gen-go/plugin" + descriptorpb "github.com/golang/protobuf/protoc-gen-go/descriptor" + pluginpb "github.com/golang/protobuf/protoc-gen-go/plugin" // "google.golang.org/genproto/googleapis/api/annotations" annotations "github.com/binchencoder/ease-gateway/httpoptions" ) -// Registry is a registry of information extracted from plugin.CodeGeneratorRequest. +// Registry is a registry of information extracted from pluginpb.CodeGeneratorRequest. type Registry struct { // msgs is a mapping from fully-qualified message name to descriptor msgs map[string]*Message @@ -43,10 +43,10 @@ type Registry struct { // externalHttpRules is a mapping from fully qualified service method names to additional HttpRules applicable besides the ones found in annotations. externalHTTPRules map[string][]*annotations.HttpRule - // allowMerge generation one swagger file out of multiple protos + // allowMerge generation one OpenAPI file out of multiple protos allowMerge bool - // mergeFileName target swagger file name after merge + // mergeFileName target OpenAPI file name after merge mergeFileName string // allowRepeatedFieldsInBody permits repeated field in body field path of `google.api.http` annotation option @@ -59,20 +59,16 @@ type Registry struct { // repeatedPathParamSeparator specifies how path parameter repeated fields are separated repeatedPathParamSeparator repeatedFieldSeparator - // useJSONNamesForFields if true json tag name is used for generating fields in swagger definitions, - // otherwise the original proto name is used. It's helpful for synchronizing the swagger definition + // useJSONNamesForFields if true json tag name is used for generating fields in OpenAPI definitions, + // otherwise the original proto name is used. It's helpful for synchronizing the OpenAPI definition // with grpc-gateway response, if it uses json tags for marshaling. useJSONNamesForFields bool - // useFQNForSwaggerName if true swagger names will use the full qualified name (FQN) from proto definition, - // and generate a dot-separated swagger name concatenating all elements from the proto FQN. + // useFQNForOpenAPIName if true OpenAPI names will use the full qualified name (FQN) from proto definition, + // and generate a dot-separated OpenAPI name concatenating all elements from the proto FQN. // If false, the default behavior is to concat the last 2 elements of the FQN if they are unique, otherwise concat // all the elements of the FQN without any separator - useFQNForSwaggerName bool - - // allowColonFinalSegments determines whether colons are permitted - // in the final segment of a path. - allowColonFinalSegments bool + useFQNForOpenAPIName bool // useGoTemplate determines whether you want to use GO templates // in your protofile comments @@ -88,6 +84,8 @@ type Registry struct { // simpleOperationIDs removes the service prefix from the generated // operationIDs. This risks generating duplicate operationIDs. simpleOperationIDs bool + + standalone bool } type repeatedFieldSeparator struct { @@ -117,7 +115,7 @@ func NewRegistry() *Registry { } // Load loads definitions of services, methods, messages, enumerations and fields from "req". -func (r *Registry) Load(req *plugin.CodeGeneratorRequest) error { +func (r *Registry) Load(req *pluginpb.CodeGeneratorRequest) error { for _, file := range req.GetProtoFile() { r.loadFile(file) } @@ -147,11 +145,15 @@ func (r *Registry) Load(req *plugin.CodeGeneratorRequest) error { // loadFile loads messages, enumerations and fields from "file". // It does not loads services and methods in "file". You need to call // loadServices after loadFiles is called for all files to load services and methods. -func (r *Registry) loadFile(file *descriptor.FileDescriptorProto) { +func (r *Registry) loadFile(file *descriptorpb.FileDescriptorProto) { pkg := GoPackage{ Path: r.goPackagePath(file), Name: r.defaultGoPackageName(file), } + if r.standalone { + pkg.Alias = "ext" + strings.Title(pkg.Name) + } + if err := r.ReserveGoPackageAlias(pkg.Name, pkg.Path); err != nil { for i := 0; ; i++ { alias := fmt.Sprintf("%s_%d", pkg.Name, i) @@ -171,13 +173,14 @@ func (r *Registry) loadFile(file *descriptor.FileDescriptorProto) { r.registerEnum(f, nil, file.GetEnumType()) } -func (r *Registry) registerMsg(file *File, outerPath []string, msgs []*descriptor.DescriptorProto) { +func (r *Registry) registerMsg(file *File, outerPath []string, msgs []*descriptorpb.DescriptorProto) { for i, md := range msgs { m := &Message{ - File: file, - Outers: outerPath, - DescriptorProto: md, - Index: i, + File: file, + Outers: outerPath, + DescriptorProto: md, + Index: i, + ForcePrefixedName: r.standalone, } for _, fd := range md.GetField() { rule, _ := extractFieldRules(fd) @@ -190,6 +193,7 @@ func (r *Registry) registerMsg(file *File, outerPath []string, msgs []*descripto m.Fields = append(m.Fields, &Field{ Message: m, FieldDescriptorProto: fd, + ForcePrefixedName: r.standalone, Rules: rules, }) } @@ -205,13 +209,14 @@ func (r *Registry) registerMsg(file *File, outerPath []string, msgs []*descripto } } -func (r *Registry) registerEnum(file *File, outerPath []string, enums []*descriptor.EnumDescriptorProto) { +func (r *Registry) registerEnum(file *File, outerPath []string, enums []*descriptorpb.EnumDescriptorProto) { for i, ed := range enums { e := &Enum{ File: file, Outers: outerPath, EnumDescriptorProto: ed, Index: i, + ForcePrefixedName: r.standalone, } file.Enums = append(file.Enums, e) r.enums[e.FQEN()] = e @@ -323,6 +328,11 @@ func (r *Registry) SetPrefix(prefix string) { r.prefix = prefix } +// SetStandalone registers standalone flag to control package prefix +func (r *Registry) SetStandalone(standalone bool) { + r.standalone = standalone +} + // SetImportPath registers the importPath which is used as the package if no // input files declare go_package. If it contains slashes, everything up to the // rightmost slash is ignored. @@ -348,7 +358,7 @@ func (r *Registry) ReserveGoPackageAlias(alias, pkgpath string) error { // goPackagePath returns the go package path which go files generated from "f" should have. // It respects the mapping registered by AddPkgMap if exists. Or use go_package as import path // if it includes a slash, Otherwide, it generates a path from the file name of "f". -func (r *Registry) goPackagePath(f *descriptor.FileDescriptorProto) string { +func (r *Registry) goPackagePath(f *descriptorpb.FileDescriptorProto) string { name := f.GetName() if pkg, ok := r.pkgMap[name]; ok { return path.Join(r.prefix, pkg) @@ -390,17 +400,17 @@ func (r *Registry) SetAllowDeleteBody(allow bool) { r.allowDeleteBody = allow } -// SetAllowMerge controls whether generation one swagger file out of multiple protos +// SetAllowMerge controls whether generation one OpenAPI file out of multiple protos func (r *Registry) SetAllowMerge(allow bool) { r.allowMerge = allow } -// IsAllowMerge whether generation one swagger file out of multiple protos +// IsAllowMerge whether generation one OpenAPI file out of multiple protos func (r *Registry) IsAllowMerge() bool { return r.allowMerge } -// SetMergeFileName controls the target swagger file name out of multiple protos +// SetMergeFileName controls the target OpenAPI file name out of multiple protos func (r *Registry) SetMergeFileName(mergeFileName string) { r.mergeFileName = mergeFileName } @@ -474,27 +484,17 @@ func (r *Registry) GetUseJSONNamesForFields() bool { return r.useJSONNamesForFields } -// SetUseFQNForSwaggerName sets useFQNForSwaggerName -func (r *Registry) SetUseFQNForSwaggerName(use bool) { - r.useFQNForSwaggerName = use -} - -// GetAllowColonFinalSegments returns allowColonFinalSegments -func (r *Registry) GetAllowColonFinalSegments() bool { - return r.allowColonFinalSegments -} - -// SetAllowColonFinalSegments sets allowColonFinalSegments -func (r *Registry) SetAllowColonFinalSegments(use bool) { - r.allowColonFinalSegments = use +// SetUseFQNForOpenAPIName sets useFQNForOpenAPIName +func (r *Registry) SetUseFQNForOpenAPIName(use bool) { + r.useFQNForOpenAPIName = use } -// GetUseFQNForSwaggerName returns useFQNForSwaggerName -func (r *Registry) GetUseFQNForSwaggerName() bool { - return r.useFQNForSwaggerName +// GetUseFQNForOpenAPIName returns useFQNForOpenAPIName +func (r *Registry) GetUseFQNForOpenAPIName() bool { + return r.useFQNForOpenAPIName } -// GetMergeFileName return the target merge swagger file name +// GetMergeFileName return the target merge OpenAPI file name func (r *Registry) GetMergeFileName() string { return r.mergeFileName } @@ -549,7 +549,7 @@ func sanitizePackageName(pkgName string) string { // defaultGoPackageName returns the default go package name to be used for go files generated from "f". // You might need to use an unique alias for the package when you import it. Use ReserveGoPackageAlias to get a unique alias. -func (r *Registry) defaultGoPackageName(f *descriptor.FileDescriptorProto) string { +func (r *Registry) defaultGoPackageName(f *descriptorpb.FileDescriptorProto) string { name := r.packageIdentityName(f) return sanitizePackageName(name) } @@ -557,7 +557,7 @@ func (r *Registry) defaultGoPackageName(f *descriptor.FileDescriptorProto) strin // packageIdentityName returns the identity of packages. // protoc-gen-grpc-gateway rejects CodeGenerationRequests which contains more than one packages // as protoc-gen-go does. -func (r *Registry) packageIdentityName(f *descriptor.FileDescriptorProto) string { +func (r *Registry) packageIdentityName(f *descriptorpb.FileDescriptorProto) string { if f.Options != nil && f.Options.GoPackage != nil { gopkg := f.Options.GetGoPackage() idx := strings.LastIndex(gopkg, "/") diff --git a/gateway/protoc-gen-grpc-gateway/descriptor/registry_test.go b/gateway/internal/descriptor/registry_test.go similarity index 94% rename from gateway/protoc-gen-grpc-gateway/descriptor/registry_test.go rename to gateway/internal/descriptor/registry_test.go index 36c53d6..59f0579 100644 --- a/gateway/protoc-gen-grpc-gateway/descriptor/registry_test.go +++ b/gateway/internal/descriptor/registry_test.go @@ -3,14 +3,14 @@ package descriptor import ( "testing" - "github.com/golang/protobuf/proto" - descriptor "github.com/golang/protobuf/protoc-gen-go/descriptor" - plugin "github.com/golang/protobuf/protoc-gen-go/plugin" + descriptorpb "github.com/golang/protobuf/protoc-gen-go/descriptor" + pluginpb "github.com/golang/protobuf/protoc-gen-go/plugin" + "google.golang.org/protobuf/encoding/prototext" ) -func loadFile(t *testing.T, reg *Registry, src string) *descriptor.FileDescriptorProto { - var file descriptor.FileDescriptorProto - if err := proto.UnmarshalText(src, &file); err != nil { +func loadFile(t *testing.T, reg *Registry, src string) *descriptorpb.FileDescriptorProto { + var file descriptorpb.FileDescriptorProto + if err := prototext.Unmarshal([]byte(src), &file); err != nil { t.Fatalf("proto.UnmarshalText(%s, &file) failed with %v; want success", src, err) } reg.loadFile(&file) @@ -18,8 +18,8 @@ func loadFile(t *testing.T, reg *Registry, src string) *descriptor.FileDescripto } func load(t *testing.T, reg *Registry, src string) error { - var req plugin.CodeGeneratorRequest - if err := proto.UnmarshalText(src, &req); err != nil { + var req pluginpb.CodeGeneratorRequest + if err := prototext.Unmarshal([]byte(src), &req); err != nil { t.Fatalf("proto.UnmarshalText(%s, &file) failed with %v; want success", src, err) } return reg.Load(&req) @@ -550,6 +550,25 @@ func TestLoadOverridedPackageName(t *testing.T) { } } +func TestLoadWithStandalone(t *testing.T) { + reg := NewRegistry() + reg.SetStandalone(true) + loadFile(t, reg, ` + name: 'example.proto' + package: 'example' + options < go_package: 'example.com/xyz;pb' > + `) + file := reg.files["example.proto"] + if file == nil { + t.Errorf("reg.files[%q] = nil; want non-nil", "example.proto") + return + } + wantPkg := GoPackage{Path: "example.com/xyz", Name: "pb", Alias: "extPb"} + if got, want := file.GoPkg, wantPkg; got != want { + t.Errorf("file.GoPkg = %#v; want %#v", got, want) + } +} + func TestLoadSetInputPath(t *testing.T) { reg := NewRegistry() reg.SetImportPath("foo/examplepb") diff --git a/gateway/protoc-gen-grpc-gateway/descriptor/services.go b/gateway/internal/descriptor/services.go similarity index 87% rename from gateway/protoc-gen-grpc-gateway/descriptor/services.go rename to gateway/internal/descriptor/services.go index 41e82f0..24efff4 100644 --- a/gateway/protoc-gen-grpc-gateway/descriptor/services.go +++ b/gateway/internal/descriptor/services.go @@ -6,13 +6,11 @@ import ( "strings" "github.com/golang/glog" - "github.com/golang/protobuf/proto" - descriptor "github.com/golang/protobuf/protoc-gen-go/descriptor" - - "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/httprule" - + descriptorpb "github.com/golang/protobuf/protoc-gen-go/descriptor" + "github.com/grpc-ecosystem/grpc-gateway/v2/internal/httprule" // options "google.golang.org/genproto/googleapis/api/annotations" options "github.com/binchencoder/ease-gateway/httpoptions" + "google.golang.org/protobuf/proto" ) var ( @@ -50,6 +48,7 @@ func (r *Registry) loadServices(file *File) error { GenController: spec.GenController, Balancer: spec.Balancer, ServiceDescriptorProto: sd, + ForcePrefixedName: r.standalone, } for _, md := range sd.GetMethod() { glog.V(2).Infof("Processing %s.%s", sd.GetName(), md.GetName()) @@ -81,7 +80,7 @@ func (r *Registry) loadServices(file *File) error { return nil } -func (r *Registry) newMethod(svc *Service, md *descriptor.MethodDescriptorProto, optsList []*options.HttpRule, mopts *options.ApiMethod) (*Method, error) { +func (r *Registry) newMethod(svc *Service, md *descriptorpb.MethodDescriptorProto, optsList []*options.HttpRule, mopts *options.ApiMethod) (*Method, error) { requestType, err := r.LookupMsg(svc.File.GetPackage(), md.GetInputType()) if err != nil { return nil, err @@ -221,7 +220,7 @@ func (r *Registry) newMethod(svc *Service, md *descriptor.MethodDescriptorProto, return meth, nil } -func extractServiceSpec(svc *descriptor.ServiceDescriptorProto) (*options.ServiceSpec, error) { +func extractServiceSpec(svc *descriptorpb.ServiceDescriptorProto) (*options.ServiceSpec, error) { if svc.Options == nil { glog.Errorf("extractServiceSpec svc.Options == nil, %+v", svc) return nil, errNoServiceSpec @@ -230,11 +229,8 @@ func extractServiceSpec(svc *descriptor.ServiceDescriptorProto) (*options.Servic glog.Errorf("extractServiceSpec !proto.HasExtension == true, %+v", svc) return nil, errNoServiceSpec } - spec, err := proto.GetExtension(svc.Options, options.E_ServiceSpec) - if err != nil { - return nil, err - } - + spec := proto.GetExtension(svc.Options, options.E_ServiceSpec) + // Extract ease gateway service spec options. svcSpec, ok := spec.(*options.ServiceSpec) if !ok { return nil, fmt.Errorf("extension is %T; Want a service spec", spec) @@ -242,17 +238,14 @@ func extractServiceSpec(svc *descriptor.ServiceDescriptorProto) (*options.Servic return svcSpec, nil } -func extractFieldRules(field *descriptor.FieldDescriptorProto) (*options.ValidationRules, error) { +func extractFieldRules(field *descriptorpb.FieldDescriptorProto) (*options.ValidationRules, error) { if field.Options == nil { return nil, nil } if !proto.HasExtension(field.Options, options.E_Rules) { return nil, nil } - r, err := proto.GetExtension(field.Options, options.E_Rules) - if err != nil { - return nil, err - } + r := proto.GetExtension(field.Options, options.E_Rules) rules, ok := r.(*options.ValidationRules) if !ok { return nil, fmt.Errorf("Faile to extract rules: %v", rules) @@ -260,17 +253,14 @@ func extractFieldRules(field *descriptor.FieldDescriptorProto) (*options.Validat return rules, nil } -func extractAPIOptions(meth *descriptor.MethodDescriptorProto) (*options.HttpRule, *options.ApiMethod, error) { +func extractAPIOptions(meth *descriptorpb.MethodDescriptorProto) (*options.HttpRule, *options.ApiMethod, error) { if meth.Options == nil { return nil, nil, nil } if !proto.HasExtension(meth.Options, options.E_Http) { return nil, nil, nil } - ext, err := proto.GetExtension(meth.Options, options.E_Http) - if err != nil { - return nil, nil, err - } + ext := proto.GetExtension(meth.Options, options.E_Http) opts, ok := ext.(*options.HttpRule) if !ok { return nil, nil, fmt.Errorf("extension is %T; want an HttpRule", ext) @@ -280,12 +270,8 @@ func extractAPIOptions(meth *descriptor.MethodDescriptorProto) (*options.HttpRul if !proto.HasExtension(meth.Options, options.E_Method) { return opts, mopts, nil } - // Extract ease gateway method options. - m, err := proto.GetExtension(meth.Options, options.E_Method) - if err != nil { - return nil, nil, err - } + m := proto.GetExtension(meth.Options, options.E_Method) mopts, ok = m.(*options.ApiMethod) if !ok { return nil, nil, fmt.Errorf("extension is %T; want an ApiMethod", ext) @@ -305,7 +291,7 @@ func (r *Registry) newParam(meth *Method, path string) (Parameter, error) { } target := fields[l-1].Target switch target.GetType() { - case descriptor.FieldDescriptorProto_TYPE_MESSAGE, descriptor.FieldDescriptorProto_TYPE_GROUP: + case descriptorpb.FieldDescriptorProto_TYPE_MESSAGE, descriptorpb.FieldDescriptorProto_TYPE_GROUP: glog.V(2).Infoln("found aggregate type:", target, target.TypeName) if IsWellKnownType(*target.TypeName) { glog.V(2).Infoln("found well known aggregate type:", target) @@ -371,7 +357,7 @@ func (r *Registry) resolveFieldPath(msg *Message, path string, isPathParam bool) if i > 0 { f := result[i-1].Target switch f.GetType() { - case descriptor.FieldDescriptorProto_TYPE_MESSAGE, descriptor.FieldDescriptorProto_TYPE_GROUP: + case descriptorpb.FieldDescriptorProto_TYPE_MESSAGE, descriptorpb.FieldDescriptorProto_TYPE_GROUP: var err error msg, err = r.LookupMsg(msg.FQMN(), f.GetTypeName()) if err != nil { @@ -387,7 +373,7 @@ func (r *Registry) resolveFieldPath(msg *Message, path string, isPathParam bool) if f == nil { return nil, fmt.Errorf("no field %q found in %s", path, root.GetName()) } - if !(isPathParam || r.allowRepeatedFieldsInBody) && f.GetLabel() == descriptor.FieldDescriptorProto_LABEL_REPEATED { + if !(isPathParam || r.allowRepeatedFieldsInBody) && f.GetLabel() == descriptorpb.FieldDescriptorProto_LABEL_REPEATED { return nil, fmt.Errorf("repeated field not allowed in field path: %s in %s", f.GetName(), path) } result = append(result, FieldPathComponent{Name: c, Target: f}) diff --git a/gateway/protoc-gen-grpc-gateway/descriptor/services_test.go b/gateway/internal/descriptor/services_test.go similarity index 93% rename from gateway/protoc-gen-grpc-gateway/descriptor/services_test.go rename to gateway/internal/descriptor/services_test.go index 8018b0f..c665c5d 100644 --- a/gateway/protoc-gen-grpc-gateway/descriptor/services_test.go +++ b/gateway/internal/descriptor/services_test.go @@ -4,9 +4,10 @@ import ( "reflect" "testing" - "github.com/golang/protobuf/proto" - descriptor "github.com/golang/protobuf/protoc-gen-go/descriptor" - "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/httprule" + descriptorpb "github.com/golang/protobuf/protoc-gen-go/descriptor" + "github.com/grpc-ecosystem/grpc-gateway/v2/internal/httprule" + "google.golang.org/protobuf/encoding/prototext" + "google.golang.org/protobuf/proto" ) func compilePath(t *testing.T, path string) httprule.Template { @@ -17,7 +18,7 @@ func compilePath(t *testing.T, path string) httprule.Template { return parsed.Compile() } -func testExtractServices(t *testing.T, input []*descriptor.FileDescriptorProto, target string, wantSvcs []*Service) { +func testExtractServices(t *testing.T, input []*descriptorpb.FileDescriptorProto, target string, wantSvcs []*Service) { reg := NewRegistry() for _, file := range input { reg.loadFile(file) @@ -144,6 +145,9 @@ func crossLinkFixture(f *File) *File { } } } + for _, e := range f.Enums { + e.File = f + } return f } @@ -175,8 +179,8 @@ func TestExtractServicesSimple(t *testing.T) { > > ` - var fd descriptor.FileDescriptorProto - if err := proto.UnmarshalText(src, &fd); err != nil { + var fd descriptorpb.FileDescriptorProto + if err := prototext.Unmarshal([]byte(src), &fd); err != nil { t.Fatalf("proto.UnmarshalText(%s, &fd) failed with %v; want success", src, err) } msg := &Message{ @@ -216,7 +220,7 @@ func TestExtractServicesSimple(t *testing.T) { } crossLinkFixture(file) - testExtractServices(t, []*descriptor.FileDescriptorProto{&fd}, "path/to/example.proto", file.Services) + testExtractServices(t, []*descriptorpb.FileDescriptorProto{&fd}, "path/to/example.proto", file.Services) } func TestExtractServicesWithoutAnnotation(t *testing.T) { @@ -241,8 +245,8 @@ func TestExtractServicesWithoutAnnotation(t *testing.T) { > > ` - var fd descriptor.FileDescriptorProto - if err := proto.UnmarshalText(src, &fd); err != nil { + var fd descriptorpb.FileDescriptorProto + if err := prototext.Unmarshal([]byte(src), &fd); err != nil { t.Fatalf("proto.UnmarshalText(%s, &fd) failed with %v; want success", src, err) } msg := &Message{ @@ -275,7 +279,7 @@ func TestExtractServicesWithoutAnnotation(t *testing.T) { } crossLinkFixture(file) - testExtractServices(t, []*descriptor.FileDescriptorProto{&fd}, "path/to/example.proto", file.Services) + testExtractServices(t, []*descriptorpb.FileDescriptorProto{&fd}, "path/to/example.proto", file.Services) } func TestExtractServicesCrossPackage(t *testing.T) { @@ -320,10 +324,10 @@ func TestExtractServicesCrossPackage(t *testing.T) { > `, } - var fds []*descriptor.FileDescriptorProto + var fds []*descriptorpb.FileDescriptorProto for _, src := range srcs { - var fd descriptor.FileDescriptorProto - if err := proto.UnmarshalText(src, &fd); err != nil { + var fd descriptorpb.FileDescriptorProto + if err := prototext.Unmarshal([]byte(src), &fd); err != nil { t.Fatalf("proto.UnmarshalText(%s, &fd) failed with %v; want success", src, err) } fds = append(fds, &fd) @@ -426,8 +430,8 @@ func TestExtractServicesWithBodyPath(t *testing.T) { > > ` - var fd descriptor.FileDescriptorProto - if err := proto.UnmarshalText(src, &fd); err != nil { + var fd descriptorpb.FileDescriptorProto + if err := prototext.Unmarshal([]byte(src), &fd); err != nil { t.Fatalf("proto.UnmarshalText(%s, &fd) failed with %v; want success", src, err) } msg := &Message{ @@ -474,7 +478,7 @@ func TestExtractServicesWithBodyPath(t *testing.T) { } crossLinkFixture(file) - testExtractServices(t, []*descriptor.FileDescriptorProto{&fd}, "path/to/example.proto", file.Services) + testExtractServices(t, []*descriptorpb.FileDescriptorProto{&fd}, "path/to/example.proto", file.Services) } func TestExtractServicesWithPathParam(t *testing.T) { @@ -504,8 +508,8 @@ func TestExtractServicesWithPathParam(t *testing.T) { > > ` - var fd descriptor.FileDescriptorProto - if err := proto.UnmarshalText(src, &fd); err != nil { + var fd descriptorpb.FileDescriptorProto + if err := prototext.Unmarshal([]byte(src), &fd); err != nil { t.Fatalf("proto.UnmarshalText(%s, &fd) failed with %v; want success", src, err) } msg := &Message{ @@ -555,7 +559,7 @@ func TestExtractServicesWithPathParam(t *testing.T) { } crossLinkFixture(file) - testExtractServices(t, []*descriptor.FileDescriptorProto{&fd}, "path/to/example.proto", file.Services) + testExtractServices(t, []*descriptorpb.FileDescriptorProto{&fd}, "path/to/example.proto", file.Services) } func TestExtractServicesWithAdditionalBinding(t *testing.T) { @@ -593,8 +597,8 @@ func TestExtractServicesWithAdditionalBinding(t *testing.T) { > > ` - var fd descriptor.FileDescriptorProto - if err := proto.UnmarshalText(src, &fd); err != nil { + var fd descriptorpb.FileDescriptorProto + if err := prototext.Unmarshal([]byte(src), &fd); err != nil { t.Fatalf("proto.UnmarshalText(%s, &fd) failed with %v; want success", src, err) } msg := &Message{ @@ -665,7 +669,7 @@ func TestExtractServicesWithAdditionalBinding(t *testing.T) { } crossLinkFixture(file) - testExtractServices(t, []*descriptor.FileDescriptorProto{&fd}, "path/to/example.proto", file.Services) + testExtractServices(t, []*descriptorpb.FileDescriptorProto{&fd}, "path/to/example.proto", file.Services) } func TestExtractServicesWithError(t *testing.T) { @@ -964,14 +968,12 @@ func TestExtractServicesWithError(t *testing.T) { } { reg := NewRegistry() - var fds []*descriptor.FileDescriptorProto for _, src := range spec.srcs { - var fd descriptor.FileDescriptorProto - if err := proto.UnmarshalText(src, &fd); err != nil { + var fd descriptorpb.FileDescriptorProto + if err := prototext.Unmarshal([]byte(src), &fd); err != nil { t.Fatalf("proto.UnmarshalText(%s, &fd) failed with %v; want success", src, err) } reg.loadFile(&fd) - fds = append(fds, &fd) } err := reg.loadServices(reg.files[spec.target]) if err == nil { @@ -1146,8 +1148,8 @@ func TestResolveFieldPath(t *testing.T) { wantErr: true, }, } { - var file descriptor.FileDescriptorProto - if err := proto.UnmarshalText(spec.src, &file); err != nil { + var file descriptorpb.FileDescriptorProto + if err := prototext.Unmarshal([]byte(spec.src), &file); err != nil { t.Fatalf("proto.Unmarshal(%s) failed with %v; want success", spec.src, err) } reg := NewRegistry() @@ -1248,14 +1250,12 @@ func TestExtractServicesWithDeleteBody(t *testing.T) { reg := NewRegistry() reg.SetAllowDeleteBody(spec.allowDeleteBody) - var fds []*descriptor.FileDescriptorProto for _, src := range spec.srcs { - var fd descriptor.FileDescriptorProto - if err := proto.UnmarshalText(src, &fd); err != nil { + var fd descriptorpb.FileDescriptorProto + if err := prototext.Unmarshal([]byte(src), &fd); err != nil { t.Fatalf("proto.UnmarshalText(%s, &fd) failed with %v; want success", src, err) } reg.loadFile(&fd) - fds = append(fds, &fd) } err := reg.loadServices(reg.files[spec.target]) if spec.expectErr && err == nil { diff --git a/gateway/protoc-gen-grpc-gateway/descriptor/types.go b/gateway/internal/descriptor/types.go similarity index 72% rename from gateway/protoc-gen-grpc-gateway/descriptor/types.go rename to gateway/internal/descriptor/types.go index 5355c8e..12dae9e 100644 --- a/gateway/protoc-gen-grpc-gateway/descriptor/types.go +++ b/gateway/internal/descriptor/types.go @@ -4,10 +4,10 @@ import ( "fmt" "strings" "unicode" - + descriptorpb "github.com/golang/protobuf/protoc-gen-go/descriptor" + // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/casing" "github.com/binchencoder/ease-gateway/gateway/internal/casing" - "github.com/golang/protobuf/protoc-gen-go/descriptor" - "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/httprule" + "github.com/grpc-ecosystem/grpc-gateway/v2/internal/httprule" options "github.com/binchencoder/ease-gateway/httpoptions" "github.com/binchencoder/gateway-proto/data" @@ -42,9 +42,9 @@ func (p GoPackage) String() string { return fmt.Sprintf("%s %q", p.Alias, p.Path) } -// File wraps descriptor.FileDescriptorProto for richer features. +// File wraps descriptorpb.FileDescriptorProto for richer features. type File struct { - *descriptor.FileDescriptorProto + *descriptorpb.FileDescriptorProto // GoPkg is the go package of the go file generated from this file.. GoPkg GoPackage // Messages is the list of messages defined in this file. @@ -55,6 +55,15 @@ type File struct { Services []*Service } +// Pkg returns package name or alias if it's present +func (f *File) Pkg() string { + pkg := f.GoPkg.Name + if alias := f.GoPkg.Alias; alias != "" { + pkg = alias + } + return pkg +} + // proto2 determines if the syntax of the file is proto2. func (f *File) proto2() bool { return f.Syntax == nil || f.GetSyntax() == "proto2" @@ -66,12 +75,14 @@ type Message struct { File *File // Outers is a list of outer messages if this message is a nested type. Outers []string - *descriptor.DescriptorProto + *descriptorpb.DescriptorProto Fields []*Field // Index is proto path index of this message in File. Index int + ForcePrefixedName bool + // Checked fields, with key constructed with message's package, and field type, // And value as the HasRule result. // To avoid deadloop in HasRule(). Example problem messages: @@ -128,7 +139,7 @@ func (m *Message) HasRule() bool { return true } - if *f.Type == descriptor.FieldDescriptorProto_TYPE_MESSAGE { + if *f.Type == descriptorpb.FieldDescriptorProto_TYPE_MESSAGE { // It looks the field's type name is prefixed with package already. // To make it consistent with parameters passing to Reg.LookupMessage, // let's construct map key with package and type name. @@ -174,14 +185,10 @@ func (m *Message) GoType(currentPackage string) string { components = append(components, m.GetName()) name := strings.Join(components, "_") - if m.File.GoPkg.Path == currentPackage { + if !m.ForcePrefixedName && m.File.GoPkg.Path == currentPackage { return name } - pkg := m.File.GoPkg.Name - if alias := m.File.GoPkg.Alias; alias != "" { - pkg = alias - } - return fmt.Sprintf("%s.%s", pkg, name) + return fmt.Sprintf("%s.%s", m.File.Pkg(), name) } // Enum describes a protocol buffer enum types @@ -190,9 +197,11 @@ type Enum struct { File *File // Outers is a list of outer messages if this enum is a nested type. Outers []string - *descriptor.EnumDescriptorProto + *descriptorpb.EnumDescriptorProto Index int + + ForcePrefixedName bool } // FQEN returns a fully qualified enum name of this enum. @@ -215,21 +224,17 @@ func (e *Enum) GoType(currentPackage string) string { components = append(components, e.GetName()) name := strings.Join(components, "_") - if e.File.GoPkg.Path == currentPackage { + if !e.ForcePrefixedName && e.File.GoPkg.Path == currentPackage { return name } - pkg := e.File.GoPkg.Name - if alias := e.File.GoPkg.Alias; alias != "" { - pkg = alias - } - return fmt.Sprintf("%s.%s", pkg, name) + return fmt.Sprintf("%s.%s", e.File.Pkg(), name) } -// Service wraps descriptor.ServiceDescriptorProto for richer features. +// Service wraps descriptorpb.ServiceDescriptorProto for richer features. type Service struct { // File is the file where this service is defined. File *File - *descriptor.ServiceDescriptorProto + *descriptorpb.ServiceDescriptorProto // service ID uniquely identifies this service in context of org. ServiceId *data.ServiceId @@ -245,6 +250,8 @@ type Service struct { // Methods is the list of methods defined in this service. Methods []*Method + + ForcePrefixedName bool } // FQSN returns the fully qualified service name of this service. @@ -257,11 +264,28 @@ func (s *Service) FQSN() string { return strings.Join(components, ".") } -// Method wraps descriptor.MethodDescriptorProto for richer features. +// InstanceName returns object name of the service with package prefix if needed +func (s *Service) InstanceName() string { + if !s.ForcePrefixedName { + return s.GetName() + } + return fmt.Sprintf("%s.%s", s.File.Pkg(), s.GetName()) +} + +// ClientConstructorName returns name of the Client constructor with package prefix if needed +func (s *Service) ClientConstructorName() string { + constructor := "New" + s.GetName() + "Client" + if !s.ForcePrefixedName { + return constructor + } + return fmt.Sprintf("%s.%s", s.File.Pkg(), constructor) +} + +// Method wraps descriptorpb.MethodDescriptorProto for richer features. type Method struct { // Service is the service which this method belongs to. Service *Service - *descriptor.MethodDescriptorProto + *descriptorpb.MethodDescriptorProto // RequestType is the message type of requests to this method. RequestType *Message @@ -318,13 +342,15 @@ func (b *Binding) ExplicitParams() []string { return result } -// Field wraps descriptor.FieldDescriptorProto for richer features. +// Field wraps descriptorpb.FieldDescriptorProto for richer features. type Field struct { // Message is the message type which this field belongs to. Message *Message // FieldMessage is the message type of the field. FieldMessage *Message - *descriptor.FieldDescriptorProto + *descriptorpb.FieldDescriptorProto + + ForcePrefixedName bool Rules []*Rule } @@ -353,7 +379,7 @@ func (f *Field) OneOfDeclGoName() string { // IsRepeated return true if this field is repeated otherwise return false. func (f *Field) IsRepeated() bool { - return *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED + return *f.Label == descriptorpb.FieldDescriptorProto_LABEL_REPEATED } // HasRule returns true if there is any validation rule defined. @@ -482,12 +508,12 @@ func (p Parameter) ConvertFuncExpr() (string, error) { // IsEnum returns true if the field is an enum type, otherwise false is returned. func (p Parameter) IsEnum() bool { - return p.Target.GetType() == descriptor.FieldDescriptorProto_TYPE_ENUM + return p.Target.GetType() == descriptorpb.FieldDescriptorProto_TYPE_ENUM } // IsRepeated returns true if the field is repeated, otherwise false is returned. func (p Parameter) IsRepeated() bool { - return p.Target.GetLabel() == descriptor.FieldDescriptorProto_LABEL_REPEATED + return p.Target.GetLabel() == descriptorpb.FieldDescriptorProto_LABEL_REPEATED } // IsProto2 returns true if the field is proto2, otherwise false is returned. @@ -547,6 +573,10 @@ func (p FieldPath) AssignableExpr(msgExpr string) string { oneOfName := casing.Camel(msg.GetOneofDecl()[*index].GetName()) oneofFieldName := msg.GetName() + "_" + c.AssignableExpr() + if c.Target.ForcePrefixedName { + oneofFieldName = msg.File.Pkg() + "." + oneofFieldName + } + components = components + "." + oneOfName s := `if %s == nil { %s =&%s{} @@ -592,90 +622,90 @@ func (c FieldPathComponent) ValueExpr() string { } var ( - proto3ConvertFuncs = map[descriptor.FieldDescriptorProto_Type]string{ - descriptor.FieldDescriptorProto_TYPE_DOUBLE: "runtime.Float64", - descriptor.FieldDescriptorProto_TYPE_FLOAT: "runtime.Float32", - descriptor.FieldDescriptorProto_TYPE_INT64: "runtime.Int64", - descriptor.FieldDescriptorProto_TYPE_UINT64: "runtime.Uint64", - descriptor.FieldDescriptorProto_TYPE_INT32: "runtime.Int32", - descriptor.FieldDescriptorProto_TYPE_FIXED64: "runtime.Uint64", - descriptor.FieldDescriptorProto_TYPE_FIXED32: "runtime.Uint32", - descriptor.FieldDescriptorProto_TYPE_BOOL: "runtime.Bool", - descriptor.FieldDescriptorProto_TYPE_STRING: "runtime.String", + proto3ConvertFuncs = map[descriptorpb.FieldDescriptorProto_Type]string{ + descriptorpb.FieldDescriptorProto_TYPE_DOUBLE: "runtime.Float64", + descriptorpb.FieldDescriptorProto_TYPE_FLOAT: "runtime.Float32", + descriptorpb.FieldDescriptorProto_TYPE_INT64: "runtime.Int64", + descriptorpb.FieldDescriptorProto_TYPE_UINT64: "runtime.Uint64", + descriptorpb.FieldDescriptorProto_TYPE_INT32: "runtime.Int32", + descriptorpb.FieldDescriptorProto_TYPE_FIXED64: "runtime.Uint64", + descriptorpb.FieldDescriptorProto_TYPE_FIXED32: "runtime.Uint32", + descriptorpb.FieldDescriptorProto_TYPE_BOOL: "runtime.Bool", + descriptorpb.FieldDescriptorProto_TYPE_STRING: "runtime.String", // FieldDescriptorProto_TYPE_GROUP // FieldDescriptorProto_TYPE_MESSAGE - descriptor.FieldDescriptorProto_TYPE_BYTES: "runtime.Bytes", - descriptor.FieldDescriptorProto_TYPE_UINT32: "runtime.Uint32", - descriptor.FieldDescriptorProto_TYPE_ENUM: "runtime.Enum", - descriptor.FieldDescriptorProto_TYPE_SFIXED32: "runtime.Int32", - descriptor.FieldDescriptorProto_TYPE_SFIXED64: "runtime.Int64", - descriptor.FieldDescriptorProto_TYPE_SINT32: "runtime.Int32", - descriptor.FieldDescriptorProto_TYPE_SINT64: "runtime.Int64", + descriptorpb.FieldDescriptorProto_TYPE_BYTES: "runtime.Bytes", + descriptorpb.FieldDescriptorProto_TYPE_UINT32: "runtime.Uint32", + descriptorpb.FieldDescriptorProto_TYPE_ENUM: "runtime.Enum", + descriptorpb.FieldDescriptorProto_TYPE_SFIXED32: "runtime.Int32", + descriptorpb.FieldDescriptorProto_TYPE_SFIXED64: "runtime.Int64", + descriptorpb.FieldDescriptorProto_TYPE_SINT32: "runtime.Int32", + descriptorpb.FieldDescriptorProto_TYPE_SINT64: "runtime.Int64", } - proto3RepeatedConvertFuncs = map[descriptor.FieldDescriptorProto_Type]string{ - descriptor.FieldDescriptorProto_TYPE_DOUBLE: "runtime.Float64Slice", - descriptor.FieldDescriptorProto_TYPE_FLOAT: "runtime.Float32Slice", - descriptor.FieldDescriptorProto_TYPE_INT64: "runtime.Int64Slice", - descriptor.FieldDescriptorProto_TYPE_UINT64: "runtime.Uint64Slice", - descriptor.FieldDescriptorProto_TYPE_INT32: "runtime.Int32Slice", - descriptor.FieldDescriptorProto_TYPE_FIXED64: "runtime.Uint64Slice", - descriptor.FieldDescriptorProto_TYPE_FIXED32: "runtime.Uint32Slice", - descriptor.FieldDescriptorProto_TYPE_BOOL: "runtime.BoolSlice", - descriptor.FieldDescriptorProto_TYPE_STRING: "runtime.StringSlice", + proto3RepeatedConvertFuncs = map[descriptorpb.FieldDescriptorProto_Type]string{ + descriptorpb.FieldDescriptorProto_TYPE_DOUBLE: "runtime.Float64Slice", + descriptorpb.FieldDescriptorProto_TYPE_FLOAT: "runtime.Float32Slice", + descriptorpb.FieldDescriptorProto_TYPE_INT64: "runtime.Int64Slice", + descriptorpb.FieldDescriptorProto_TYPE_UINT64: "runtime.Uint64Slice", + descriptorpb.FieldDescriptorProto_TYPE_INT32: "runtime.Int32Slice", + descriptorpb.FieldDescriptorProto_TYPE_FIXED64: "runtime.Uint64Slice", + descriptorpb.FieldDescriptorProto_TYPE_FIXED32: "runtime.Uint32Slice", + descriptorpb.FieldDescriptorProto_TYPE_BOOL: "runtime.BoolSlice", + descriptorpb.FieldDescriptorProto_TYPE_STRING: "runtime.StringSlice", // FieldDescriptorProto_TYPE_GROUP // FieldDescriptorProto_TYPE_MESSAGE - descriptor.FieldDescriptorProto_TYPE_BYTES: "runtime.BytesSlice", - descriptor.FieldDescriptorProto_TYPE_UINT32: "runtime.Uint32Slice", - descriptor.FieldDescriptorProto_TYPE_ENUM: "runtime.EnumSlice", - descriptor.FieldDescriptorProto_TYPE_SFIXED32: "runtime.Int32Slice", - descriptor.FieldDescriptorProto_TYPE_SFIXED64: "runtime.Int64Slice", - descriptor.FieldDescriptorProto_TYPE_SINT32: "runtime.Int32Slice", - descriptor.FieldDescriptorProto_TYPE_SINT64: "runtime.Int64Slice", + descriptorpb.FieldDescriptorProto_TYPE_BYTES: "runtime.BytesSlice", + descriptorpb.FieldDescriptorProto_TYPE_UINT32: "runtime.Uint32Slice", + descriptorpb.FieldDescriptorProto_TYPE_ENUM: "runtime.EnumSlice", + descriptorpb.FieldDescriptorProto_TYPE_SFIXED32: "runtime.Int32Slice", + descriptorpb.FieldDescriptorProto_TYPE_SFIXED64: "runtime.Int64Slice", + descriptorpb.FieldDescriptorProto_TYPE_SINT32: "runtime.Int32Slice", + descriptorpb.FieldDescriptorProto_TYPE_SINT64: "runtime.Int64Slice", } - proto2ConvertFuncs = map[descriptor.FieldDescriptorProto_Type]string{ - descriptor.FieldDescriptorProto_TYPE_DOUBLE: "runtime.Float64P", - descriptor.FieldDescriptorProto_TYPE_FLOAT: "runtime.Float32P", - descriptor.FieldDescriptorProto_TYPE_INT64: "runtime.Int64P", - descriptor.FieldDescriptorProto_TYPE_UINT64: "runtime.Uint64P", - descriptor.FieldDescriptorProto_TYPE_INT32: "runtime.Int32P", - descriptor.FieldDescriptorProto_TYPE_FIXED64: "runtime.Uint64P", - descriptor.FieldDescriptorProto_TYPE_FIXED32: "runtime.Uint32P", - descriptor.FieldDescriptorProto_TYPE_BOOL: "runtime.BoolP", - descriptor.FieldDescriptorProto_TYPE_STRING: "runtime.StringP", + proto2ConvertFuncs = map[descriptorpb.FieldDescriptorProto_Type]string{ + descriptorpb.FieldDescriptorProto_TYPE_DOUBLE: "runtime.Float64P", + descriptorpb.FieldDescriptorProto_TYPE_FLOAT: "runtime.Float32P", + descriptorpb.FieldDescriptorProto_TYPE_INT64: "runtime.Int64P", + descriptorpb.FieldDescriptorProto_TYPE_UINT64: "runtime.Uint64P", + descriptorpb.FieldDescriptorProto_TYPE_INT32: "runtime.Int32P", + descriptorpb.FieldDescriptorProto_TYPE_FIXED64: "runtime.Uint64P", + descriptorpb.FieldDescriptorProto_TYPE_FIXED32: "runtime.Uint32P", + descriptorpb.FieldDescriptorProto_TYPE_BOOL: "runtime.BoolP", + descriptorpb.FieldDescriptorProto_TYPE_STRING: "runtime.StringP", // FieldDescriptorProto_TYPE_GROUP // FieldDescriptorProto_TYPE_MESSAGE // FieldDescriptorProto_TYPE_BYTES // TODO(yugui) Handle bytes - descriptor.FieldDescriptorProto_TYPE_UINT32: "runtime.Uint32P", - descriptor.FieldDescriptorProto_TYPE_ENUM: "runtime.EnumP", - descriptor.FieldDescriptorProto_TYPE_SFIXED32: "runtime.Int32P", - descriptor.FieldDescriptorProto_TYPE_SFIXED64: "runtime.Int64P", - descriptor.FieldDescriptorProto_TYPE_SINT32: "runtime.Int32P", - descriptor.FieldDescriptorProto_TYPE_SINT64: "runtime.Int64P", + descriptorpb.FieldDescriptorProto_TYPE_UINT32: "runtime.Uint32P", + descriptorpb.FieldDescriptorProto_TYPE_ENUM: "runtime.EnumP", + descriptorpb.FieldDescriptorProto_TYPE_SFIXED32: "runtime.Int32P", + descriptorpb.FieldDescriptorProto_TYPE_SFIXED64: "runtime.Int64P", + descriptorpb.FieldDescriptorProto_TYPE_SINT32: "runtime.Int32P", + descriptorpb.FieldDescriptorProto_TYPE_SINT64: "runtime.Int64P", } - proto2RepeatedConvertFuncs = map[descriptor.FieldDescriptorProto_Type]string{ - descriptor.FieldDescriptorProto_TYPE_DOUBLE: "runtime.Float64Slice", - descriptor.FieldDescriptorProto_TYPE_FLOAT: "runtime.Float32Slice", - descriptor.FieldDescriptorProto_TYPE_INT64: "runtime.Int64Slice", - descriptor.FieldDescriptorProto_TYPE_UINT64: "runtime.Uint64Slice", - descriptor.FieldDescriptorProto_TYPE_INT32: "runtime.Int32Slice", - descriptor.FieldDescriptorProto_TYPE_FIXED64: "runtime.Uint64Slice", - descriptor.FieldDescriptorProto_TYPE_FIXED32: "runtime.Uint32Slice", - descriptor.FieldDescriptorProto_TYPE_BOOL: "runtime.BoolSlice", - descriptor.FieldDescriptorProto_TYPE_STRING: "runtime.StringSlice", + proto2RepeatedConvertFuncs = map[descriptorpb.FieldDescriptorProto_Type]string{ + descriptorpb.FieldDescriptorProto_TYPE_DOUBLE: "runtime.Float64Slice", + descriptorpb.FieldDescriptorProto_TYPE_FLOAT: "runtime.Float32Slice", + descriptorpb.FieldDescriptorProto_TYPE_INT64: "runtime.Int64Slice", + descriptorpb.FieldDescriptorProto_TYPE_UINT64: "runtime.Uint64Slice", + descriptorpb.FieldDescriptorProto_TYPE_INT32: "runtime.Int32Slice", + descriptorpb.FieldDescriptorProto_TYPE_FIXED64: "runtime.Uint64Slice", + descriptorpb.FieldDescriptorProto_TYPE_FIXED32: "runtime.Uint32Slice", + descriptorpb.FieldDescriptorProto_TYPE_BOOL: "runtime.BoolSlice", + descriptorpb.FieldDescriptorProto_TYPE_STRING: "runtime.StringSlice", // FieldDescriptorProto_TYPE_GROUP // FieldDescriptorProto_TYPE_MESSAGE // FieldDescriptorProto_TYPE_BYTES // TODO(maros7) Handle bytes - descriptor.FieldDescriptorProto_TYPE_UINT32: "runtime.Uint32Slice", - descriptor.FieldDescriptorProto_TYPE_ENUM: "runtime.EnumSlice", - descriptor.FieldDescriptorProto_TYPE_SFIXED32: "runtime.Int32Slice", - descriptor.FieldDescriptorProto_TYPE_SFIXED64: "runtime.Int64Slice", - descriptor.FieldDescriptorProto_TYPE_SINT32: "runtime.Int32Slice", - descriptor.FieldDescriptorProto_TYPE_SINT64: "runtime.Int64Slice", + descriptorpb.FieldDescriptorProto_TYPE_UINT32: "runtime.Uint32Slice", + descriptorpb.FieldDescriptorProto_TYPE_ENUM: "runtime.EnumSlice", + descriptorpb.FieldDescriptorProto_TYPE_SFIXED32: "runtime.Int32Slice", + descriptorpb.FieldDescriptorProto_TYPE_SFIXED64: "runtime.Int64Slice", + descriptorpb.FieldDescriptorProto_TYPE_SINT32: "runtime.Int32Slice", + descriptorpb.FieldDescriptorProto_TYPE_SINT64: "runtime.Int64Slice", } wellKnownTypeConv = map[string]string{ diff --git a/gateway/protoc-gen-grpc-gateway/descriptor/types_test.go b/gateway/internal/descriptor/types_test.go similarity index 68% rename from gateway/protoc-gen-grpc-gateway/descriptor/types_test.go rename to gateway/internal/descriptor/types_test.go index 1dcdb34..60e5bc0 100644 --- a/gateway/protoc-gen-grpc-gateway/descriptor/types_test.go +++ b/gateway/internal/descriptor/types_test.go @@ -3,8 +3,8 @@ package descriptor import ( "testing" - "github.com/golang/protobuf/proto" - descriptor "github.com/golang/protobuf/protoc-gen-go/descriptor" + descriptorpb "github.com/golang/protobuf/protoc-gen-go/descriptor" + "google.golang.org/protobuf/encoding/prototext" ) func TestGoPackageStandard(t *testing.T) { @@ -21,7 +21,7 @@ func TestGoPackageStandard(t *testing.T) { want: true, }, { - pkg: GoPackage{Path: "github.com/golang/protobuf/jsonpb", Name: "jsonpb"}, + pkg: GoPackage{Path: "google.golang.org/protobuf/encoding/protojson", Name: "jsonpb"}, want: false, }, { @@ -57,8 +57,8 @@ func TestGoPackageString(t *testing.T) { want: `"encoding/json"`, }, { - pkg: GoPackage{Path: "github.com/golang/protobuf/jsonpb", Name: "jsonpb"}, - want: `"github.com/golang/protobuf/jsonpb"`, + pkg: GoPackage{Path: "google.golang.org/protobuf/encoding/protojson", Name: "jsonpb"}, + want: `"google.golang.org/protobuf/encoding/protojson"`, }, { pkg: GoPackage{Path: "golang.org/x/net/context", Name: "context"}, @@ -80,7 +80,7 @@ func TestGoPackageString(t *testing.T) { } func TestFieldPath(t *testing.T) { - var fds []*descriptor.FileDescriptorProto + var fds []*descriptorpb.FileDescriptorProto for _, src := range []string{ ` name: 'example.proto' @@ -124,8 +124,8 @@ func TestFieldPath(t *testing.T) { syntax: "proto2" `, } { - var fd descriptor.FileDescriptorProto - if err := proto.UnmarshalText(src, &fd); err != nil { + var fd descriptorpb.FileDescriptorProto + if err := prototext.Unmarshal([]byte(src), &fd); err != nil { t.Fatalf("proto.UnmarshalText(%s, &fd) failed with %v; want success", src, err) } fds = append(fds, &fd) @@ -204,3 +204,66 @@ func TestFieldPath(t *testing.T) { t.Errorf("fpEmpty.AssignableExpr(%q) = %q; want %q", "resp", got, want) } } + +func TestGoType(t *testing.T) { + src := ` + name: 'example.proto' + package: 'example' + message_type < + name: 'Message' + field < + name: 'field' + type: TYPE_STRING + number: 1 + > + >, + enum_type < + name: 'EnumName' + >, + ` + + var fd descriptorpb.FileDescriptorProto + if err := prototext.Unmarshal([]byte(src), &fd); err != nil { + t.Fatalf("proto.UnmarshalText(%s, &fd) failed with %v; want success", src, err) + } + + msg := &Message{ + DescriptorProto: fd.MessageType[0], + Fields: []*Field{ + {FieldDescriptorProto: fd.MessageType[0].Field[0]}, + }, + } + enum := &Enum{ + EnumDescriptorProto: fd.EnumType[0], + } + file := &File{ + FileDescriptorProto: &fd, + GoPkg: GoPackage{Path: "example", Name: "example"}, + Messages: []*Message{msg}, + Enums: []*Enum{enum}, + } + crossLinkFixture(file) + + if got, want := msg.GoType("example"), "Message"; got != want { + t.Errorf("msg.GoType() = %q; want %q", got, want) + } + if got, want := msg.GoType("extPackage"), "example.Message"; got != want { + t.Errorf("msg.GoType() = %q; want %q", got, want) + } + msg.ForcePrefixedName = true + if got, want := msg.GoType("example"), "example.Message"; got != want { + t.Errorf("msg.GoType() = %q; want %q", got, want) + } + + if got, want := enum.GoType("example"), "EnumName"; got != want { + t.Errorf("enum.GoType() = %q; want %q", got, want) + } + if got, want := enum.GoType("extPackage"), "example.EnumName"; got != want { + t.Errorf("enum.GoType() = %q; want %q", got, want) + } + enum.ForcePrefixedName = true + if got, want := enum.GoType("example"), "example.EnumName"; got != want { + t.Errorf("enum.GoType() = %q; want %q", got, want) + } + +} diff --git a/gateway/internal/errors.pb.go b/gateway/internal/errors.pb.go index e53f387..4716d8e 100644 --- a/gateway/internal/errors.pb.go +++ b/gateway/internal/errors.pb.go @@ -8,8 +8,8 @@ import ( math "math" frontend "github.com/binchencoder/gateway-proto/frontend" - proto "github.com/golang/protobuf/proto" any "github.com/golang/protobuf/ptypes/any" + proto "google.golang.org/protobuf/proto" ) // Reference imports to suppress errors if they are not otherwise used. diff --git a/gateway/protoc-gen-grpc-gateway/generator/BUILD.bazel b/gateway/internal/generator/BUILD.bazel similarity index 60% rename from gateway/protoc-gen-grpc-gateway/generator/BUILD.bazel rename to gateway/internal/generator/BUILD.bazel index dcabc5e..c17f265 100644 --- a/gateway/protoc-gen-grpc-gateway/generator/BUILD.bazel +++ b/gateway/internal/generator/BUILD.bazel @@ -5,9 +5,9 @@ package(default_visibility = ["//visibility:public"]) go_library( name = "go_default_library", srcs = ["generator.go"], - importpath = "github.com/binchencoder/ease-gateway/gateway/protoc-gen-grpc-gateway/generator", + importpath = "github.com/binchencoder/ease-gateway/gateway/internal/generator", deps = [ - "//gateway/protoc-gen-grpc-gateway/descriptor:go_default_library", + "//gateway/internal/descriptor:go_default_library", "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", ], ) diff --git a/gateway/internal/generator/generator.go b/gateway/internal/generator/generator.go new file mode 100644 index 0000000..8ec129a --- /dev/null +++ b/gateway/internal/generator/generator.go @@ -0,0 +1,14 @@ +// Package generator provides an abstract interface to code generators. +package generator + +import ( + pluginpb "github.com/golang/protobuf/protoc-gen-go/plugin" + // descriptorpb "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor" + descriptorpb "github.com/binchencoder/ease-gateway/gateway/internal/descriptor" +) + +// Generator is an abstraction of code generators. +type Generator interface { + // Generate generates output files from input .proto files. + Generate(targets []*descriptorpb.File) ([]*pluginpb.CodeGeneratorResponse_File, error) +} diff --git a/gateway/protoc-gen-grpc-gateway/BUILD.bazel b/gateway/protoc-gen-grpc-gateway/BUILD.bazel index 6eeb869..48a3ca8 100644 --- a/gateway/protoc-gen-grpc-gateway/BUILD.bazel +++ b/gateway/protoc-gen-grpc-gateway/BUILD.bazel @@ -8,12 +8,12 @@ go_library( srcs = ["main.go"], importpath = "github.com/binchencoder/ease-gateway/gateway/protoc-gen-grpc-gateway", deps = [ - "//gateway/protoc-gen-grpc-gateway/descriptor:go_default_library", + "//gateway/internal/descriptor:go_default_library", "//gateway/protoc-gen-grpc-gateway/internal/gengateway:go_default_library", "@com_github_golang_glog//:go_default_library", - "@com_github_golang_protobuf//proto:go_default_library", - "@com_github_grpc_ecosystem_grpc_gateway//codegenerator:go_default_library", + "@com_github_grpc_ecosystem_grpc_gateway//internal/codegenerator:go_default_library", "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", + "@org_golang_google_protobuf//proto:go_default_library", ], ) @@ -37,11 +37,11 @@ go_proto_compiler( "@com_github_binchencoder_gateway_proto//data:go_default_library", "@com_github_binchencoder_gateway_proto//frontend:go_default_library", "@com_github_grpc_ecosystem_grpc_gateway//utilities:go_default_library", - "@com_github_golang_protobuf//proto:go_default_library", "@org_golang_google_grpc//:go_default_library", "@org_golang_google_grpc//codes:go_default_library", "@org_golang_google_grpc//grpclog:go_default_library", "@org_golang_google_grpc//status:go_default_library", "@org_golang_x_net//context:go_default_library", + "@org_golang_google_protobuf//proto:go_default_library", ], ) diff --git a/gateway/protoc-gen-grpc-gateway/descriptor/grpc_api_service.go b/gateway/protoc-gen-grpc-gateway/descriptor/grpc_api_service.go deleted file mode 100644 index 534daae..0000000 --- a/gateway/protoc-gen-grpc-gateway/descriptor/grpc_api_service.go +++ /dev/null @@ -1,32 +0,0 @@ -package descriptor - -import ( - "github.com/golang/protobuf/proto" - // "google.golang.org/genproto/googleapis/api/annotations" - annotations "github.com/binchencoder/ease-gateway/httpoptions" -) - -// GrpcAPIService represents a stripped down version of google.api.Service . -// Compare to https://github.com/googleapis/googleapis/blob/master/google/api/service.proto -// The original imports 23 other protobuf files we are not interested in. If a significant -// subset (>50%) of these start being reproduced in this file we should swap to using the -// full generated version instead. -// -// For the purposes of the gateway generator we only consider a small subset of all -// available features google supports in their service descriptions. Thanks to backwards -// compatibility guarantees by protobuf it is safe for us to remove the other fields. -// We also only implement the absolute minimum of protobuf generator boilerplate to use -// our simplified version. These should be pretty stable too. -type GrpcAPIService struct { - // Http Rule. Named Http in the actual proto. Changed to suppress linter warning. - HTTP *annotations.Http `protobuf:"bytes,9,opt,name=http" json:"http,omitempty"` -} - -// ProtoMessage returns an empty GrpcAPIService element -func (*GrpcAPIService) ProtoMessage() {} - -// Reset resets the GrpcAPIService -func (m *GrpcAPIService) Reset() { *m = GrpcAPIService{} } - -// String returns the string representation of the GrpcAPIService -func (m *GrpcAPIService) String() string { return proto.CompactTextString(m) } diff --git a/gateway/protoc-gen-grpc-gateway/generator/generator.go b/gateway/protoc-gen-grpc-gateway/generator/generator.go deleted file mode 100644 index 9816224..0000000 --- a/gateway/protoc-gen-grpc-gateway/generator/generator.go +++ /dev/null @@ -1,14 +0,0 @@ -// Package generator provides an abstract interface to code generators. -package generator - -import ( - plugin "github.com/golang/protobuf/protoc-gen-go/plugin" - // "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/descriptor" - "github.com/binchencoder/ease-gateway/gateway/protoc-gen-grpc-gateway/descriptor" -) - -// Generator is an abstraction of code generators. -type Generator interface { - // Generate generates output files from input .proto files. - Generate(targets []*descriptor.File) ([]*plugin.CodeGeneratorResponse_File, error) -} diff --git a/gateway/protoc-gen-grpc-gateway/internal/gengateway/BUILD.bazel b/gateway/protoc-gen-grpc-gateway/internal/gengateway/BUILD.bazel index 85b9987..a3b18ba 100644 --- a/gateway/protoc-gen-grpc-gateway/internal/gengateway/BUILD.bazel +++ b/gateway/protoc-gen-grpc-gateway/internal/gengateway/BUILD.bazel @@ -14,13 +14,12 @@ go_library( "//httpoptions:go_default_library", "//gateway/internal/casing:go_default_library", "//gateway/runtime:go_default_library", - "//gateway/protoc-gen-grpc-gateway/descriptor:go_default_library", - "//gateway/protoc-gen-grpc-gateway/generator:go_default_library", + "//gateway/internal/descriptor:go_default_library", + "//gateway/internal/generator:go_default_library", "@com_github_grpc_ecosystem_grpc_gateway//utilities:go_default_library", "@com_github_golang_glog//:go_default_library", - "@com_github_golang_protobuf//proto:go_default_library", - "@com_github_golang_protobuf//protoc-gen-go/generator:go_default_library_gen", "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", + "@org_golang_google_protobuf//proto:go_default_library", ], ) @@ -33,9 +32,9 @@ go_test( ], embed = [":go_default_library"], deps = [ - "//gateway/protoc-gen-grpc-gateway/descriptor:go_default_library", - "@com_github_golang_protobuf//proto:go_default_library", - "@com_github_grpc_ecosystem_grpc_gateway//protoc-gen-grpc-gateway/httprule:go_default_library", + "//gateway/internal/descriptor:go_default_library", + "@com_github_grpc_ecosystem_grpc_gateway//internal/httprule:go_default_library", "@io_bazel_rules_go//proto/wkt:descriptor_go_proto", + "@org_golang_google_protobuf//proto:go_default_library", ], ) diff --git a/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator.go b/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator.go index df96d3b..82684ac 100644 --- a/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator.go +++ b/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator.go @@ -9,14 +9,14 @@ import ( "strings" "github.com/golang/glog" - "github.com/golang/protobuf/proto" - plugin "github.com/golang/protobuf/protoc-gen-go/plugin" + pluginpb "github.com/golang/protobuf/protoc-gen-go/plugin" - // "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/descriptor" - "github.com/binchencoder/ease-gateway/gateway/protoc-gen-grpc-gateway/descriptor" + // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor" + "github.com/binchencoder/ease-gateway/gateway/internal/descriptor" - // gen "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/generator" - gen "github.com/binchencoder/ease-gateway/gateway/protoc-gen-grpc-gateway/generator" + // gen "github.com/grpc-ecosystem/grpc-gateway/v2/internal/generator" + gen "github.com/binchencoder/ease-gateway/gateway/internal/generator" + "google.golang.org/protobuf/proto" options "github.com/binchencoder/ease-gateway/httpoptions" ) @@ -40,10 +40,12 @@ type generator struct { pathType pathType modulePath string allowPatchFeature bool + standalone bool } // New returns a new generator which generates grpc gateway files. -func New(reg *descriptor.Registry, useRequestContext bool, registerFuncSuffix, pathTypeString, modulePathString string, allowPatchFeature bool) gen.Generator { +func New(reg *descriptor.Registry, useRequestContext bool, registerFuncSuffix, pathTypeString, modulePathString string, + allowPatchFeature, standalone bool) gen.Generator { var imports []descriptor.GoPackage for pkgpath, alias := range map[string]string{ "context": "", @@ -53,9 +55,10 @@ func New(reg *descriptor.Registry, useRequestContext bool, registerFuncSuffix, p "strings": "", "sync": "", "unicode/utf8": "", + // "github.com/grpc-ecosystem/grpc-gateway/v2/runtime", "github.com/binchencoder/ease-gateway/gateway/runtime": "", - "github.com/grpc-ecosystem/grpc-gateway/utilities": "", - "github.com/golang/protobuf/proto": "", + "github.com/grpc-ecosystem/grpc-gateway/v2/utilities": "", + "google.golang.org/protobuf/proto": "", "github.com/binchencoder/gateway-proto/data": "vexpb", "github.com/binchencoder/gateway-proto/frontend": "fpb", "github.com/binchencoder/letsgo/grpc": "lgr", @@ -107,11 +110,12 @@ func New(reg *descriptor.Registry, useRequestContext bool, registerFuncSuffix, p pathType: pathType, modulePath: modulePathString, allowPatchFeature: allowPatchFeature, + standalone: standalone, } } -func (g *generator) Generate(targets []*descriptor.File) ([]*plugin.CodeGeneratorResponse_File, error) { - var files []*plugin.CodeGeneratorResponse_File +func (g *generator) Generate(targets []*descriptor.File) ([]*pluginpb.CodeGeneratorResponse_File, error) { + var files []*pluginpb.CodeGeneratorResponse_File for _, file := range targets { glog.V(1).Infof("Processing %s", file.GetName()) code, err := g.generate(file) @@ -135,7 +139,7 @@ func (g *generator) Generate(targets []*descriptor.File) ([]*plugin.CodeGenerato ext := filepath.Ext(name) base := strings.TrimSuffix(name, ext) output := fmt.Sprintf("%s.pb.gw.go", base) - files = append(files, &plugin.CodeGeneratorResponse_File{ + files = append(files, &pluginpb.CodeGeneratorResponse_File{ Name: proto.String(output), Content: proto.String(string(formatted)), }) @@ -172,6 +176,11 @@ func (g *generator) generate(file *descriptor.File) (string, error) { pkgSeen[pkg.Path] = true imports = append(imports, pkg) } + + if g.standalone { + imports = append(imports, file.GoPkg) + } + for _, svc := range file.Services { for _, m := range svc.Methods { imports = append(imports, g.addEnumPathParamImports(file, m, pkgSeen)...) diff --git a/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator_test.go b/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator_test.go index fa09216..32fdc80 100644 --- a/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator_test.go +++ b/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator_test.go @@ -1,14 +1,15 @@ package gengateway import ( + "errors" "path/filepath" "strings" "testing" - "github.com/golang/protobuf/proto" - protodescriptor "github.com/golang/protobuf/protoc-gen-go/descriptor" - // "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/descriptor" - "github.com/binchencoder/ease-gateway/gateway/protoc-gen-grpc-gateway/descriptor" + descriptorpb "github.com/golang/protobuf/protoc-gen-go/descriptor" + // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor" + "github.com/binchencoder/ease-gateway/gateway/internal/descriptor" + "google.golang.org/protobuf/proto" ) func newExampleFileDescriptor() *descriptor.File { @@ -21,7 +22,7 @@ func newExampleFileDescriptor() *descriptor.File { } func newExampleFileDescriptorWithGoPkg(gp *descriptor.GoPackage) *descriptor.File { - msgdesc := &protodescriptor.DescriptorProto{ + msgdesc := &descriptorpb.DescriptorProto{ Name: proto.String("ExampleMessage"), } msg := &descriptor.Message{ @@ -32,31 +33,31 @@ func newExampleFileDescriptorWithGoPkg(gp *descriptor.GoPackage) *descriptor.Fil File: &descriptor.File{ GoPkg: descriptor.GoPackage{ Path: "github.com/golang/protobuf/ptypes/empty", - Name: "empty", + Name: "emptypb", }, }, } - meth := &protodescriptor.MethodDescriptorProto{ + meth := &descriptorpb.MethodDescriptorProto{ Name: proto.String("Example"), InputType: proto.String("ExampleMessage"), OutputType: proto.String("ExampleMessage"), } - meth1 := &protodescriptor.MethodDescriptorProto{ + meth1 := &descriptorpb.MethodDescriptorProto{ Name: proto.String("ExampleWithoutBindings"), InputType: proto.String("empty.Empty"), OutputType: proto.String("empty.Empty"), } - svc := &protodescriptor.ServiceDescriptorProto{ + svc := &descriptorpb.ServiceDescriptorProto{ Name: proto.String("ExampleService"), - Method: []*protodescriptor.MethodDescriptorProto{meth, meth1}, + Method: []*descriptorpb.MethodDescriptorProto{meth, meth1}, } return &descriptor.File{ - FileDescriptorProto: &protodescriptor.FileDescriptorProto{ + FileDescriptorProto: &descriptorpb.FileDescriptorProto{ Name: proto.String("example.proto"), Package: proto.String("example"), Dependency: []string{"a.example/b/c.proto", "a.example/d/e.proto"}, - MessageType: []*protodescriptor.DescriptorProto{msgdesc}, - Service: []*protodescriptor.ServiceDescriptorProto{svc}, + MessageType: []*descriptorpb.DescriptorProto{msgdesc}, + Service: []*descriptorpb.ServiceDescriptorProto{svc}, }, GoPkg: *gp, Messages: []*descriptor.Message{msg}, @@ -101,9 +102,11 @@ func TestGenerateServiceWithoutBindings(t *testing.T) { func TestGenerateOutputPath(t *testing.T) { cases := []struct { - file *descriptor.File - pathType pathType - expected string + file *descriptor.File + pathType pathType + modulePath string + expected string + expectedError error }{ { file: newExampleFileDescriptorWithGoPkg( @@ -143,13 +146,79 @@ func TestGenerateOutputPath(t *testing.T) { pathType: pathTypeSourceRelative, expected: ".", }, + { + file: newExampleFileDescriptorWithGoPkg( + &descriptor.GoPackage{ + Path: "example.com/path/root", + Name: "example_pb", + }, + ), + modulePath: "example.com/path/root", + expected: ".", + }, + { + file: newExampleFileDescriptorWithGoPkg( + &descriptor.GoPackage{ + Path: "example.com/path/to/example", + Name: "example_pb", + }, + ), + modulePath: "example.com/path/to", + expected: "example", + }, + { + file: newExampleFileDescriptorWithGoPkg( + &descriptor.GoPackage{ + Path: "example.com/path/to/example/with/many/nested/paths", + Name: "example_pb", + }, + ), + modulePath: "example.com/path/to", + expected: "example/with/many/nested/paths", + }, + + // Error cases + { + file: newExampleFileDescriptorWithGoPkg( + &descriptor.GoPackage{ + Path: "example.com/path/root", + Name: "example_pb", + }, + ), + modulePath: "example.com/path/root", + pathType: pathTypeSourceRelative, // Not allowed + expectedError: errors.New("cannot use module= with paths="), + }, + { + file: newExampleFileDescriptorWithGoPkg( + &descriptor.GoPackage{ + Path: "example.com/path/rootextra", + Name: "example_pb", + }, + ), + modulePath: "example.com/path/root", + expectedError: errors.New("example.com/path/rootextra: file go path does not match module prefix: example.com/path/root/"), + }, } for _, c := range cases { - g := &generator{pathType: c.pathType} + g := &generator{ + pathType: c.pathType, + modulePath: c.modulePath, + } file := c.file gots, err := g.Generate([]*descriptor.File{crossLinkFixture(file)}) + + // If we expect an error response, check it matches what we want + if c.expectedError != nil { + if err == nil || err.Error() != c.expectedError.Error() { + t.Errorf("Generate(%#v) failed with %v; wants error of: %v", file, err, c.expectedError) + } + return + } + + // Handle case where we don't expect an error if err != nil { t.Errorf("Generate(%#v) failed with %v; wants success", file, err) return diff --git a/gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go b/gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go index 1a5edad..f70c8c5 100644 --- a/gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go +++ b/gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go @@ -8,12 +8,12 @@ import ( "text/template" "unicode" - "github.com/binchencoder/ease-gateway/gateway/internal/casing" "github.com/golang/glog" - - // "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/descriptor" - "github.com/binchencoder/ease-gateway/gateway/protoc-gen-grpc-gateway/descriptor" - "github.com/grpc-ecosystem/grpc-gateway/utilities" + // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/casing" + "github.com/binchencoder/ease-gateway/gateway/internal/casing" + // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor" + "github.com/binchencoder/ease-gateway/gateway/internal/descriptor" + "github.com/grpc-ecosystem/grpc-gateway/v2/utilities" ) type param struct { @@ -43,7 +43,7 @@ func (b binding) GetBodyFieldStructName() (string, error) { if b.Body != nil && len(b.Body.FieldPath) != 0 { return casing.Camel(b.Body.FieldPath.String()), nil } - return "", errors.New("No body field found") + return "", errors.New("no body field found") } // badToUnderscore is the mapping function used to generate Go names from @@ -165,7 +165,6 @@ type trailerParams struct { Services []*descriptor.Service UseRequestContext bool RegisterFuncSuffix string - AssumeColonVerb bool } func applyTemplate(p param, reg *descriptor.Registry) (string, error) { @@ -184,10 +183,12 @@ func applyTemplate(p param, reg *descriptor.Registry) (string, error) { msgName := casing.Camel(*msg.Name) msg.Name = &msgName } + for _, svc := range p.Services { var methodWithBindingsSeen bool svcName := casing.Camel(*svc.Name) svc.Name = &svcName + for _, meth := range svc.Methods { glog.V(2).Infof("Processing %s.%s", svc.GetName(), meth.GetName()) methName := casing.Camel(*meth.Name) @@ -220,15 +221,10 @@ func applyTemplate(p param, reg *descriptor.Registry) (string, error) { return "", errNoTargetService } - assumeColonVerb := true - if reg != nil { - assumeColonVerb = !reg.GetAllowColonFinalSegments() - } tp := trailerParams{ Services: targetServices, UseRequestContext: p.UseRequestContext, RegisterFuncSuffix: p.RegisterFuncSuffix, - AssumeColonVerb: assumeColonVerb, } // Local if err := localTrailerTemplate.Execute(w, tp); err != nil { @@ -450,9 +446,9 @@ var {{.GetUniqueName}}_error = lgr.ToGrpcError(codes.InvalidArgument, &fpb.Error _ = 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) +func request_{{.Method.Service.GetName}}_{{.Method.GetName}}_{{.Index}}(ctx context.Context, marshaler runtime.Marshaler, client {{.Method.Service.InstanceName}}Client, req *http.Request, pathParams map[string]string) ({{.Method.Service.InstanceName}}_{{.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) +func request_{{.Method.Service.GetName}}_{{.Method.GetName}}_{{.Index}}(ctx context.Context, marshaler runtime.Marshaler, client {{.Method.Service.InstanceName}}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(` @@ -525,8 +521,7 @@ var ( } {{- 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 { + if fieldMask, err := runtime.FieldMaskFromRequestBody(newReader(), protoReq.{{.GetBodyFieldStructName}}); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } else { protoReq.{{.FieldMaskField}} = fieldMask @@ -557,25 +552,34 @@ var ( } {{if $param.IsNestedProto3}} err = runtime.PopulateFieldFromPath(&protoReq, {{$param | printf "%q"}}, val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", {{$param | printf "%q"}}, err) + } {{if $enum}} - 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) + e{{if $param.IsRepeated}}s{{end}}, err = {{$param.ConvertFuncExpr}}(val{{if $param.IsRepeated}}, {{$binding.Registry.GetRepeatedPathParamSeparator | printf "%c" | printf "%q"}}{{end}}, {{$enum.GoType $param.Target.Message.File.GoPkg.Path}}_value) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "could not parse path as enum value, parameter: %s, error: %v", {{$param | printf "%q"}}, err) + } {{end}} {{else if $enum}} - 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) + e{{if $param.IsRepeated}}s{{end}}, err = {{$param.ConvertFuncExpr}}(val{{if $param.IsRepeated}}, {{$binding.Registry.GetRepeatedPathParamSeparator | printf "%c" | printf "%q"}}{{end}}, {{$enum.GoType $param.Target.Message.File.GoPkg.Path}}_value) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", {{$param | printf "%q"}}, err) + } {{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) } +{{end}} {{if and $enum $param.IsRepeated}} - s := make([]{{$enum.GoType $param.Method.Service.File.GoPkg.Path}}, len(es)) + s := make([]{{$enum.GoType $param.Target.Message.File.GoPkg.Path}}, len(es)) for i, v := range es { - s[i] = {{$enum.GoType $param.Method.Service.File.GoPkg.Path}}(v) + s[i] = {{$enum.GoType $param.Target.Message.File.GoPkg.Path}}(v) } {{$param.AssignableExpr "protoReq"}} = s {{else if $enum}} - {{$param.AssignableExpr "protoReq"}} = {{$enum.GoType $param.Method.Service.File.GoPkg.Path}}(e) + {{$param.AssignableExpr "protoReq"}} = {{$enum.GoType $param.Target.Message.File.GoPkg.Path}}(e) {{end}} {{end}} {{end}} @@ -686,7 +690,7 @@ var ( _ = 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) +func local_request_{{.Method.Service.GetName}}_{{.Method.GetName}}_{{.Index}}(ctx context.Context, marshaler runtime.Marshaler, server {{.Method.Service.InstanceName}}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(` @@ -704,8 +708,7 @@ func local_request_{{.Method.Service.GetName}}_{{.Method.GetName}}_{{.Index}}(ct } {{- 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 { + if fieldMask, err := runtime.FieldMaskFromRequestBody(newReader(), protoReq.{{.GetBodyFieldStructName}}); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } else { protoReq.{{.FieldMaskField}} = fieldMask @@ -735,25 +738,35 @@ func local_request_{{.Method.Service.GetName}}_{{.Method.GetName}}_{{.Index}}(ct } {{if $param.IsNestedProto3}} err = runtime.PopulateFieldFromPath(&protoReq, {{$param | printf "%q"}}, val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", {{$param | printf "%q"}}, err) + } {{if $enum}} - 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) + e{{if $param.IsRepeated}}s{{end}}, err = {{$param.ConvertFuncExpr}}(val{{if $param.IsRepeated}}, {{$binding.Registry.GetRepeatedPathParamSeparator | printf "%c" | printf "%q"}}{{end}}, {{$enum.GoType $param.Target.Message.File.GoPkg.Path}}_value) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "could not parse path as enum value, parameter: %s, error: %v", {{$param | printf "%q"}}, err) + } {{end}} {{else if $enum}} - 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) + e{{if $param.IsRepeated}}s{{end}}, err = {{$param.ConvertFuncExpr}}(val{{if $param.IsRepeated}}, {{$binding.Registry.GetRepeatedPathParamSeparator | printf "%c" | printf "%q"}}{{end}}, {{$enum.GoType $param.Target.Message.File.GoPkg.Path}}_value) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", {{$param | printf "%q"}}, err) + } {{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) } +{{end}} + {{if and $enum $param.IsRepeated}} - s := make([]{{$enum.GoType $param.Method.Service.File.GoPkg.Path}}, len(es)) + s := make([]{{$enum.GoType $param.Target.Message.File.GoPkg.Path}}, len(es)) for i, v := range es { - s[i] = {{$enum.GoType $param.Method.Service.File.GoPkg.Path}}(v) + s[i] = {{$enum.GoType $param.Target.Message.File.GoPkg.Path}}(v) } {{$param.AssignableExpr "protoReq"}} = s {{else if $enum}} - {{$param.AssignableExpr "protoReq"}} = {{$enum.GoType $param.Method.Service.File.GoPkg.Path}}(e) + {{$param.AssignableExpr "protoReq"}} = {{$enum.GoType $param.Target.Message.File.GoPkg.Path}}(e) {{end}} {{end}} {{end}} @@ -780,7 +793,7 @@ func local_request_{{.Method.Service.GetName}}_{{.Method.GetName}}_{{.Index}}(ct // UnaryRPC :call {{$svc.GetName}}Server directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. // Note that using this registration option will cause many gRPC library features (such as grpc.SendHeader, etc) to stop working. Consider using Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}FromEndpoint instead. -func Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}Server(ctx context.Context, mux *runtime.ServeMux, server {{$svc.GetName}}Server) error { +func Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}Server(ctx context.Context, mux *runtime.ServeMux, server {{$svc.InstanceName}}Server) error { {{range $m := $svc.Methods}} {{range $b := $m.Bindings}} {{if or $m.GetClientStreaming $m.GetServerStreaming}} @@ -799,7 +812,7 @@ func Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}Server(ctx context.Context, {{- end }} defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/{{$svc.File.GetPackage}}.{{$svc.GetName}}/{{$m.GetName}}") if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -888,8 +901,8 @@ func Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}(ctx context.Context, mux * // 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 { +// "{{$svc.InstanceName}}Client" to call the correct interceptors. +func Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}Client(ctx context.Context, mux *runtime.ServeMux, client {{$svc.InstanceName}}Client) error { spec := internal_{{$svc.GetName}}_{{$svc.ServiceId}}_spec {{range $m := $svc.Methods}} @@ -900,12 +913,13 @@ func Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}Client(ctx context.Context, // internal_{{$svc.ServiceId}}__{{$svc.Namespace}}__{{$svc.PortName}}_lock.RLock() // defer internal_{{$svc.ServiceId}}__{{$svc.Namespace}}__{{$svc.PortName}}_lock.RUnlock() client := internal_{{$svc.GetName}}_{{$svc.ServiceId}}_client + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) if client == nil { - runtime.DefaultOtherErrorHandler(w, req, "service disabled", http.StatusInternalServerError) + err := status.Error(codes.Internal, "service disabled") + runtime.HTTPError(inctx, mux, outboundMarshaler, w, req, err) return } - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) ctx, err := runtime.RequestAccepted(inctx, internal_{{$svc.GetName}}_{{$svc.ServiceId}}_spec, "{{$svc.GetName}}", "{{$m.GetName}}", w, req) if err != nil { grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) @@ -919,7 +933,7 @@ func Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}Client(ctx context.Context, ctx, cancel := context.WithCancel(ctx) {{- end }} defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req, "/{{$svc.File.GetPackage}}.{{$svc.GetName}}/{{$m.GetName}}") if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -1023,7 +1037,7 @@ func Disable{{$svc.GetName}}_Service() { var ( {{range $m := $svc.Methods}} {{range $b := $m.Bindings}} - 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}}))) + 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"}})) {{end}} {{end}} ) diff --git a/gateway/protoc-gen-grpc-gateway/internal/gengateway/template_test.go b/gateway/protoc-gen-grpc-gateway/internal/gengateway/template_test.go index 92e1a01..e6fffb0 100644 --- a/gateway/protoc-gen-grpc-gateway/internal/gengateway/template_test.go +++ b/gateway/protoc-gen-grpc-gateway/internal/gengateway/template_test.go @@ -4,12 +4,12 @@ import ( "strings" "testing" - "github.com/golang/protobuf/proto" - protodescriptor "github.com/golang/protobuf/protoc-gen-go/descriptor" - - // "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/descriptor" - "github.com/binchencoder/ease-gateway/gateway/protoc-gen-grpc-gateway/descriptor" - "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/httprule" + descriptorpb "github.com/golang/protobuf/protoc-gen-go/descriptor" + // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor" + "github.com/binchencoder/ease-gateway/gateway/internal/descriptor" + // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/httprule" + "github.com/grpc-ecosystem/grpc-gateway/v2/internal/httprule" + "google.golang.org/protobuf/proto" ) func crossLinkFixture(f *descriptor.File) *descriptor.File { @@ -32,28 +32,28 @@ func crossLinkFixture(f *descriptor.File) *descriptor.File { } func TestApplyTemplateHeader(t *testing.T) { - msgdesc := &protodescriptor.DescriptorProto{ + msgdesc := &descriptorpb.DescriptorProto{ Name: proto.String("ExampleMessage"), } - meth := &protodescriptor.MethodDescriptorProto{ + meth := &descriptorpb.MethodDescriptorProto{ Name: proto.String("Example"), InputType: proto.String("ExampleMessage"), OutputType: proto.String("ExampleMessage"), } - svc := &protodescriptor.ServiceDescriptorProto{ + svc := &descriptorpb.ServiceDescriptorProto{ Name: proto.String("ExampleService"), - Method: []*protodescriptor.MethodDescriptorProto{meth}, + Method: []*descriptorpb.MethodDescriptorProto{meth}, } msg := &descriptor.Message{ DescriptorProto: msgdesc, } file := descriptor.File{ - FileDescriptorProto: &protodescriptor.FileDescriptorProto{ + FileDescriptorProto: &descriptorpb.FileDescriptorProto{ Name: proto.String("example.proto"), Package: proto.String("example"), Dependency: []string{"a.example/b/c.proto", "a.example/d/e.proto"}, - MessageType: []*protodescriptor.DescriptorProto{msgdesc}, - Service: []*protodescriptor.ServiceDescriptorProto{svc}, + MessageType: []*descriptorpb.DescriptorProto{msgdesc}, + Service: []*descriptorpb.ServiceDescriptorProto{svc}, }, GoPkg: descriptor.GoPackage{ Path: "example.com/path/to/example/example.pb", @@ -90,44 +90,44 @@ func TestApplyTemplateHeader(t *testing.T) { } func TestApplyTemplateRequestWithoutClientStreaming(t *testing.T) { - msgdesc := &protodescriptor.DescriptorProto{ + msgdesc := &descriptorpb.DescriptorProto{ Name: proto.String("ExampleMessage"), - Field: []*protodescriptor.FieldDescriptorProto{ + Field: []*descriptorpb.FieldDescriptorProto{ { Name: proto.String("nested"), - Label: protodescriptor.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: protodescriptor.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), TypeName: proto.String("NestedMessage"), Number: proto.Int32(1), }, }, } - nesteddesc := &protodescriptor.DescriptorProto{ + nesteddesc := &descriptorpb.DescriptorProto{ Name: proto.String("NestedMessage"), - Field: []*protodescriptor.FieldDescriptorProto{ + Field: []*descriptorpb.FieldDescriptorProto{ { Name: proto.String("int32"), - Label: protodescriptor.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: protodescriptor.FieldDescriptorProto_TYPE_INT32.Enum(), + Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_INT32.Enum(), Number: proto.Int32(1), }, { Name: proto.String("bool"), - Label: protodescriptor.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: protodescriptor.FieldDescriptorProto_TYPE_BOOL.Enum(), + Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_BOOL.Enum(), Number: proto.Int32(2), }, }, } - meth := &protodescriptor.MethodDescriptorProto{ + meth := &descriptorpb.MethodDescriptorProto{ Name: proto.String("Echo"), InputType: proto.String("ExampleMessage"), OutputType: proto.String("ExampleMessage"), ClientStreaming: proto.Bool(false), } - svc := &protodescriptor.ServiceDescriptorProto{ + svc := &descriptorpb.ServiceDescriptorProto{ Name: proto.String("ExampleService"), - Method: []*protodescriptor.MethodDescriptorProto{meth}, + Method: []*descriptorpb.MethodDescriptorProto{meth}, } for _, spec := range []struct { serverStreaming bool @@ -164,11 +164,11 @@ func TestApplyTemplateRequestWithoutClientStreaming(t *testing.T) { FieldDescriptorProto: nested.GetField()[1], } file := descriptor.File{ - FileDescriptorProto: &protodescriptor.FileDescriptorProto{ + FileDescriptorProto: &descriptorpb.FileDescriptorProto{ Name: proto.String("example.proto"), Package: proto.String("example"), - MessageType: []*protodescriptor.DescriptorProto{msgdesc, nesteddesc}, - Service: []*protodescriptor.ServiceDescriptorProto{svc}, + MessageType: []*descriptorpb.DescriptorProto{msgdesc, nesteddesc}, + Service: []*descriptorpb.ServiceDescriptorProto{svc}, }, GoPkg: descriptor.GoPackage{ Path: "example.com/path/to/example/example.pb", @@ -244,51 +244,54 @@ func TestApplyTemplateRequestWithoutClientStreaming(t *testing.T) { if want := `func RegisterExampleServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {`; !strings.Contains(got, want) { t.Errorf("applyTemplate(%#v) = %s; want to contain %s", file, got, want) } - if want := `pattern_ExampleService_Echo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{0, 0}, []string(nil), "", runtime.AssumeColonVerbOpt(true)))`; !strings.Contains(got, want) { + if want := `pattern_ExampleService_Echo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{0, 0}, []string(nil), ""))`; !strings.Contains(got, want) { + t.Errorf("applyTemplate(%#v) = %s; want to contain %s", file, got, want) + } + if want := `rctx, err := runtime.AnnotateContext(ctx, mux, req, "/example.ExampleService/Echo")`; !strings.Contains(got, want) { t.Errorf("applyTemplate(%#v) = %s; want to contain %s", file, got, want) } } } func TestApplyTemplateRequestWithClientStreaming(t *testing.T) { - msgdesc := &protodescriptor.DescriptorProto{ + msgdesc := &descriptorpb.DescriptorProto{ Name: proto.String("ExampleMessage"), - Field: []*protodescriptor.FieldDescriptorProto{ + Field: []*descriptorpb.FieldDescriptorProto{ { Name: proto.String("nested"), - Label: protodescriptor.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: protodescriptor.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), TypeName: proto.String("NestedMessage"), Number: proto.Int32(1), }, }, } - nesteddesc := &protodescriptor.DescriptorProto{ + nesteddesc := &descriptorpb.DescriptorProto{ Name: proto.String("NestedMessage"), - Field: []*protodescriptor.FieldDescriptorProto{ + Field: []*descriptorpb.FieldDescriptorProto{ { Name: proto.String("int32"), - Label: protodescriptor.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: protodescriptor.FieldDescriptorProto_TYPE_INT32.Enum(), + Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_INT32.Enum(), Number: proto.Int32(1), }, { Name: proto.String("bool"), - Label: protodescriptor.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: protodescriptor.FieldDescriptorProto_TYPE_BOOL.Enum(), + Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_BOOL.Enum(), Number: proto.Int32(2), }, }, } - meth := &protodescriptor.MethodDescriptorProto{ + meth := &descriptorpb.MethodDescriptorProto{ Name: proto.String("Echo"), InputType: proto.String("ExampleMessage"), OutputType: proto.String("ExampleMessage"), ClientStreaming: proto.Bool(true), } - svc := &protodescriptor.ServiceDescriptorProto{ + svc := &descriptorpb.ServiceDescriptorProto{ Name: proto.String("ExampleService"), - Method: []*protodescriptor.MethodDescriptorProto{meth}, + Method: []*descriptorpb.MethodDescriptorProto{meth}, } for _, spec := range []struct { serverStreaming bool @@ -325,11 +328,11 @@ func TestApplyTemplateRequestWithClientStreaming(t *testing.T) { FieldDescriptorProto: nested.GetField()[1], } file := descriptor.File{ - FileDescriptorProto: &protodescriptor.FileDescriptorProto{ + FileDescriptorProto: &descriptorpb.FileDescriptorProto{ Name: proto.String("example.proto"), Package: proto.String("example"), - MessageType: []*protodescriptor.DescriptorProto{msgdesc, nesteddesc}, - Service: []*protodescriptor.ServiceDescriptorProto{svc}, + MessageType: []*descriptorpb.DescriptorProto{msgdesc, nesteddesc}, + Service: []*descriptorpb.ServiceDescriptorProto{svc}, }, GoPkg: descriptor.GoPackage{ Path: "example.com/path/to/example/example.pb", @@ -396,51 +399,51 @@ func TestApplyTemplateRequestWithClientStreaming(t *testing.T) { if want := `func RegisterExampleServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {`; !strings.Contains(got, want) { t.Errorf("applyTemplate(%#v) = %s; want to contain %s", file, got, want) } - if want := `pattern_ExampleService_Echo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{0, 0}, []string(nil), "", runtime.AssumeColonVerbOpt(true)))`; !strings.Contains(got, want) { + if want := `pattern_ExampleService_Echo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{0, 0}, []string(nil), ""))`; !strings.Contains(got, want) { t.Errorf("applyTemplate(%#v) = %s; want to contain %s", file, got, want) } } } func TestApplyTemplateInProcess(t *testing.T) { - msgdesc := &protodescriptor.DescriptorProto{ + msgdesc := &descriptorpb.DescriptorProto{ Name: proto.String("ExampleMessage"), - Field: []*protodescriptor.FieldDescriptorProto{ + Field: []*descriptorpb.FieldDescriptorProto{ { Name: proto.String("nested"), - Label: protodescriptor.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: protodescriptor.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), TypeName: proto.String("NestedMessage"), Number: proto.Int32(1), }, }, } - nesteddesc := &protodescriptor.DescriptorProto{ + nesteddesc := &descriptorpb.DescriptorProto{ Name: proto.String("NestedMessage"), - Field: []*protodescriptor.FieldDescriptorProto{ + Field: []*descriptorpb.FieldDescriptorProto{ { Name: proto.String("int32"), - Label: protodescriptor.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: protodescriptor.FieldDescriptorProto_TYPE_INT32.Enum(), + Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_INT32.Enum(), Number: proto.Int32(1), }, { Name: proto.String("bool"), - Label: protodescriptor.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: protodescriptor.FieldDescriptorProto_TYPE_BOOL.Enum(), + Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_BOOL.Enum(), Number: proto.Int32(2), }, }, } - meth := &protodescriptor.MethodDescriptorProto{ + meth := &descriptorpb.MethodDescriptorProto{ Name: proto.String("Echo"), InputType: proto.String("ExampleMessage"), OutputType: proto.String("ExampleMessage"), ClientStreaming: proto.Bool(true), } - svc := &protodescriptor.ServiceDescriptorProto{ + svc := &descriptorpb.ServiceDescriptorProto{ Name: proto.String("ExampleService"), - Method: []*protodescriptor.MethodDescriptorProto{meth}, + Method: []*descriptorpb.MethodDescriptorProto{meth}, } for _, spec := range []struct { clientStreaming bool @@ -500,11 +503,11 @@ func TestApplyTemplateInProcess(t *testing.T) { FieldDescriptorProto: nested.GetField()[1], } file := descriptor.File{ - FileDescriptorProto: &protodescriptor.FileDescriptorProto{ + FileDescriptorProto: &descriptorpb.FileDescriptorProto{ Name: proto.String("example.proto"), Package: proto.String("example"), - MessageType: []*protodescriptor.DescriptorProto{msgdesc, nesteddesc}, - Service: []*protodescriptor.ServiceDescriptorProto{svc}, + MessageType: []*descriptorpb.DescriptorProto{msgdesc, nesteddesc}, + Service: []*descriptorpb.ServiceDescriptorProto{svc}, }, GoPkg: descriptor.GoPackage{ Path: "example.com/path/to/example/example.pb", @@ -579,25 +582,25 @@ func TestApplyTemplateInProcess(t *testing.T) { } func TestAllowPatchFeature(t *testing.T) { - updateMaskDesc := &protodescriptor.FieldDescriptorProto{ + updateMaskDesc := &descriptorpb.FieldDescriptorProto{ Name: proto.String("UpdateMask"), - Label: protodescriptor.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: protodescriptor.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), TypeName: proto.String(".google.protobuf.FieldMask"), Number: proto.Int32(1), } - msgdesc := &protodescriptor.DescriptorProto{ + msgdesc := &descriptorpb.DescriptorProto{ Name: proto.String("ExampleMessage"), - Field: []*protodescriptor.FieldDescriptorProto{updateMaskDesc}, + Field: []*descriptorpb.FieldDescriptorProto{updateMaskDesc}, } - meth := &protodescriptor.MethodDescriptorProto{ + meth := &descriptorpb.MethodDescriptorProto{ Name: proto.String("Example"), InputType: proto.String("ExampleMessage"), OutputType: proto.String("ExampleMessage"), } - svc := &protodescriptor.ServiceDescriptorProto{ + svc := &descriptorpb.ServiceDescriptorProto{ Name: proto.String("ExampleService"), - Method: []*protodescriptor.MethodDescriptorProto{meth}, + Method: []*descriptorpb.MethodDescriptorProto{meth}, } msg := &descriptor.Message{ DescriptorProto: msgdesc, @@ -608,11 +611,11 @@ func TestAllowPatchFeature(t *testing.T) { } msg.Fields = append(msg.Fields, updateMaskField) file := descriptor.File{ - FileDescriptorProto: &protodescriptor.FileDescriptorProto{ + FileDescriptorProto: &descriptorpb.FileDescriptorProto{ Name: proto.String("example.proto"), Package: proto.String("example"), - MessageType: []*protodescriptor.DescriptorProto{msgdesc}, - Service: []*protodescriptor.ServiceDescriptorProto{svc}, + MessageType: []*descriptorpb.DescriptorProto{msgdesc}, + Service: []*descriptorpb.ServiceDescriptorProto{svc}, }, GoPkg: descriptor.GoPackage{ Path: "example.com/path/to/example/example.pb", @@ -661,25 +664,25 @@ func TestAllowPatchFeature(t *testing.T) { } func TestIdentifierCapitalization(t *testing.T) { - msgdesc1 := &protodescriptor.DescriptorProto{ + msgdesc1 := &descriptorpb.DescriptorProto{ Name: proto.String("Exam_pleRequest"), } - msgdesc2 := &protodescriptor.DescriptorProto{ + msgdesc2 := &descriptorpb.DescriptorProto{ Name: proto.String("example_response"), } - meth1 := &protodescriptor.MethodDescriptorProto{ + meth1 := &descriptorpb.MethodDescriptorProto{ Name: proto.String("ExampleGe2t"), InputType: proto.String("Exam_pleRequest"), OutputType: proto.String("example_response"), } - meth2 := &protodescriptor.MethodDescriptorProto{ + meth2 := &descriptorpb.MethodDescriptorProto{ Name: proto.String("Exampl_eGet"), InputType: proto.String("Exam_pleRequest"), OutputType: proto.String("example_response"), } - svc := &protodescriptor.ServiceDescriptorProto{ + svc := &descriptorpb.ServiceDescriptorProto{ Name: proto.String("Example"), - Method: []*protodescriptor.MethodDescriptorProto{meth1, meth2}, + Method: []*descriptorpb.MethodDescriptorProto{meth1, meth2}, } msg1 := &descriptor.Message{ DescriptorProto: msgdesc1, @@ -688,12 +691,12 @@ func TestIdentifierCapitalization(t *testing.T) { DescriptorProto: msgdesc2, } file := descriptor.File{ - FileDescriptorProto: &protodescriptor.FileDescriptorProto{ + FileDescriptorProto: &descriptorpb.FileDescriptorProto{ Name: proto.String("example.proto"), Package: proto.String("example"), Dependency: []string{"a.example/b/c.proto", "a.example/d/e.proto"}, - MessageType: []*protodescriptor.DescriptorProto{msgdesc1, msgdesc2}, - Service: []*protodescriptor.ServiceDescriptorProto{svc}, + MessageType: []*descriptorpb.DescriptorProto{msgdesc1, msgdesc2}, + Service: []*descriptorpb.ServiceDescriptorProto{svc}, }, GoPkg: descriptor.GoPackage{ Path: "example.com/path/to/example/example.pb", diff --git a/gateway/protoc-gen-grpc-gateway/main.go b/gateway/protoc-gen-grpc-gateway/main.go index 3ebe467..2a2ce12 100644 --- a/gateway/protoc-gen-grpc-gateway/main.go +++ b/gateway/protoc-gen-grpc-gateway/main.go @@ -15,16 +15,15 @@ import ( "strings" "github.com/golang/glog" - "github.com/golang/protobuf/proto" - plugin "github.com/golang/protobuf/protoc-gen-go/plugin" + pluginpb "github.com/golang/protobuf/protoc-gen-go/plugin" + "github.com/grpc-ecosystem/grpc-gateway/v2/internal/codegenerator" - "github.com/grpc-ecosystem/grpc-gateway/codegenerator" + // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor" + "github.com/binchencoder/ease-gateway/gateway/internal/descriptor" - // "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/descriptor" - "github.com/binchencoder/ease-gateway/gateway/protoc-gen-grpc-gateway/descriptor" - - // "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/internal/gengateway" + // "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway/internal/gengateway" "github.com/binchencoder/ease-gateway/gateway/protoc-gen-grpc-gateway/internal/gengateway" + "google.golang.org/protobuf/proto" ) var ( @@ -39,7 +38,7 @@ var ( allowRepeatedFieldsInBody = flag.Bool("allow_repeated_fields_in_body", false, "allows to use repeated field in `body` and `response_body` field of `google.api.http` annotation option") repeatedPathParamSeparator = flag.String("repeated_path_param_separator", "csv", "configures how repeated fields should be split. Allowed values are `csv`, `pipes`, `ssv` and `tsv`.") allowPatchFeature = flag.Bool("allow_patch_feature", true, "determines whether to use PATCH feature involving update masks (using google.protobuf.FieldMask).") - allowColonFinalSegments = flag.Bool("allow_colon_final_segments", false, "determines whether colons are permitted in the final segment of a path") + standalone = flag.Bool("standalone", false, "generates a standalone gateway package, which imports the target service package") versionFlag = flag.Bool("version", false, "print the current version") ) @@ -88,7 +87,7 @@ func main() { } } - g := gengateway.New(reg, *useRequestContext, *registerFuncSuffix, *pathType, *modulePath, *allowPatchFeature) + g := gengateway.New(reg, *useRequestContext, *registerFuncSuffix, *pathType, *modulePath, *allowPatchFeature, *standalone) if *grpcAPIConfiguration != "" { if err := reg.LoadGrpcAPIServiceFromYAML(*grpcAPIConfiguration); err != nil { @@ -97,11 +96,11 @@ func main() { } } + reg.SetStandalone(*standalone) reg.SetPrefix(*importPrefix) reg.SetImportPath(*importPath) reg.SetAllowDeleteBody(*allowDeleteBody) reg.SetAllowRepeatedFieldsInBody(*allowRepeatedFieldsInBody) - reg.SetAllowColonFinalSegments(*allowColonFinalSegments) if err := reg.SetRepeatedPathParamSeparator(*repeatedPathParamSeparator); err != nil { emitError(err) return @@ -110,6 +109,7 @@ func main() { emitError(err) return } + unboundHTTPRules := reg.UnboundExternalHTTPRules() if len(unboundHTTPRules) != 0 { emitError(fmt.Errorf("HTTP rules without a matching selector: %s", strings.Join(unboundHTTPRules, ", "))) @@ -134,15 +134,15 @@ func main() { emitFiles(out) } -func emitFiles(out []*plugin.CodeGeneratorResponse_File) { - emitResp(&plugin.CodeGeneratorResponse{File: out}) +func emitFiles(out []*pluginpb.CodeGeneratorResponse_File) { + emitResp(&pluginpb.CodeGeneratorResponse{File: out}) } func emitError(err error) { - emitResp(&plugin.CodeGeneratorResponse{Error: proto.String(err.Error())}) + emitResp(&pluginpb.CodeGeneratorResponse{Error: proto.String(err.Error())}) } -func emitResp(resp *plugin.CodeGeneratorResponse) { +func emitResp(resp *pluginpb.CodeGeneratorResponse) { buf, err := proto.Marshal(resp) if err != nil { glog.Fatal(err) diff --git a/gateway/protoc-gen-swagger/BUILD.bazel b/gateway/protoc-gen-openapiv2/BUILD.bazel similarity index 63% rename from gateway/protoc-gen-swagger/BUILD.bazel rename to gateway/protoc-gen-openapiv2/BUILD.bazel index e2dc53d..d9afac7 100644 --- a/gateway/protoc-gen-swagger/BUILD.bazel +++ b/gateway/protoc-gen-openapiv2/BUILD.bazel @@ -5,19 +5,19 @@ package(default_visibility = ["//visibility:public"]) go_library( name = "go_default_library", srcs = ["main.go"], - importpath = "github.com/binchencoder/ease-gateway/gateway/protoc-gen-swagger", + importpath = "github.com/binchencoder/ease-gateway/gateway/protoc-gen-openapiv2", deps = [ - "//gateway/protoc-gen-grpc-gateway/descriptor:go_default_library", - "//gateway/protoc-gen-swagger/genswagger:go_default_library", + "//gateway/internal/descriptor:go_default_library", + "//gateway/protoc-gen-openapiv2/internal/genopenapi:go_default_library", "@com_github_golang_glog//:go_default_library", - "@com_github_golang_protobuf//proto:go_default_library", - "@com_github_grpc_ecosystem_grpc_gateway//codegenerator:go_default_library", + "@com_github_grpc_ecosystem_grpc_gateway//internal/codegenerator:go_default_library", "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", + "@org_golang_google_protobuf//proto:go_default_library", ], ) go_binary( - name = "protoc-gen-swagger", + name = "protoc-gen-openapiv2", embed = [":go_default_library"], visibility = ["//visibility:public"], ) diff --git a/gateway/protoc-gen-swagger/defs.bzl b/gateway/protoc-gen-openapiv2/defs.bzl similarity index 78% rename from gateway/protoc-gen-swagger/defs.bzl rename to gateway/protoc-gen-openapiv2/defs.bzl index f1fac21..71822d5 100644 --- a/gateway/protoc-gen-swagger/defs.bzl +++ b/gateway/protoc-gen-openapiv2/defs.bzl @@ -44,30 +44,30 @@ def _direct_source_infos(proto_info, provided_sources = []): return infos -def _run_proto_gen_swagger( +def _run_proto_gen_openapi( actions, proto_info, target_name, transitive_proto_srcs, protoc, - protoc_gen_swagger, + protoc_gen_openapiv2, grpc_api_configuration, single_output, json_names_for_fields): args = actions.args() - args.add("--plugin", "protoc-gen-swagger=%s" % protoc_gen_swagger.path) + args.add("--plugin", "protoc-gen-openapiv2=%s" % protoc_gen_openapiv2.path) - args.add("--swagger_opt", "logtostderr=true") - args.add("--swagger_opt", "allow_repeated_fields_in_body=true") + args.add("--openapiv2_opt", "logtostderr=true") + args.add("--openapiv2_opt", "allow_repeated_fields_in_body=true") extra_inputs = [] if grpc_api_configuration: extra_inputs.append(grpc_api_configuration) - args.add("--swagger_opt", "grpc_api_configuration=%s" % grpc_api_configuration.path) + args.add("--openapiv2_opt", "grpc_api_configuration=%s" % grpc_api_configuration.path) - if json_names_for_fields: - args.add("--swagger_opt", "json_names_for_fields=true") + if not json_names_for_fields: + args.add("--openapiv2_opt", "json_names_for_fields=false") proto_file_infos = _direct_source_infos(proto_info) @@ -76,30 +76,30 @@ def _run_proto_gen_swagger( args.add_all(proto_info.transitive_proto_path, format_each = "--proto_path=%s") if single_output: - args.add("--swagger_opt", "allow_merge=true") - args.add("--swagger_opt", "merge_file_name=%s" % target_name) + args.add("--openapiv2_opt", "allow_merge=true") + args.add("--openapiv2_opt", "merge_file_name=%s" % target_name) - swagger_file = actions.declare_file("%s.swagger.json" % target_name) - args.add("--swagger_out", swagger_file.dirname) + openapi_file = actions.declare_file("%s.swagger.json" % target_name) + args.add("--openapiv2_out", openapi_file.dirname) args.add_all([f.import_path for f in proto_file_infos]) actions.run( executable = protoc, - tools = [protoc_gen_swagger], + tools = [protoc_gen_openapiv2], inputs = depset( direct = extra_inputs, transitive = [transitive_proto_srcs], ), - outputs = [swagger_file], + outputs = [openapi_file], arguments = [args], ) - return [swagger_file] + return [openapi_file] # TODO(yannic): We may be able to generate all files in a single action, # but that will change at least the semantics of `use_go_template.proto`. - swagger_files = [] + openapi_files = [] for proto_file_info in proto_file_infos: # TODO(yannic): This probably doesn't work as expected: we only add this # option after we have seen it, so `.proto` sources that happen to be @@ -107,40 +107,40 @@ def _run_proto_gen_swagger( # compiled without this option, and all sources that get compiled after # `use_go_template.proto` will have this option on. if proto_file_info.file.basename == "use_go_template.proto": - args.add("--swagger_opt", "use_go_templates=true") + args.add("--openapiv2_opt", "use_go_templates=true") file_name = "%s.swagger.json" % proto_file_info.import_path[:-len(".proto")] - swagger_file = actions.declare_file( + openapi_file = actions.declare_file( "_virtual_imports/%s/%s" % (target_name, file_name), ) file_args = actions.args() offset = len(file_name) + 1 # + '/'. - file_args.add("--swagger_out", swagger_file.path[:-offset]) + file_args.add("--openapiv2_out", openapi_file.path[:-offset]) file_args.add(proto_file_info.import_path) actions.run( executable = protoc, - tools = [protoc_gen_swagger], + tools = [protoc_gen_openapiv2], inputs = depset( direct = extra_inputs, transitive = [transitive_proto_srcs], ), - outputs = [swagger_file], + outputs = [openapi_file], arguments = [args, file_args], ) - swagger_files.append(swagger_file) + openapi_files.append(openapi_file) - return swagger_files + return openapi_files -def _proto_gen_swagger_impl(ctx): +def _proto_gen_openapi_impl(ctx): proto = ctx.attr.proto[ProtoInfo] return [ DefaultInfo( files = depset( - _run_proto_gen_swagger( + _run_proto_gen_openapi( actions = ctx.actions, proto_info = proto, target_name = ctx.attr.name, @@ -149,7 +149,7 @@ def _proto_gen_swagger_impl(ctx): transitive = [proto.transitive_sources], ), protoc = ctx.executable._protoc, - protoc_gen_swagger = ctx.executable._protoc_gen_swagger, + protoc_gen_openapiv2 = ctx.executable._protoc_gen_openapi, grpc_api_configuration = ctx.file.grpc_api_configuration, single_output = ctx.attr.single_output, json_names_for_fields = ctx.attr.json_names_for_fields, @@ -158,7 +158,7 @@ def _proto_gen_swagger_impl(ctx): ), ] -protoc_gen_swagger = rule( +protoc_gen_openapiv2 = rule( attrs = { "proto": attr.label( mandatory = True, @@ -173,7 +173,7 @@ protoc_gen_swagger = rule( mandatory = False, ), "json_names_for_fields": attr.bool( - default = False, + default = True, mandatory = False, ), "_protoc": attr.label( @@ -185,11 +185,11 @@ protoc_gen_swagger = rule( default = "@com_google_protobuf//:well_known_protos", allow_files = True, ), - "_protoc_gen_swagger": attr.label( - default = Label("//gateway/protoc-gen-swagger:protoc-gen-swagger"), + "_protoc_gen_openapi": attr.label( + default = Label("//gateway/protoc-gen-openapiv2:protoc-gen-openapiv2"), executable = True, cfg = "host", ), }, - implementation = _proto_gen_swagger_impl, + implementation = _proto_gen_openapi_impl, ) diff --git a/gateway/protoc-gen-swagger/genswagger/BUILD.bazel b/gateway/protoc-gen-openapiv2/internal/genopenapi/BUILD.bazel similarity index 61% rename from gateway/protoc-gen-swagger/genswagger/BUILD.bazel rename to gateway/protoc-gen-openapiv2/internal/genopenapi/BUILD.bazel index a2b19ab..eb346c7 100644 --- a/gateway/protoc-gen-swagger/genswagger/BUILD.bazel +++ b/gateway/protoc-gen-openapiv2/internal/genopenapi/BUILD.bazel @@ -12,23 +12,23 @@ go_library( "template.go", "types.go", ], - importpath = "github.com/binchencoder/ease-gateway/gateway/protoc-gen-swagger/genswagger", + importpath = "github.com/binchencoder/ease-gateway/gateway/protoc-gen-openapiv2/internal/genopenapi", deps = [ "//gateway/internal:go_default_library", "//gateway/internal/casing:go_default_library", - "//gateway/protoc-gen-grpc-gateway/descriptor:go_default_library", - "//gateway/protoc-gen-grpc-gateway/generator:go_default_library", - "//gateway/protoc-gen-swagger/options:go_default_library", + "//gateway/internal/descriptor:go_default_library", + "//gateway/internal/generator:go_default_library", + "//gateway/protoc-gen-openapiv2/options:go_default_library", "//httpoptions:go_default_library", "@com_github_golang_glog//:go_default_library", "@com_github_golang_protobuf//descriptor:go_default_library_gen", - "@com_github_golang_protobuf//jsonpb:go_default_library_gen", - "@com_github_golang_protobuf//proto:go_default_library", - "@com_github_golang_protobuf//protoc-gen-go/generator:go_default_library_gen", + "@go_googleapis//google/rpc:status_go_proto", "@io_bazel_rules_go//proto/wkt:any_go_proto", "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", "@io_bazel_rules_go//proto/wkt:descriptor_go_proto", "@io_bazel_rules_go//proto/wkt:struct_go_proto", + "@org_golang_google_protobuf//encoding/protojson:go_default_library", + "@org_golang_google_protobuf//proto:go_default_library", ], ) @@ -38,13 +38,15 @@ go_test( srcs = ["template_test.go"], embed = [":go_default_library"], deps = [ - "//gateway/protoc-gen-grpc-gateway/descriptor:go_default_library", - "//gateway/protoc-gen-swagger/options:go_default_library", - "@com_github_golang_protobuf//proto:go_default_library", - "@com_github_grpc_ecosystem_grpc_gateway//protoc-gen-grpc-gateway/httprule:go_default_library", + "//gateway/internal/descriptor:go_default_library", + "//gateway/protoc-gen-openapiv2/options:go_default_library", + "//gateway/runtime:go_default_library", + "@com_github_grpc_ecosystem_grpc_gateway//internal/httprule:go_default_library", + "@com_github_google_go_cmp//cmp:go_default_library", "@io_bazel_rules_go//proto/wkt:any_go_proto", "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", "@io_bazel_rules_go//proto/wkt:descriptor_go_proto", "@io_bazel_rules_go//proto/wkt:struct_go_proto", + "@org_golang_google_protobuf//proto:go_default_library", ], ) diff --git a/gateway/protoc-gen-openapiv2/internal/genopenapi/doc.go b/gateway/protoc-gen-openapiv2/internal/genopenapi/doc.go new file mode 100644 index 0000000..42f9237 --- /dev/null +++ b/gateway/protoc-gen-openapiv2/internal/genopenapi/doc.go @@ -0,0 +1,2 @@ +// Package genopenapi provides a code generator for OpenAPI v2. +package genopenapi diff --git a/gateway/protoc-gen-swagger/genswagger/generator.go b/gateway/protoc-gen-openapiv2/internal/genopenapi/generator.go similarity index 59% rename from gateway/protoc-gen-swagger/genswagger/generator.go rename to gateway/protoc-gen-openapiv2/internal/genopenapi/generator.go index 0a9965e..16a25ca 100644 --- a/gateway/protoc-gen-swagger/genswagger/generator.go +++ b/gateway/protoc-gen-openapiv2/internal/genopenapi/generator.go @@ -1,4 +1,4 @@ -package genswagger +package genopenapi import ( "bytes" @@ -10,23 +10,22 @@ import ( "strings" "github.com/golang/glog" - pbdescriptor "github.com/golang/protobuf/descriptor" - "github.com/golang/protobuf/proto" - protocdescriptor "github.com/golang/protobuf/protoc-gen-go/descriptor" - plugin "github.com/golang/protobuf/protoc-gen-go/plugin" - "github.com/golang/protobuf/ptypes/any" - - // "github.com/grpc-ecosystem/grpc-gateway/internal" - "github.com/binchencoder/ease-gateway/gateway/internal" - - // "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/descriptor" - "github.com/binchencoder/ease-gateway/gateway/protoc-gen-grpc-gateway/descriptor" - - // gen "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/generator" - gen "github.com/binchencoder/ease-gateway/gateway/protoc-gen-grpc-gateway/generator" - - // swagger_options "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger/options" - swagger_options "github.com/binchencoder/ease-gateway/gateway/protoc-gen-swagger/options" + descriptorpb "github.com/golang/protobuf/protoc-gen-go/descriptor" + pluginpb "github.com/golang/protobuf/protoc-gen-go/plugin" + anypb "github.com/golang/protobuf/ptypes/any" + //"github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor" + "github.com/binchencoder/ease-gateway/gateway/internal/descriptor" + // gen "github.com/grpc-ecosystem/grpc-gateway/v2/internal/generator" + gen "github.com/binchencoder/ease-gateway/gateway/internal/generator" + // openapi_options "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options" + openapi_options "github.com/binchencoder/ease-gateway/gateway/protoc-gen-openapiv2/options" + statuspb "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/protobuf/proto" + + //lint:ignore SA1019 known issue, will be replaced when possible + legacydescriptor "github.com/golang/protobuf/descriptor" + + ) var ( @@ -39,7 +38,7 @@ type generator struct { type wrapper struct { fileName string - swagger *swaggerObject + swagger *openapiSwaggerObject } // New returns a new generator which generates grpc gateway files. @@ -47,7 +46,7 @@ func New(reg *descriptor.Registry) gen.Generator { return &generator{reg: reg} } -// Merge a lot of swagger file (wrapper) to single one swagger file +// Merge a lot of OpenAPI file (wrapper) to single one OpenAPI file func mergeTargetFile(targets []*wrapper, mergeFileName string) *wrapper { var mergedTarget *wrapper for _, f := range targets { @@ -81,28 +80,28 @@ func mergeTargetFile(targets []*wrapper, mergeFileName string) *wrapper { // on them. See http://choly.ca/post/go-json-marshalling/ (or, if it ever // goes away, use // https://web.archive.org/web/20190806073003/http://choly.ca/post/go-json-marshalling/. -func (so swaggerObject) MarshalJSON() ([]byte, error) { - type alias swaggerObject +func (so openapiSwaggerObject) MarshalJSON() ([]byte, error) { + type alias openapiSwaggerObject return extensionMarshalJSON(alias(so), so.extensions) } -func (so swaggerInfoObject) MarshalJSON() ([]byte, error) { - type alias swaggerInfoObject +func (so openapiInfoObject) MarshalJSON() ([]byte, error) { + type alias openapiInfoObject return extensionMarshalJSON(alias(so), so.extensions) } -func (so swaggerSecuritySchemeObject) MarshalJSON() ([]byte, error) { - type alias swaggerSecuritySchemeObject +func (so openapiSecuritySchemeObject) MarshalJSON() ([]byte, error) { + type alias openapiSecuritySchemeObject return extensionMarshalJSON(alias(so), so.extensions) } -func (so swaggerOperationObject) MarshalJSON() ([]byte, error) { - type alias swaggerOperationObject +func (so openapiOperationObject) MarshalJSON() ([]byte, error) { + type alias openapiOperationObject return extensionMarshalJSON(alias(so), so.extensions) } -func (so swaggerResponseObject) MarshalJSON() ([]byte, error) { - type alias swaggerResponseObject +func (so openapiResponseObject) MarshalJSON() ([]byte, error) { + type alias openapiResponseObject return extensionMarshalJSON(alias(so), so.extensions) } @@ -113,14 +112,14 @@ func extensionMarshalJSON(so interface{}, extensions []extension) ([]byte, error // // The struct will look like // struct { - // *swaggerCore + // *openapiCore // XGrpcGatewayFoo json.RawMessage `json:"x-grpc-gateway-foo"` // XGrpcGatewayBar json.RawMessage `json:"x-grpc-gateway-bar"` // } - // and thus render into what we want -- the JSON of swaggerCore with the + // and thus render into what we want -- the JSON of openapiCore with the // extensions appended. fields := []reflect.StructField{ - reflect.StructField{ // embedded + { // embedded Name: "Embedded", Type: reflect.TypeOf(so), Anonymous: true, @@ -143,8 +142,8 @@ func extensionMarshalJSON(so interface{}, extensions []extension) ([]byte, error return json.Marshal(s.Interface()) } -// encodeSwagger converts swagger file obj to plugin.CodeGeneratorResponse_File -func encodeSwagger(file *wrapper) (*plugin.CodeGeneratorResponse_File, error) { +// encodeOpenAPI converts OpenAPI file obj to pluginpb.CodeGeneratorResponse_File +func encodeOpenAPI(file *wrapper) (*pluginpb.CodeGeneratorResponse_File, error) { var formatted bytes.Buffer enc := json.NewEncoder(&formatted) enc.SetIndent("", " ") @@ -155,19 +154,19 @@ func encodeSwagger(file *wrapper) (*plugin.CodeGeneratorResponse_File, error) { ext := filepath.Ext(name) base := strings.TrimSuffix(name, ext) output := fmt.Sprintf("%s.swagger.json", base) - return &plugin.CodeGeneratorResponse_File{ + return &pluginpb.CodeGeneratorResponse_File{ Name: proto.String(output), Content: proto.String(formatted.String()), }, nil } -func (g *generator) Generate(targets []*descriptor.File) ([]*plugin.CodeGeneratorResponse_File, error) { - var files []*plugin.CodeGeneratorResponse_File +func (g *generator) Generate(targets []*descriptor.File) ([]*pluginpb.CodeGeneratorResponse_File, error) { + var files []*pluginpb.CodeGeneratorResponse_File if g.reg.IsAllowMerge() { var mergedTarget *descriptor.File // try to find proto leader for _, f := range targets { - if proto.HasExtension(f.Options, swagger_options.E_Openapiv2Swagger) { + if proto.HasExtension(f.Options, openapi_options.E_Openapiv2Swagger) { mergedTarget = f break } @@ -187,7 +186,7 @@ func (g *generator) Generate(targets []*descriptor.File) ([]*plugin.CodeGenerato targets = append(targets, mergedTarget) } - var swaggers []*wrapper + var openapis []*wrapper for _, file := range targets { glog.V(1).Infof("Processing %s", file.GetName()) swagger, err := applyTemplate(param{File: file, reg: g.reg}) @@ -198,51 +197,48 @@ func (g *generator) Generate(targets []*descriptor.File) ([]*plugin.CodeGenerato if err != nil { return nil, err } - swaggers = append(swaggers, &wrapper{ + openapis = append(openapis, &wrapper{ fileName: file.GetName(), swagger: swagger, }) } if g.reg.IsAllowMerge() { - targetSwagger := mergeTargetFile(swaggers, g.reg.GetMergeFileName()) - f, err := encodeSwagger(targetSwagger) + targetOpenAPI := mergeTargetFile(openapis, g.reg.GetMergeFileName()) + f, err := encodeOpenAPI(targetOpenAPI) if err != nil { - return nil, fmt.Errorf("failed to encode swagger for %s: %s", g.reg.GetMergeFileName(), err) + return nil, fmt.Errorf("failed to encode OpenAPI for %s: %s", g.reg.GetMergeFileName(), err) } files = append(files, f) - glog.V(1).Infof("New swagger file will emit") + glog.V(1).Infof("New OpenAPI file will emit") } else { - for _, file := range swaggers { - f, err := encodeSwagger(file) + for _, file := range openapis { + f, err := encodeOpenAPI(file) if err != nil { - return nil, fmt.Errorf("failed to encode swagger for %s: %s", file.fileName, err) + return nil, fmt.Errorf("failed to encode OpenAPI for %s: %s", file.fileName, err) } files = append(files, f) - glog.V(1).Infof("New swagger file will emit") + glog.V(1).Infof("New OpenAPI file will emit") } } return files, nil } -//AddStreamError Adds grpc.gateway.runtime.StreamError and google.protobuf.Any to registry for stream responses -func AddStreamError(reg *descriptor.Registry) error { - //load internal protos - any := fileDescriptorProtoForMessage(&any.Any{}) - streamError := fileDescriptorProtoForMessage(&internal.StreamError{}) - if err := reg.Load(&plugin.CodeGeneratorRequest{ - ProtoFile: []*protocdescriptor.FileDescriptorProto{ +// AddErrorDefs Adds google.rpc.Status and google.protobuf.Any +// to registry (used for error-related API responses) +func AddErrorDefs(reg *descriptor.Registry) error { + // load internal protos + any, _ := legacydescriptor.MessageDescriptorProto(&anypb.Any{}) + any.SourceCodeInfo = new(descriptorpb.SourceCodeInfo) + status, _ := legacydescriptor.MessageDescriptorProto(&statuspb.Status{}) + status.SourceCodeInfo = new(descriptorpb.SourceCodeInfo) + // TODO(johanbrandhorst): Use new conversion later when possible + // any := protodesc.ToFileDescriptorProto((&anypb.Any{}).ProtoReflect().Descriptor().ParentFile()) + // status := protodesc.ToFileDescriptorProto((&statuspb.Status{}).ProtoReflect().Descriptor().ParentFile()) + return reg.Load(&pluginpb.CodeGeneratorRequest{ + ProtoFile: []*descriptorpb.FileDescriptorProto{ any, - streamError, + status, }, - }); err != nil { - return err - } - return nil -} - -func fileDescriptorProtoForMessage(msg pbdescriptor.Message) *protocdescriptor.FileDescriptorProto { - fdp, _ := pbdescriptor.ForMessage(msg) - fdp.SourceCodeInfo = &protocdescriptor.SourceCodeInfo{} - return fdp + }) } diff --git a/gateway/protoc-gen-swagger/genswagger/helpers.go b/gateway/protoc-gen-openapiv2/internal/genopenapi/helpers.go similarity index 86% rename from gateway/protoc-gen-swagger/genswagger/helpers.go rename to gateway/protoc-gen-openapiv2/internal/genopenapi/helpers.go index 3615596..c53d680 100644 --- a/gateway/protoc-gen-swagger/genswagger/helpers.go +++ b/gateway/protoc-gen-openapiv2/internal/genopenapi/helpers.go @@ -1,6 +1,6 @@ //+build go1.12 -package genswagger +package genopenapi import "strings" diff --git a/gateway/protoc-gen-swagger/genswagger/helpers_go111_old.go b/gateway/protoc-gen-openapiv2/internal/genopenapi/helpers_go111_old.go similarity index 87% rename from gateway/protoc-gen-swagger/genswagger/helpers_go111_old.go rename to gateway/protoc-gen-openapiv2/internal/genopenapi/helpers_go111_old.go index 8e9458d..b8db119 100644 --- a/gateway/protoc-gen-swagger/genswagger/helpers_go111_old.go +++ b/gateway/protoc-gen-openapiv2/internal/genopenapi/helpers_go111_old.go @@ -1,6 +1,6 @@ //+build !go1.12 -package genswagger +package genopenapi import "strings" diff --git a/gateway/protoc-gen-swagger/genswagger/template.go b/gateway/protoc-gen-openapiv2/internal/genopenapi/template.go similarity index 77% rename from gateway/protoc-gen-swagger/genswagger/template.go rename to gateway/protoc-gen-openapiv2/internal/genopenapi/template.go index 742aa9f..f2b6f84 100644 --- a/gateway/protoc-gen-swagger/genswagger/template.go +++ b/gateway/protoc-gen-openapiv2/internal/genopenapi/template.go @@ -1,4 +1,4 @@ -package genswagger +package genopenapi import ( "bytes" @@ -15,76 +15,78 @@ import ( "text/template" "github.com/golang/glog" - "github.com/golang/protobuf/jsonpb" - "github.com/golang/protobuf/proto" - pbdescriptor "github.com/golang/protobuf/protoc-gen-go/descriptor" + descriptorpb "github.com/golang/protobuf/protoc-gen-go/descriptor" structpb "github.com/golang/protobuf/ptypes/struct" + // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/casing" "github.com/binchencoder/ease-gateway/gateway/internal/casing" - // "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/descriptor" - "github.com/binchencoder/ease-gateway/gateway/protoc-gen-grpc-gateway/descriptor" + // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor" + "github.com/binchencoder/ease-gateway/gateway/internal/descriptor" + options "github.com/binchencoder/ease-gateway/httpoptions" - // swagger_options "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger/options" - swagger_options "github.com/binchencoder/ease-gateway/gateway/protoc-gen-swagger/options" + // openapi_options "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options" + openapi_options "github.com/binchencoder/ease-gateway/gateway/protoc-gen-openapiv2/options" + "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var wktSchemas = map[string]schemaCore{ - ".google.protobuf.Timestamp": schemaCore{ + ".google.protobuf.Timestamp": { Type: "string", Format: "date-time", }, - ".google.protobuf.Duration": schemaCore{ + ".google.protobuf.Duration": { Type: "string", }, - ".google.protobuf.StringValue": schemaCore{ + ".google.protobuf.StringValue": { Type: "string", }, - ".google.protobuf.BytesValue": schemaCore{ + ".google.protobuf.BytesValue": { Type: "string", Format: "byte", }, - ".google.protobuf.Int32Value": schemaCore{ + ".google.protobuf.Int32Value": { Type: "integer", Format: "int32", }, - ".google.protobuf.UInt32Value": schemaCore{ + ".google.protobuf.UInt32Value": { Type: "integer", Format: "int64", }, - ".google.protobuf.Int64Value": schemaCore{ + ".google.protobuf.Int64Value": { Type: "string", Format: "int64", }, - ".google.protobuf.UInt64Value": schemaCore{ + ".google.protobuf.UInt64Value": { Type: "string", Format: "uint64", }, - ".google.protobuf.FloatValue": schemaCore{ + ".google.protobuf.FloatValue": { Type: "number", Format: "float", }, - ".google.protobuf.DoubleValue": schemaCore{ + ".google.protobuf.DoubleValue": { Type: "number", Format: "double", }, - ".google.protobuf.BoolValue": schemaCore{ - Type: "boolean", + ".google.protobuf.BoolValue": { + Type: "boolean", }, - ".google.protobuf.Empty": schemaCore{}, - ".google.protobuf.Struct": schemaCore{ + ".google.protobuf.Empty": {}, + ".google.protobuf.Struct": { Type: "object", }, - ".google.protobuf.Value": schemaCore{ + ".google.protobuf.Value": { Type: "object", }, - ".google.protobuf.ListValue": schemaCore{ + ".google.protobuf.ListValue": { Type: "array", - Items: (*swaggerItemsObject)(&schemaCore{ + Items: (*openapiItemsObject)(&schemaCore{ Type: "object", }), }, - ".google.protobuf.NullValue": schemaCore{ + ".google.protobuf.NullValue": { Type: "string", }, } @@ -112,8 +114,8 @@ func getEnumDefault(enum *descriptor.Enum) string { return "" } -// messageToQueryParameters converts a message to a list of swagger query parameters. -func messageToQueryParameters(message *descriptor.Message, reg *descriptor.Registry, pathParams []descriptor.Parameter) (params []swaggerParameterObject, err error) { +// messageToQueryParameters converts a message to a list of OpenAPI query parameters. +func messageToQueryParameters(message *descriptor.Message, reg *descriptor.Registry, pathParams []descriptor.Parameter) (params []openapiParameterObject, err error) { for _, field := range message.Fields { p, err := queryParams(message, field, "", reg, pathParams) if err != nil { @@ -124,18 +126,18 @@ func messageToQueryParameters(message *descriptor.Message, reg *descriptor.Regis return params, nil } -// queryParams converts a field to a list of swagger query parameters recursively through the use of nestedQueryParams. -func queryParams(message *descriptor.Message, field *descriptor.Field, prefix string, reg *descriptor.Registry, pathParams []descriptor.Parameter) (params []swaggerParameterObject, err error) { +// queryParams converts a field to a list of OpenAPI query parameters recursively through the use of nestedQueryParams. +func queryParams(message *descriptor.Message, field *descriptor.Field, prefix string, reg *descriptor.Registry, pathParams []descriptor.Parameter) (params []openapiParameterObject, err error) { return nestedQueryParams(message, field, prefix, reg, pathParams, map[string]bool{}) } -// nestedQueryParams converts a field to a list of swagger query parameters recursively. +// nestedQueryParams converts a field to a list of OpenAPI query parameters recursively. // This function is a helper function for queryParams, that keeps track of cyclical message references // through the use of // touched map[string]bool // If a cycle is discovered, an error is returned, as cyclical data structures aren't allowed // in query parameters. -func nestedQueryParams(message *descriptor.Message, field *descriptor.Field, prefix string, reg *descriptor.Registry, pathParams []descriptor.Parameter, touchedIn map[string]bool) (params []swaggerParameterObject, err error) { +func nestedQueryParams(message *descriptor.Message, field *descriptor.Field, prefix string, reg *descriptor.Registry, pathParams []descriptor.Parameter, touchedIn map[string]bool) (params []openapiParameterObject, err error) { // make sure the parameter is not already listed as a path parameter for _, pathParam := range pathParams { if pathParam.Target == field { @@ -146,12 +148,12 @@ func nestedQueryParams(message *descriptor.Message, field *descriptor.Field, pre fieldType := field.GetTypeName() if message.File != nil { comments := fieldProtoComments(reg, message, field) - if err := updateSwaggerDataFromComments(reg, &schema, message, comments, false); err != nil { + if err := updateOpenAPIDataFromComments(reg, &schema, message, comments, false); err != nil { return nil, err } } - isEnum := field.GetType() == pbdescriptor.FieldDescriptorProto_TYPE_ENUM + isEnum := field.GetType() == descriptorpb.FieldDescriptorProto_TYPE_ENUM items := schema.Items if schema.Type != "" || isEnum { if schema.Type == "object" { @@ -174,7 +176,7 @@ func nestedQueryParams(message *descriptor.Message, field *descriptor.Field, pre } } - param := swaggerParameterObject{ + param := openapiParameterObject{ Description: desc, In: "query", Default: schema.Default, @@ -199,7 +201,7 @@ func nestedQueryParams(message *descriptor.Message, field *descriptor.Field, pre return nil, fmt.Errorf("unknown enum type %s", fieldType) } if items != nil { // array - param.Items = &swaggerItemsObject{ + param.Items = &openapiItemsObject{ Type: "string", Enum: listEnumNames(enum), } @@ -222,7 +224,7 @@ func nestedQueryParams(message *descriptor.Message, field *descriptor.Field, pre param.Description = strings.TrimLeft(param.Description+"\n\n "+valueComments, "\n") } } - return []swaggerParameterObject{param}, nil + return []openapiParameterObject{param}, nil } // nested type, recurse @@ -268,9 +270,9 @@ func findServicesMessagesAndEnumerations(s []*descriptor.Service, reg *descripto for _, meth := range svc.Methods { // Request may be fully included in query { - swgReqName, ok := fullyQualifiedNameToSwaggerName(meth.RequestType.FQMN(), reg) + swgReqName, ok := fullyQualifiedNameToOpenAPIName(meth.RequestType.FQMN(), reg) if !ok { - glog.Errorf("couldn't resolve swagger name for FQMN '%v'", meth.RequestType.FQMN()) + glog.Errorf("couldn't resolve OpenAPI name for FQMN '%v'", meth.RequestType.FQMN()) continue } if _, ok := refs[fmt.Sprintf("#/definitions/%s", swgReqName)]; ok { @@ -280,9 +282,9 @@ func findServicesMessagesAndEnumerations(s []*descriptor.Service, reg *descripto } } - swgRspName, ok := fullyQualifiedNameToSwaggerName(meth.ResponseType.FQMN(), reg) + swgRspName, ok := fullyQualifiedNameToOpenAPIName(meth.ResponseType.FQMN(), reg) if !ok && !skipRenderingRef(meth.ResponseType.FQMN()) { - glog.Errorf("couldn't resolve swagger name for FQMN '%v'", meth.ResponseType.FQMN()) + glog.Errorf("couldn't resolve OpenAPI name for FQMN '%v'", meth.ResponseType.FQMN()) continue } @@ -290,18 +292,6 @@ func findServicesMessagesAndEnumerations(s []*descriptor.Service, reg *descripto if !skipRenderingRef(meth.ResponseType.FQMN()) { m[swgRspName] = meth.ResponseType - if meth.GetServerStreaming() { - streamError, runtimeStreamError, err := lookupMsgAndSwaggerName(".grpc.gateway.runtime", "StreamError", reg) - if err != nil { - glog.Error(err) - } else { - glog.V(1).Infof("StreamError: %v", streamError) - glog.V(1).Infof("StreamError FQMN: %s", runtimeStreamError) - m[runtimeStreamError] = streamError - findNestedMessagesAndEnumerations(streamError, reg, m, e) - } - ms[swgRspName] = meth.ResponseType - } } findNestedMessagesAndEnumerations(meth.ResponseType, reg, m, e) } @@ -337,11 +327,11 @@ func skipRenderingRef(refName string) bool { return ok } -func renderMessagesAsDefinition(messages messageMap, d swaggerDefinitionsObject, reg *descriptor.Registry, customRefs refMap) { +func renderMessagesAsDefinition(messages messageMap, d openapiDefinitionsObject, reg *descriptor.Registry, customRefs refMap) { for name, msg := range messages { - swgName, ok := fullyQualifiedNameToSwaggerName(msg.FQMN(), reg) + swgName, ok := fullyQualifiedNameToOpenAPIName(msg.FQMN(), reg) if !ok { - panic(fmt.Sprintf("can't resolve swagger name from '%v'", msg.FQMN())) + panic(fmt.Sprintf("can't resolve OpenAPI name from '%v'", msg.FQMN())) } if skipRenderingRef(name) { continue @@ -350,13 +340,13 @@ func renderMessagesAsDefinition(messages messageMap, d swaggerDefinitionsObject, if opt := msg.GetOptions(); opt != nil && opt.MapEntry != nil && *opt.MapEntry { continue } - schema := swaggerSchemaObject{ + schema := openapiSchemaObject{ schemaCore: schemaCore{ Type: "object", }, } msgComments := protoComments(reg, msg.File, msg.Outers, "MessageType", int32(msg.Index)) - if err := updateSwaggerDataFromComments(reg, &schema, msg, msgComments, false); err != nil { + if err := updateOpenAPIDataFromComments(reg, &schema, msg, msgComments, false); err != nil { panic(err) } opts, err := extractSchemaOptionFromMessageDescriptor(msg.DescriptorProto) @@ -364,7 +354,7 @@ func renderMessagesAsDefinition(messages messageMap, d swaggerDefinitionsObject, panic(err) } if opts != nil { - protoSchema := swaggerSchemaFromProtoSchema(opts, reg, customRefs, msg) + protoSchema := openapiSchemaFromProtoSchema(opts, reg, customRefs, msg) // Warning: Make sure not to overwrite any fields already set on the schema type. schema.ExternalDocs = protoSchema.ExternalDocs @@ -401,7 +391,7 @@ func renderMessagesAsDefinition(messages messageMap, d swaggerDefinitionsObject, for _, f := range msg.Fields { fieldValue := schemaOfField(f, reg, customRefs) comments := fieldProtoComments(reg, msg, f) - if err := updateSwaggerDataFromComments(reg, &fieldValue, f, comments, false); err != nil { + if err := updateOpenAPIDataFromComments(reg, &fieldValue, f, comments, false); err != nil { panic(err) } @@ -412,7 +402,7 @@ func renderMessagesAsDefinition(messages messageMap, d swaggerDefinitionsObject, kv.Key = f.GetName() } if schema.Properties == nil { - schema.Properties = &swaggerSchemaObjectProperties{} + schema.Properties = &openapiSchemaObjectProperties{} } *schema.Properties = append(*schema.Properties, kv) } @@ -420,8 +410,8 @@ func renderMessagesAsDefinition(messages messageMap, d swaggerDefinitionsObject, } } -// schemaOfField returns a swagger Schema Object for a protobuf field. -func schemaOfField(f *descriptor.Field, reg *descriptor.Registry, refs refMap) swaggerSchemaObject { +// schemaOfField returns a OpenAPI Schema Object for a protobuf field. +func schemaOfField(f *descriptor.Field, reg *descriptor.Registry, refs refMap) openapiSchemaObject { const ( singular = 0 array = 1 @@ -439,24 +429,24 @@ func schemaOfField(f *descriptor.Field, reg *descriptor.Registry, refs refMap) s aggregate = object } } - if fd.GetLabel() == pbdescriptor.FieldDescriptorProto_LABEL_REPEATED { + if fd.GetLabel() == descriptorpb.FieldDescriptorProto_LABEL_REPEATED { aggregate = array } - var props *swaggerSchemaObjectProperties + var props *openapiSchemaObjectProperties switch ft := fd.GetType(); ft { - case pbdescriptor.FieldDescriptorProto_TYPE_ENUM, pbdescriptor.FieldDescriptorProto_TYPE_MESSAGE, pbdescriptor.FieldDescriptorProto_TYPE_GROUP: + case descriptorpb.FieldDescriptorProto_TYPE_ENUM, descriptorpb.FieldDescriptorProto_TYPE_MESSAGE, descriptorpb.FieldDescriptorProto_TYPE_GROUP: if wktSchema, ok := wktSchemas[fd.GetTypeName()]; ok { core = wktSchema if fd.GetTypeName() == ".google.protobuf.Empty" { - props = &swaggerSchemaObjectProperties{} + props = &openapiSchemaObjectProperties{} } } else { - swgRef, ok := fullyQualifiedNameToSwaggerName(fd.GetTypeName(), reg) + swgRef, ok := fullyQualifiedNameToOpenAPIName(fd.GetTypeName(), reg) if !ok { - panic(fmt.Sprintf("can't resolve swagger ref from typename '%v'", fd.GetTypeName())) + panic(fmt.Sprintf("can't resolve OpenAPI ref from typename '%v'", fd.GetTypeName())) } core = schemaCore{ Ref: "#/definitions/" + swgRef, @@ -478,32 +468,32 @@ func schemaOfField(f *descriptor.Field, reg *descriptor.Registry, refs refMap) s } } - ret := swaggerSchemaObject{} + ret := openapiSchemaObject{} switch aggregate { case array: - ret = swaggerSchemaObject{ + ret = openapiSchemaObject{ schemaCore: schemaCore{ Type: "array", - Items: (*swaggerItemsObject)(&core), + Items: (*openapiItemsObject)(&core), }, } case object: - ret = swaggerSchemaObject{ + ret = openapiSchemaObject{ schemaCore: schemaCore{ Type: "object", }, - AdditionalProperties: &swaggerSchemaObject{Properties: props, schemaCore: core}, + AdditionalProperties: &openapiSchemaObject{Properties: props, schemaCore: core}, } default: - ret = swaggerSchemaObject{ + ret = openapiSchemaObject{ schemaCore: core, Properties: props, } } if j, err := extractJSONSchemaFromFieldDescriptor(fd); err == nil { - updateSwaggerObjectFromJSONSchema(&ret, j, reg, f) + updateswaggerObjectFromJSONSchema(&ret, j, reg, f) } return ret @@ -512,46 +502,46 @@ func schemaOfField(f *descriptor.Field, reg *descriptor.Registry, refs refMap) s // primitiveSchema returns a pair of "Type" and "Format" in JSON Schema for // the given primitive field type. // The last return parameter is true iff the field type is actually primitive. -func primitiveSchema(t pbdescriptor.FieldDescriptorProto_Type) (ftype, format string, ok bool) { +func primitiveSchema(t descriptorpb.FieldDescriptorProto_Type) (ftype, format string, ok bool) { switch t { - case pbdescriptor.FieldDescriptorProto_TYPE_DOUBLE: + case descriptorpb.FieldDescriptorProto_TYPE_DOUBLE: return "number", "double", true - case pbdescriptor.FieldDescriptorProto_TYPE_FLOAT: + case descriptorpb.FieldDescriptorProto_TYPE_FLOAT: return "number", "float", true - case pbdescriptor.FieldDescriptorProto_TYPE_INT64: + case descriptorpb.FieldDescriptorProto_TYPE_INT64: return "string", "int64", true - case pbdescriptor.FieldDescriptorProto_TYPE_UINT64: + case descriptorpb.FieldDescriptorProto_TYPE_UINT64: // 64bit integer types are marshaled as string in the default JSONPb marshaler. // TODO(yugui) Add an option to declare 64bit integers as int64. // - // NOTE: uint64 is not a predefined format of integer type in Swagger spec. - // So we cannot expect that uint64 is commonly supported by swagger processor. + // NOTE: uint64 is not a predefined format of integer type in OpenAPI spec. + // So we cannot expect that uint64 is commonly supported by OpenAPI processor. return "string", "uint64", true - case pbdescriptor.FieldDescriptorProto_TYPE_INT32: + case descriptorpb.FieldDescriptorProto_TYPE_INT32: return "integer", "int32", true - case pbdescriptor.FieldDescriptorProto_TYPE_FIXED64: + case descriptorpb.FieldDescriptorProto_TYPE_FIXED64: // Ditto. return "string", "uint64", true - case pbdescriptor.FieldDescriptorProto_TYPE_FIXED32: + case descriptorpb.FieldDescriptorProto_TYPE_FIXED32: // Ditto. return "integer", "int64", true - case pbdescriptor.FieldDescriptorProto_TYPE_BOOL: + case descriptorpb.FieldDescriptorProto_TYPE_BOOL: return "boolean", "boolean", true - case pbdescriptor.FieldDescriptorProto_TYPE_STRING: - // NOTE: in swagger specifition, format should be empty on string type + case descriptorpb.FieldDescriptorProto_TYPE_STRING: + // NOTE: in OpenAPI specifition, format should be empty on string type return "string", "", true - case pbdescriptor.FieldDescriptorProto_TYPE_BYTES: + case descriptorpb.FieldDescriptorProto_TYPE_BYTES: return "string", "byte", true - case pbdescriptor.FieldDescriptorProto_TYPE_UINT32: + case descriptorpb.FieldDescriptorProto_TYPE_UINT32: // Ditto. return "integer", "int64", true - case pbdescriptor.FieldDescriptorProto_TYPE_SFIXED32: + case descriptorpb.FieldDescriptorProto_TYPE_SFIXED32: return "integer", "int32", true - case pbdescriptor.FieldDescriptorProto_TYPE_SFIXED64: + case descriptorpb.FieldDescriptorProto_TYPE_SFIXED64: return "string", "int64", true - case pbdescriptor.FieldDescriptorProto_TYPE_SINT32: + case descriptorpb.FieldDescriptorProto_TYPE_SINT32: return "integer", "int32", true - case pbdescriptor.FieldDescriptorProto_TYPE_SINT64: + case descriptorpb.FieldDescriptorProto_TYPE_SINT64: return "string", "int64", true default: return "", "", false @@ -568,11 +558,11 @@ func getRules(rules []*descriptor.Rule) []options.ValidationRule { } // renderEnumerationsAsDefinition inserts enums into the definitions object. -func renderEnumerationsAsDefinition(enums enumMap, d swaggerDefinitionsObject, reg *descriptor.Registry) { +func renderEnumerationsAsDefinition(enums enumMap, d openapiDefinitionsObject, reg *descriptor.Registry) { for _, enum := range enums { - swgName, ok := fullyQualifiedNameToSwaggerName(enum.FQEN(), reg) + swgName, ok := fullyQualifiedNameToOpenAPIName(enum.FQEN(), reg) if !ok { - panic(fmt.Sprintf("can't resolve swagger name from FQEN '%v'", enum.FQEN())) + panic(fmt.Sprintf("can't resolve OpenAPI name from FQEN '%v'", enum.FQEN())) } enumComments := protoComments(reg, enum.File, enum.Outers, "EnumType", int32(enum.Index)) @@ -583,7 +573,7 @@ func renderEnumerationsAsDefinition(enums enumMap, d swaggerDefinitionsObject, r if valueComments != "" { enumComments = strings.TrimLeft(enumComments+"\n\n "+valueComments, "\n") } - enumSchemaObject := swaggerSchemaObject{ + enumSchemaObject := openapiSchemaObject{ schemaCore: schemaCore{ Type: "string", Enum: enumNames, @@ -596,7 +586,7 @@ func renderEnumerationsAsDefinition(enums enumMap, d swaggerDefinitionsObject, r enumSchemaObject.Default = "0" enumSchemaObject.Enum = listEnumNumbers(enum) } - if err := updateSwaggerDataFromComments(reg, &enumSchemaObject, enum, enumComments, false); err != nil { + if err := updateOpenAPIDataFromComments(reg, &enumSchemaObject, enum, enumComments, false); err != nil { panic(err) } @@ -604,36 +594,36 @@ func renderEnumerationsAsDefinition(enums enumMap, d swaggerDefinitionsObject, r } } -// Take in a FQMN or FQEN and return a swagger safe version of the FQMN and +// Take in a FQMN or FQEN and return a OpenAPI safe version of the FQMN and // a boolean indicating if FQMN was properly resolved. -func fullyQualifiedNameToSwaggerName(fqn string, reg *descriptor.Registry) (string, bool) { +func fullyQualifiedNameToOpenAPIName(fqn string, reg *descriptor.Registry) (string, bool) { registriesSeenMutex.Lock() defer registriesSeenMutex.Unlock() if mapping, present := registriesSeen[reg]; present { ret, ok := mapping[fqn] return ret, ok } - mapping := resolveFullyQualifiedNameToSwaggerNames(append(reg.GetAllFQMNs(), reg.GetAllFQENs()...), reg.GetUseFQNForSwaggerName()) + mapping := resolveFullyQualifiedNameToOpenAPINames(append(reg.GetAllFQMNs(), reg.GetAllFQENs()...), reg.GetUseFQNForOpenAPIName()) registriesSeen[reg] = mapping ret, ok := mapping[fqn] return ret, ok } -// Lookup message type by location.name and return a swagger-safe version +// Lookup message type by location.name and return a openapiv2-safe version // of its FQMN. -func lookupMsgAndSwaggerName(location, name string, reg *descriptor.Registry) (*descriptor.Message, string, error) { +func lookupMsgAndOpenAPIName(location, name string, reg *descriptor.Registry) (*descriptor.Message, string, error) { msg, err := reg.LookupMsg(location, name) if err != nil { return nil, "", err } - swgName, ok := fullyQualifiedNameToSwaggerName(msg.FQMN(), reg) + swgName, ok := fullyQualifiedNameToOpenAPIName(msg.FQMN(), reg) if !ok { - return nil, "", fmt.Errorf("can't map swagger name from FQMN '%v'", msg.FQMN()) + return nil, "", fmt.Errorf("can't map OpenAPI name from FQMN '%v'", msg.FQMN()) } return msg, swgName, nil } -// registriesSeen is used to memoise calls to resolveFullyQualifiedNameToSwaggerNames so +// registriesSeen is used to memoise calls to resolveFullyQualifiedNameToOpenAPINames so // we don't repeat it unnecessarily, since it can take some time. var registriesSeen = map[*descriptor.Registry]map[string]string{} var registriesSeenMutex sync.Mutex @@ -645,7 +635,7 @@ var registriesSeenMutex sync.Mutex // This likely could be made better. This will always generate the same names // but may not always produce optimal names. This is a reasonably close // approximation of what they should look like in most cases. -func resolveFullyQualifiedNameToSwaggerNames(messages []string, useFQNForSwaggerName bool) map[string]string { +func resolveFullyQualifiedNameToOpenAPINames(messages []string, useFQNForOpenAPIName bool) map[string]string { packagesByDepth := make(map[int][][]string) uniqueNames := make(map[string]string) @@ -674,7 +664,7 @@ func resolveFullyQualifiedNameToSwaggerNames(messages []string, useFQNForSwagger } for _, p := range messages { - if useFQNForSwaggerName { + if useFQNForOpenAPIName { // strip leading dot from proto fqn uniqueNames[p] = p[1:] } else { @@ -695,8 +685,8 @@ func resolveFullyQualifiedNameToSwaggerNames(messages []string, useFQNForSwagger var canRegexp = regexp.MustCompile("{([a-zA-Z][a-zA-Z0-9_.]*).*}") -// Swagger expects paths of the form /path/{string_value} but grpc-gateway paths are expected to be of the form /path/{string_value=strprefix/*}. This should reformat it correctly. -func templateToSwaggerPath(path string, reg *descriptor.Registry, fields []*descriptor.Field, msgs []*descriptor.Message) string { +// OpenAPI expects paths of the form /path/{string_value} but grpc-gateway paths are expected to be of the form /path/{string_value=strprefix/*}. This should reformat it correctly. +func templateToOpenAPIPath(path string, reg *descriptor.Registry, fields []*descriptor.Field, msgs []*descriptor.Message) string { // It seems like the right thing to do here is to just use // strings.Split(path, "/") but that breaks badly when you hit a url like // /{my_field=prefix/*}/ and end up with 2 sections representing my_field. @@ -714,7 +704,6 @@ func templateToSwaggerPath(path string, reg *descriptor.Registry, fields []*desc buffer += string(char) jsonBuffer = "" jsonBuffer += string(char) - break case '}': if depth == 0 { panic("Encountered } without matching { before it.") @@ -743,7 +732,6 @@ func templateToSwaggerPath(path string, reg *descriptor.Registry, fields []*desc default: buffer += string(char) jsonBuffer += string(char) - break } } @@ -774,7 +762,7 @@ func isResourceName(prefix string) bool { return field == "parent" || field == "name" } -func renderServices(services []*descriptor.Service, paths swaggerPathsObject, reg *descriptor.Registry, requestResponseRefs, customRefs refMap, msgs []*descriptor.Message) error { +func renderServices(services []*descriptor.Service, paths openapiPathsObject, reg *descriptor.Registry, requestResponseRefs, customRefs refMap, msgs []*descriptor.Message) error { // Correctness of svcIdx and methIdx depends on 'services' containing the services in the same order as the 'file.Service' array. svcBaseIdx := 0 var lastFile *descriptor.File = nil @@ -785,16 +773,16 @@ func renderServices(services []*descriptor.Service, paths swaggerPathsObject, re } for methIdx, meth := range svc.Methods { for bIdx, b := range meth.Bindings { - // Iterate over all the swagger parameters - parameters := swaggerParametersObject{} + // Iterate over all the OpenAPI parameters + parameters := openapiParametersObject{} for _, parameter := range b.PathParams { var paramType, paramFormat, desc, collectionFormat, defaultValue string var enumNames []string - var items *swaggerItemsObject + var items *openapiItemsObject var minItems *int switch pt := parameter.Target.GetType(); pt { - case pbdescriptor.FieldDescriptorProto_TYPE_GROUP, pbdescriptor.FieldDescriptorProto_TYPE_MESSAGE: + case descriptorpb.FieldDescriptorProto_TYPE_GROUP, descriptorpb.FieldDescriptorProto_TYPE_MESSAGE: if descriptor.IsWellKnownType(parameter.Target.GetTypeName()) { if parameter.IsRepeated() { return fmt.Errorf("only primitive and enum types are allowed in repeated path parameters") @@ -807,7 +795,7 @@ func renderServices(services []*descriptor.Service, paths swaggerPathsObject, re } else { return fmt.Errorf("only primitive and well-known types are allowed in path parameters") } - case pbdescriptor.FieldDescriptorProto_TYPE_ENUM: + case descriptorpb.FieldDescriptorProto_TYPE_ENUM: enum, err := reg.LookupEnum("", parameter.Target.GetTypeName()) if err != nil { return err @@ -842,7 +830,7 @@ func renderServices(services []*descriptor.Service, paths swaggerPathsObject, re core.Enum = enumNames enumNames = s } - items = (*swaggerItemsObject)(&core) + items = (*openapiItemsObject)(&core) paramType = "array" paramFormat = "" collectionFormat = reg.GetRepeatedPathParamSeparatorName() @@ -857,7 +845,7 @@ func renderServices(services []*descriptor.Service, paths swaggerPathsObject, re if reg.GetUseJSONNamesForFields() { parameterString = lowerCamelCase(parameterString, meth.RequestType.Fields, msgs) } - parameters = append(parameters, swaggerParameterObject{ + parameters = append(parameters, openapiParameterObject{ Name: parameterString, Description: desc, In: "path", @@ -874,11 +862,11 @@ func renderServices(services []*descriptor.Service, paths swaggerPathsObject, re } // Now check if there is a body parameter if b.Body != nil { - var schema swaggerSchemaObject + var schema openapiSchemaObject desc := "" if len(b.Body.FieldPath) == 0 { - schema = swaggerSchemaObject{ + schema = openapiSchemaObject{ schemaCore: schemaCore{}, } @@ -893,7 +881,7 @@ func renderServices(services []*descriptor.Service, paths swaggerPathsObject, re // Special workaround for Empty: it's well-known type but wknSchemas only returns schema.schemaCore; but we need to set schema.Properties which is a level higher. if meth.RequestType.FQMN() == ".google.protobuf.Empty" { - schema.Properties = &swaggerSchemaObjectProperties{} + schema.Properties = &openapiSchemaObjectProperties{} } } } else { @@ -909,7 +897,7 @@ func renderServices(services []*descriptor.Service, paths swaggerPathsObject, re if meth.GetClientStreaming() { desc += " (streaming inputs)" } - parameters = append(parameters, swaggerParameterObject{ + parameters = append(parameters, openapiParameterObject{ Name: "body", Description: desc, In: "body", @@ -925,17 +913,17 @@ func renderServices(services []*descriptor.Service, paths swaggerPathsObject, re parameters = append(parameters, queryParams...) } - pathItemObject, ok := paths[templateToSwaggerPath(b.PathTmpl.Template, reg, meth.RequestType.Fields, msgs)] + pathItemObject, ok := paths[templateToOpenAPIPath(b.PathTmpl.Template, reg, meth.RequestType.Fields, msgs)] if !ok { - pathItemObject = swaggerPathItemObject{} + pathItemObject = openapiPathItemObject{} } - methProtoPath := protoPathIndex(reflect.TypeOf((*pbdescriptor.ServiceDescriptorProto)(nil)), "Method") + methProtoPath := protoPathIndex(reflect.TypeOf((*descriptorpb.ServiceDescriptorProto)(nil)), "Method") desc := "A successful response." - var responseSchema swaggerSchemaObject + var responseSchema openapiSchemaObject if b.ResponseBody == nil || len(b.ResponseBody.FieldPath) == 0 { - responseSchema = swaggerSchemaObject{ + responseSchema = openapiSchemaObject{ schemaCore: schemaCore{}, } @@ -954,7 +942,7 @@ func renderServices(services []*descriptor.Service, paths swaggerPathsObject, re // Special workaround for Empty: it's well-known type but wknSchemas only returns schema.schemaCore; but we need to set schema.Properties which is a level higher. if meth.ResponseType.FQMN() == ".google.protobuf.Empty" { - responseSchema.Properties = &swaggerSchemaObjectProperties{} + responseSchema.Properties = &openapiSchemaObjectProperties{} } } } else { @@ -970,24 +958,24 @@ func renderServices(services []*descriptor.Service, paths swaggerPathsObject, re if meth.GetServerStreaming() { desc += "(streaming responses)" responseSchema.Type = "object" - swgRef, _ := fullyQualifiedNameToSwaggerName(meth.ResponseType.FQMN(), reg) + swgRef, _ := fullyQualifiedNameToOpenAPIName(meth.ResponseType.FQMN(), reg) responseSchema.Title = "Stream result of " + swgRef - props := swaggerSchemaObjectProperties{ + props := openapiSchemaObjectProperties{ keyVal{ Key: "result", - Value: swaggerSchemaObject{ + Value: openapiSchemaObject{ schemaCore: schemaCore{ Ref: responseSchema.Ref, }, }, }, } - streamErrDef, hasStreamError := fullyQualifiedNameToSwaggerName(".grpc.gateway.runtime.StreamError", reg) + streamErrDef, hasStreamError := fullyQualifiedNameToOpenAPIName(".grpc.gateway.runtime.StreamError", reg) if hasStreamError { props = append(props, keyVal{ Key: "error", - Value: swaggerSchemaObject{ + Value: openapiSchemaObject{ schemaCore: schemaCore{ Ref: fmt.Sprintf("#/definitions/%s", streamErrDef)}, }, @@ -1002,23 +990,23 @@ func renderServices(services []*descriptor.Service, paths swaggerPathsObject, re tag = pkg + "." + tag } - operationObject := &swaggerOperationObject{ + operationObject := &openapiOperationObject{ Tags: []string{tag}, Parameters: parameters, - Responses: swaggerResponsesObject{ - "200": swaggerResponseObject{ + Responses: openapiResponsesObject{ + "200": openapiResponseObject{ Description: desc, Schema: responseSchema, }, }, } if !reg.GetDisableDefaultErrors() { - errDef, hasErrDef := fullyQualifiedNameToSwaggerName(".grpc.gateway.runtime.Error", reg) + errDef, hasErrDef := fullyQualifiedNameToOpenAPIName(".grpc.gateway.runtime.Error", reg) if hasErrDef { // https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#responses-object - operationObject.Responses["default"] = swaggerResponseObject{ + operationObject.Responses["default"] = openapiResponseObject{ Description: "An unexpected error response", - Schema: swaggerSchemaObject{ + Schema: openapiSchemaObject{ schemaCore: schemaCore{ Ref: fmt.Sprintf("#/definitions/%s", errDef), }, @@ -1028,7 +1016,7 @@ func renderServices(services []*descriptor.Service, paths swaggerPathsObject, re } operationObject.OperationID = fmt.Sprintf("%s_%s", svc.GetName(), meth.GetName()) if reg.GetSimpleOperationIDs() { - operationObject.OperationID = fmt.Sprintf("%s", meth.GetName()) + operationObject.OperationID = meth.GetName() } if bIdx != 0 { // OperationID must be unique in an OpenAPI v2 definition. @@ -1043,7 +1031,7 @@ func renderServices(services []*descriptor.Service, paths swaggerPathsObject, re } methComments := protoComments(reg, svc.File, nil, "Service", int32(svcIdx-svcBaseIdx), methProtoPath, int32(methIdx)) - if err := updateSwaggerDataFromComments(reg, operationObject, meth, methComments, false); err != nil { + if err := updateOpenAPIDataFromComments(reg, operationObject, meth, methComments, false); err != nil { panic(err) } @@ -1052,7 +1040,7 @@ func renderServices(services []*descriptor.Service, paths swaggerPathsObject, re if err != nil { panic(err) } - operationObject.ExternalDocs = protoExternalDocumentationToSwaggerExternalDocumentation(opts.ExternalDocs, reg, meth) + operationObject.ExternalDocs = protoExternalDocumentationToOpenAPIExternalDocumentation(opts.ExternalDocs, reg, meth) // TODO(ivucica): this would be better supported by looking whether the method is deprecated in the proto file operationObject.Deprecated = opts.Deprecated @@ -1070,12 +1058,12 @@ func renderServices(services []*descriptor.Service, paths swaggerPathsObject, re operationObject.OperationID = opts.OperationId } if opts.Security != nil { - newSecurity := []swaggerSecurityRequirementObject{} + newSecurity := []openapiSecurityRequirementObject{} if operationObject.Security != nil { newSecurity = *operationObject.Security } for _, secReq := range opts.Security { - newSecReq := swaggerSecurityRequirementObject{} + newSecReq := openapiSecurityRequirementObject{} for secReqKey, secReqValue := range secReq.SecurityRequirement { if secReqValue == nil { continue @@ -1100,10 +1088,10 @@ func renderServices(services []*descriptor.Service, paths swaggerPathsObject, re respObj.Description = resp.Description } if resp.Schema != nil { - respObj.Schema = swaggerSchemaFromProtoSchema(resp.Schema, reg, customRefs, meth) + respObj.Schema = openapiSchemaFromProtoSchema(resp.Schema, reg, customRefs, meth) } if resp.Examples != nil { - respObj.Examples = swaggerExamplesFromProtoExamples(resp.Examples) + respObj.Examples = openapiExamplesFromProtoExamples(resp.Examples) } if resp.Extensions != nil { exts, err := processExtensions(resp.Extensions) @@ -1135,21 +1123,16 @@ func renderServices(services []*descriptor.Service, paths swaggerPathsObject, re switch b.HTTPMethod { case "DELETE": pathItemObject.Delete = operationObject - break case "GET": pathItemObject.Get = operationObject - break case "POST": pathItemObject.Post = operationObject - break case "PUT": pathItemObject.Put = operationObject - break case "PATCH": pathItemObject.Patch = operationObject - break } - paths[templateToSwaggerPath(b.PathTmpl.Template, reg, meth.RequestType.Fields, msgs)] = pathItemObject + paths[templateToOpenAPIPath(b.PathTmpl.Template, reg, meth.RequestType.Fields, msgs)] = pathItemObject } } } @@ -1159,17 +1142,17 @@ func renderServices(services []*descriptor.Service, paths swaggerPathsObject, re } // This function is called with a param which contains the entire definition of a method. -func applyTemplate(p param) (*swaggerObject, error) { +func applyTemplate(p param) (*openapiSwaggerObject, error) { // Create the basic template object. This is the object that everything is // defined off of. - s := swaggerObject{ - // Swagger 2.0 is the version of this document + s := openapiSwaggerObject{ + // OpenAPI 2.0 is the version of this document Swagger: "2.0", Consumes: []string{"application/json"}, Produces: []string{"application/json"}, - Paths: make(swaggerPathsObject), - Definitions: make(swaggerDefinitionsObject), - Info: swaggerInfoObject{ + Paths: make(openapiPathsObject), + Definitions: make(openapiDefinitionsObject), + Info: openapiInfoObject{ Title: *p.File.Name, Version: "version not set", }, @@ -1189,7 +1172,7 @@ func applyTemplate(p param) (*swaggerObject, error) { if !p.reg.GetDisableDefaultErrors() { // Add the error type to the message map - runtimeError, swgRef, err := lookupMsgAndSwaggerName(".grpc.gateway.runtime", "Error", p.reg) + runtimeError, swgRef, err := lookupMsgAndOpenAPIName(".grpc.gateway.runtime", "Error", p.reg) if err == nil { messages[swgRef] = runtimeError } else { @@ -1205,14 +1188,14 @@ func applyTemplate(p param) (*swaggerObject, error) { renderEnumerationsAsDefinition(enums, s.Definitions, p.reg) // File itself might have some comments and metadata. - packageProtoPath := protoPathIndex(reflect.TypeOf((*pbdescriptor.FileDescriptorProto)(nil)), "Package") + packageProtoPath := protoPathIndex(reflect.TypeOf((*descriptorpb.FileDescriptorProto)(nil)), "Package") packageComments := protoComments(p.reg, p.File, nil, "Package", packageProtoPath) - if err := updateSwaggerDataFromComments(p.reg, &s, p, packageComments, true); err != nil { + if err := updateOpenAPIDataFromComments(p.reg, &s, p, packageComments, true); err != nil { panic(err) } - // There may be additional options in the swagger option in the proto. - spb, err := extractSwaggerOptionFromFileDescriptor(p.FileDescriptorProto) + // There may be additional options in the OpenAPI option in the proto. + spb, err := extractOpenAPIOptionFromFileDescriptor(p.FileDescriptorProto) if err != nil { panic(err) } @@ -1235,7 +1218,7 @@ func applyTemplate(p param) (*swaggerObject, error) { } if spb.Info.Contact != nil { if s.Info.Contact == nil { - s.Info.Contact = &swaggerContactObject{} + s.Info.Contact = &openapiContactObject{} } if spb.Info.Contact.Name != "" { s.Info.Contact.Name = spb.Info.Contact.Name @@ -1249,7 +1232,7 @@ func applyTemplate(p param) (*swaggerObject, error) { } if spb.Info.License != nil { if s.Info.License == nil { - s.Info.License = &swaggerLicenseObject{} + s.Info.License = &openapiLicenseObject{} } if spb.Info.License.Name != "" { s.Info.License.Name = spb.Info.License.Name @@ -1288,22 +1271,22 @@ func applyTemplate(p param) (*swaggerObject, error) { } if spb.SecurityDefinitions != nil && spb.SecurityDefinitions.Security != nil { if s.SecurityDefinitions == nil { - s.SecurityDefinitions = swaggerSecurityDefinitionsObject{} + s.SecurityDefinitions = openapiSecurityDefinitionsObject{} } for secDefKey, secDefValue := range spb.SecurityDefinitions.Security { - var newSecDefValue swaggerSecuritySchemeObject + var newSecDefValue openapiSecuritySchemeObject if oldSecDefValue, ok := s.SecurityDefinitions[secDefKey]; !ok { - newSecDefValue = swaggerSecuritySchemeObject{} + newSecDefValue = openapiSecuritySchemeObject{} } else { newSecDefValue = oldSecDefValue } - if secDefValue.Type != swagger_options.SecurityScheme_TYPE_INVALID { + if secDefValue.Type != openapi_options.SecurityScheme_TYPE_INVALID { switch secDefValue.Type { - case swagger_options.SecurityScheme_TYPE_BASIC: + case openapi_options.SecurityScheme_TYPE_BASIC: newSecDefValue.Type = "basic" - case swagger_options.SecurityScheme_TYPE_API_KEY: + case openapi_options.SecurityScheme_TYPE_API_KEY: newSecDefValue.Type = "apiKey" - case swagger_options.SecurityScheme_TYPE_OAUTH2: + case openapi_options.SecurityScheme_TYPE_OAUTH2: newSecDefValue.Type = "oauth2" } } @@ -1313,23 +1296,23 @@ func applyTemplate(p param) (*swaggerObject, error) { if secDefValue.Name != "" { newSecDefValue.Name = secDefValue.Name } - if secDefValue.In != swagger_options.SecurityScheme_IN_INVALID { + if secDefValue.In != openapi_options.SecurityScheme_IN_INVALID { switch secDefValue.In { - case swagger_options.SecurityScheme_IN_QUERY: + case openapi_options.SecurityScheme_IN_QUERY: newSecDefValue.In = "query" - case swagger_options.SecurityScheme_IN_HEADER: + case openapi_options.SecurityScheme_IN_HEADER: newSecDefValue.In = "header" } } - if secDefValue.Flow != swagger_options.SecurityScheme_FLOW_INVALID { + if secDefValue.Flow != openapi_options.SecurityScheme_FLOW_INVALID { switch secDefValue.Flow { - case swagger_options.SecurityScheme_FLOW_IMPLICIT: + case openapi_options.SecurityScheme_FLOW_IMPLICIT: newSecDefValue.Flow = "implicit" - case swagger_options.SecurityScheme_FLOW_PASSWORD: + case openapi_options.SecurityScheme_FLOW_PASSWORD: newSecDefValue.Flow = "password" - case swagger_options.SecurityScheme_FLOW_APPLICATION: + case openapi_options.SecurityScheme_FLOW_APPLICATION: newSecDefValue.Flow = "application" - case swagger_options.SecurityScheme_FLOW_ACCESS_CODE: + case openapi_options.SecurityScheme_FLOW_ACCESS_CODE: newSecDefValue.Flow = "accessCode" } } @@ -1341,7 +1324,7 @@ func applyTemplate(p param) (*swaggerObject, error) { } if secDefValue.Scopes != nil { if newSecDefValue.Scopes == nil { - newSecDefValue.Scopes = swaggerScopesObject{} + newSecDefValue.Scopes = openapiScopesObject{} } for scopeKey, scopeDesc := range secDefValue.Scopes.Scope { newSecDefValue.Scopes[scopeKey] = scopeDesc @@ -1358,14 +1341,12 @@ func applyTemplate(p param) (*swaggerObject, error) { } } if spb.Security != nil { - newSecurity := []swaggerSecurityRequirementObject{} - if s.Security == nil { - newSecurity = []swaggerSecurityRequirementObject{} - } else { + var newSecurity []openapiSecurityRequirementObject + if s.Security != nil { newSecurity = s.Security } for _, secReq := range spb.Security { - newSecReq := swaggerSecurityRequirementObject{} + newSecReq := openapiSecurityRequirementObject{} for secReqKey, secReqValue := range secReq.SecurityRequirement { newSecReqValue := make([]string, len(secReqValue.Scope)) copy(newSecReqValue, secReqValue.Scope) @@ -1375,12 +1356,12 @@ func applyTemplate(p param) (*swaggerObject, error) { } s.Security = newSecurity } - s.ExternalDocs = protoExternalDocumentationToSwaggerExternalDocumentation(spb.ExternalDocs, p.reg, spb) + s.ExternalDocs = protoExternalDocumentationToOpenAPIExternalDocumentation(spb.ExternalDocs, p.reg, spb) // Populate all Paths with Responses set at top level, // preferring Responses already set over those at the top level. if spb.Responses != nil { for _, verbs := range s.Paths { - var maps []swaggerResponsesObject + var maps []openapiResponsesObject if verbs.Delete != nil { maps = append(maps, verbs.Delete.Responses) } @@ -1403,10 +1384,10 @@ func applyTemplate(p param) (*swaggerObject, error) { // Don't overwrite already existing Responses continue } - respMap[k] = swaggerResponseObject{ + respMap[k] = openapiResponseObject{ Description: v.Description, - Schema: swaggerSchemaFromProtoSchema(v.Schema, p.reg, customRefs, nil), - Examples: swaggerExamplesFromProtoExamples(v.Examples), + Schema: openapiSchemaFromProtoSchema(v.Schema, p.reg, customRefs, nil), + Examples: openapiExamplesFromProtoExamples(v.Examples), } } } @@ -1421,7 +1402,7 @@ func applyTemplate(p param) (*swaggerObject, error) { s.extensions = exts } - // Additional fields on the OpenAPI v2 spec's "Swagger" object + // Additional fields on the OpenAPI v2 spec's "OpenAPI" object // should be added here, once supported in the proto. } @@ -1436,9 +1417,9 @@ func processExtensions(inputExts map[string]*structpb.Value) ([]extension, error exts := []extension{} for k, v := range inputExts { if !strings.HasPrefix(k, "x-") { - return nil, fmt.Errorf("Extension keys need to start with \"x-\": %q", k) + return nil, fmt.Errorf("extension keys need to start with \"x-\": %q", k) } - ext, err := (&jsonpb.Marshaler{Indent: " "}).MarshalToString(v) + ext, err := (&protojson.MarshalOptions{Indent: " "}).Marshal(v) if err != nil { return nil, err } @@ -1448,7 +1429,7 @@ func processExtensions(inputExts map[string]*structpb.Value) ([]extension, error return exts, nil } -// updateSwaggerDataFromComments updates a Swagger object based on a comment +// updateOpenAPIDataFromComments updates a OpenAPI object based on a comment // from the proto file. // // First paragraph of a comment is used for summary. Remaining paragraphs of @@ -1460,7 +1441,7 @@ func processExtensions(inputExts map[string]*structpb.Value) ([]extension, error // // If there is no 'Summary', the same behavior will be attempted on 'Title', // but only if the last character is not a period. -func updateSwaggerDataFromComments(reg *descriptor.Registry, swaggerObject interface{}, data interface{}, comment string, isPackageObject bool) error { +func updateOpenAPIDataFromComments(reg *descriptor.Registry, swaggerObject interface{}, data interface{}, comment string, isPackageObject bool) error { if len(comment) == 0 { return nil } @@ -1509,7 +1490,7 @@ func updateSwaggerDataFromComments(reg *descriptor.Registry, swaggerObject inter } if len(description) > 0 { if !descriptionValue.CanSet() { - return fmt.Errorf("Encountered object type with a summary, but no description") + return fmt.Errorf("encountered object type with a summary, but no description") } // overrides the schema value only if it's empty // keep the comment precedence when updating the package definition @@ -1522,7 +1503,7 @@ func updateSwaggerDataFromComments(reg *descriptor.Registry, swaggerObject inter } // There was no summary field on the swaggerObject. Try to apply the - // whole comment into description if the swagger object description is empty. + // whole comment into description if the OpenAPI object description is empty. if descriptionValue.CanSet() { if descriptionValue.Len() == 0 || isPackageObject { descriptionValue.Set(reflect.ValueOf(strings.Join(paragraphs, "\n\n"))) @@ -1534,7 +1515,7 @@ func updateSwaggerDataFromComments(reg *descriptor.Registry, swaggerObject inter } func fieldProtoComments(reg *descriptor.Registry, msg *descriptor.Message, field *descriptor.Field) string { - protoPath := protoPathIndex(reflect.TypeOf((*pbdescriptor.DescriptorProto)(nil)), "Field") + protoPath := protoPathIndex(reflect.TypeOf((*descriptorpb.DescriptorProto)(nil)), "Field") for i, f := range msg.Fields { if f == field { return protoComments(reg, msg.File, msg.Outers, "MessageType", int32(msg.Index), protoPath, int32(i)) @@ -1544,7 +1525,7 @@ func fieldProtoComments(reg *descriptor.Registry, msg *descriptor.Message, field } func enumValueProtoComments(reg *descriptor.Registry, enum *descriptor.Enum) string { - protoPath := protoPathIndex(reflect.TypeOf((*pbdescriptor.EnumDescriptorProto)(nil)), "Value") + protoPath := protoPathIndex(reflect.TypeOf((*descriptorpb.EnumDescriptorProto)(nil)), "Value") var comments []string for idx, value := range enum.GetValue() { name := value.GetName() @@ -1634,11 +1615,11 @@ func goTemplateComments(comment string, data interface{}, reg *descriptor.Regist return temp.String() } -var messageProtoPath = protoPathIndex(reflect.TypeOf((*pbdescriptor.FileDescriptorProto)(nil)), "MessageType") -var nestedProtoPath = protoPathIndex(reflect.TypeOf((*pbdescriptor.DescriptorProto)(nil)), "NestedType") -var packageProtoPath = protoPathIndex(reflect.TypeOf((*pbdescriptor.FileDescriptorProto)(nil)), "Package") -var serviceProtoPath = protoPathIndex(reflect.TypeOf((*pbdescriptor.FileDescriptorProto)(nil)), "Service") -var methodProtoPath = protoPathIndex(reflect.TypeOf((*pbdescriptor.ServiceDescriptorProto)(nil)), "Method") +var messageProtoPath = protoPathIndex(reflect.TypeOf((*descriptorpb.FileDescriptorProto)(nil)), "MessageType") +var nestedProtoPath = protoPathIndex(reflect.TypeOf((*descriptorpb.DescriptorProto)(nil)), "NestedType") +var packageProtoPath = protoPathIndex(reflect.TypeOf((*descriptorpb.FileDescriptorProto)(nil)), "Package") +var serviceProtoPath = protoPathIndex(reflect.TypeOf((*descriptorpb.FileDescriptorProto)(nil)), "Service") +var methodProtoPath = protoPathIndex(reflect.TypeOf((*descriptorpb.ServiceDescriptorProto)(nil)), "Method") func isProtoPathMatches(paths []int32, outerPaths []int32, typeName string, typeIndex int32, fieldPaths []int32) bool { if typeName == "Package" && typeIndex == packageProtoPath { @@ -1660,7 +1641,7 @@ func isProtoPathMatches(paths []int32, outerPaths []int32, typeName string, type } paths = paths[2:] } else { - typeNameDescriptor := reflect.TypeOf((*pbdescriptor.FileDescriptorProto)(nil)) + typeNameDescriptor := reflect.TypeOf((*descriptorpb.FileDescriptorProto)(nil)) if len(outerPaths) > 0 { if paths[0] != messageProtoPath || paths[1] != outerPaths[0] { @@ -1679,7 +1660,7 @@ func isProtoPathMatches(paths []int32, outerPaths []int32, typeName string, type if typeName == "MessageType" { typeName = "NestedType" } - typeNameDescriptor = reflect.TypeOf((*pbdescriptor.DescriptorProto)(nil)) + typeNameDescriptor = reflect.TypeOf((*descriptorpb.DescriptorProto)(nil)) } if paths[0] != protoPathIndex(typeNameDescriptor, typeName) || paths[1] != typeIndex { @@ -1738,19 +1719,16 @@ func protoPathIndex(descriptorType reflect.Type, what string) int32 { } // extractOperationOptionFromMethodDescriptor extracts the message of type -// swagger_options.Operation from a given proto method's descriptor. -func extractOperationOptionFromMethodDescriptor(meth *pbdescriptor.MethodDescriptorProto) (*swagger_options.Operation, error) { +// openapi_options.Operation from a given proto method's descriptor. +func extractOperationOptionFromMethodDescriptor(meth *descriptorpb.MethodDescriptorProto) (*openapi_options.Operation, error) { if meth.Options == nil { return nil, nil } - if !proto.HasExtension(meth.Options, swagger_options.E_Openapiv2Operation) { + if !proto.HasExtension(meth.Options, openapi_options.E_Openapiv2Operation) { return nil, nil } - ext, err := proto.GetExtension(meth.Options, swagger_options.E_Openapiv2Operation) - if err != nil { - return nil, err - } - opts, ok := ext.(*swagger_options.Operation) + ext := proto.GetExtension(meth.Options, openapi_options.E_Openapiv2Operation) + opts, ok := ext.(*openapi_options.Operation) if !ok { return nil, fmt.Errorf("extension is %T; want an Operation", ext) } @@ -1758,70 +1736,61 @@ func extractOperationOptionFromMethodDescriptor(meth *pbdescriptor.MethodDescrip } // extractSchemaOptionFromMessageDescriptor extracts the message of type -// swagger_options.Schema from a given proto message's descriptor. -func extractSchemaOptionFromMessageDescriptor(msg *pbdescriptor.DescriptorProto) (*swagger_options.Schema, error) { +// openapi_options.Schema from a given proto message's descriptor. +func extractSchemaOptionFromMessageDescriptor(msg *descriptorpb.DescriptorProto) (*openapi_options.Schema, error) { if msg.Options == nil { return nil, nil } - if !proto.HasExtension(msg.Options, swagger_options.E_Openapiv2Schema) { + if !proto.HasExtension(msg.Options, openapi_options.E_Openapiv2Schema) { return nil, nil } - ext, err := proto.GetExtension(msg.Options, swagger_options.E_Openapiv2Schema) - if err != nil { - return nil, err - } - opts, ok := ext.(*swagger_options.Schema) + ext := proto.GetExtension(msg.Options, openapi_options.E_Openapiv2Schema) + opts, ok := ext.(*openapi_options.Schema) if !ok { return nil, fmt.Errorf("extension is %T; want a Schema", ext) } return opts, nil } -// extractSwaggerOptionFromFileDescriptor extracts the message of type -// swagger_options.Swagger from a given proto method's descriptor. -func extractSwaggerOptionFromFileDescriptor(file *pbdescriptor.FileDescriptorProto) (*swagger_options.Swagger, error) { +// extractOpenAPIOptionFromFileDescriptor extracts the message of type +// openapi_options.OpenAPI from a given proto method's descriptor. +func extractOpenAPIOptionFromFileDescriptor(file *descriptorpb.FileDescriptorProto) (*openapi_options.Swagger, error) { if file.Options == nil { return nil, nil } - if !proto.HasExtension(file.Options, swagger_options.E_Openapiv2Swagger) { + if !proto.HasExtension(file.Options, openapi_options.E_Openapiv2Swagger) { return nil, nil } - ext, err := proto.GetExtension(file.Options, swagger_options.E_Openapiv2Swagger) - if err != nil { - return nil, err - } - opts, ok := ext.(*swagger_options.Swagger) + ext := proto.GetExtension(file.Options, openapi_options.E_Openapiv2Swagger) + opts, ok := ext.(*openapi_options.Swagger) if !ok { - return nil, fmt.Errorf("extension is %T; want a Swagger object", ext) + return nil, fmt.Errorf("extension is %T; want a OpenAPI object", ext) } return opts, nil } -func extractJSONSchemaFromFieldDescriptor(fd *pbdescriptor.FieldDescriptorProto) (*swagger_options.JSONSchema, error) { +func extractJSONSchemaFromFieldDescriptor(fd *descriptorpb.FieldDescriptorProto) (*openapi_options.JSONSchema, error) { if fd.Options == nil { return nil, nil } - if !proto.HasExtension(fd.Options, swagger_options.E_Openapiv2Field) { + if !proto.HasExtension(fd.Options, openapi_options.E_Openapiv2Field) { return nil, nil } - ext, err := proto.GetExtension(fd.Options, swagger_options.E_Openapiv2Field) - if err != nil { - return nil, err - } - opts, ok := ext.(*swagger_options.JSONSchema) + ext := proto.GetExtension(fd.Options, openapi_options.E_Openapiv2Field) + opts, ok := ext.(*openapi_options.JSONSchema) if !ok { return nil, fmt.Errorf("extension is %T; want a JSONSchema object", ext) } return opts, nil } -func protoJSONSchemaToSwaggerSchemaCore(j *swagger_options.JSONSchema, reg *descriptor.Registry, refs refMap) schemaCore { +func protoJSONSchemaToOpenAPISchemaCore(j *openapi_options.JSONSchema, reg *descriptor.Registry, refs refMap) schemaCore { ret := schemaCore{} if j.GetRef() != "" { - swaggerName, ok := fullyQualifiedNameToSwaggerName(j.GetRef(), reg) + openapiName, ok := fullyQualifiedNameToOpenAPIName(j.GetRef(), reg) if ok { - ret.Ref = "#/definitions/" + swaggerName + ret.Ref = "#/definitions/" + openapiName if refs != nil { refs[j.GetRef()] = struct{}{} } @@ -1837,7 +1806,7 @@ func protoJSONSchemaToSwaggerSchemaCore(j *swagger_options.JSONSchema, reg *desc return ret } -func updateSwaggerObjectFromJSONSchema(s *swaggerSchemaObject, j *swagger_options.JSONSchema, reg *descriptor.Registry, data interface{}) { +func updateswaggerObjectFromJSONSchema(s *openapiSchemaObject, j *openapi_options.JSONSchema, reg *descriptor.Registry, data interface{}) { s.Title = j.GetTitle() s.Description = j.GetDescription() if reg.GetUseGoTemplate() { @@ -1866,13 +1835,13 @@ func updateSwaggerObjectFromJSONSchema(s *swaggerSchemaObject, j *swagger_option } } -func swaggerSchemaFromProtoSchema(s *swagger_options.Schema, reg *descriptor.Registry, refs refMap, data interface{}) swaggerSchemaObject { - ret := swaggerSchemaObject{ - ExternalDocs: protoExternalDocumentationToSwaggerExternalDocumentation(s.GetExternalDocs(), reg, data), +func openapiSchemaFromProtoSchema(s *openapi_options.Schema, reg *descriptor.Registry, refs refMap, data interface{}) openapiSchemaObject { + ret := openapiSchemaObject{ + ExternalDocs: protoExternalDocumentationToOpenAPIExternalDocumentation(s.GetExternalDocs(), reg, data), } - ret.schemaCore = protoJSONSchemaToSwaggerSchemaCore(s.GetJsonSchema(), reg, refs) - updateSwaggerObjectFromJSONSchema(&ret, s.GetJsonSchema(), reg, data) + ret.schemaCore = protoJSONSchemaToOpenAPISchemaCore(s.GetJsonSchema(), reg, refs) + updateswaggerObjectFromJSONSchema(&ret, s.GetJsonSchema(), reg, data) if s != nil && s.Example != nil { ret.Example = json.RawMessage(s.Example.Value) @@ -1881,7 +1850,7 @@ func swaggerSchemaFromProtoSchema(s *swagger_options.Schema, reg *descriptor.Reg return ret } -func swaggerExamplesFromProtoExamples(in map[string]string) map[string]interface{} { +func openapiExamplesFromProtoExamples(in map[string]string) map[string]interface{} { if len(in) == 0 { return nil } @@ -1899,7 +1868,7 @@ func swaggerExamplesFromProtoExamples(in map[string]string) map[string]interface return out } -func protoJSONSchemaTypeToFormat(in []swagger_options.JSONSchema_JSONSchemaSimpleTypes) (string, string) { +func protoJSONSchemaTypeToFormat(in []openapi_options.JSONSchema_JSONSchemaSimpleTypes) (string, string) { if len(in) == 0 { return "", "" } @@ -1913,20 +1882,20 @@ func protoJSONSchemaTypeToFormat(in []swagger_options.JSONSchema_JSONSchemaSimpl // https://swagger.io/specification/#itemsObject // https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.5.2 switch in[0] { - case swagger_options.JSONSchema_UNKNOWN, swagger_options.JSONSchema_NULL: + case openapi_options.JSONSchema_UNKNOWN, openapi_options.JSONSchema_NULL: return "", "" - case swagger_options.JSONSchema_OBJECT: + case openapi_options.JSONSchema_OBJECT: return "object", "" - case swagger_options.JSONSchema_ARRAY: + case openapi_options.JSONSchema_ARRAY: return "array", "" - case swagger_options.JSONSchema_BOOLEAN: + case openapi_options.JSONSchema_BOOLEAN: return "boolean", "boolean" - case swagger_options.JSONSchema_INTEGER: + case openapi_options.JSONSchema_INTEGER: return "integer", "int32" - case swagger_options.JSONSchema_NUMBER: + case openapi_options.JSONSchema_NUMBER: return "number", "double" - case swagger_options.JSONSchema_STRING: - // NOTE: in swagger specifition, format should be empty on string type + case openapi_options.JSONSchema_STRING: + // NOTE: in OpenAPI specifition, format should be empty on string type return "string", "" default: // Maybe panic? @@ -1934,7 +1903,7 @@ func protoJSONSchemaTypeToFormat(in []swagger_options.JSONSchema_JSONSchemaSimpl } } -func protoExternalDocumentationToSwaggerExternalDocumentation(in *swagger_options.ExternalDocumentation, reg *descriptor.Registry, data interface{}) *swaggerExternalDocumentationObject { +func protoExternalDocumentationToOpenAPIExternalDocumentation(in *openapi_options.ExternalDocumentation, reg *descriptor.Registry, data interface{}) *openapiExternalDocumentationObject { if in == nil { return nil } @@ -1943,22 +1912,22 @@ func protoExternalDocumentationToSwaggerExternalDocumentation(in *swagger_option in.Description = goTemplateComments(in.Description, data, reg) } - return &swaggerExternalDocumentationObject{ + return &openapiExternalDocumentationObject{ Description: in.Description, URL: in.Url, } } -func addCustomRefs(d swaggerDefinitionsObject, reg *descriptor.Registry, refs refMap) { +func addCustomRefs(d openapiDefinitionsObject, reg *descriptor.Registry, refs refMap) { if len(refs) == 0 { return } msgMap := make(messageMap) enumMap := make(enumMap) for ref := range refs { - swgName, swgOk := fullyQualifiedNameToSwaggerName(ref, reg) + swgName, swgOk := fullyQualifiedNameToOpenAPIName(ref, reg) if !swgOk { - glog.Errorf("can't resolve swagger name from CustomRef '%v'", ref) + glog.Errorf("can't resolve OpenAPI name from CustomRef '%v'", ref) continue } if _, ok := d[swgName]; ok { @@ -1992,10 +1961,10 @@ func lowerCamelCase(fieldName string, fields []*descriptor.Field, msgs []*descri return oneField.GetJsonName() } } - messageNameToFieldsToJSONName := make(map[string]map[string]string, 0) - fieldNameToType := make(map[string]string, 0) + messageNameToFieldsToJSONName := make(map[string]map[string]string) + fieldNameToType := make(map[string]string) for _, msg := range msgs { - fieldNameToJSONName := make(map[string]string, 0) + fieldNameToJSONName := make(map[string]string) for _, oneField := range msg.GetField() { fieldNameToJSONName[oneField.GetName()] = oneField.GetJsonName() fieldNameToType[oneField.GetName()] = oneField.GetTypeName() diff --git a/gateway/protoc-gen-swagger/genswagger/template_test.go b/gateway/protoc-gen-openapiv2/internal/genopenapi/template_test.go similarity index 66% rename from gateway/protoc-gen-swagger/genswagger/template_test.go rename to gateway/protoc-gen-openapiv2/internal/genopenapi/template_test.go index 9311399..78a3ef7 100644 --- a/gateway/protoc-gen-swagger/genswagger/template_test.go +++ b/gateway/protoc-gen-openapiv2/internal/genopenapi/template_test.go @@ -1,4 +1,4 @@ -package genswagger +package genopenapi import ( "encoding/json" @@ -8,21 +8,24 @@ import ( "strings" "testing" - "github.com/golang/protobuf/proto" - protodescriptor "github.com/golang/protobuf/protoc-gen-go/descriptor" - plugin "github.com/golang/protobuf/protoc-gen-go/plugin" - "github.com/golang/protobuf/ptypes/any" + descriptorpb "github.com/golang/protobuf/protoc-gen-go/descriptor" + pluginpb "github.com/golang/protobuf/protoc-gen-go/plugin" + anypb "github.com/golang/protobuf/ptypes/any" structpb "github.com/golang/protobuf/ptypes/struct" - - // "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/descriptor" - "github.com/binchencoder/ease-gateway/gateway/protoc-gen-grpc-gateway/descriptor" - - "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/httprule" - - // swagger_options "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger/options" - swagger_options "github.com/binchencoder/ease-gateway/gateway/protoc-gen-swagger/options" + "github.com/google/go-cmp/cmp" + // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor" + "github.com/binchencoder/ease-gateway/gateway/internal/descriptor" + "github.com/grpc-ecosystem/grpc-gateway/v2/internal/httprule" + + // openapi_options "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options" + openapi_options "github.com/binchencoder/ease-gateway/gateway/protoc-gen-openapiv2/options" + // "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" + "github.com/binchencoder/ease-gateway/gateway/runtime" + "google.golang.org/protobuf/proto" ) +var marshaler = &runtime.JSONPb{} + func crossLinkFixture(f *descriptor.File) *descriptor.File { for _, m := range f.Messages { m.File = f @@ -42,9 +45,9 @@ func crossLinkFixture(f *descriptor.File) *descriptor.File { return f } -func reqFromFile(f *descriptor.File) *plugin.CodeGeneratorRequest { - return &plugin.CodeGeneratorRequest{ - ProtoFile: []*protodescriptor.FileDescriptorProto{ +func reqFromFile(f *descriptor.File) *pluginpb.CodeGeneratorRequest { + return &pluginpb.CodeGeneratorRequest{ + ProtoFile: []*descriptorpb.FileDescriptorProto{ f.FileDescriptorProto, }, FileToGenerate: []string{f.GetName()}, @@ -53,52 +56,52 @@ func reqFromFile(f *descriptor.File) *plugin.CodeGeneratorRequest { func TestMessageToQueryParametersWithEnumAsInt(t *testing.T) { type test struct { - MsgDescs []*protodescriptor.DescriptorProto + MsgDescs []*descriptorpb.DescriptorProto Message string - Params []swaggerParameterObject + Params []openapiParameterObject } tests := []test{ { - MsgDescs: []*protodescriptor.DescriptorProto{ - &protodescriptor.DescriptorProto{ + MsgDescs: []*descriptorpb.DescriptorProto{ + { Name: proto.String("ExampleMessage"), - Field: []*protodescriptor.FieldDescriptorProto{ + Field: []*descriptorpb.FieldDescriptorProto{ { Name: proto.String("a"), - Type: protodescriptor.FieldDescriptorProto_TYPE_STRING.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), Number: proto.Int32(1), }, { Name: proto.String("b"), - Type: protodescriptor.FieldDescriptorProto_TYPE_DOUBLE.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_DOUBLE.Enum(), Number: proto.Int32(2), }, { Name: proto.String("c"), - Type: protodescriptor.FieldDescriptorProto_TYPE_STRING.Enum(), - Label: protodescriptor.FieldDescriptorProto_LABEL_REPEATED.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), + Label: descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(), Number: proto.Int32(3), }, }, }, }, Message: "ExampleMessage", - Params: []swaggerParameterObject{ - swaggerParameterObject{ + Params: []openapiParameterObject{ + { Name: "a", In: "query", Required: false, Type: "string", }, - swaggerParameterObject{ + { Name: "b", In: "query", Required: false, Type: "number", Format: "double", }, - swaggerParameterObject{ + { Name: "c", In: "query", Required: false, @@ -108,52 +111,52 @@ func TestMessageToQueryParametersWithEnumAsInt(t *testing.T) { }, }, { - MsgDescs: []*protodescriptor.DescriptorProto{ - &protodescriptor.DescriptorProto{ + MsgDescs: []*descriptorpb.DescriptorProto{ + { Name: proto.String("ExampleMessage"), - Field: []*protodescriptor.FieldDescriptorProto{ + Field: []*descriptorpb.FieldDescriptorProto{ { Name: proto.String("nested"), - Type: protodescriptor.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), TypeName: proto.String(".example.Nested"), Number: proto.Int32(1), }, }, }, - &protodescriptor.DescriptorProto{ + { Name: proto.String("Nested"), - Field: []*protodescriptor.FieldDescriptorProto{ + Field: []*descriptorpb.FieldDescriptorProto{ { Name: proto.String("a"), - Type: protodescriptor.FieldDescriptorProto_TYPE_STRING.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), Number: proto.Int32(1), }, { Name: proto.String("deep"), - Type: protodescriptor.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), TypeName: proto.String(".example.Nested.DeepNested"), Number: proto.Int32(2), }, }, - NestedType: []*protodescriptor.DescriptorProto{{ + NestedType: []*descriptorpb.DescriptorProto{{ Name: proto.String("DeepNested"), - Field: []*protodescriptor.FieldDescriptorProto{ + Field: []*descriptorpb.FieldDescriptorProto{ { Name: proto.String("b"), - Type: protodescriptor.FieldDescriptorProto_TYPE_STRING.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), Number: proto.Int32(1), }, { Name: proto.String("c"), - Type: protodescriptor.FieldDescriptorProto_TYPE_ENUM.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_ENUM.Enum(), TypeName: proto.String(".example.Nested.DeepNested.DeepEnum"), Number: proto.Int32(2), }, }, - EnumType: []*protodescriptor.EnumDescriptorProto{ + EnumType: []*descriptorpb.EnumDescriptorProto{ { Name: proto.String("DeepEnum"), - Value: []*protodescriptor.EnumValueDescriptorProto{ + Value: []*descriptorpb.EnumValueDescriptorProto{ {Name: proto.String("FALSE"), Number: proto.Int32(0)}, {Name: proto.String("TRUE"), Number: proto.Int32(1)}, }, @@ -163,20 +166,20 @@ func TestMessageToQueryParametersWithEnumAsInt(t *testing.T) { }, }, Message: "ExampleMessage", - Params: []swaggerParameterObject{ - swaggerParameterObject{ + Params: []openapiParameterObject{ + { Name: "nested.a", In: "query", Required: false, Type: "string", }, - swaggerParameterObject{ + { Name: "nested.deep.b", In: "query", Required: false, Type: "string", }, - swaggerParameterObject{ + { Name: "nested.deep.c", In: "query", Required: false, @@ -196,13 +199,13 @@ func TestMessageToQueryParametersWithEnumAsInt(t *testing.T) { msgs = append(msgs, &descriptor.Message{DescriptorProto: msgdesc}) } file := descriptor.File{ - FileDescriptorProto: &protodescriptor.FileDescriptorProto{ - SourceCodeInfo: &protodescriptor.SourceCodeInfo{}, + FileDescriptorProto: &descriptorpb.FileDescriptorProto{ + SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, Name: proto.String("example.proto"), Package: proto.String("example"), Dependency: []string{}, MessageType: test.MsgDescs, - Service: []*protodescriptor.ServiceDescriptorProto{}, + Service: []*descriptorpb.ServiceDescriptorProto{}, }, GoPkg: descriptor.GoPackage{ Path: "example.com/path/to/example/example.pb", @@ -210,8 +213,8 @@ func TestMessageToQueryParametersWithEnumAsInt(t *testing.T) { }, Messages: msgs, } - reg.Load(&plugin.CodeGeneratorRequest{ - ProtoFile: []*protodescriptor.FileDescriptorProto{file.FileDescriptorProto}, + reg.Load(&pluginpb.CodeGeneratorRequest{ + ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto}, }) message, err := reg.LookupMsg("", ".example."+test.Message) @@ -234,52 +237,52 @@ func TestMessageToQueryParametersWithEnumAsInt(t *testing.T) { func TestMessageToQueryParameters(t *testing.T) { type test struct { - MsgDescs []*protodescriptor.DescriptorProto + MsgDescs []*descriptorpb.DescriptorProto Message string - Params []swaggerParameterObject + Params []openapiParameterObject } tests := []test{ { - MsgDescs: []*protodescriptor.DescriptorProto{ - &protodescriptor.DescriptorProto{ + MsgDescs: []*descriptorpb.DescriptorProto{ + { Name: proto.String("ExampleMessage"), - Field: []*protodescriptor.FieldDescriptorProto{ + Field: []*descriptorpb.FieldDescriptorProto{ { Name: proto.String("a"), - Type: protodescriptor.FieldDescriptorProto_TYPE_STRING.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), Number: proto.Int32(1), }, { Name: proto.String("b"), - Type: protodescriptor.FieldDescriptorProto_TYPE_DOUBLE.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_DOUBLE.Enum(), Number: proto.Int32(2), }, { Name: proto.String("c"), - Type: protodescriptor.FieldDescriptorProto_TYPE_STRING.Enum(), - Label: protodescriptor.FieldDescriptorProto_LABEL_REPEATED.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), + Label: descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(), Number: proto.Int32(3), }, }, }, }, Message: "ExampleMessage", - Params: []swaggerParameterObject{ - swaggerParameterObject{ + Params: []openapiParameterObject{ + { Name: "a", In: "query", Required: false, Type: "string", }, - swaggerParameterObject{ + { Name: "b", In: "query", Required: false, Type: "number", Format: "double", }, - swaggerParameterObject{ + { Name: "c", In: "query", Required: false, @@ -289,52 +292,52 @@ func TestMessageToQueryParameters(t *testing.T) { }, }, { - MsgDescs: []*protodescriptor.DescriptorProto{ - &protodescriptor.DescriptorProto{ + MsgDescs: []*descriptorpb.DescriptorProto{ + { Name: proto.String("ExampleMessage"), - Field: []*protodescriptor.FieldDescriptorProto{ + Field: []*descriptorpb.FieldDescriptorProto{ { Name: proto.String("nested"), - Type: protodescriptor.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), TypeName: proto.String(".example.Nested"), Number: proto.Int32(1), }, }, }, - &protodescriptor.DescriptorProto{ + { Name: proto.String("Nested"), - Field: []*protodescriptor.FieldDescriptorProto{ + Field: []*descriptorpb.FieldDescriptorProto{ { Name: proto.String("a"), - Type: protodescriptor.FieldDescriptorProto_TYPE_STRING.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), Number: proto.Int32(1), }, { Name: proto.String("deep"), - Type: protodescriptor.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), TypeName: proto.String(".example.Nested.DeepNested"), Number: proto.Int32(2), }, }, - NestedType: []*protodescriptor.DescriptorProto{{ + NestedType: []*descriptorpb.DescriptorProto{{ Name: proto.String("DeepNested"), - Field: []*protodescriptor.FieldDescriptorProto{ + Field: []*descriptorpb.FieldDescriptorProto{ { Name: proto.String("b"), - Type: protodescriptor.FieldDescriptorProto_TYPE_STRING.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), Number: proto.Int32(1), }, { Name: proto.String("c"), - Type: protodescriptor.FieldDescriptorProto_TYPE_ENUM.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_ENUM.Enum(), TypeName: proto.String(".example.Nested.DeepNested.DeepEnum"), Number: proto.Int32(2), }, }, - EnumType: []*protodescriptor.EnumDescriptorProto{ + EnumType: []*descriptorpb.EnumDescriptorProto{ { Name: proto.String("DeepEnum"), - Value: []*protodescriptor.EnumValueDescriptorProto{ + Value: []*descriptorpb.EnumValueDescriptorProto{ {Name: proto.String("FALSE"), Number: proto.Int32(0)}, {Name: proto.String("TRUE"), Number: proto.Int32(1)}, }, @@ -344,20 +347,20 @@ func TestMessageToQueryParameters(t *testing.T) { }, }, Message: "ExampleMessage", - Params: []swaggerParameterObject{ - swaggerParameterObject{ + Params: []openapiParameterObject{ + { Name: "nested.a", In: "query", Required: false, Type: "string", }, - swaggerParameterObject{ + { Name: "nested.deep.b", In: "query", Required: false, Type: "string", }, - swaggerParameterObject{ + { Name: "nested.deep.c", In: "query", Required: false, @@ -376,13 +379,13 @@ func TestMessageToQueryParameters(t *testing.T) { msgs = append(msgs, &descriptor.Message{DescriptorProto: msgdesc}) } file := descriptor.File{ - FileDescriptorProto: &protodescriptor.FileDescriptorProto{ - SourceCodeInfo: &protodescriptor.SourceCodeInfo{}, + FileDescriptorProto: &descriptorpb.FileDescriptorProto{ + SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, Name: proto.String("example.proto"), Package: proto.String("example"), Dependency: []string{}, MessageType: test.MsgDescs, - Service: []*protodescriptor.ServiceDescriptorProto{}, + Service: []*descriptorpb.ServiceDescriptorProto{}, }, GoPkg: descriptor.GoPackage{ Path: "example.com/path/to/example/example.pb", @@ -390,8 +393,8 @@ func TestMessageToQueryParameters(t *testing.T) { }, Messages: msgs, } - reg.Load(&plugin.CodeGeneratorRequest{ - ProtoFile: []*protodescriptor.FileDescriptorProto{file.FileDescriptorProto}, + reg.Load(&pluginpb.CodeGeneratorRequest{ + ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto}, }) message, err := reg.LookupMsg("", ".example."+test.Message) @@ -416,7 +419,7 @@ func TestMessageToQueryParameters(t *testing.T) { // are not falsely detected given previous known edge-cases. func TestMessageToQueryParametersNoRecursive(t *testing.T) { type test struct { - MsgDescs []*protodescriptor.DescriptorProto + MsgDescs []*descriptorpb.DescriptorProto Message string } @@ -437,48 +440,48 @@ func TestMessageToQueryParametersNoRecursive(t *testing.T) { // string second = 2; // } { - MsgDescs: []*protodescriptor.DescriptorProto{ - &protodescriptor.DescriptorProto{ + MsgDescs: []*descriptorpb.DescriptorProto{ + &descriptorpb.DescriptorProto{ Name: proto.String("QueryMessage"), - Field: []*protodescriptor.FieldDescriptorProto{ + Field: []*descriptorpb.FieldDescriptorProto{ { Name: proto.String("first"), - Type: protodescriptor.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), TypeName: proto.String(".example.BaseMessage"), Number: proto.Int32(1), }, { Name: proto.String("second"), - Type: protodescriptor.FieldDescriptorProto_TYPE_STRING.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), Number: proto.Int32(2), }, }, }, - &protodescriptor.DescriptorProto{ + &descriptorpb.DescriptorProto{ Name: proto.String("BaseMessage"), - Field: []*protodescriptor.FieldDescriptorProto{ + Field: []*descriptorpb.FieldDescriptorProto{ { Name: proto.String("first"), - Type: protodescriptor.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), TypeName: proto.String(".example.NonRecursiveMessage"), Number: proto.Int32(1), }, { Name: proto.String("second"), - Type: protodescriptor.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), TypeName: proto.String(".example.NonRecursiveMessage"), Number: proto.Int32(2), }, }, }, // Note there is no recursive nature to this message - &protodescriptor.DescriptorProto{ + &descriptorpb.DescriptorProto{ Name: proto.String("NonRecursiveMessage"), - Field: []*protodescriptor.FieldDescriptorProto{ + Field: []*descriptorpb.FieldDescriptorProto{ { Name: proto.String("field"), - //Label: protodescriptor.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: protodescriptor.FieldDescriptorProto_TYPE_STRING.Enum(), + //Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), Number: proto.Int32(1), }, }, @@ -495,13 +498,13 @@ func TestMessageToQueryParametersNoRecursive(t *testing.T) { msgs = append(msgs, &descriptor.Message{DescriptorProto: msgdesc}) } file := descriptor.File{ - FileDescriptorProto: &protodescriptor.FileDescriptorProto{ - SourceCodeInfo: &protodescriptor.SourceCodeInfo{}, + FileDescriptorProto: &descriptorpb.FileDescriptorProto{ + SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, Name: proto.String("example.proto"), Package: proto.String("example"), Dependency: []string{}, MessageType: test.MsgDescs, - Service: []*protodescriptor.ServiceDescriptorProto{}, + Service: []*descriptorpb.ServiceDescriptorProto{}, }, GoPkg: descriptor.GoPackage{ Path: "example.com/path/to/example/example.pb", @@ -509,8 +512,8 @@ func TestMessageToQueryParametersNoRecursive(t *testing.T) { }, Messages: msgs, } - reg.Load(&plugin.CodeGeneratorRequest{ - ProtoFile: []*protodescriptor.FileDescriptorProto{file.FileDescriptorProto}, + reg.Load(&pluginpb.CodeGeneratorRequest{ + ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto}, }) message, err := reg.LookupMsg("", ".example."+test.Message) @@ -530,75 +533,75 @@ func TestMessageToQueryParametersNoRecursive(t *testing.T) { // references to query-parameters returns an error message. func TestMessageToQueryParametersRecursive(t *testing.T) { type test struct { - MsgDescs []*protodescriptor.DescriptorProto + MsgDescs []*descriptorpb.DescriptorProto Message string } tests := []test{ - // First test: - // Here we test that a message that references it self through a field will return an error. - // Example proto: - // message DirectRecursiveMessage { - // DirectRecursiveMessage nested = 1; - // } + // First test: + // Here we test that a message that references it self through a field will return an error. + // Example proto: + // message DirectRecursiveMessage { + // DirectRecursiveMessage nested = 1; + // } { - MsgDescs: []*protodescriptor.DescriptorProto{ - &protodescriptor.DescriptorProto{ + MsgDescs: []*descriptorpb.DescriptorProto{ + { Name: proto.String("DirectRecursiveMessage"), - Field: []*protodescriptor.FieldDescriptorProto{ - { - Name: proto.String("nested"), - Label: protodescriptor.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: protodescriptor.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - TypeName: proto.String(".example.DirectRecursiveMessage"), - Number: proto.Int32(1), + Field: []*descriptorpb.FieldDescriptorProto{ + { + Name: proto.String("nested"), + Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + TypeName: proto.String(".example.DirectRecursiveMessage"), + Number: proto.Int32(1), }, }, }, }, Message: "DirectRecursiveMessage", }, - // Second test: - // Here we test that a cycle through multiple messages is detected and that an error is returned. - // Sample: - // message Root { NodeMessage nested = 1; } - // message NodeMessage { CycleMessage nested = 1; } - // message CycleMessage { Root nested = 1; } + // Second test: + // Here we test that a cycle through multiple messages is detected and that an error is returned. + // Sample: + // message Root { NodeMessage nested = 1; } + // message NodeMessage { CycleMessage nested = 1; } + // message CycleMessage { Root nested = 1; } { - MsgDescs: []*protodescriptor.DescriptorProto{ - &protodescriptor.DescriptorProto{ + MsgDescs: []*descriptorpb.DescriptorProto{ + { Name: proto.String("RootMessage"), - Field: []*protodescriptor.FieldDescriptorProto{ - { - Name: proto.String("nested"), - Label: protodescriptor.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: protodescriptor.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - TypeName: proto.String(".example.NodeMessage"), - Number: proto.Int32(1), + Field: []*descriptorpb.FieldDescriptorProto{ + { + Name: proto.String("nested"), + Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + TypeName: proto.String(".example.NodeMessage"), + Number: proto.Int32(1), }, }, }, - &protodescriptor.DescriptorProto{ + { Name: proto.String("NodeMessage"), - Field: []*protodescriptor.FieldDescriptorProto{ - { - Name: proto.String("nested"), - Label: protodescriptor.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: protodescriptor.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - TypeName: proto.String(".example.CycleMessage"), - Number: proto.Int32(1), + Field: []*descriptorpb.FieldDescriptorProto{ + { + Name: proto.String("nested"), + Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + TypeName: proto.String(".example.CycleMessage"), + Number: proto.Int32(1), }, }, }, - &protodescriptor.DescriptorProto{ + { Name: proto.String("CycleMessage"), - Field: []*protodescriptor.FieldDescriptorProto{ - { - Name: proto.String("nested"), - Label: protodescriptor.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: protodescriptor.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - TypeName: proto.String(".example.RootMessage"), - Number: proto.Int32(1), + Field: []*descriptorpb.FieldDescriptorProto{ + { + Name: proto.String("nested"), + Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + TypeName: proto.String(".example.RootMessage"), + Number: proto.Int32(1), }, }, }, @@ -614,13 +617,13 @@ func TestMessageToQueryParametersRecursive(t *testing.T) { msgs = append(msgs, &descriptor.Message{DescriptorProto: msgdesc}) } file := descriptor.File{ - FileDescriptorProto: &protodescriptor.FileDescriptorProto{ - SourceCodeInfo: &protodescriptor.SourceCodeInfo{}, + FileDescriptorProto: &descriptorpb.FileDescriptorProto{ + SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, Name: proto.String("example.proto"), Package: proto.String("example"), Dependency: []string{}, MessageType: test.MsgDescs, - Service: []*protodescriptor.ServiceDescriptorProto{}, + Service: []*descriptorpb.ServiceDescriptorProto{}, }, GoPkg: descriptor.GoPackage{ Path: "example.com/path/to/example/example.pb", @@ -628,8 +631,8 @@ func TestMessageToQueryParametersRecursive(t *testing.T) { }, Messages: msgs, } - reg.Load(&plugin.CodeGeneratorRequest{ - ProtoFile: []*protodescriptor.FileDescriptorProto{file.FileDescriptorProto}, + reg.Load(&pluginpb.CodeGeneratorRequest{ + ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto}, }) message, err := reg.LookupMsg("", ".example."+test.Message) @@ -645,20 +648,20 @@ func TestMessageToQueryParametersRecursive(t *testing.T) { func TestMessageToQueryParametersWithJsonName(t *testing.T) { type test struct { - MsgDescs []*protodescriptor.DescriptorProto + MsgDescs []*descriptorpb.DescriptorProto Message string - Params []swaggerParameterObject + Params []openapiParameterObject } tests := []test{ { - MsgDescs: []*protodescriptor.DescriptorProto{ - &protodescriptor.DescriptorProto{ + MsgDescs: []*descriptorpb.DescriptorProto{ + { Name: proto.String("ExampleMessage"), - Field: []*protodescriptor.FieldDescriptorProto{ + Field: []*descriptorpb.FieldDescriptorProto{ { Name: proto.String("test_field_a"), - Type: protodescriptor.FieldDescriptorProto_TYPE_STRING.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), Number: proto.Int32(1), JsonName: proto.String("testFieldA"), }, @@ -666,8 +669,8 @@ func TestMessageToQueryParametersWithJsonName(t *testing.T) { }, }, Message: "ExampleMessage", - Params: []swaggerParameterObject{ - swaggerParameterObject{ + Params: []openapiParameterObject{ + { Name: "testFieldA", In: "query", Required: false, @@ -676,24 +679,24 @@ func TestMessageToQueryParametersWithJsonName(t *testing.T) { }, }, { - MsgDescs: []*protodescriptor.DescriptorProto{ - &protodescriptor.DescriptorProto{ + MsgDescs: []*descriptorpb.DescriptorProto{ + { Name: proto.String("SubMessage"), - Field: []*protodescriptor.FieldDescriptorProto{ + Field: []*descriptorpb.FieldDescriptorProto{ { Name: proto.String("test_field_a"), - Type: protodescriptor.FieldDescriptorProto_TYPE_STRING.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), Number: proto.Int32(1), JsonName: proto.String("testFieldA"), }, }, }, - &protodescriptor.DescriptorProto{ + { Name: proto.String("ExampleMessage"), - Field: []*protodescriptor.FieldDescriptorProto{ + Field: []*descriptorpb.FieldDescriptorProto{ { Name: proto.String("sub_message"), - Type: protodescriptor.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), TypeName: proto.String(".example.SubMessage"), Number: proto.Int32(1), JsonName: proto.String("subMessage"), @@ -702,8 +705,8 @@ func TestMessageToQueryParametersWithJsonName(t *testing.T) { }, }, Message: "ExampleMessage", - Params: []swaggerParameterObject{ - swaggerParameterObject{ + Params: []openapiParameterObject{ + { Name: "subMessage.testFieldA", In: "query", Required: false, @@ -721,13 +724,13 @@ func TestMessageToQueryParametersWithJsonName(t *testing.T) { msgs = append(msgs, &descriptor.Message{DescriptorProto: msgdesc}) } file := descriptor.File{ - FileDescriptorProto: &protodescriptor.FileDescriptorProto{ - SourceCodeInfo: &protodescriptor.SourceCodeInfo{}, + FileDescriptorProto: &descriptorpb.FileDescriptorProto{ + SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, Name: proto.String("example.proto"), Package: proto.String("example"), Dependency: []string{}, MessageType: test.MsgDescs, - Service: []*protodescriptor.ServiceDescriptorProto{}, + Service: []*descriptorpb.ServiceDescriptorProto{}, }, GoPkg: descriptor.GoPackage{ Path: "example.com/path/to/example/example.pb", @@ -735,8 +738,8 @@ func TestMessageToQueryParametersWithJsonName(t *testing.T) { }, Messages: msgs, } - reg.Load(&plugin.CodeGeneratorRequest{ - ProtoFile: []*protodescriptor.FileDescriptorProto{file.FileDescriptorProto}, + reg.Load(&pluginpb.CodeGeneratorRequest{ + ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto}, }) message, err := reg.LookupMsg("", ".example."+test.Message) @@ -754,29 +757,29 @@ func TestMessageToQueryParametersWithJsonName(t *testing.T) { } func TestApplyTemplateSimple(t *testing.T) { - msgdesc := &protodescriptor.DescriptorProto{ + msgdesc := &descriptorpb.DescriptorProto{ Name: proto.String("ExampleMessage"), } - meth := &protodescriptor.MethodDescriptorProto{ + meth := &descriptorpb.MethodDescriptorProto{ Name: proto.String("Example"), InputType: proto.String("ExampleMessage"), OutputType: proto.String("ExampleMessage"), } - svc := &protodescriptor.ServiceDescriptorProto{ + svc := &descriptorpb.ServiceDescriptorProto{ Name: proto.String("ExampleService"), - Method: []*protodescriptor.MethodDescriptorProto{meth}, + Method: []*descriptorpb.MethodDescriptorProto{meth}, } msg := &descriptor.Message{ DescriptorProto: msgdesc, } file := descriptor.File{ - FileDescriptorProto: &protodescriptor.FileDescriptorProto{ - SourceCodeInfo: &protodescriptor.SourceCodeInfo{}, + FileDescriptorProto: &descriptorpb.FileDescriptorProto{ + SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, Name: proto.String("example.proto"), Package: proto.String("example"), Dependency: []string{"a.example/b/c.proto", "a.example/d/e.proto"}, - MessageType: []*protodescriptor.DescriptorProto{msgdesc}, - Service: []*protodescriptor.ServiceDescriptorProto{svc}, + MessageType: []*descriptorpb.DescriptorProto{msgdesc}, + Service: []*descriptorpb.ServiceDescriptorProto{svc}, }, GoPkg: descriptor.GoPackage{ Path: "example.com/path/to/example/example.pb", @@ -808,6 +811,10 @@ func TestApplyTemplateSimple(t *testing.T) { }, } reg := descriptor.NewRegistry() + if err := AddErrorDefs(reg); err != nil { + t.Errorf("AddErrorDefs(%#v) failed with %v; want success", reg, err) + return + } fileCL := crossLinkFixture(&file) err := reg.Load(reqFromFile(fileCL)) if err != nil { @@ -843,10 +850,10 @@ func TestApplyTemplateSimple(t *testing.T) { } func TestApplyTemplateMultiService(t *testing.T) { - msgdesc := &protodescriptor.DescriptorProto{ + msgdesc := &descriptorpb.DescriptorProto{ Name: proto.String("ExampleMessage"), } - meth := &protodescriptor.MethodDescriptorProto{ + meth := &descriptorpb.MethodDescriptorProto{ Name: proto.String("Example"), InputType: proto.String("ExampleMessage"), OutputType: proto.String("ExampleMessage"), @@ -854,26 +861,26 @@ func TestApplyTemplateMultiService(t *testing.T) { // Create two services that have the same method name. We will test that the // operation IDs are different - svc := &protodescriptor.ServiceDescriptorProto{ + svc := &descriptorpb.ServiceDescriptorProto{ Name: proto.String("ExampleService"), - Method: []*protodescriptor.MethodDescriptorProto{meth}, + Method: []*descriptorpb.MethodDescriptorProto{meth}, } - svc2 := &protodescriptor.ServiceDescriptorProto{ + svc2 := &descriptorpb.ServiceDescriptorProto{ Name: proto.String("OtherService"), - Method: []*protodescriptor.MethodDescriptorProto{meth}, + Method: []*descriptorpb.MethodDescriptorProto{meth}, } msg := &descriptor.Message{ DescriptorProto: msgdesc, } file := descriptor.File{ - FileDescriptorProto: &protodescriptor.FileDescriptorProto{ - SourceCodeInfo: &protodescriptor.SourceCodeInfo{}, + FileDescriptorProto: &descriptorpb.FileDescriptorProto{ + SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, Name: proto.String("example.proto"), Package: proto.String("example"), Dependency: []string{"a.example/b/c.proto", "a.example/d/e.proto"}, - MessageType: []*protodescriptor.DescriptorProto{msgdesc}, - Service: []*protodescriptor.ServiceDescriptorProto{svc}, + MessageType: []*descriptorpb.DescriptorProto{msgdesc}, + Service: []*descriptorpb.ServiceDescriptorProto{svc}, }, GoPkg: descriptor.GoPackage{ Path: "example.com/path/to/example/example.pb", @@ -926,6 +933,10 @@ func TestApplyTemplateMultiService(t *testing.T) { }, } reg := descriptor.NewRegistry() + if err := AddErrorDefs(reg); err != nil { + t.Errorf("AddErrorDefs(%#v) failed with %v; want success", reg, err) + return + } fileCL := crossLinkFixture(&file) err := reg.Load(reqFromFile(fileCL)) if err != nil { @@ -955,37 +966,34 @@ func TestApplyTemplateMultiService(t *testing.T) { } func TestApplyTemplateOverrideOperationID(t *testing.T) { - msgdesc := &protodescriptor.DescriptorProto{ + msgdesc := &descriptorpb.DescriptorProto{ Name: proto.String("ExampleMessage"), } - meth := &protodescriptor.MethodDescriptorProto{ + meth := &descriptorpb.MethodDescriptorProto{ Name: proto.String("Example"), InputType: proto.String("ExampleMessage"), OutputType: proto.String("ExampleMessage"), - Options: &protodescriptor.MethodOptions{}, + Options: &descriptorpb.MethodOptions{}, } - swaggerOperation := swagger_options.Operation{ + openapiOperation := openapi_options.Operation{ OperationId: "MyExample", } - if err := proto.SetExtension(proto.Message(meth.Options), swagger_options.E_Openapiv2Operation, &swaggerOperation); err != nil { - t.Fatalf("proto.SetExtension(MethodDescriptorProto.Options) failed: %v", err) - } - - svc := &protodescriptor.ServiceDescriptorProto{ + proto.SetExtension(proto.Message(meth.Options), openapi_options.E_Openapiv2Operation, &openapiOperation) + svc := &descriptorpb.ServiceDescriptorProto{ Name: proto.String("ExampleService"), - Method: []*protodescriptor.MethodDescriptorProto{meth}, + Method: []*descriptorpb.MethodDescriptorProto{meth}, } msg := &descriptor.Message{ DescriptorProto: msgdesc, } file := descriptor.File{ - FileDescriptorProto: &protodescriptor.FileDescriptorProto{ - SourceCodeInfo: &protodescriptor.SourceCodeInfo{}, + FileDescriptorProto: &descriptorpb.FileDescriptorProto{ + SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, Name: proto.String("example.proto"), Package: proto.String("example"), Dependency: []string{"a.example/b/c.proto", "a.example/d/e.proto"}, - MessageType: []*protodescriptor.DescriptorProto{msgdesc}, - Service: []*protodescriptor.ServiceDescriptorProto{svc}, + MessageType: []*descriptorpb.DescriptorProto{msgdesc}, + Service: []*descriptorpb.ServiceDescriptorProto{svc}, }, GoPkg: descriptor.GoPackage{ Path: "example.com/path/to/example/example.pb", @@ -1018,6 +1026,10 @@ func TestApplyTemplateOverrideOperationID(t *testing.T) { } reg := descriptor.NewRegistry() + if err := AddErrorDefs(reg); err != nil { + t.Errorf("AddErrorDefs(%#v) failed with %v; want success", reg, err) + return + } fileCL := crossLinkFixture(&file) err := reg.Load(reqFromFile(fileCL)) if err != nil { @@ -1041,31 +1053,31 @@ func TestApplyTemplateOverrideOperationID(t *testing.T) { } func TestApplyTemplateExtensions(t *testing.T) { - msgdesc := &protodescriptor.DescriptorProto{ + msgdesc := &descriptorpb.DescriptorProto{ Name: proto.String("ExampleMessage"), } - meth := &protodescriptor.MethodDescriptorProto{ + meth := &descriptorpb.MethodDescriptorProto{ Name: proto.String("Example"), InputType: proto.String("ExampleMessage"), OutputType: proto.String("ExampleMessage"), - Options: &protodescriptor.MethodOptions{}, + Options: &descriptorpb.MethodOptions{}, } - svc := &protodescriptor.ServiceDescriptorProto{ + svc := &descriptorpb.ServiceDescriptorProto{ Name: proto.String("ExampleService"), - Method: []*protodescriptor.MethodDescriptorProto{meth}, + Method: []*descriptorpb.MethodDescriptorProto{meth}, } msg := &descriptor.Message{ DescriptorProto: msgdesc, } file := descriptor.File{ - FileDescriptorProto: &protodescriptor.FileDescriptorProto{ - SourceCodeInfo: &protodescriptor.SourceCodeInfo{}, + FileDescriptorProto: &descriptorpb.FileDescriptorProto{ + SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, Name: proto.String("example.proto"), Package: proto.String("example"), Dependency: []string{"a.example/b/c.proto", "a.example/d/e.proto"}, - MessageType: []*protodescriptor.DescriptorProto{msgdesc}, - Service: []*protodescriptor.ServiceDescriptorProto{svc}, - Options: &protodescriptor.FileOptions{}, + MessageType: []*descriptorpb.DescriptorProto{msgdesc}, + Service: []*descriptorpb.ServiceDescriptorProto{svc}, + Options: &descriptorpb.FileOptions{}, }, GoPkg: descriptor.GoPackage{ Path: "example.com/path/to/example/example.pb", @@ -1096,49 +1108,48 @@ func TestApplyTemplateExtensions(t *testing.T) { }, }, } - swagger := swagger_options.Swagger{ - Info: &swagger_options.Info{ + swagger := openapi_options.Swagger{ + Info: &openapi_options.Info{ Title: "test", Extensions: map[string]*structpb.Value{ - "x-info-extension": &structpb.Value{Kind: &structpb.Value_StringValue{StringValue: "bar"}}, + "x-info-extension": {Kind: &structpb.Value_StringValue{StringValue: "bar"}}, }, }, Extensions: map[string]*structpb.Value{ - "x-foo": &structpb.Value{Kind: &structpb.Value_StringValue{StringValue: "bar"}}, - "x-bar": &structpb.Value{Kind: &structpb.Value_ListValue{ListValue: &structpb.ListValue{ + "x-foo": {Kind: &structpb.Value_StringValue{StringValue: "bar"}}, + "x-bar": {Kind: &structpb.Value_ListValue{ListValue: &structpb.ListValue{ Values: []*structpb.Value{{Kind: &structpb.Value_StringValue{StringValue: "baz"}}}, }}}, }, - SecurityDefinitions: &swagger_options.SecurityDefinitions{ - Security: map[string]*swagger_options.SecurityScheme{ - "somescheme": &swagger_options.SecurityScheme{ + SecurityDefinitions: &openapi_options.SecurityDefinitions{ + Security: map[string]*openapi_options.SecurityScheme{ + "somescheme": { Extensions: map[string]*structpb.Value{ - "x-security-baz": &structpb.Value{Kind: &structpb.Value_BoolValue{BoolValue: true}}, + "x-security-baz": {Kind: &structpb.Value_BoolValue{BoolValue: true}}, }, }, }, }, } - if err := proto.SetExtension(proto.Message(file.FileDescriptorProto.Options), swagger_options.E_Openapiv2Swagger, &swagger); err != nil { - t.Fatalf("proto.SetExtension(FileDescriptorProto.Options) failed: %v", err) - } - - swaggerOperation := swagger_options.Operation{ - Responses: map[string]*swagger_options.Response{ - "200": &swagger_options.Response{ + proto.SetExtension(proto.Message(file.FileDescriptorProto.Options), openapi_options.E_Openapiv2Swagger, &swagger) + openapiOperation := openapi_options.Operation{ + Responses: map[string]*openapi_options.Response{ + "200": { Extensions: map[string]*structpb.Value{ - "x-resp-id": &structpb.Value{Kind: &structpb.Value_StringValue{StringValue: "resp1000"}}, + "x-resp-id": {Kind: &structpb.Value_StringValue{StringValue: "resp1000"}}, }, }, }, Extensions: map[string]*structpb.Value{ - "x-op-foo": &structpb.Value{Kind: &structpb.Value_StringValue{StringValue: "baz"}}, + "x-op-foo": {Kind: &structpb.Value_StringValue{StringValue: "baz"}}, }, } - if err := proto.SetExtension(proto.Message(meth.Options), swagger_options.E_Openapiv2Operation, &swaggerOperation); err != nil { - t.Fatalf("proto.SetExtension(MethodDescriptorProto.Options) failed: %v", err) - } + proto.SetExtension(proto.Message(meth.Options), openapi_options.E_Openapiv2Operation, &openapiOperation) reg := descriptor.NewRegistry() + if err := AddErrorDefs(reg); err != nil { + t.Errorf("AddErrorDefs(%#v) failed with %v; want success", reg, err) + return + } fileCL := crossLinkFixture(&file) err := reg.Load(reqFromFile(fileCL)) if err != nil { @@ -1153,14 +1164,39 @@ func TestApplyTemplateExtensions(t *testing.T) { if want, is, name := "2.0", result.Swagger, "Swagger"; !reflect.DeepEqual(is, want) { t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want) } - if want, is, name := []extension{ - {key: "x-bar", value: json.RawMessage("[\n \"baz\"\n ]")}, - {key: "x-foo", value: json.RawMessage("\"bar\"")}, - }, result.extensions, "Extensions"; !reflect.DeepEqual(is, want) { - t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want) + if got, want := len(result.extensions), 2; got != want { + t.Fatalf("len(applyTemplate(%#v).Extensions) = %d want to be %d", file, got, want) + } + if got, want := result.extensions[0].key, "x-bar"; got != want { + t.Errorf("applyTemplate(%#v).Extensions[0].key = %s want to be %s", file, got, want) + } + if got, want := result.extensions[1].key, "x-foo"; got != want { + t.Errorf("applyTemplate(%#v).Extensions[1].key = %s want to be %s", file, got, want) + } + { + var got []string + err = marshaler.Unmarshal(result.extensions[0].value, &got) + if err != nil { + t.Fatalf("marshaler.Unmarshal failed: %v", err) + } + want := []string{"baz"} + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf(diff) + } + } + { + var got string + err = marshaler.Unmarshal(result.extensions[1].value, &got) + if err != nil { + t.Fatalf("marshaler.Unmarshal failed: %v", err) + } + want := "bar" + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf(diff) + } } - var scheme swaggerSecuritySchemeObject + var scheme openapiSecuritySchemeObject for _, v := range result.SecurityDefinitions { scheme = v } @@ -1176,8 +1212,8 @@ func TestApplyTemplateExtensions(t *testing.T) { t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want) } - var operation *swaggerOperationObject - var response swaggerResponseObject + var operation *openapiOperationObject + var response openapiResponseObject for _, v := range result.Paths { operation = v.Get response = v.Get.Responses["200"] @@ -1195,44 +1231,44 @@ func TestApplyTemplateExtensions(t *testing.T) { } func TestApplyTemplateRequestWithoutClientStreaming(t *testing.T) { - msgdesc := &protodescriptor.DescriptorProto{ + msgdesc := &descriptorpb.DescriptorProto{ Name: proto.String("ExampleMessage"), - Field: []*protodescriptor.FieldDescriptorProto{ + Field: []*descriptorpb.FieldDescriptorProto{ { Name: proto.String("nested"), - Label: protodescriptor.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: protodescriptor.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), TypeName: proto.String("NestedMessage"), Number: proto.Int32(1), }, }, } - nesteddesc := &protodescriptor.DescriptorProto{ + nesteddesc := &descriptorpb.DescriptorProto{ Name: proto.String("NestedMessage"), - Field: []*protodescriptor.FieldDescriptorProto{ + Field: []*descriptorpb.FieldDescriptorProto{ { Name: proto.String("int32"), - Label: protodescriptor.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: protodescriptor.FieldDescriptorProto_TYPE_INT32.Enum(), + Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_INT32.Enum(), Number: proto.Int32(1), }, { Name: proto.String("bool"), - Label: protodescriptor.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: protodescriptor.FieldDescriptorProto_TYPE_BOOL.Enum(), + Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_BOOL.Enum(), Number: proto.Int32(2), }, }, } - meth := &protodescriptor.MethodDescriptorProto{ + meth := &descriptorpb.MethodDescriptorProto{ Name: proto.String("Echo"), InputType: proto.String("ExampleMessage"), OutputType: proto.String("ExampleMessage"), ClientStreaming: proto.Bool(false), } - svc := &protodescriptor.ServiceDescriptorProto{ + svc := &descriptorpb.ServiceDescriptorProto{ Name: proto.String("ExampleService"), - Method: []*protodescriptor.MethodDescriptorProto{meth}, + Method: []*descriptorpb.MethodDescriptorProto{meth}, } meth.ServerStreaming = proto.Bool(false) @@ -1257,12 +1293,12 @@ func TestApplyTemplateRequestWithoutClientStreaming(t *testing.T) { FieldDescriptorProto: nested.GetField()[1], } file := descriptor.File{ - FileDescriptorProto: &protodescriptor.FileDescriptorProto{ - SourceCodeInfo: &protodescriptor.SourceCodeInfo{}, + FileDescriptorProto: &descriptorpb.FileDescriptorProto{ + SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, Name: proto.String("example.proto"), Package: proto.String("example"), - MessageType: []*protodescriptor.DescriptorProto{msgdesc, nesteddesc}, - Service: []*protodescriptor.ServiceDescriptorProto{svc}, + MessageType: []*descriptorpb.DescriptorProto{msgdesc, nesteddesc}, + Service: []*descriptorpb.ServiceDescriptorProto{svc}, }, GoPkg: descriptor.GoPackage{ Path: "example.com/path/to/example/example.pb", @@ -1320,7 +1356,11 @@ func TestApplyTemplateRequestWithoutClientStreaming(t *testing.T) { }, } reg := descriptor.NewRegistry() - reg.Load(&plugin.CodeGeneratorRequest{ProtoFile: []*protodescriptor.FileDescriptorProto{file.FileDescriptorProto}}) + if err := AddErrorDefs(reg); err != nil { + t.Errorf("AddErrorDefs(%#v) failed with %v; want success", reg, err) + return + } + reg.Load(&pluginpb.CodeGeneratorRequest{ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto}}) result, err := applyTemplate(param{File: crossLinkFixture(&file), reg: reg}) if err != nil { t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err) @@ -1350,45 +1390,45 @@ func TestApplyTemplateRequestWithoutClientStreaming(t *testing.T) { } func TestApplyTemplateRequestWithClientStreaming(t *testing.T) { - msgdesc := &protodescriptor.DescriptorProto{ + msgdesc := &descriptorpb.DescriptorProto{ Name: proto.String("ExampleMessage"), - Field: []*protodescriptor.FieldDescriptorProto{ + Field: []*descriptorpb.FieldDescriptorProto{ { Name: proto.String("nested"), - Label: protodescriptor.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: protodescriptor.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), TypeName: proto.String("NestedMessage"), Number: proto.Int32(1), }, }, } - nesteddesc := &protodescriptor.DescriptorProto{ + nesteddesc := &descriptorpb.DescriptorProto{ Name: proto.String("NestedMessage"), - Field: []*protodescriptor.FieldDescriptorProto{ + Field: []*descriptorpb.FieldDescriptorProto{ { Name: proto.String("int32"), - Label: protodescriptor.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: protodescriptor.FieldDescriptorProto_TYPE_INT32.Enum(), + Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_INT32.Enum(), Number: proto.Int32(1), }, { Name: proto.String("bool"), - Label: protodescriptor.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: protodescriptor.FieldDescriptorProto_TYPE_BOOL.Enum(), + Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_BOOL.Enum(), Number: proto.Int32(2), }, }, } - meth := &protodescriptor.MethodDescriptorProto{ + meth := &descriptorpb.MethodDescriptorProto{ Name: proto.String("Echo"), InputType: proto.String("ExampleMessage"), OutputType: proto.String("ExampleMessage"), ClientStreaming: proto.Bool(true), ServerStreaming: proto.Bool(true), } - svc := &protodescriptor.ServiceDescriptorProto{ + svc := &descriptorpb.ServiceDescriptorProto{ Name: proto.String("ExampleService"), - Method: []*protodescriptor.MethodDescriptorProto{meth}, + Method: []*descriptorpb.MethodDescriptorProto{meth}, } msg := &descriptor.Message{ @@ -1411,12 +1451,12 @@ func TestApplyTemplateRequestWithClientStreaming(t *testing.T) { FieldDescriptorProto: nested.GetField()[1], } file := descriptor.File{ - FileDescriptorProto: &protodescriptor.FileDescriptorProto{ - SourceCodeInfo: &protodescriptor.SourceCodeInfo{}, + FileDescriptorProto: &descriptorpb.FileDescriptorProto{ + SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, Name: proto.String("example.proto"), Package: proto.String("example"), - MessageType: []*protodescriptor.DescriptorProto{msgdesc, nesteddesc}, - Service: []*protodescriptor.ServiceDescriptorProto{svc}, + MessageType: []*descriptorpb.DescriptorProto{msgdesc, nesteddesc}, + Service: []*descriptorpb.ServiceDescriptorProto{svc}, }, GoPkg: descriptor.GoPackage{ Path: "example.com/path/to/example/example.pb", @@ -1474,11 +1514,11 @@ func TestApplyTemplateRequestWithClientStreaming(t *testing.T) { }, } reg := descriptor.NewRegistry() - if err := AddStreamError(reg); err != nil { - t.Errorf("AddStreamError(%#v) failed with %v; want success", reg, err) + if err := AddErrorDefs(reg); err != nil { + t.Errorf("AddErrorDefs(%#v) failed with %v; want success", reg, err) return } - reg.Load(&plugin.CodeGeneratorRequest{ProtoFile: []*protodescriptor.FileDescriptorProto{file.FileDescriptorProto}}) + reg.Load(&pluginpb.CodeGeneratorRequest{ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto}}) result, err := applyTemplate(param{File: crossLinkFixture(&file), reg: reg}) if err != nil { t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err) @@ -1486,7 +1526,7 @@ func TestApplyTemplateRequestWithClientStreaming(t *testing.T) { } // Only ExampleMessage must be present, not NestedMessage - if want, got, name := 4, len(result.Definitions), "len(Definitions)"; !reflect.DeepEqual(got, want) { + if want, got, name := 3, len(result.Definitions), "len(Definitions)"; !reflect.DeepEqual(got, want) { t.Errorf("applyTemplate(%#v).%s = %d want to be %d", file, name, got, want) } if _, ok := result.Paths["/v1/echo"].Post.Responses["200"]; !ok { @@ -1510,16 +1550,16 @@ func TestApplyTemplateRequestWithClientStreaming(t *testing.T) { if want, got, name := "result", resultProperty.Key, `(*(StreamDefinitions["exampleExampleMessage"].Properties))[0].Key`; !reflect.DeepEqual(got, want) { t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, got, want) } - result := resultProperty.Value.(swaggerSchemaObject) - if want, got, name := "#/definitions/exampleExampleMessage", result.Ref, `((*(StreamDefinitions["exampleExampleMessage"].Properties))[0].Value.(swaggerSchemaObject)).Ref`; !reflect.DeepEqual(got, want) { + result := resultProperty.Value.(openapiSchemaObject) + if want, got, name := "#/definitions/exampleExampleMessage", result.Ref, `((*(StreamDefinitions["exampleExampleMessage"].Properties))[0].Value.(openapiSchemaObject)).Ref`; !reflect.DeepEqual(got, want) { t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, got, want) } errorProperty := streamExampleExampleMessageProperties[1] if want, got, name := "error", errorProperty.Key, `(*(StreamDefinitions["exampleExampleMessage"].Properties))[0].Key`; !reflect.DeepEqual(got, want) { t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, got, want) } - err := errorProperty.Value.(swaggerSchemaObject) - if want, got, name := "#/definitions/runtimeStreamError", err.Ref, `((*(StreamDefinitions["exampleExampleMessage"].Properties))[0].Value.(swaggerSchemaObject)).Ref`; !reflect.DeepEqual(got, want) { + err := errorProperty.Value.(openapiSchemaObject) + if want, got, name := "#/definitions/rpcStatus", err.Ref, `((*(StreamDefinitions["exampleExampleMessage"].Properties))[0].Value.(openapiSchemaObject)).Ref`; !reflect.DeepEqual(got, want) { t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, got, want) } } @@ -1533,30 +1573,30 @@ func TestApplyTemplateRequestWithClientStreaming(t *testing.T) { } func TestApplyTemplateRequestWithUnusedReferences(t *testing.T) { - reqdesc := &protodescriptor.DescriptorProto{ + reqdesc := &descriptorpb.DescriptorProto{ Name: proto.String("ExampleMessage"), - Field: []*protodescriptor.FieldDescriptorProto{ + Field: []*descriptorpb.FieldDescriptorProto{ { Name: proto.String("string"), - Label: protodescriptor.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: protodescriptor.FieldDescriptorProto_TYPE_STRING.Enum(), + Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), Number: proto.Int32(1), }, }, } - respdesc := &protodescriptor.DescriptorProto{ + respdesc := &descriptorpb.DescriptorProto{ Name: proto.String("EmptyMessage"), } - meth := &protodescriptor.MethodDescriptorProto{ + meth := &descriptorpb.MethodDescriptorProto{ Name: proto.String("Example"), InputType: proto.String("ExampleMessage"), OutputType: proto.String("EmptyMessage"), ClientStreaming: proto.Bool(false), ServerStreaming: proto.Bool(false), } - svc := &protodescriptor.ServiceDescriptorProto{ + svc := &descriptorpb.ServiceDescriptorProto{ Name: proto.String("ExampleService"), - Method: []*protodescriptor.MethodDescriptorProto{meth}, + Method: []*descriptorpb.MethodDescriptorProto{meth}, } req := &descriptor.Message{ @@ -1570,12 +1610,12 @@ func TestApplyTemplateRequestWithUnusedReferences(t *testing.T) { FieldDescriptorProto: req.GetField()[0], } file := descriptor.File{ - FileDescriptorProto: &protodescriptor.FileDescriptorProto{ - SourceCodeInfo: &protodescriptor.SourceCodeInfo{}, + FileDescriptorProto: &descriptorpb.FileDescriptorProto{ + SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, Name: proto.String("example.proto"), Package: proto.String("example"), - MessageType: []*protodescriptor.DescriptorProto{reqdesc, respdesc}, - Service: []*protodescriptor.ServiceDescriptorProto{svc}, + MessageType: []*descriptorpb.DescriptorProto{reqdesc, respdesc}, + Service: []*descriptorpb.ServiceDescriptorProto{svc}, }, GoPkg: descriptor.GoPackage{ Path: "example.com/path/to/example/example.pb", @@ -1634,15 +1674,19 @@ func TestApplyTemplateRequestWithUnusedReferences(t *testing.T) { } reg := descriptor.NewRegistry() - reg.Load(&plugin.CodeGeneratorRequest{ProtoFile: []*protodescriptor.FileDescriptorProto{file.FileDescriptorProto}}) + if err := AddErrorDefs(reg); err != nil { + t.Errorf("AddErrorDefs(%#v) failed with %v; want success", reg, err) + return + } + reg.Load(&pluginpb.CodeGeneratorRequest{ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto}}) result, err := applyTemplate(param{File: crossLinkFixture(&file), reg: reg}) if err != nil { t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err) return } - // Only EmptyMessage must be present, not ExampleMessage - if want, got, name := 1, len(result.Definitions), "len(Definitions)"; !reflect.DeepEqual(got, want) { + // Only EmptyMessage must be present, not ExampleMessage (plus error status) + if want, got, name := 3, len(result.Definitions), "len(Definitions)"; !reflect.DeepEqual(got, want) { t.Errorf("applyTemplate(%#v).%s = %d want to be %d", file, name, got, want) } @@ -1657,7 +1701,7 @@ func generateFieldsForJSONReservedName() []*descriptor.Field { fields := make([]*descriptor.Field, 0) fieldName := string("json_name") fieldJSONName := string("jsonNAME") - fieldDescriptor := protodescriptor.FieldDescriptorProto{Name: &fieldName, JsonName: &fieldJSONName} + fieldDescriptor := descriptorpb.FieldDescriptorProto{Name: &fieldName, JsonName: &fieldJSONName} field := &descriptor.Field{FieldDescriptorProto: &fieldDescriptor} return append(fields, field) } @@ -1670,11 +1714,11 @@ func generateMsgsForJSONReservedName() []*descriptor.Message { fieldJSONName := "fieldAbc" messageName1 := "message1" messageType := "pkg.a.NewType" - pfd := protodescriptor.FieldDescriptorProto{Name: &fieldName, JsonName: &fieldJSONName, TypeName: &messageType} + pfd := descriptorpb.FieldDescriptorProto{Name: &fieldName, JsonName: &fieldJSONName, TypeName: &messageType} result = append(result, &descriptor.Message{ - DescriptorProto: &protodescriptor.DescriptorProto{ - Name: &messageName1, Field: []*protodescriptor.FieldDescriptorProto{&pfd}, + DescriptorProto: &descriptorpb.DescriptorProto{ + Name: &messageName1, Field: []*descriptorpb.FieldDescriptorProto{&pfd}, }, }) // The second message, its name is NewName, its type is string @@ -1684,10 +1728,10 @@ func generateMsgsForJSONReservedName() []*descriptor.Message { messageName := "NewType" field := "field_newName" fieldJSONName2 := "RESERVEDJSONNAME" - pfd2 := protodescriptor.FieldDescriptorProto{Name: &field, JsonName: &fieldJSONName2} + pfd2 := descriptorpb.FieldDescriptorProto{Name: &field, JsonName: &fieldJSONName2} result = append(result, &descriptor.Message{ - DescriptorProto: &protodescriptor.DescriptorProto{ - Name: &messageName, Field: []*protodescriptor.FieldDescriptorProto{&pfd2}, + DescriptorProto: &descriptorpb.DescriptorProto{ + Name: &messageName, Field: []*descriptorpb.FieldDescriptorProto{&pfd2}, }, }) return result @@ -1715,9 +1759,9 @@ func TestTemplateWithJsonCamelCase(t *testing.T) { reg := descriptor.NewRegistry() reg.SetUseJSONNamesForFields(true) for _, data := range tests { - actual := templateToSwaggerPath(data.input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName()) + actual := templateToOpenAPIPath(data.input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName()) if data.expected != actual { - t.Errorf("Expected templateToSwaggerPath(%v) = %v, actual: %v", data.input, data.expected, actual) + t.Errorf("Expected templateToOpenAPIPath(%v) = %v, actual: %v", data.input, data.expected, actual) } } } @@ -1743,14 +1787,14 @@ func TestTemplateWithoutJsonCamelCase(t *testing.T) { reg := descriptor.NewRegistry() reg.SetUseJSONNamesForFields(false) for _, data := range tests { - actual := templateToSwaggerPath(data.input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName()) + actual := templateToOpenAPIPath(data.input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName()) if data.expected != actual { - t.Errorf("Expected templateToSwaggerPath(%v) = %v, actual: %v", data.input, data.expected, actual) + t.Errorf("Expected templateToOpenAPIPath(%v) = %v, actual: %v", data.input, data.expected, actual) } } } -func TestTemplateToSwaggerPath(t *testing.T) { +func TestTemplateToOpenAPIPath(t *testing.T) { var tests = []struct { input string expected string @@ -1775,21 +1819,21 @@ func TestTemplateToSwaggerPath(t *testing.T) { reg := descriptor.NewRegistry() reg.SetUseJSONNamesForFields(false) for _, data := range tests { - actual := templateToSwaggerPath(data.input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName()) + actual := templateToOpenAPIPath(data.input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName()) if data.expected != actual { - t.Errorf("Expected templateToSwaggerPath(%v) = %v, actual: %v", data.input, data.expected, actual) + t.Errorf("Expected templateToOpenAPIPath(%v) = %v, actual: %v", data.input, data.expected, actual) } } reg.SetUseJSONNamesForFields(true) for _, data := range tests { - actual := templateToSwaggerPath(data.input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName()) + actual := templateToOpenAPIPath(data.input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName()) if data.expected != actual { - t.Errorf("Expected templateToSwaggerPath(%v) = %v, actual: %v", data.input, data.expected, actual) + t.Errorf("Expected templateToOpenAPIPath(%v) = %v, actual: %v", data.input, data.expected, actual) } } } -func BenchmarkTemplateToSwaggerPath(b *testing.B) { +func BenchmarkTemplateToOpenAPIPath(b *testing.B) { const input = "/{user.name=prefix1/*/prefix2/*}:customMethod" b.Run("with JSON names", func(b *testing.B) { @@ -1797,7 +1841,7 @@ func BenchmarkTemplateToSwaggerPath(b *testing.B) { reg.SetUseJSONNamesForFields(false) for i := 0; i < b.N; i++ { - _ = templateToSwaggerPath(input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName()) + _ = templateToOpenAPIPath(input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName()) } }) @@ -1806,17 +1850,17 @@ func BenchmarkTemplateToSwaggerPath(b *testing.B) { reg.SetUseJSONNamesForFields(true) for i := 0; i < b.N; i++ { - _ = templateToSwaggerPath(input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName()) + _ = templateToOpenAPIPath(input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName()) } }) } -func TestResolveFullyQualifiedNameToSwaggerName(t *testing.T) { +func TestResolveFullyQualifiedNameToOpenAPIName(t *testing.T) { var tests = []struct { input string output string listOfFQMNs []string - useFQNForSwaggerName bool + useFQNForOpenAPIName bool }{ { ".a.b.C", @@ -1858,16 +1902,16 @@ func TestResolveFullyQualifiedNameToSwaggerName(t *testing.T) { } for _, data := range tests { - names := resolveFullyQualifiedNameToSwaggerNames(data.listOfFQMNs, data.useFQNForSwaggerName) + names := resolveFullyQualifiedNameToOpenAPINames(data.listOfFQMNs, data.useFQNForOpenAPIName) output := names[data.input] if output != data.output { - t.Errorf("Expected fullyQualifiedNameToSwaggerName(%v) to be %s but got %s", + t.Errorf("Expected fullyQualifiedNameToOpenAPIName(%v) to be %s but got %s", data.input, data.output, output) } } } -func TestFQMNtoSwaggerName(t *testing.T) { +func TestFQMNtoOpenAPIName(t *testing.T) { var tests = []struct { input string expected string @@ -1882,16 +1926,16 @@ func TestFQMNtoSwaggerName(t *testing.T) { reg := descriptor.NewRegistry() reg.SetUseJSONNamesForFields(false) for _, data := range tests { - actual := templateToSwaggerPath(data.input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName()) + actual := templateToOpenAPIPath(data.input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName()) if data.expected != actual { - t.Errorf("Expected templateToSwaggerPath(%v) = %v, actual: %v", data.input, data.expected, actual) + t.Errorf("Expected templateToOpenAPIPath(%v) = %v, actual: %v", data.input, data.expected, actual) } } reg.SetUseJSONNamesForFields(true) for _, data := range tests { - actual := templateToSwaggerPath(data.input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName()) + actual := templateToOpenAPIPath(data.input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName()) if data.expected != actual { - t.Errorf("Expected templateToSwaggerPath(%v) = %v, actual: %v", data.input, data.expected, actual) + t.Errorf("Expected templateToOpenAPIPath(%v) = %v, actual: %v", data.input, data.expected, actual) } } } @@ -1906,9 +1950,9 @@ func TestSchemaOfField(t *testing.T) { tests := []test{ { field: &descriptor.Field{ - FieldDescriptorProto: &protodescriptor.FieldDescriptorProto{ + FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ Name: proto.String("primitive_field"), - Type: protodescriptor.FieldDescriptorProto_TYPE_STRING.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), }, }, refs: make(refMap), @@ -1918,26 +1962,26 @@ func TestSchemaOfField(t *testing.T) { }, { field: &descriptor.Field{ - FieldDescriptorProto: &protodescriptor.FieldDescriptorProto{ + FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ Name: proto.String("repeated_primitive_field"), - Type: protodescriptor.FieldDescriptorProto_TYPE_STRING.Enum(), - Label: protodescriptor.FieldDescriptorProto_LABEL_REPEATED.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), + Label: descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(), }, }, refs: make(refMap), expected: schemaCore{ Type: "array", - Items: &swaggerItemsObject{ + Items: &openapiItemsObject{ Type: "string", }, }, }, { field: &descriptor.Field{ - FieldDescriptorProto: &protodescriptor.FieldDescriptorProto{ + FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ Name: proto.String("wrapped_field"), TypeName: proto.String(".google.protobuf.StringValue"), - Type: protodescriptor.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), }, }, refs: make(refMap), @@ -1947,27 +1991,27 @@ func TestSchemaOfField(t *testing.T) { }, { field: &descriptor.Field{ - FieldDescriptorProto: &protodescriptor.FieldDescriptorProto{ + FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ Name: proto.String("repeated_wrapped_field"), TypeName: proto.String(".google.protobuf.StringValue"), - Type: protodescriptor.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - Label: protodescriptor.FieldDescriptorProto_LABEL_REPEATED.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + Label: descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(), }, }, refs: make(refMap), expected: schemaCore{ Type: "array", - Items: &swaggerItemsObject{ + Items: &openapiItemsObject{ Type: "string", }, }, }, { field: &descriptor.Field{ - FieldDescriptorProto: &protodescriptor.FieldDescriptorProto{ + FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ Name: proto.String("wrapped_field"), TypeName: proto.String(".google.protobuf.BytesValue"), - Type: protodescriptor.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), }, }, refs: make(refMap), @@ -1978,10 +2022,10 @@ func TestSchemaOfField(t *testing.T) { }, { field: &descriptor.Field{ - FieldDescriptorProto: &protodescriptor.FieldDescriptorProto{ + FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ Name: proto.String("wrapped_field"), TypeName: proto.String(".google.protobuf.Int32Value"), - Type: protodescriptor.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), }, }, refs: make(refMap), @@ -1992,10 +2036,10 @@ func TestSchemaOfField(t *testing.T) { }, { field: &descriptor.Field{ - FieldDescriptorProto: &protodescriptor.FieldDescriptorProto{ + FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ Name: proto.String("wrapped_field"), TypeName: proto.String(".google.protobuf.UInt32Value"), - Type: protodescriptor.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), }, }, refs: make(refMap), @@ -2006,10 +2050,10 @@ func TestSchemaOfField(t *testing.T) { }, { field: &descriptor.Field{ - FieldDescriptorProto: &protodescriptor.FieldDescriptorProto{ + FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ Name: proto.String("wrapped_field"), TypeName: proto.String(".google.protobuf.Int64Value"), - Type: protodescriptor.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), }, }, refs: make(refMap), @@ -2020,10 +2064,10 @@ func TestSchemaOfField(t *testing.T) { }, { field: &descriptor.Field{ - FieldDescriptorProto: &protodescriptor.FieldDescriptorProto{ + FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ Name: proto.String("wrapped_field"), TypeName: proto.String(".google.protobuf.UInt64Value"), - Type: protodescriptor.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), }, }, refs: make(refMap), @@ -2034,10 +2078,10 @@ func TestSchemaOfField(t *testing.T) { }, { field: &descriptor.Field{ - FieldDescriptorProto: &protodescriptor.FieldDescriptorProto{ + FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ Name: proto.String("wrapped_field"), TypeName: proto.String(".google.protobuf.FloatValue"), - Type: protodescriptor.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), }, }, refs: make(refMap), @@ -2048,10 +2092,10 @@ func TestSchemaOfField(t *testing.T) { }, { field: &descriptor.Field{ - FieldDescriptorProto: &protodescriptor.FieldDescriptorProto{ + FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ Name: proto.String("wrapped_field"), TypeName: proto.String(".google.protobuf.DoubleValue"), - Type: protodescriptor.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), }, }, refs: make(refMap), @@ -2062,10 +2106,10 @@ func TestSchemaOfField(t *testing.T) { }, { field: &descriptor.Field{ - FieldDescriptorProto: &protodescriptor.FieldDescriptorProto{ + FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ Name: proto.String("wrapped_field"), TypeName: proto.String(".google.protobuf.BoolValue"), - Type: protodescriptor.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), }, }, refs: make(refMap), @@ -2075,10 +2119,10 @@ func TestSchemaOfField(t *testing.T) { }, { field: &descriptor.Field{ - FieldDescriptorProto: &protodescriptor.FieldDescriptorProto{ + FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ Name: proto.String("wrapped_field"), TypeName: proto.String(".google.protobuf.Struct"), - Type: protodescriptor.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), }, }, refs: make(refMap), @@ -2088,10 +2132,10 @@ func TestSchemaOfField(t *testing.T) { }, { field: &descriptor.Field{ - FieldDescriptorProto: &protodescriptor.FieldDescriptorProto{ + FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ Name: proto.String("wrapped_field"), TypeName: proto.String(".google.protobuf.Value"), - Type: protodescriptor.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), }, }, refs: make(refMap), @@ -2101,26 +2145,26 @@ func TestSchemaOfField(t *testing.T) { }, { field: &descriptor.Field{ - FieldDescriptorProto: &protodescriptor.FieldDescriptorProto{ + FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ Name: proto.String("wrapped_field"), TypeName: proto.String(".google.protobuf.ListValue"), - Type: protodescriptor.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), }, }, refs: make(refMap), expected: schemaCore{ Type: "array", - Items: (*swaggerItemsObject)(&schemaCore{ + Items: (*openapiItemsObject)(&schemaCore{ Type: "object", }), }, }, { field: &descriptor.Field{ - FieldDescriptorProto: &protodescriptor.FieldDescriptorProto{ + FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ Name: proto.String("wrapped_field"), TypeName: proto.String(".google.protobuf.NullValue"), - Type: protodescriptor.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), }, }, refs: make(refMap), @@ -2130,10 +2174,10 @@ func TestSchemaOfField(t *testing.T) { }, { field: &descriptor.Field{ - FieldDescriptorProto: &protodescriptor.FieldDescriptorProto{ + FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ Name: proto.String("message_field"), TypeName: proto.String(".example.Message"), - Type: protodescriptor.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), }, }, refs: refMap{".example.Message": struct{}{}}, @@ -2144,30 +2188,30 @@ func TestSchemaOfField(t *testing.T) { } reg := descriptor.NewRegistry() - reg.Load(&plugin.CodeGeneratorRequest{ - ProtoFile: []*protodescriptor.FileDescriptorProto{ + reg.Load(&pluginpb.CodeGeneratorRequest{ + ProtoFile: []*descriptorpb.FileDescriptorProto{ { - SourceCodeInfo: &protodescriptor.SourceCodeInfo{}, + SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, Name: proto.String("example.proto"), Package: proto.String("example"), Dependency: []string{}, - MessageType: []*protodescriptor.DescriptorProto{ + MessageType: []*descriptorpb.DescriptorProto{ { Name: proto.String("Message"), - Field: []*protodescriptor.FieldDescriptorProto{ + Field: []*descriptorpb.FieldDescriptorProto{ { Name: proto.String("value"), - Type: protodescriptor.FieldDescriptorProto_TYPE_STRING.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), }, }, }, }, - EnumType: []*protodescriptor.EnumDescriptorProto{ + EnumType: []*descriptorpb.EnumDescriptorProto{ { Name: proto.String("Message"), }, }, - Service: []*protodescriptor.ServiceDescriptorProto{}, + Service: []*descriptorpb.ServiceDescriptorProto{}, }, }, }) @@ -2175,7 +2219,7 @@ func TestSchemaOfField(t *testing.T) { for _, test := range tests { refs := make(refMap) actual := schemaOfField(test.field, reg, refs) - expectedSchemaObject := swaggerSchemaObject{schemaCore: test.expected} + expectedSchemaObject := openapiSchemaObject{schemaCore: test.expected} if e, a := expectedSchemaObject, actual; !reflect.DeepEqual(a, e) { t.Errorf("Expected schemaOfField(%v) = %v, actual: %v", test.field, e, a) } @@ -2189,35 +2233,35 @@ func TestRenderMessagesAsDefinition(t *testing.T) { tests := []struct { descr string - msgDescs []*protodescriptor.DescriptorProto - schema map[string]swagger_options.Schema // per-message schema to add - defs swaggerDefinitionsObject + msgDescs []*descriptorpb.DescriptorProto + schema map[string]openapi_options.Schema // per-message schema to add + defs openapiDefinitionsObject }{ { - descr: "no swagger options", - msgDescs: []*protodescriptor.DescriptorProto{ - &protodescriptor.DescriptorProto{Name: proto.String("Message")}, + descr: "no OpenAPI options", + msgDescs: []*descriptorpb.DescriptorProto{ + {Name: proto.String("Message")}, }, - schema: map[string]swagger_options.Schema{}, - defs: map[string]swaggerSchemaObject{ - "Message": swaggerSchemaObject{schemaCore: schemaCore{Type: "object"}}, + schema: map[string]openapi_options.Schema{}, + defs: map[string]openapiSchemaObject{ + "Message": {schemaCore: schemaCore{Type: "object"}}, }, }, { descr: "example option", - msgDescs: []*protodescriptor.DescriptorProto{ - &protodescriptor.DescriptorProto{Name: proto.String("Message")}, + msgDescs: []*descriptorpb.DescriptorProto{ + {Name: proto.String("Message")}, }, - schema: map[string]swagger_options.Schema{ - "Message": swagger_options.Schema{ - Example: &any.Any{ + schema: map[string]openapi_options.Schema{ + "Message": { + Example: &anypb.Any{ TypeUrl: "this_isnt_used", Value: []byte(`{"foo":"bar"}`), }, }, }, - defs: map[string]swaggerSchemaObject{ - "Message": swaggerSchemaObject{schemaCore: schemaCore{ + defs: map[string]openapiSchemaObject{ + "Message": {schemaCore: schemaCore{ Type: "object", Example: json.RawMessage(`{"foo":"bar"}`), }}, @@ -2225,18 +2269,18 @@ func TestRenderMessagesAsDefinition(t *testing.T) { }, { descr: "example option with something non-json", - msgDescs: []*protodescriptor.DescriptorProto{ - &protodescriptor.DescriptorProto{Name: proto.String("Message")}, + msgDescs: []*descriptorpb.DescriptorProto{ + {Name: proto.String("Message")}, }, - schema: map[string]swagger_options.Schema{ - "Message": swagger_options.Schema{ - Example: &any.Any{ + schema: map[string]openapi_options.Schema{ + "Message": { + Example: &anypb.Any{ Value: []byte(`XXXX anything goes XXXX`), }, }, }, - defs: map[string]swaggerSchemaObject{ - "Message": swaggerSchemaObject{schemaCore: schemaCore{ + defs: map[string]openapiSchemaObject{ + "Message": {schemaCore: schemaCore{ Type: "object", Example: json.RawMessage(`XXXX anything goes XXXX`), }}, @@ -2244,23 +2288,23 @@ func TestRenderMessagesAsDefinition(t *testing.T) { }, { descr: "external docs option", - msgDescs: []*protodescriptor.DescriptorProto{ - &protodescriptor.DescriptorProto{Name: proto.String("Message")}, + msgDescs: []*descriptorpb.DescriptorProto{ + {Name: proto.String("Message")}, }, - schema: map[string]swagger_options.Schema{ - "Message": swagger_options.Schema{ - ExternalDocs: &swagger_options.ExternalDocumentation{ + schema: map[string]openapi_options.Schema{ + "Message": { + ExternalDocs: &openapi_options.ExternalDocumentation{ Description: "glorious docs", Url: "https://nada", }, }, }, - defs: map[string]swaggerSchemaObject{ - "Message": swaggerSchemaObject{ + defs: map[string]openapiSchemaObject{ + "Message": { schemaCore: schemaCore{ Type: "object", }, - ExternalDocs: &swaggerExternalDocumentationObject{ + ExternalDocs: &openapiExternalDocumentationObject{ Description: "glorious docs", URL: "https://nada", }, @@ -2269,12 +2313,12 @@ func TestRenderMessagesAsDefinition(t *testing.T) { }, { descr: "JSONSchema options", - msgDescs: []*protodescriptor.DescriptorProto{ - &protodescriptor.DescriptorProto{Name: proto.String("Message")}, + msgDescs: []*descriptorpb.DescriptorProto{ + {Name: proto.String("Message")}, }, - schema: map[string]swagger_options.Schema{ - "Message": swagger_options.Schema{ - JsonSchema: &swagger_options.JSONSchema{ + schema: map[string]openapi_options.Schema{ + "Message": { + JsonSchema: &openapi_options.JSONSchema{ Title: "title", Description: "desc", MultipleOf: 100, @@ -2295,8 +2339,8 @@ func TestRenderMessagesAsDefinition(t *testing.T) { }, }, }, - defs: map[string]swaggerSchemaObject{ - "Message": swaggerSchemaObject{ + defs: map[string]openapiSchemaObject{ + "Message": { schemaCore: schemaCore{ Type: "object", }, @@ -2327,25 +2371,25 @@ func TestRenderMessagesAsDefinition(t *testing.T) { msgs := []*descriptor.Message{} for _, msgdesc := range test.msgDescs { - msgdesc.Options = &protodescriptor.MessageOptions{} + msgdesc.Options = &descriptorpb.MessageOptions{} msgs = append(msgs, &descriptor.Message{DescriptorProto: msgdesc}) } reg := descriptor.NewRegistry() file := descriptor.File{ - FileDescriptorProto: &protodescriptor.FileDescriptorProto{ - SourceCodeInfo: &protodescriptor.SourceCodeInfo{}, + FileDescriptorProto: &descriptorpb.FileDescriptorProto{ + SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, Name: proto.String("example.proto"), Package: proto.String("example"), Dependency: []string{}, MessageType: test.msgDescs, - EnumType: []*protodescriptor.EnumDescriptorProto{}, - Service: []*protodescriptor.ServiceDescriptorProto{}, + EnumType: []*descriptorpb.EnumDescriptorProto{}, + Service: []*descriptorpb.ServiceDescriptorProto{}, }, Messages: msgs, } - reg.Load(&plugin.CodeGeneratorRequest{ - ProtoFile: []*protodescriptor.FileDescriptorProto{file.FileDescriptorProto}, + reg.Load(&pluginpb.CodeGeneratorRequest{ + ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto}, }) msgMap := map[string]*descriptor.Message{} @@ -2358,15 +2402,12 @@ func TestRenderMessagesAsDefinition(t *testing.T) { msgMap[msg.FQMN()] = msg if schema, ok := test.schema[name]; ok { - err := proto.SetExtension(d.Options, swagger_options.E_Openapiv2Schema, &schema) - if err != nil { - t.Fatalf("SetExtension(%s, ...) returned error: %v", msg, err) - } + proto.SetExtension(d.Options, openapi_options.E_Openapiv2Schema, &schema) } } refs := make(refMap) - actual := make(swaggerDefinitionsObject) + actual := make(openapiDefinitionsObject) renderMessagesAsDefinition(msgMap, actual, reg, refs) if !reflect.DeepEqual(actual, test.defs) { @@ -2376,27 +2417,27 @@ func TestRenderMessagesAsDefinition(t *testing.T) { } } -func TestUpdateSwaggerDataFromComments(t *testing.T) { +func TestUpdateOpenAPIDataFromComments(t *testing.T) { tests := []struct { descr string - swaggerObject interface{} + openapiSwaggerObject interface{} comments string expectedError error - expectedSwaggerObject interface{} + expectedOpenAPIObject interface{} useGoTemplate bool }{ { descr: "empty comments", - swaggerObject: nil, - expectedSwaggerObject: nil, + openapiSwaggerObject: nil, + expectedOpenAPIObject: nil, comments: "", expectedError: nil, }, { - descr: "set field to read only", - swaggerObject: &swaggerSchemaObject{}, - expectedSwaggerObject: &swaggerSchemaObject{ + descr: "set field to read only", + openapiSwaggerObject: &openapiSchemaObject{}, + expectedOpenAPIObject: &openapiSchemaObject{ ReadOnly: true, Description: "... Output only. ...", }, @@ -2404,18 +2445,18 @@ func TestUpdateSwaggerDataFromComments(t *testing.T) { expectedError: nil, }, { - descr: "set title", - swaggerObject: &swaggerSchemaObject{}, - expectedSwaggerObject: &swaggerSchemaObject{ + descr: "set title", + openapiSwaggerObject: &openapiSchemaObject{}, + expectedOpenAPIObject: &openapiSchemaObject{ Title: "Comment with no trailing dot", }, comments: "Comment with no trailing dot", expectedError: nil, }, { - descr: "set description", - swaggerObject: &swaggerSchemaObject{}, - expectedSwaggerObject: &swaggerSchemaObject{ + descr: "set description", + openapiSwaggerObject: &openapiSchemaObject{}, + expectedOpenAPIObject: &openapiSchemaObject{ Description: "Comment with trailing dot.", }, comments: "Comment with trailing dot.", @@ -2423,11 +2464,11 @@ func TestUpdateSwaggerDataFromComments(t *testing.T) { }, { descr: "use info object", - swaggerObject: &swaggerObject{ - Info: swaggerInfoObject{}, + openapiSwaggerObject: &openapiSwaggerObject{ + Info: openapiInfoObject{}, }, - expectedSwaggerObject: &swaggerObject{ - Info: swaggerInfoObject{ + expectedOpenAPIObject: &openapiSwaggerObject{ + Info: openapiInfoObject{ Description: "Comment with trailing dot.", }, }, @@ -2435,9 +2476,9 @@ func TestUpdateSwaggerDataFromComments(t *testing.T) { expectedError: nil, }, { - descr: "multi line comment with title", - swaggerObject: &swaggerSchemaObject{}, - expectedSwaggerObject: &swaggerSchemaObject{ + descr: "multi line comment with title", + openapiSwaggerObject: &openapiSchemaObject{}, + expectedOpenAPIObject: &openapiSchemaObject{ Title: "First line", Description: "Second line", }, @@ -2445,18 +2486,18 @@ func TestUpdateSwaggerDataFromComments(t *testing.T) { expectedError: nil, }, { - descr: "multi line comment no title", - swaggerObject: &swaggerSchemaObject{}, - expectedSwaggerObject: &swaggerSchemaObject{ + descr: "multi line comment no title", + openapiSwaggerObject: &openapiSchemaObject{}, + expectedOpenAPIObject: &openapiSchemaObject{ Description: "First line.\n\nSecond line", }, comments: "First line.\n\nSecond line", expectedError: nil, }, { - descr: "multi line comment with summary with dot", - swaggerObject: &swaggerOperationObject{}, - expectedSwaggerObject: &swaggerOperationObject{ + descr: "multi line comment with summary with dot", + openapiSwaggerObject: &openapiOperationObject{}, + expectedOpenAPIObject: &openapiOperationObject{ Summary: "First line.", Description: "Second line", }, @@ -2464,9 +2505,9 @@ func TestUpdateSwaggerDataFromComments(t *testing.T) { expectedError: nil, }, { - descr: "multi line comment with summary no dot", - swaggerObject: &swaggerOperationObject{}, - expectedSwaggerObject: &swaggerOperationObject{ + descr: "multi line comment with summary no dot", + openapiSwaggerObject: &openapiOperationObject{}, + expectedOpenAPIObject: &openapiOperationObject{ Summary: "First line", Description: "Second line", }, @@ -2475,15 +2516,15 @@ func TestUpdateSwaggerDataFromComments(t *testing.T) { }, { descr: "multi line comment with summary no dot", - swaggerObject: &schemaCore{}, - expectedSwaggerObject: &schemaCore{}, + openapiSwaggerObject: &schemaCore{}, + expectedOpenAPIObject: &schemaCore{}, comments: "Any comment", expectedError: errors.New("no description nor summary property"), }, { - descr: "without use_go_template", - swaggerObject: &swaggerSchemaObject{}, - expectedSwaggerObject: &swaggerSchemaObject{ + descr: "without use_go_template", + openapiSwaggerObject: &openapiSchemaObject{}, + expectedOpenAPIObject: &openapiSchemaObject{ Title: "First line", Description: "{{import \"documentation.md\"}}", }, @@ -2491,9 +2532,9 @@ func TestUpdateSwaggerDataFromComments(t *testing.T) { expectedError: nil, }, { - descr: "error with use_go_template", - swaggerObject: &swaggerSchemaObject{}, - expectedSwaggerObject: &swaggerSchemaObject{ + descr: "error with use_go_template", + openapiSwaggerObject: &openapiSchemaObject{}, + expectedOpenAPIObject: &openapiSchemaObject{ Title: "First line", Description: "open noneexistingfile.txt: no such file or directory", }, @@ -2502,9 +2543,9 @@ func TestUpdateSwaggerDataFromComments(t *testing.T) { useGoTemplate: true, }, { - descr: "template with use_go_template", - swaggerObject: &swaggerSchemaObject{}, - expectedSwaggerObject: &swaggerSchemaObject{ + descr: "template with use_go_template", + openapiSwaggerObject: &openapiSchemaObject{}, + expectedOpenAPIObject: &openapiSchemaObject{ Title: "Template", Description: `Description "which means nothing"`, }, @@ -2520,20 +2561,20 @@ func TestUpdateSwaggerDataFromComments(t *testing.T) { if test.useGoTemplate { reg.SetUseGoTemplate(true) } - err := updateSwaggerDataFromComments(reg, test.swaggerObject, nil, test.comments, false) + err := updateOpenAPIDataFromComments(reg, test.openapiSwaggerObject, nil, test.comments, false) if test.expectedError == nil { if err != nil { t.Errorf("unexpected error '%v'", err) } - if !reflect.DeepEqual(test.swaggerObject, test.expectedSwaggerObject) { - t.Errorf("swaggerObject was not updated corretly, expected '%+v', got '%+v'", test.expectedSwaggerObject, test.swaggerObject) + if !reflect.DeepEqual(test.openapiSwaggerObject, test.expectedOpenAPIObject) { + t.Errorf("openapiSwaggerObject was not updated correctly, expected '%+v', got '%+v'", test.expectedOpenAPIObject, test.openapiSwaggerObject) } } else { if err == nil { t.Error("expected update error not returned") } - if !reflect.DeepEqual(test.swaggerObject, test.expectedSwaggerObject) { - t.Errorf("swaggerObject was not updated corretly, expected '%+v', got '%+v'", test.expectedSwaggerObject, test.swaggerObject) + if !reflect.DeepEqual(test.openapiSwaggerObject, test.expectedOpenAPIObject) { + t.Errorf("openapiSwaggerObject was not updated correctly, expected '%+v', got '%+v'", test.expectedOpenAPIObject, test.openapiSwaggerObject) } if err.Error() != test.expectedError.Error() { t.Errorf("expected error malformed, expected %q, got %q", test.expectedError.Error(), err.Error()) @@ -2546,35 +2587,35 @@ func TestUpdateSwaggerDataFromComments(t *testing.T) { func TestMessageOptionsWithGoTemplate(t *testing.T) { tests := []struct { descr string - msgDescs []*protodescriptor.DescriptorProto - schema map[string]swagger_options.Schema // per-message schema to add - defs swaggerDefinitionsObject + msgDescs []*descriptorpb.DescriptorProto + schema map[string]openapi_options.Schema // per-message schema to add + defs openapiDefinitionsObject useGoTemplate bool }{ { descr: "external docs option", - msgDescs: []*protodescriptor.DescriptorProto{ - &protodescriptor.DescriptorProto{Name: proto.String("Message")}, + msgDescs: []*descriptorpb.DescriptorProto{ + {Name: proto.String("Message")}, }, - schema: map[string]swagger_options.Schema{ - "Message": swagger_options.Schema{ - JsonSchema: &swagger_options.JSONSchema{ + schema: map[string]openapi_options.Schema{ + "Message": { + JsonSchema: &openapi_options.JSONSchema{ Title: "{{.Name}}", Description: "Description {{with \"which means nothing\"}}{{printf \"%q\" .}}{{end}}", }, - ExternalDocs: &swagger_options.ExternalDocumentation{ + ExternalDocs: &openapi_options.ExternalDocumentation{ Description: "Description {{with \"which means nothing\"}}{{printf \"%q\" .}}{{end}}", }, }, }, - defs: map[string]swaggerSchemaObject{ - "Message": swaggerSchemaObject{ + defs: map[string]openapiSchemaObject{ + "Message": { schemaCore: schemaCore{ Type: "object", }, Title: "Message", Description: `Description "which means nothing"`, - ExternalDocs: &swaggerExternalDocumentationObject{ + ExternalDocs: &openapiExternalDocumentationObject{ Description: `Description "which means nothing"`, }, }, @@ -2583,28 +2624,28 @@ func TestMessageOptionsWithGoTemplate(t *testing.T) { }, { descr: "external docs option", - msgDescs: []*protodescriptor.DescriptorProto{ - &protodescriptor.DescriptorProto{Name: proto.String("Message")}, + msgDescs: []*descriptorpb.DescriptorProto{ + {Name: proto.String("Message")}, }, - schema: map[string]swagger_options.Schema{ - "Message": swagger_options.Schema{ - JsonSchema: &swagger_options.JSONSchema{ + schema: map[string]openapi_options.Schema{ + "Message": { + JsonSchema: &openapi_options.JSONSchema{ Title: "{{.Name}}", Description: "Description {{with \"which means nothing\"}}{{printf \"%q\" .}}{{end}}", }, - ExternalDocs: &swagger_options.ExternalDocumentation{ + ExternalDocs: &openapi_options.ExternalDocumentation{ Description: "Description {{with \"which means nothing\"}}{{printf \"%q\" .}}{{end}}", }, }, }, - defs: map[string]swaggerSchemaObject{ - "Message": swaggerSchemaObject{ + defs: map[string]openapiSchemaObject{ + "Message": { schemaCore: schemaCore{ Type: "object", }, Title: "{{.Name}}", Description: "Description {{with \"which means nothing\"}}{{printf \"%q\" .}}{{end}}", - ExternalDocs: &swaggerExternalDocumentationObject{ + ExternalDocs: &openapiExternalDocumentationObject{ Description: "Description {{with \"which means nothing\"}}{{printf \"%q\" .}}{{end}}", }, }, @@ -2618,26 +2659,26 @@ func TestMessageOptionsWithGoTemplate(t *testing.T) { msgs := []*descriptor.Message{} for _, msgdesc := range test.msgDescs { - msgdesc.Options = &protodescriptor.MessageOptions{} + msgdesc.Options = &descriptorpb.MessageOptions{} msgs = append(msgs, &descriptor.Message{DescriptorProto: msgdesc}) } reg := descriptor.NewRegistry() reg.SetUseGoTemplate(test.useGoTemplate) file := descriptor.File{ - FileDescriptorProto: &protodescriptor.FileDescriptorProto{ - SourceCodeInfo: &protodescriptor.SourceCodeInfo{}, + FileDescriptorProto: &descriptorpb.FileDescriptorProto{ + SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, Name: proto.String("example.proto"), Package: proto.String("example"), Dependency: []string{}, MessageType: test.msgDescs, - EnumType: []*protodescriptor.EnumDescriptorProto{}, - Service: []*protodescriptor.ServiceDescriptorProto{}, + EnumType: []*descriptorpb.EnumDescriptorProto{}, + Service: []*descriptorpb.ServiceDescriptorProto{}, }, Messages: msgs, } - reg.Load(&plugin.CodeGeneratorRequest{ - ProtoFile: []*protodescriptor.FileDescriptorProto{file.FileDescriptorProto}, + reg.Load(&pluginpb.CodeGeneratorRequest{ + ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto}, }) msgMap := map[string]*descriptor.Message{} @@ -2650,15 +2691,12 @@ func TestMessageOptionsWithGoTemplate(t *testing.T) { msgMap[msg.FQMN()] = msg if schema, ok := test.schema[name]; ok { - err := proto.SetExtension(d.Options, swagger_options.E_Openapiv2Schema, &schema) - if err != nil { - t.Fatalf("SetExtension(%s, ...) returned error: %v", msg, err) - } + proto.SetExtension(d.Options, openapi_options.E_Openapiv2Schema, &schema) } } refs := make(refMap) - actual := make(swaggerDefinitionsObject) + actual := make(openapiDefinitionsObject) renderMessagesAsDefinition(msgMap, actual, reg, refs) if !reflect.DeepEqual(actual, test.defs) { @@ -2669,18 +2707,18 @@ func TestMessageOptionsWithGoTemplate(t *testing.T) { } func TestTemplateWithoutErrorDefinition(t *testing.T) { - msgdesc := &protodescriptor.DescriptorProto{ + msgdesc := &descriptorpb.DescriptorProto{ Name: proto.String("ExampleMessage"), - Field: []*protodescriptor.FieldDescriptorProto{}, + Field: []*descriptorpb.FieldDescriptorProto{}, } - meth := &protodescriptor.MethodDescriptorProto{ + meth := &descriptorpb.MethodDescriptorProto{ Name: proto.String("Echo"), InputType: proto.String("ExampleMessage"), OutputType: proto.String("ExampleMessage"), } - svc := &protodescriptor.ServiceDescriptorProto{ + svc := &descriptorpb.ServiceDescriptorProto{ Name: proto.String("ExampleService"), - Method: []*protodescriptor.MethodDescriptorProto{meth}, + Method: []*descriptorpb.MethodDescriptorProto{meth}, } msg := &descriptor.Message{ @@ -2688,12 +2726,12 @@ func TestTemplateWithoutErrorDefinition(t *testing.T) { } file := descriptor.File{ - FileDescriptorProto: &protodescriptor.FileDescriptorProto{ - SourceCodeInfo: &protodescriptor.SourceCodeInfo{}, + FileDescriptorProto: &descriptorpb.FileDescriptorProto{ + SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, Name: proto.String("example.proto"), Package: proto.String("example"), - MessageType: []*protodescriptor.DescriptorProto{msgdesc, msgdesc}, - Service: []*protodescriptor.ServiceDescriptorProto{svc}, + MessageType: []*descriptorpb.DescriptorProto{msgdesc, msgdesc}, + Service: []*descriptorpb.ServiceDescriptorProto{svc}, }, GoPkg: descriptor.GoPackage{ Path: "example.com/path/to/example/example.pb", @@ -2727,7 +2765,7 @@ func TestTemplateWithoutErrorDefinition(t *testing.T) { }, } reg := descriptor.NewRegistry() - reg.Load(&plugin.CodeGeneratorRequest{ProtoFile: []*protodescriptor.FileDescriptorProto{file.FileDescriptorProto}}) + reg.Load(&pluginpb.CodeGeneratorRequest{ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto}}) result, err := applyTemplate(param{File: crossLinkFixture(&file), reg: reg}) if err != nil { t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err) diff --git a/gateway/protoc-gen-swagger/genswagger/types.go b/gateway/protoc-gen-openapiv2/internal/genopenapi/types.go similarity index 70% rename from gateway/protoc-gen-swagger/genswagger/types.go rename to gateway/protoc-gen-openapiv2/internal/genopenapi/types.go index 2201972..40e7d0f 100644 --- a/gateway/protoc-gen-swagger/genswagger/types.go +++ b/gateway/protoc-gen-openapiv2/internal/genopenapi/types.go @@ -1,12 +1,12 @@ -package genswagger +package genopenapi import ( "bytes" "encoding/json" "fmt" - // "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/descriptor" - "github.com/binchencoder/ease-gateway/gateway/protoc-gen-grpc-gateway/descriptor" + // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor" + "github.com/binchencoder/ease-gateway/gateway/internal/descriptor" options "github.com/binchencoder/ease-gateway/httpoptions" ) @@ -15,38 +15,34 @@ type param struct { reg *descriptor.Registry } -type binding struct { - *descriptor.Binding -} - // http://swagger.io/specification/#infoObject -type swaggerInfoObject struct { +type openapiInfoObject struct { Title string `json:"title"` Description string `json:"description,omitempty"` TermsOfService string `json:"termsOfService,omitempty"` Version string `json:"version"` - Contact *swaggerContactObject `json:"contact,omitempty"` - License *swaggerLicenseObject `json:"license,omitempty"` + Contact *openapiContactObject `json:"contact,omitempty"` + License *openapiLicenseObject `json:"license,omitempty"` extensions []extension } // http://swagger.io/specification/#contactObject -type swaggerContactObject struct { +type openapiContactObject struct { Name string `json:"name,omitempty"` URL string `json:"url,omitempty"` Email string `json:"email,omitempty"` } // http://swagger.io/specification/#licenseObject -type swaggerLicenseObject struct { +type openapiLicenseObject struct { Name string `json:"name,omitempty"` URL string `json:"url,omitempty"` } // http://swagger.io/specification/#externalDocumentationObject -type swaggerExternalDocumentationObject struct { +type openapiExternalDocumentationObject struct { Description string `json:"description,omitempty"` URL string `json:"url,omitempty"` } @@ -57,28 +53,28 @@ type extension struct { } // http://swagger.io/specification/#swaggerObject -type swaggerObject struct { +type openapiSwaggerObject struct { Swagger string `json:"swagger"` - Info swaggerInfoObject `json:"info"` + Info openapiInfoObject `json:"info"` Host string `json:"host,omitempty"` BasePath string `json:"basePath,omitempty"` Schemes []string `json:"schemes,omitempty"` Consumes []string `json:"consumes"` Produces []string `json:"produces"` - Paths swaggerPathsObject `json:"paths"` - Definitions swaggerDefinitionsObject `json:"definitions"` - SecurityDefinitions swaggerSecurityDefinitionsObject `json:"securityDefinitions,omitempty"` - Security []swaggerSecurityRequirementObject `json:"security,omitempty"` - ExternalDocs *swaggerExternalDocumentationObject `json:"externalDocs,omitempty"` + Paths openapiPathsObject `json:"paths"` + Definitions openapiDefinitionsObject `json:"definitions"` + SecurityDefinitions openapiSecurityDefinitionsObject `json:"securityDefinitions,omitempty"` + Security []openapiSecurityRequirementObject `json:"security,omitempty"` + ExternalDocs *openapiExternalDocumentationObject `json:"externalDocs,omitempty"` extensions []extension } // http://swagger.io/specification/#securityDefinitionsObject -type swaggerSecurityDefinitionsObject map[string]swaggerSecuritySchemeObject +type openapiSecurityDefinitionsObject map[string]openapiSecuritySchemeObject // http://swagger.io/specification/#securitySchemeObject -type swaggerSecuritySchemeObject struct { +type openapiSecuritySchemeObject struct { Type string `json:"type"` Description string `json:"description,omitempty"` Name string `json:"name,omitempty"` @@ -86,57 +82,57 @@ type swaggerSecuritySchemeObject struct { Flow string `json:"flow,omitempty"` AuthorizationURL string `json:"authorizationUrl,omitempty"` TokenURL string `json:"tokenUrl,omitempty"` - Scopes swaggerScopesObject `json:"scopes,omitempty"` + Scopes openapiScopesObject `json:"scopes,omitempty"` extensions []extension } // http://swagger.io/specification/#scopesObject -type swaggerScopesObject map[string]string +type openapiScopesObject map[string]string // http://swagger.io/specification/#securityRequirementObject -type swaggerSecurityRequirementObject map[string][]string +type openapiSecurityRequirementObject map[string][]string // http://swagger.io/specification/#pathsObject -type swaggerPathsObject map[string]swaggerPathItemObject +type openapiPathsObject map[string]openapiPathItemObject // http://swagger.io/specification/#pathItemObject -type swaggerPathItemObject struct { - Get *swaggerOperationObject `json:"get,omitempty"` - Delete *swaggerOperationObject `json:"delete,omitempty"` - Post *swaggerOperationObject `json:"post,omitempty"` - Put *swaggerOperationObject `json:"put,omitempty"` - Patch *swaggerOperationObject `json:"patch,omitempty"` +type openapiPathItemObject struct { + Get *openapiOperationObject `json:"get,omitempty"` + Delete *openapiOperationObject `json:"delete,omitempty"` + Post *openapiOperationObject `json:"post,omitempty"` + Put *openapiOperationObject `json:"put,omitempty"` + Patch *openapiOperationObject `json:"patch,omitempty"` } // http://swagger.io/specification/#operationObject -type swaggerOperationObject struct { +type openapiOperationObject struct { Summary string `json:"summary,omitempty"` Description string `json:"description,omitempty"` OperationID string `json:"operationId"` - Responses swaggerResponsesObject `json:"responses"` - Parameters swaggerParametersObject `json:"parameters,omitempty"` + Responses openapiResponsesObject `json:"responses"` + Parameters openapiParametersObject `json:"parameters,omitempty"` Tags []string `json:"tags,omitempty"` Deprecated bool `json:"deprecated,omitempty"` Produces []string `json:"produces,omitempty"` - Security *[]swaggerSecurityRequirementObject `json:"security,omitempty"` - ExternalDocs *swaggerExternalDocumentationObject `json:"externalDocs,omitempty"` + Security *[]openapiSecurityRequirementObject `json:"security,omitempty"` + ExternalDocs *openapiExternalDocumentationObject `json:"externalDocs,omitempty"` extensions []extension } -type swaggerParametersObject []swaggerParameterObject +type openapiParametersObject []openapiParameterObject // http://swagger.io/specification/#parameterObject -type swaggerParameterObject struct { +type openapiParameterObject struct { Name string `json:"name"` Description string `json:"description,omitempty"` In string `json:"in,omitempty"` Required bool `json:"required"` Type string `json:"type,omitempty"` Format string `json:"format,omitempty"` - Items *swaggerItemsObject `json:"items,omitempty"` + Items *openapiItemsObject `json:"items,omitempty"` Enum []string `json:"enum,omitempty"` CollectionFormat string `json:"collectionFormat,omitempty"` Default string `json:"default,omitempty"` @@ -144,7 +140,7 @@ type swaggerParameterObject struct { // Or you can explicitly refer to another type. If this is defined all // other fields should be empty - Schema *swaggerSchemaObject `json:"schema,omitempty"` + Schema *openapiSchemaObject `json:"schema,omitempty"` } // core part of schema, which is common to itemsObject and schemaObject. @@ -155,7 +151,7 @@ type schemaCore struct { Ref string `json:"$ref,omitempty"` Example json.RawMessage `json:"example,omitempty"` - Items *swaggerItemsObject `json:"items,omitempty"` + Items *openapiItemsObject `json:"items,omitempty"` // If the item is an enumeration include a list of all the *NAMES* of the // enum values. I'm not sure how well this will work but assuming all enums @@ -166,23 +162,23 @@ type schemaCore struct { } func (s *schemaCore) setRefFromFQN(ref string, reg *descriptor.Registry) error { - name, ok := fullyQualifiedNameToSwaggerName(ref, reg) + name, ok := fullyQualifiedNameToOpenAPIName(ref, reg) if !ok { - return fmt.Errorf("setRefFromFQN: can't resolve swagger name from '%v'", ref) + return fmt.Errorf("setRefFromFQN: can't resolve OpenAPI name from '%v'", ref) } s.Ref = fmt.Sprintf("#/definitions/%s", name) return nil } -type swaggerItemsObject schemaCore +type openapiItemsObject schemaCore // http://swagger.io/specification/#responsesObject -type swaggerResponsesObject map[string]swaggerResponseObject +type openapiResponsesObject map[string]openapiResponseObject // http://swagger.io/specification/#responseObject -type swaggerResponseObject struct { +type openapiResponseObject struct { Description string `json:"description"` - Schema swaggerSchemaObject `json:"schema"` + Schema openapiSchemaObject `json:"schema"` Examples map[string]interface{} `json:"examples,omitempty"` extensions []extension @@ -193,9 +189,9 @@ type keyVal struct { Value interface{} } -type swaggerSchemaObjectProperties []keyVal +type openapiSchemaObjectProperties []keyVal -func (op swaggerSchemaObjectProperties) MarshalJSON() ([]byte, error) { +func (op openapiSchemaObjectProperties) MarshalJSON() ([]byte, error) { var buf bytes.Buffer buf.WriteString("{") for i, kv := range op { @@ -220,16 +216,16 @@ func (op swaggerSchemaObjectProperties) MarshalJSON() ([]byte, error) { } // http://swagger.io/specification/#schemaObject -type swaggerSchemaObject struct { +type openapiSchemaObject struct { schemaCore // Properties can be recursively defined - Properties *swaggerSchemaObjectProperties `json:"properties,omitempty"` - AdditionalProperties *swaggerSchemaObject `json:"additionalProperties,omitempty"` + Properties *openapiSchemaObjectProperties `json:"properties,omitempty"` + AdditionalProperties *openapiSchemaObject `json:"additionalProperties,omitempty"` Description string `json:"description,omitempty"` Title string `json:"title,omitempty"` - ExternalDocs *swaggerExternalDocumentationObject `json:"externalDocs,omitempty"` + ExternalDocs *openapiExternalDocumentationObject `json:"externalDocs,omitempty"` ReadOnly bool `json:"readOnly,omitempty"` MultipleOf float64 `json:"multipleOf,omitempty"` @@ -248,13 +244,8 @@ type swaggerSchemaObject struct { Required []string `json:"required,omitempty"` } -// http://swagger.io/specification/#referenceObject -type swaggerReferenceObject struct { - Ref string `json:"$ref"` -} - // http://swagger.io/specification/#definitionsObject -type swaggerDefinitionsObject map[string]swaggerSchemaObject +type openapiDefinitionsObject map[string]openapiSchemaObject // Internal type mapping from FQMN to descriptor.Message. Used as a set by the // findServiceMessages function. diff --git a/gateway/protoc-gen-swagger/main.go b/gateway/protoc-gen-openapiv2/main.go similarity index 78% rename from gateway/protoc-gen-swagger/main.go rename to gateway/protoc-gen-openapiv2/main.go index b805bfe..c3f497a 100644 --- a/gateway/protoc-gen-swagger/main.go +++ b/gateway/protoc-gen-openapiv2/main.go @@ -7,16 +7,13 @@ import ( "strings" "github.com/golang/glog" - "github.com/golang/protobuf/proto" - plugin "github.com/golang/protobuf/protoc-gen-go/plugin" - - "github.com/grpc-ecosystem/grpc-gateway/codegenerator" - - // "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/descriptor" - "github.com/binchencoder/ease-gateway/gateway/protoc-gen-grpc-gateway/descriptor" - - // "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger/genswagger" - "github.com/binchencoder/ease-gateway/gateway/protoc-gen-swagger/genswagger" + pluginpb "github.com/golang/protobuf/protoc-gen-go/plugin" + "github.com/grpc-ecosystem/grpc-gateway/v2/internal/codegenerator" + // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor" + "github.com/binchencoder/ease-gateway/gateway/internal/descriptor" + // genopenapi "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/internal/genopenapi" + genopenapi "github.com/binchencoder/ease-gateway/gateway/protoc-gen-openapiv2/internal/genopenapi" + "google.golang.org/protobuf/proto" ) var ( @@ -24,14 +21,14 @@ var ( file = flag.String("file", "-", "where to load data from") allowDeleteBody = flag.Bool("allow_delete_body", false, "unless set, HTTP DELETE methods may not have a body") grpcAPIConfiguration = flag.String("grpc_api_configuration", "", "path to gRPC API Configuration in YAML format") - allowMerge = flag.Bool("allow_merge", false, "if set, generation one swagger file out of multiple protos") - mergeFileName = flag.String("merge_file_name", "apidocs", "target swagger file name prefix after merge") - useJSONNamesForFields = flag.Bool("json_names_for_fields", false, "if it sets Field.GetJsonName() will be used for generating swagger definitions, otherwise Field.GetName() will be used") + allowMerge = flag.Bool("allow_merge", false, "if set, generation one OpenAPI file out of multiple protos") + mergeFileName = flag.String("merge_file_name", "apidocs", "target OpenAPI file name prefix after merge") + useJSONNamesForFields = flag.Bool("json_names_for_fields", true, "if disabled, the original proto name will be used for generating OpenAPI definitions") repeatedPathParamSeparator = flag.String("repeated_path_param_separator", "csv", "configures how repeated fields should be split. Allowed values are `csv`, `pipes`, `ssv` and `tsv`.") versionFlag = flag.Bool("version", false, "print the current version") allowRepeatedFieldsInBody = flag.Bool("allow_repeated_fields_in_body", false, "allows to use repeated field in `body` and `response_body` field of `google.api.http` annotation option") includePackageInTags = flag.Bool("include_package_in_tags", false, "if unset, the gRPC service name is added to the `Tags` field of each operation. if set and the `package` directive is shown in the proto file, the package name will be prepended to the service name") - useFQNForSwaggerName = flag.Bool("fqn_for_swagger_name", false, "if set, the object's swagger names will use the fully qualify name from the proto definition (ie my.package.MyMessage.MyInnerMessage") + useFQNForOpenAPIName = flag.Bool("fqn_for_openapi_name", false, "if set, the object's OpenAPI names will use the fully qualify name from the proto definition (ie my.package.MyMessage.MyInnerMessage") useGoTemplate = flag.Bool("use_go_templates", false, "if set, you can use Go templates in protofile comments") disableDefaultErrors = flag.Bool("disable_default_errors", false, "if set, disables generation of default errors. This is useful if you have defined custom error handling") enumsAsInts = flag.Bool("enums_as_ints", false, "whether to render enum values as integers, as opposed to string values") @@ -86,7 +83,7 @@ func main() { reg.SetUseJSONNamesForFields(*useJSONNamesForFields) reg.SetAllowRepeatedFieldsInBody(*allowRepeatedFieldsInBody) reg.SetIncludePackageInTags(*includePackageInTags) - reg.SetUseFQNForSwaggerName(*useFQNForSwaggerName) + reg.SetUseFQNForOpenAPIName(*useFQNForOpenAPIName) reg.SetUseGoTemplate(*useGoTemplate) reg.SetEnumsAsInts(*enumsAsInts) reg.SetDisableDefaultErrors(*disableDefaultErrors) @@ -106,9 +103,9 @@ func main() { } } - g := genswagger.New(reg) + g := genopenapi.New(reg) - if err := genswagger.AddStreamError(reg); err != nil { + if err := genopenapi.AddErrorDefs(reg); err != nil { emitError(err) return } @@ -136,15 +133,15 @@ func main() { emitFiles(out) } -func emitFiles(out []*plugin.CodeGeneratorResponse_File) { - emitResp(&plugin.CodeGeneratorResponse{File: out}) +func emitFiles(out []*pluginpb.CodeGeneratorResponse_File) { + emitResp(&pluginpb.CodeGeneratorResponse{File: out}) } func emitError(err error) { - emitResp(&plugin.CodeGeneratorResponse{Error: proto.String(err.Error())}) + emitResp(&pluginpb.CodeGeneratorResponse{Error: proto.String(err.Error())}) } -func emitResp(resp *plugin.CodeGeneratorResponse) { +func emitResp(resp *pluginpb.CodeGeneratorResponse) { buf, err := proto.Marshal(resp) if err != nil { glog.Fatal(err) @@ -167,34 +164,34 @@ func parseReqParam(param string, f *flag.FlagSet, pkgMap map[string]string) erro if spec[0] == "allow_delete_body" { err := f.Set(spec[0], "true") if err != nil { - return fmt.Errorf("Cannot set flag %s: %v", p, err) + return fmt.Errorf("cannot set flag %s: %v", p, err) } continue } if spec[0] == "allow_merge" { err := f.Set(spec[0], "true") if err != nil { - return fmt.Errorf("Cannot set flag %s: %v", p, err) + return fmt.Errorf("cannot set flag %s: %v", p, err) } continue } if spec[0] == "allow_repeated_fields_in_body" { err := f.Set(spec[0], "true") if err != nil { - return fmt.Errorf("Cannot set flag %s: %v", p, err) + return fmt.Errorf("cannot set flag %s: %v", p, err) } continue } if spec[0] == "include_package_in_tags" { err := f.Set(spec[0], "true") if err != nil { - return fmt.Errorf("Cannot set flag %s: %v", p, err) + return fmt.Errorf("cannot set flag %s: %v", p, err) } continue } err := f.Set(spec[0], "") if err != nil { - return fmt.Errorf("Cannot set flag %s: %v", p, err) + return fmt.Errorf("cannot set flag %s: %v", p, err) } continue } @@ -204,7 +201,7 @@ func parseReqParam(param string, f *flag.FlagSet, pkgMap map[string]string) erro continue } if err := f.Set(name, value); err != nil { - return fmt.Errorf("Cannot set flag %s: %v", p, err) + return fmt.Errorf("cannot set flag %s: %v", p, err) } } return nil diff --git a/gateway/protoc-gen-swagger/main_test.go b/gateway/protoc-gen-openapiv2/main_test.go similarity index 89% rename from gateway/protoc-gen-swagger/main_test.go rename to gateway/protoc-gen-openapiv2/main_test.go index 7dcbf0c..514840a 100644 --- a/gateway/protoc-gen-swagger/main_test.go +++ b/gateway/protoc-gen-openapiv2/main_test.go @@ -21,7 +21,7 @@ func TestParseReqParam(t *testing.T) { fileV string importPathV string mergeFileNameV string - useFQNForSwaggerNameV bool + useFQNForOpenAPINameV bool }{ { // this one must be first - with no leading clearFlags call it @@ -65,7 +65,7 @@ func TestParseReqParam(t *testing.T) { name: "Test 5", expected: map[string]string{}, request: "unknown_param=17", - expectedError: errors.New("Cannot set flag unknown_param=17: no such flag -unknown_param"), + expectedError: errors.New("cannot set flag unknown_param=17: no such flag -unknown_param"), allowDeleteBodyV: false, allowMergeV: false, allowRepeatedFieldsInBodyV: false, includePackageInTagsV: false, fileV: "stdin", importPathV: "", mergeFileNameV: "apidocs", }, @@ -73,7 +73,7 @@ func TestParseReqParam(t *testing.T) { name: "Test 6", expected: map[string]string{}, request: "Mfoo", - expectedError: errors.New("Cannot set flag Mfoo: no such flag -Mfoo"), + expectedError: errors.New("cannot set flag Mfoo: no such flag -Mfoo"), allowDeleteBodyV: false, allowMergeV: false, allowRepeatedFieldsInBodyV: false, includePackageInTagsV: false, fileV: "stdin", importPathV: "", mergeFileNameV: "apidocs", }, @@ -88,7 +88,7 @@ func TestParseReqParam(t *testing.T) { name: "Test 8", expected: map[string]string{}, request: "allow_delete_body,file,import_prefix,allow_merge,allow_repeated_fields_in_body=3,merge_file_name", - expectedError: errors.New(`Cannot set flag allow_repeated_fields_in_body=3: parse error`), + expectedError: errors.New(`cannot set flag allow_repeated_fields_in_body=3: parse error`), allowDeleteBodyV: true, allowMergeV: true, allowRepeatedFieldsInBodyV: false, includePackageInTagsV: false, fileV: "", importPathV: "", mergeFileNameV: "apidocs", }, @@ -96,23 +96,23 @@ func TestParseReqParam(t *testing.T) { name: "Test 9", expected: map[string]string{}, request: "include_package_in_tags=3", - expectedError: errors.New(`Cannot set flag include_package_in_tags=3: parse error`), + expectedError: errors.New(`cannot set flag include_package_in_tags=3: parse error`), allowDeleteBodyV: false, allowMergeV: false, allowRepeatedFieldsInBodyV: false, includePackageInTagsV: false, fileV: "stdin", importPathV: "", mergeFileNameV: "apidocs", }, { name: "Test 10", expected: map[string]string{}, - request: "fqn_for_swagger_name=3", - expectedError: errors.New(`Cannot set flag fqn_for_swagger_name=3: parse error`), - allowDeleteBodyV: false, allowMergeV: false, allowRepeatedFieldsInBodyV: false, includePackageInTagsV: false, useFQNForSwaggerNameV: false, + request: "fqn_for_openapi_name=3", + expectedError: errors.New(`cannot set flag fqn_for_openapi_name=3: parse error`), + allowDeleteBodyV: false, allowMergeV: false, allowRepeatedFieldsInBodyV: false, includePackageInTagsV: false, useFQNForOpenAPINameV: false, fileV: "stdin", importPathV: "", mergeFileNameV: "apidocs", }, { name: "Test 11", expected: map[string]string{}, - request: "fqn_for_swagger_name=true", - allowDeleteBodyV: false, allowMergeV: false, allowRepeatedFieldsInBodyV: false, includePackageInTagsV: false, useFQNForSwaggerNameV: true, + request: "fqn_for_openapi_name=true", + allowDeleteBodyV: false, allowMergeV: false, allowRepeatedFieldsInBodyV: false, includePackageInTagsV: false, useFQNForOpenAPINameV: true, fileV: "stdin", importPathV: "", mergeFileNameV: "apidocs", }, } @@ -140,7 +140,7 @@ func TestParseReqParam(t *testing.T) { tt.Errorf("expected error malformed, expected %q, got %q", tc.expectedError.Error(), err.Error()) } } - checkFlags(tc.allowDeleteBodyV, tc.allowMergeV, tc.allowRepeatedFieldsInBodyV, tc.includePackageInTagsV, tc.useFQNForSwaggerNameV, tc.fileV, tc.importPathV, tc.mergeFileNameV, tt, i) + checkFlags(tc.allowDeleteBodyV, tc.allowMergeV, tc.allowRepeatedFieldsInBodyV, tc.includePackageInTagsV, tc.useFQNForOpenAPINameV, tc.fileV, tc.importPathV, tc.mergeFileNameV, tt, i) clearFlags() }) @@ -148,7 +148,7 @@ func TestParseReqParam(t *testing.T) { } -func checkFlags(allowDeleteV, allowMergeV, allowRepeatedFieldsInBodyV, includePackageInTagsV bool, useFQNForSwaggerNameV bool, fileV, importPathV, mergeFileNameV string, t *testing.T, tid int) { +func checkFlags(allowDeleteV, allowMergeV, allowRepeatedFieldsInBodyV, includePackageInTagsV bool, useFQNForOpenAPINameV bool, fileV, importPathV, mergeFileNameV string, t *testing.T, tid int) { if *importPrefix != importPathV { t.Errorf("Test %v: import_prefix misparsed, expected '%v', got '%v'", tid, importPathV, *importPrefix) } @@ -170,8 +170,8 @@ func checkFlags(allowDeleteV, allowMergeV, allowRepeatedFieldsInBodyV, includePa if *includePackageInTags != includePackageInTagsV { t.Errorf("Test %v: include_package_in_tags misparsed, expected '%v', got '%v'", tid, includePackageInTagsV, *includePackageInTags) } - if *useFQNForSwaggerName != useFQNForSwaggerNameV { - t.Errorf("Test %v: fqn_for_swagger_name misparsed, expected '%v', got '%v'", tid, useFQNForSwaggerNameV, *useFQNForSwaggerName) + if *useFQNForOpenAPIName != useFQNForOpenAPINameV { + t.Errorf("Test %v: fqn_for_openapi_name misparsed, expected '%v', got '%v'", tid, useFQNForOpenAPINameV, *useFQNForOpenAPIName) } } diff --git a/gateway/protoc-gen-swagger/options/BUILD.bazel b/gateway/protoc-gen-openapiv2/options/BUILD.bazel similarity index 90% rename from gateway/protoc-gen-swagger/options/BUILD.bazel rename to gateway/protoc-gen-openapiv2/options/BUILD.bazel index 19e4b0e..4d22229 100644 --- a/gateway/protoc-gen-swagger/options/BUILD.bazel +++ b/gateway/protoc-gen-openapiv2/options/BUILD.bazel @@ -15,7 +15,7 @@ filegroup( go_library( name = "go_default_library", embed = [":options_go_proto"], - importpath = "github.com/binchencoder/ease-gateway/gateway/protoc-gen-swagger/options", + importpath = "github.com/binchencoder/ease-gateway/gateway/protoc-gen-openapiv2/options", ) proto_library( @@ -33,6 +33,7 @@ proto_library( go_proto_library( name = "options_go_proto", - importpath = "github.com/binchencoder/ease-gateway/gateway/protoc-gen-swagger/options", + compilers = ["//:go_apiv2"], + importpath = "github.com/binchencoder/ease-gateway/gateway/protoc-gen-openapiv2/options", proto = ":options_proto", ) diff --git a/gateway/protoc-gen-swagger/options/annotations.proto b/gateway/protoc-gen-openapiv2/options/annotations.proto similarity index 91% rename from gateway/protoc-gen-swagger/options/annotations.proto rename to gateway/protoc-gen-openapiv2/options/annotations.proto index 09a56b1..ad054db 100644 --- a/gateway/protoc-gen-swagger/options/annotations.proto +++ b/gateway/protoc-gen-openapiv2/options/annotations.proto @@ -1,11 +1,11 @@ syntax = "proto3"; -package grpc.gateway.protoc_gen_swagger.options; +package grpc.gateway.protoc_gen_openapiv2.options; -option go_package = "github.com/binchencoder/ease-gateway/gateway/protoc-gen-swagger/options"; +option go_package = "github.com/binchencoder/ease-gateway/gateway/protoc-gen-openapiv2/options"; import "google/protobuf/descriptor.proto"; -import "gateway/protoc-gen-swagger/options/openapiv2.proto"; +import "gateway/protoc-gen-openapiv2/options/openapiv2.proto"; extend google.protobuf.FileOptions { // ID assigned by protobuf-global-extension-registry@google.com for grpc-gateway project. diff --git a/gateway/protoc-gen-swagger/options/openapiv2.proto b/gateway/protoc-gen-openapiv2/options/openapiv2.proto similarity index 93% rename from gateway/protoc-gen-swagger/options/openapiv2.proto rename to gateway/protoc-gen-openapiv2/options/openapiv2.proto index b6d16c9..f0040d6 100644 --- a/gateway/protoc-gen-swagger/options/openapiv2.proto +++ b/gateway/protoc-gen-openapiv2/options/openapiv2.proto @@ -1,19 +1,29 @@ syntax = "proto3"; -package grpc.gateway.protoc_gen_swagger.options; +package grpc.gateway.protoc_gen_openapiv2.options; -option go_package = "github.com/binchencoder/ease-gateway/gateway/protoc-gen-swagger/options"; +option go_package = "github.com/binchencoder/ease-gateway/gateway/protoc-gen-openapiv2/options"; import "google/protobuf/any.proto"; import "google/protobuf/struct.proto"; +// Scheme describes the schemes supported by the OpenAPI Swagger +// and Operation objects. +enum Scheme { + UNKNOWN = 0; + HTTP = 1; + HTTPS = 2; + WS = 3; + WSS = 4; +} + // `Swagger` is a representation of OpenAPI v2 specification's Swagger object. // // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#swaggerObject // // Example: // -// option (grpc.gateway.protoc_gen_swagger.options.openapiv2_swagger) = { +// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { // info: { // title: "Echo API"; // version: "1.0"; @@ -34,8 +44,8 @@ import "google/protobuf/struct.proto"; // }; // message Swagger { - // Specifies the Swagger Specification version being used. It can be - // used by the Swagger UI and other clients to interpret the API listing. The + // Specifies the OpenAPI Specification version being used. It can be + // used by the OpenAPI UI and other clients to interpret the API listing. The // value MUST be "2.0". string swagger = 1; // Provides metadata about the API. The metadata can be used by the @@ -51,22 +61,15 @@ message Swagger { // MUST start with a leading slash (/). The basePath does not support path // templating. // Note that using `base_path` does not change the endpoint paths that are - // generated in the resulting Swagger file. If you wish to use `base_path` - // with relatively generated Swagger paths, the `base_path` prefix must be + // generated in the resulting OpenAPI file. If you wish to use `base_path` + // with relatively generated OpenAPI paths, the `base_path` prefix must be // manually removed from your `google.api.http` paths and your code changed to // serve the API from the `base_path`. string base_path = 4; - enum SwaggerScheme { - UNKNOWN = 0; - HTTP = 1; - HTTPS = 2; - WS = 3; - WSS = 4; - } // The transfer protocol of the API. Values MUST be from the list: "http", // "https", "ws", "wss". If the schemes is not included, the default scheme to - // be used is the one used to access the Swagger definition itself. - repeated SwaggerScheme schemes = 5; + // be used is the one used to access the OpenAPI definition itself. + repeated Scheme schemes = 5; // A list of MIME types the APIs can consume. This is global to all APIs but // can be overridden on specific API calls. Value MUST be as described under // Mime Types. @@ -111,7 +114,7 @@ message Swagger { // get: "/v1/example/echo/{id}" // }; // -// option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = { +// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { // summary: "Get a message."; // operation_id: "getMessage"; // tags: "echo"; @@ -142,11 +145,11 @@ message Operation { // to follow common programming naming conventions. string operation_id = 5; // A list of MIME types the operation can consume. This overrides the consumes - // definition at the Swagger Object. An empty value MAY be used to clear the + // definition at the OpenAPI Object. An empty value MAY be used to clear the // global definition. Value MUST be as described under Mime Types. repeated string consumes = 6; // A list of MIME types the operation can produce. This overrides the produces - // definition at the Swagger Object. An empty value MAY be used to clear the + // definition at the OpenAPI Object. An empty value MAY be used to clear the // global definition. Value MUST be as described under Mime Types. repeated string produces = 7; // field 8 is reserved for 'parameters'. @@ -155,9 +158,9 @@ message Operation { // operation. map responses = 9; // The transfer protocol for the operation. Values MUST be from the list: - // "http", "https", "ws", "wss". The value overrides the Swagger Object + // "http", "https", "ws", "wss". The value overrides the OpenAPI Object // schemes definition. - repeated string schemes = 10; + repeated Scheme schemes = 10; // Declares this operation to be deprecated. Usage of the declared operation // should be refrained. Default value is false. bool deprecated = 11; @@ -195,7 +198,7 @@ message Response { // // Example: // -// option (grpc.gateway.protoc_gen_swagger.options.openapiv2_swagger) = { +// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { // info: { // title: "Echo API"; // version: "1.0"; @@ -237,7 +240,7 @@ message Info { // // Example: // -// option (grpc.gateway.protoc_gen_swagger.options.openapiv2_swagger) = { +// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { // info: { // ... // contact: { @@ -267,7 +270,7 @@ message Contact { // // Example: // -// option (grpc.gateway.protoc_gen_swagger.options.openapiv2_swagger) = { +// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { // info: { // ... // license: { @@ -293,7 +296,7 @@ message License { // // Example: // -// option (grpc.gateway.protoc_gen_swagger.options.openapiv2_swagger) = { +// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { // ... // external_docs: { // description: "More about gRPC-Gateway"; @@ -350,7 +353,7 @@ message Schema { // Example: // // message SimpleMessage { -// option (grpc.gateway.protoc_gen_swagger.options.openapiv2_schema) = { +// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema) = { // json_schema: { // title: "SimpleMessage" // description: "A simple message." @@ -360,7 +363,7 @@ message Schema { // // // Id represents the message identifier. // string id = 1; [ -// (grpc.gateway.protoc_gen_swagger.options.openapiv2_field) = { +// (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { // {description: "The unique identifier of the simple message." // }]; // } @@ -464,7 +467,7 @@ message Tag { // // TODO(ivucica): Add 'name' property. Use it to allow override of the name of // global Tag object, then use that name to reference the tag throughout the - // Swagger file. + // OpenAPI file. reserved 1; // A short description for the tag. GFM syntax can be used for rich text // representation. diff --git a/gateway/protoc-gen-swagger/genswagger/doc.go b/gateway/protoc-gen-swagger/genswagger/doc.go deleted file mode 100644 index 4d28716..0000000 --- a/gateway/protoc-gen-swagger/genswagger/doc.go +++ /dev/null @@ -1,2 +0,0 @@ -// Package genswagger provides a code generator for swagger. -package genswagger diff --git a/gateway/protoc-gen-swagger/options/annotations.pb.go b/gateway/protoc-gen-swagger/options/annotations.pb.go deleted file mode 100644 index 6514002..0000000 --- a/gateway/protoc-gen-swagger/options/annotations.pb.go +++ /dev/null @@ -1,105 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// source: protoc-gen-swagger/options/annotations.proto - -package options - -import ( - fmt "fmt" - proto "github.com/golang/protobuf/proto" - descriptor "github.com/golang/protobuf/protoc-gen-go/descriptor" - 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.ProtoPackageIsVersion3 // please upgrade the proto package - -var E_Openapiv2Swagger = &proto.ExtensionDesc{ - ExtendedType: (*descriptor.FileOptions)(nil), - ExtensionType: (*Swagger)(nil), - Field: 1042, - Name: "grpc.gateway.protoc_gen_swagger.options.openapiv2_swagger", - Tag: "bytes,1042,opt,name=openapiv2_swagger", - Filename: "protoc-gen-swagger/options/annotations.proto", -} - -var E_Openapiv2Operation = &proto.ExtensionDesc{ - ExtendedType: (*descriptor.MethodOptions)(nil), - ExtensionType: (*Operation)(nil), - Field: 1042, - Name: "grpc.gateway.protoc_gen_swagger.options.openapiv2_operation", - Tag: "bytes,1042,opt,name=openapiv2_operation", - Filename: "protoc-gen-swagger/options/annotations.proto", -} - -var E_Openapiv2Schema = &proto.ExtensionDesc{ - ExtendedType: (*descriptor.MessageOptions)(nil), - ExtensionType: (*Schema)(nil), - Field: 1042, - Name: "grpc.gateway.protoc_gen_swagger.options.openapiv2_schema", - Tag: "bytes,1042,opt,name=openapiv2_schema", - Filename: "protoc-gen-swagger/options/annotations.proto", -} - -var E_Openapiv2Tag = &proto.ExtensionDesc{ - ExtendedType: (*descriptor.ServiceOptions)(nil), - ExtensionType: (*Tag)(nil), - Field: 1042, - Name: "grpc.gateway.protoc_gen_swagger.options.openapiv2_tag", - Tag: "bytes,1042,opt,name=openapiv2_tag", - Filename: "protoc-gen-swagger/options/annotations.proto", -} - -var E_Openapiv2Field = &proto.ExtensionDesc{ - ExtendedType: (*descriptor.FieldOptions)(nil), - ExtensionType: (*JSONSchema)(nil), - Field: 1042, - Name: "grpc.gateway.protoc_gen_swagger.options.openapiv2_field", - Tag: "bytes,1042,opt,name=openapiv2_field", - Filename: "protoc-gen-swagger/options/annotations.proto", -} - -func init() { - proto.RegisterExtension(E_Openapiv2Swagger) - proto.RegisterExtension(E_Openapiv2Operation) - proto.RegisterExtension(E_Openapiv2Schema) - proto.RegisterExtension(E_Openapiv2Tag) - proto.RegisterExtension(E_Openapiv2Field) -} - -func init() { - proto.RegisterFile("protoc-gen-swagger/options/annotations.proto", fileDescriptor_a6a34ca6badab664) -} - -var fileDescriptor_a6a34ca6badab664 = []byte{ - // 346 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0x4f, 0x4f, 0xea, 0x40, - 0x14, 0xc5, 0xc3, 0xe6, 0xe5, 0xa5, 0xef, 0xa9, 0x58, 0x37, 0x86, 0xf8, 0x87, 0x9d, 0xc6, 0xc0, - 0x8c, 0x81, 0x5d, 0x77, 0x6a, 0xe2, 0xc2, 0x44, 0x49, 0x0a, 0x2b, 0x37, 0x64, 0x18, 0x2e, 0x97, - 0x49, 0x4a, 0xef, 0x64, 0x66, 0x80, 0x90, 0xb0, 0xf4, 0x13, 0xf8, 0x89, 0x8d, 0xd3, 0xd2, 0x9a, - 0x8a, 0xa6, 0xbb, 0xce, 0xe9, 0xbd, 0xe7, 0x77, 0x7a, 0x3a, 0x41, 0x47, 0x1b, 0x72, 0x24, 0xbb, - 0x08, 0x69, 0xd7, 0xae, 0x05, 0x22, 0x18, 0x4e, 0xda, 0x29, 0x4a, 0x2d, 0x17, 0x69, 0x4a, 0x4e, - 0xf8, 0x67, 0xe6, 0xc7, 0xc2, 0x2b, 0x34, 0x5a, 0x32, 0x14, 0x0e, 0xd6, 0x62, 0x93, 0x69, 0x72, - 0x8c, 0x90, 0x8e, 0xf3, 0x55, 0x96, 0xaf, 0xb6, 0xda, 0x48, 0x84, 0x09, 0x70, 0x3f, 0x32, 0x59, - 0xce, 0xf8, 0x14, 0xac, 0x34, 0x4a, 0x3b, 0x32, 0xd9, 0x5a, 0xeb, 0xe6, 0x17, 0x30, 0x69, 0x48, - 0x85, 0x56, 0xab, 0x5e, 0x36, 0x1b, 0x6d, 0x83, 0xe3, 0x42, 0xda, 0xa1, 0xc2, 0x33, 0x96, 0x31, - 0xd8, 0x8e, 0xc1, 0x1e, 0x55, 0x02, 0x83, 0xcc, 0xe2, 0xf4, 0xfd, 0x6f, 0xbb, 0x71, 0xfd, 0xaf, - 0x77, 0xcb, 0x6a, 0x26, 0x66, 0xc3, 0xec, 0x1c, 0x37, 0x0b, 0x52, 0xae, 0x44, 0x6f, 0x8d, 0xe0, - 0xa4, 0xc4, 0x93, 0x06, 0xe3, 0x3b, 0x09, 0x2f, 0xbe, 0x05, 0x78, 0x06, 0x37, 0xa7, 0x69, 0x25, - 0x42, 0xaf, 0x76, 0x84, 0xc1, 0xce, 0x3a, 0x0e, 0x0b, 0x5e, 0xa1, 0x45, 0xdb, 0xa0, 0xf9, 0xa5, - 0x04, 0x39, 0x87, 0x85, 0x08, 0x2f, 0xf7, 0x44, 0xb0, 0x56, 0x60, 0xb5, 0x06, 0x5e, 0xbf, 0x06, - 0x6f, 0x1c, 0x1f, 0x95, 0x2d, 0x78, 0x21, 0xb2, 0xc1, 0x41, 0x49, 0x77, 0x02, 0xf7, 0xa0, 0x87, - 0x60, 0x56, 0x4a, 0x56, 0xd1, 0x9d, 0xda, 0xe8, 0x91, 0xc0, 0xf8, 0x7f, 0x01, 0x19, 0x09, 0x8c, - 0xb6, 0x41, 0x99, 0x63, 0x3c, 0x53, 0x90, 0x4c, 0xc3, 0xf3, 0x3d, 0x7f, 0x1d, 0x92, 0x6a, 0xe7, - 0xfd, 0xda, 0xd0, 0xa7, 0xe1, 0xe0, 0x25, 0xff, 0xe6, 0xc3, 0x82, 0xe5, 0x2d, 0xef, 0x1f, 0x5e, - 0xef, 0x50, 0xb9, 0xf9, 0x72, 0xc2, 0x24, 0x2d, 0xf8, 0xa7, 0x61, 0x17, 0x24, 0xd9, 0x8d, 0x75, - 0x90, 0x1f, 0x73, 0x7f, 0xfe, 0xf3, 0x55, 0x9e, 0xfc, 0xf1, 0xef, 0xfa, 0x1f, 0x01, 0x00, 0x00, - 0xff, 0xff, 0x59, 0x78, 0xb0, 0x03, 0x68, 0x03, 0x00, 0x00, -} diff --git a/gateway/protoc-gen-swagger/options/openapiv2.pb.go b/gateway/protoc-gen-swagger/options/openapiv2.pb.go deleted file mode 100644 index c15e2d1..0000000 --- a/gateway/protoc-gen-swagger/options/openapiv2.pb.go +++ /dev/null @@ -1,1721 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// source: protoc-gen-swagger/options/openapiv2.proto - -package options - -import ( - fmt "fmt" - proto "github.com/golang/protobuf/proto" - any "github.com/golang/protobuf/ptypes/any" - _struct "github.com/golang/protobuf/ptypes/struct" - 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.ProtoPackageIsVersion3 // please upgrade the proto package - -type Swagger_SwaggerScheme int32 - -const ( - Swagger_UNKNOWN Swagger_SwaggerScheme = 0 - Swagger_HTTP Swagger_SwaggerScheme = 1 - Swagger_HTTPS Swagger_SwaggerScheme = 2 - Swagger_WS Swagger_SwaggerScheme = 3 - Swagger_WSS Swagger_SwaggerScheme = 4 -) - -var Swagger_SwaggerScheme_name = map[int32]string{ - 0: "UNKNOWN", - 1: "HTTP", - 2: "HTTPS", - 3: "WS", - 4: "WSS", -} - -var Swagger_SwaggerScheme_value = map[string]int32{ - "UNKNOWN": 0, - "HTTP": 1, - "HTTPS": 2, - "WS": 3, - "WSS": 4, -} - -func (x Swagger_SwaggerScheme) String() string { - return proto.EnumName(Swagger_SwaggerScheme_name, int32(x)) -} - -func (Swagger_SwaggerScheme) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_ba35ad8af024fb48, []int{0, 0} -} - -type JSONSchema_JSONSchemaSimpleTypes int32 - -const ( - JSONSchema_UNKNOWN JSONSchema_JSONSchemaSimpleTypes = 0 - JSONSchema_ARRAY JSONSchema_JSONSchemaSimpleTypes = 1 - JSONSchema_BOOLEAN JSONSchema_JSONSchemaSimpleTypes = 2 - JSONSchema_INTEGER JSONSchema_JSONSchemaSimpleTypes = 3 - JSONSchema_NULL JSONSchema_JSONSchemaSimpleTypes = 4 - JSONSchema_NUMBER JSONSchema_JSONSchemaSimpleTypes = 5 - JSONSchema_OBJECT JSONSchema_JSONSchemaSimpleTypes = 6 - JSONSchema_STRING JSONSchema_JSONSchemaSimpleTypes = 7 -) - -var JSONSchema_JSONSchemaSimpleTypes_name = map[int32]string{ - 0: "UNKNOWN", - 1: "ARRAY", - 2: "BOOLEAN", - 3: "INTEGER", - 4: "NULL", - 5: "NUMBER", - 6: "OBJECT", - 7: "STRING", -} - -var JSONSchema_JSONSchemaSimpleTypes_value = map[string]int32{ - "UNKNOWN": 0, - "ARRAY": 1, - "BOOLEAN": 2, - "INTEGER": 3, - "NULL": 4, - "NUMBER": 5, - "OBJECT": 6, - "STRING": 7, -} - -func (x JSONSchema_JSONSchemaSimpleTypes) String() string { - return proto.EnumName(JSONSchema_JSONSchemaSimpleTypes_name, int32(x)) -} - -func (JSONSchema_JSONSchemaSimpleTypes) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_ba35ad8af024fb48, []int{8, 0} -} - -// The type of the security scheme. Valid values are "basic", -// "apiKey" or "oauth2". -type SecurityScheme_Type int32 - -const ( - SecurityScheme_TYPE_INVALID SecurityScheme_Type = 0 - SecurityScheme_TYPE_BASIC SecurityScheme_Type = 1 - SecurityScheme_TYPE_API_KEY SecurityScheme_Type = 2 - SecurityScheme_TYPE_OAUTH2 SecurityScheme_Type = 3 -) - -var SecurityScheme_Type_name = map[int32]string{ - 0: "TYPE_INVALID", - 1: "TYPE_BASIC", - 2: "TYPE_API_KEY", - 3: "TYPE_OAUTH2", -} - -var SecurityScheme_Type_value = map[string]int32{ - "TYPE_INVALID": 0, - "TYPE_BASIC": 1, - "TYPE_API_KEY": 2, - "TYPE_OAUTH2": 3, -} - -func (x SecurityScheme_Type) String() string { - return proto.EnumName(SecurityScheme_Type_name, int32(x)) -} - -func (SecurityScheme_Type) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_ba35ad8af024fb48, []int{11, 0} -} - -// The location of the API key. Valid values are "query" or "header". -type SecurityScheme_In int32 - -const ( - SecurityScheme_IN_INVALID SecurityScheme_In = 0 - SecurityScheme_IN_QUERY SecurityScheme_In = 1 - SecurityScheme_IN_HEADER SecurityScheme_In = 2 -) - -var SecurityScheme_In_name = map[int32]string{ - 0: "IN_INVALID", - 1: "IN_QUERY", - 2: "IN_HEADER", -} - -var SecurityScheme_In_value = map[string]int32{ - "IN_INVALID": 0, - "IN_QUERY": 1, - "IN_HEADER": 2, -} - -func (x SecurityScheme_In) String() string { - return proto.EnumName(SecurityScheme_In_name, int32(x)) -} - -func (SecurityScheme_In) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_ba35ad8af024fb48, []int{11, 1} -} - -// The flow used by the OAuth2 security scheme. Valid values are -// "implicit", "password", "application" or "accessCode". -type SecurityScheme_Flow int32 - -const ( - SecurityScheme_FLOW_INVALID SecurityScheme_Flow = 0 - SecurityScheme_FLOW_IMPLICIT SecurityScheme_Flow = 1 - SecurityScheme_FLOW_PASSWORD SecurityScheme_Flow = 2 - SecurityScheme_FLOW_APPLICATION SecurityScheme_Flow = 3 - SecurityScheme_FLOW_ACCESS_CODE SecurityScheme_Flow = 4 -) - -var SecurityScheme_Flow_name = map[int32]string{ - 0: "FLOW_INVALID", - 1: "FLOW_IMPLICIT", - 2: "FLOW_PASSWORD", - 3: "FLOW_APPLICATION", - 4: "FLOW_ACCESS_CODE", -} - -var SecurityScheme_Flow_value = map[string]int32{ - "FLOW_INVALID": 0, - "FLOW_IMPLICIT": 1, - "FLOW_PASSWORD": 2, - "FLOW_APPLICATION": 3, - "FLOW_ACCESS_CODE": 4, -} - -func (x SecurityScheme_Flow) String() string { - return proto.EnumName(SecurityScheme_Flow_name, int32(x)) -} - -func (SecurityScheme_Flow) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_ba35ad8af024fb48, []int{11, 2} -} - -// `Swagger` is a representation of OpenAPI v2 specification's Swagger object. -// -// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#swaggerObject -// -type Swagger struct { - // Specifies the Swagger Specification version being used. It can be - // used by the Swagger UI and other clients to interpret the API listing. The - // value MUST be "2.0". - Swagger string `protobuf:"bytes,1,opt,name=swagger,proto3" json:"swagger,omitempty"` - // Provides metadata about the API. The metadata can be used by the - // clients if needed. - Info *Info `protobuf:"bytes,2,opt,name=info,proto3" json:"info,omitempty"` - // The host (name or ip) serving the API. This MUST be the host only and does - // not include the scheme nor sub-paths. It MAY include a port. If the host is - // not included, the host serving the documentation is to be used (including - // the port). The host does not support path templating. - Host string `protobuf:"bytes,3,opt,name=host,proto3" json:"host,omitempty"` - // The base path on which the API is served, which is relative to the host. If - // it is not included, the API is served directly under the host. The value - // MUST start with a leading slash (/). The basePath does not support path - // templating. - // Note that using `base_path` does not change the endpoint paths that are - // generated in the resulting Swagger file. If you wish to use `base_path` - // with relatively generated Swagger paths, the `base_path` prefix must be - // manually removed from your `google.api.http` paths and your code changed to - // serve the API from the `base_path`. - BasePath string `protobuf:"bytes,4,opt,name=base_path,json=basePath,proto3" json:"base_path,omitempty"` - // The transfer protocol of the API. Values MUST be from the list: "http", - // "https", "ws", "wss". If the schemes is not included, the default scheme to - // be used is the one used to access the Swagger definition itself. - Schemes []Swagger_SwaggerScheme `protobuf:"varint,5,rep,packed,name=schemes,proto3,enum=grpc.gateway.protoc_gen_swagger.options.Swagger_SwaggerScheme" json:"schemes,omitempty"` - // A list of MIME types the APIs can consume. This is global to all APIs but - // can be overridden on specific API calls. Value MUST be as described under - // Mime Types. - Consumes []string `protobuf:"bytes,6,rep,name=consumes,proto3" json:"consumes,omitempty"` - // A list of MIME types the APIs can produce. This is global to all APIs but - // can be overridden on specific API calls. Value MUST be as described under - // Mime Types. - Produces []string `protobuf:"bytes,7,rep,name=produces,proto3" json:"produces,omitempty"` - // An object to hold responses that can be used across operations. This - // property does not define global responses for all operations. - Responses map[string]*Response `protobuf:"bytes,10,rep,name=responses,proto3" json:"responses,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - // Security scheme definitions that can be used across the specification. - SecurityDefinitions *SecurityDefinitions `protobuf:"bytes,11,opt,name=security_definitions,json=securityDefinitions,proto3" json:"security_definitions,omitempty"` - // A declaration of which security schemes are applied for the API as a whole. - // The list of values describes alternative security schemes that can be used - // (that is, there is a logical OR between the security requirements). - // Individual operations can override this definition. - Security []*SecurityRequirement `protobuf:"bytes,12,rep,name=security,proto3" json:"security,omitempty"` - // Additional external documentation. - ExternalDocs *ExternalDocumentation `protobuf:"bytes,14,opt,name=external_docs,json=externalDocs,proto3" json:"external_docs,omitempty"` - Extensions map[string]*_struct.Value `protobuf:"bytes,15,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *Swagger) Reset() { *m = Swagger{} } -func (m *Swagger) String() string { return proto.CompactTextString(m) } -func (*Swagger) ProtoMessage() {} -func (*Swagger) Descriptor() ([]byte, []int) { - return fileDescriptor_ba35ad8af024fb48, []int{0} -} - -func (m *Swagger) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Swagger.Unmarshal(m, b) -} -func (m *Swagger) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Swagger.Marshal(b, m, deterministic) -} -func (m *Swagger) XXX_Merge(src proto.Message) { - xxx_messageInfo_Swagger.Merge(m, src) -} -func (m *Swagger) XXX_Size() int { - return xxx_messageInfo_Swagger.Size(m) -} -func (m *Swagger) XXX_DiscardUnknown() { - xxx_messageInfo_Swagger.DiscardUnknown(m) -} - -var xxx_messageInfo_Swagger proto.InternalMessageInfo - -func (m *Swagger) GetSwagger() string { - if m != nil { - return m.Swagger - } - return "" -} - -func (m *Swagger) GetInfo() *Info { - if m != nil { - return m.Info - } - return nil -} - -func (m *Swagger) GetHost() string { - if m != nil { - return m.Host - } - return "" -} - -func (m *Swagger) GetBasePath() string { - if m != nil { - return m.BasePath - } - return "" -} - -func (m *Swagger) GetSchemes() []Swagger_SwaggerScheme { - if m != nil { - return m.Schemes - } - return nil -} - -func (m *Swagger) GetConsumes() []string { - if m != nil { - return m.Consumes - } - return nil -} - -func (m *Swagger) GetProduces() []string { - if m != nil { - return m.Produces - } - return nil -} - -func (m *Swagger) GetResponses() map[string]*Response { - if m != nil { - return m.Responses - } - return nil -} - -func (m *Swagger) GetSecurityDefinitions() *SecurityDefinitions { - if m != nil { - return m.SecurityDefinitions - } - return nil -} - -func (m *Swagger) GetSecurity() []*SecurityRequirement { - if m != nil { - return m.Security - } - return nil -} - -func (m *Swagger) GetExternalDocs() *ExternalDocumentation { - if m != nil { - return m.ExternalDocs - } - return nil -} - -func (m *Swagger) GetExtensions() map[string]*_struct.Value { - if m != nil { - return m.Extensions - } - return nil -} - -// `Operation` is a representation of OpenAPI v2 specification's Operation object. -// -// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#operationObject -// -type Operation struct { - // A list of tags for API documentation control. Tags can be used for logical - // grouping of operations by resources or any other qualifier. - Tags []string `protobuf:"bytes,1,rep,name=tags,proto3" json:"tags,omitempty"` - // A short summary of what the operation does. For maximum readability in the - // swagger-ui, this field SHOULD be less than 120 characters. - Summary string `protobuf:"bytes,2,opt,name=summary,proto3" json:"summary,omitempty"` - // A verbose explanation of the operation behavior. GFM syntax can be used for - // rich text representation. - Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"` - // Additional external documentation for this operation. - ExternalDocs *ExternalDocumentation `protobuf:"bytes,4,opt,name=external_docs,json=externalDocs,proto3" json:"external_docs,omitempty"` - // Unique string used to identify the operation. The id MUST be unique among - // all operations described in the API. Tools and libraries MAY use the - // operationId to uniquely identify an operation, therefore, it is recommended - // to follow common programming naming conventions. - OperationId string `protobuf:"bytes,5,opt,name=operation_id,json=operationId,proto3" json:"operation_id,omitempty"` - // A list of MIME types the operation can consume. This overrides the consumes - // definition at the Swagger Object. An empty value MAY be used to clear the - // global definition. Value MUST be as described under Mime Types. - Consumes []string `protobuf:"bytes,6,rep,name=consumes,proto3" json:"consumes,omitempty"` - // A list of MIME types the operation can produce. This overrides the produces - // definition at the Swagger Object. An empty value MAY be used to clear the - // global definition. Value MUST be as described under Mime Types. - Produces []string `protobuf:"bytes,7,rep,name=produces,proto3" json:"produces,omitempty"` - // The list of possible responses as they are returned from executing this - // operation. - Responses map[string]*Response `protobuf:"bytes,9,rep,name=responses,proto3" json:"responses,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - // The transfer protocol for the operation. Values MUST be from the list: - // "http", "https", "ws", "wss". The value overrides the Swagger Object - // schemes definition. - Schemes []string `protobuf:"bytes,10,rep,name=schemes,proto3" json:"schemes,omitempty"` - // Declares this operation to be deprecated. Usage of the declared operation - // should be refrained. Default value is false. - Deprecated bool `protobuf:"varint,11,opt,name=deprecated,proto3" json:"deprecated,omitempty"` - // A declaration of which security schemes are applied for this operation. The - // list of values describes alternative security schemes that can be used - // (that is, there is a logical OR between the security requirements). This - // definition overrides any declared top-level security. To remove a top-level - // security declaration, an empty array can be used. - Security []*SecurityRequirement `protobuf:"bytes,12,rep,name=security,proto3" json:"security,omitempty"` - Extensions map[string]*_struct.Value `protobuf:"bytes,13,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *Operation) Reset() { *m = Operation{} } -func (m *Operation) String() string { return proto.CompactTextString(m) } -func (*Operation) ProtoMessage() {} -func (*Operation) Descriptor() ([]byte, []int) { - return fileDescriptor_ba35ad8af024fb48, []int{1} -} - -func (m *Operation) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Operation.Unmarshal(m, b) -} -func (m *Operation) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Operation.Marshal(b, m, deterministic) -} -func (m *Operation) XXX_Merge(src proto.Message) { - xxx_messageInfo_Operation.Merge(m, src) -} -func (m *Operation) XXX_Size() int { - return xxx_messageInfo_Operation.Size(m) -} -func (m *Operation) XXX_DiscardUnknown() { - xxx_messageInfo_Operation.DiscardUnknown(m) -} - -var xxx_messageInfo_Operation proto.InternalMessageInfo - -func (m *Operation) GetTags() []string { - if m != nil { - return m.Tags - } - return nil -} - -func (m *Operation) GetSummary() string { - if m != nil { - return m.Summary - } - return "" -} - -func (m *Operation) GetDescription() string { - if m != nil { - return m.Description - } - return "" -} - -func (m *Operation) GetExternalDocs() *ExternalDocumentation { - if m != nil { - return m.ExternalDocs - } - return nil -} - -func (m *Operation) GetOperationId() string { - if m != nil { - return m.OperationId - } - return "" -} - -func (m *Operation) GetConsumes() []string { - if m != nil { - return m.Consumes - } - return nil -} - -func (m *Operation) GetProduces() []string { - if m != nil { - return m.Produces - } - return nil -} - -func (m *Operation) GetResponses() map[string]*Response { - if m != nil { - return m.Responses - } - return nil -} - -func (m *Operation) GetSchemes() []string { - if m != nil { - return m.Schemes - } - return nil -} - -func (m *Operation) GetDeprecated() bool { - if m != nil { - return m.Deprecated - } - return false -} - -func (m *Operation) GetSecurity() []*SecurityRequirement { - if m != nil { - return m.Security - } - return nil -} - -func (m *Operation) GetExtensions() map[string]*_struct.Value { - if m != nil { - return m.Extensions - } - return nil -} - -// `Response` is a representation of OpenAPI v2 specification's Response object. -// -// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#responseObject -// -type Response struct { - // `Description` is a short description of the response. - // GFM syntax can be used for rich text representation. - Description string `protobuf:"bytes,1,opt,name=description,proto3" json:"description,omitempty"` - // `Schema` optionally defines the structure of the response. - // If `Schema` is not provided, it means there is no content to the response. - Schema *Schema `protobuf:"bytes,2,opt,name=schema,proto3" json:"schema,omitempty"` - // `Examples` gives per-mimetype response examples. - // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#example-object - Examples map[string]string `protobuf:"bytes,4,rep,name=examples,proto3" json:"examples,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - Extensions map[string]*_struct.Value `protobuf:"bytes,5,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *Response) Reset() { *m = Response{} } -func (m *Response) String() string { return proto.CompactTextString(m) } -func (*Response) ProtoMessage() {} -func (*Response) Descriptor() ([]byte, []int) { - return fileDescriptor_ba35ad8af024fb48, []int{2} -} - -func (m *Response) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Response.Unmarshal(m, b) -} -func (m *Response) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Response.Marshal(b, m, deterministic) -} -func (m *Response) XXX_Merge(src proto.Message) { - xxx_messageInfo_Response.Merge(m, src) -} -func (m *Response) XXX_Size() int { - return xxx_messageInfo_Response.Size(m) -} -func (m *Response) XXX_DiscardUnknown() { - xxx_messageInfo_Response.DiscardUnknown(m) -} - -var xxx_messageInfo_Response proto.InternalMessageInfo - -func (m *Response) GetDescription() string { - if m != nil { - return m.Description - } - return "" -} - -func (m *Response) GetSchema() *Schema { - if m != nil { - return m.Schema - } - return nil -} - -func (m *Response) GetExamples() map[string]string { - if m != nil { - return m.Examples - } - return nil -} - -func (m *Response) GetExtensions() map[string]*_struct.Value { - if m != nil { - return m.Extensions - } - return nil -} - -// `Info` is a representation of OpenAPI v2 specification's Info object. -// -// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#infoObject -// -type Info struct { - // The title of the application. - Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` - // A short description of the application. GFM syntax can be used for rich - // text representation. - Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` - // The Terms of Service for the API. - TermsOfService string `protobuf:"bytes,3,opt,name=terms_of_service,json=termsOfService,proto3" json:"terms_of_service,omitempty"` - // The contact information for the exposed API. - Contact *Contact `protobuf:"bytes,4,opt,name=contact,proto3" json:"contact,omitempty"` - // The license information for the exposed API. - License *License `protobuf:"bytes,5,opt,name=license,proto3" json:"license,omitempty"` - // Provides the version of the application API (not to be confused - // with the specification version). - Version string `protobuf:"bytes,6,opt,name=version,proto3" json:"version,omitempty"` - Extensions map[string]*_struct.Value `protobuf:"bytes,7,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *Info) Reset() { *m = Info{} } -func (m *Info) String() string { return proto.CompactTextString(m) } -func (*Info) ProtoMessage() {} -func (*Info) Descriptor() ([]byte, []int) { - return fileDescriptor_ba35ad8af024fb48, []int{3} -} - -func (m *Info) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Info.Unmarshal(m, b) -} -func (m *Info) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Info.Marshal(b, m, deterministic) -} -func (m *Info) XXX_Merge(src proto.Message) { - xxx_messageInfo_Info.Merge(m, src) -} -func (m *Info) XXX_Size() int { - return xxx_messageInfo_Info.Size(m) -} -func (m *Info) XXX_DiscardUnknown() { - xxx_messageInfo_Info.DiscardUnknown(m) -} - -var xxx_messageInfo_Info proto.InternalMessageInfo - -func (m *Info) GetTitle() string { - if m != nil { - return m.Title - } - return "" -} - -func (m *Info) GetDescription() string { - if m != nil { - return m.Description - } - return "" -} - -func (m *Info) GetTermsOfService() string { - if m != nil { - return m.TermsOfService - } - return "" -} - -func (m *Info) GetContact() *Contact { - if m != nil { - return m.Contact - } - return nil -} - -func (m *Info) GetLicense() *License { - if m != nil { - return m.License - } - return nil -} - -func (m *Info) GetVersion() string { - if m != nil { - return m.Version - } - return "" -} - -func (m *Info) GetExtensions() map[string]*_struct.Value { - if m != nil { - return m.Extensions - } - return nil -} - -// `Contact` is a representation of OpenAPI v2 specification's Contact object. -// -// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#contactObject -// -type Contact struct { - // The identifying name of the contact person/organization. - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - // The URL pointing to the contact information. MUST be in the format of a - // URL. - Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"` - // The email address of the contact person/organization. MUST be in the format - // of an email address. - Email string `protobuf:"bytes,3,opt,name=email,proto3" json:"email,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *Contact) Reset() { *m = Contact{} } -func (m *Contact) String() string { return proto.CompactTextString(m) } -func (*Contact) ProtoMessage() {} -func (*Contact) Descriptor() ([]byte, []int) { - return fileDescriptor_ba35ad8af024fb48, []int{4} -} - -func (m *Contact) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Contact.Unmarshal(m, b) -} -func (m *Contact) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Contact.Marshal(b, m, deterministic) -} -func (m *Contact) XXX_Merge(src proto.Message) { - xxx_messageInfo_Contact.Merge(m, src) -} -func (m *Contact) XXX_Size() int { - return xxx_messageInfo_Contact.Size(m) -} -func (m *Contact) XXX_DiscardUnknown() { - xxx_messageInfo_Contact.DiscardUnknown(m) -} - -var xxx_messageInfo_Contact proto.InternalMessageInfo - -func (m *Contact) GetName() string { - if m != nil { - return m.Name - } - return "" -} - -func (m *Contact) GetUrl() string { - if m != nil { - return m.Url - } - return "" -} - -func (m *Contact) GetEmail() string { - if m != nil { - return m.Email - } - return "" -} - -// `License` is a representation of OpenAPI v2 specification's License object. -// -// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#licenseObject -// -type License struct { - // The license name used for the API. - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - // A URL to the license used for the API. MUST be in the format of a URL. - Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *License) Reset() { *m = License{} } -func (m *License) String() string { return proto.CompactTextString(m) } -func (*License) ProtoMessage() {} -func (*License) Descriptor() ([]byte, []int) { - return fileDescriptor_ba35ad8af024fb48, []int{5} -} - -func (m *License) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_License.Unmarshal(m, b) -} -func (m *License) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_License.Marshal(b, m, deterministic) -} -func (m *License) XXX_Merge(src proto.Message) { - xxx_messageInfo_License.Merge(m, src) -} -func (m *License) XXX_Size() int { - return xxx_messageInfo_License.Size(m) -} -func (m *License) XXX_DiscardUnknown() { - xxx_messageInfo_License.DiscardUnknown(m) -} - -var xxx_messageInfo_License proto.InternalMessageInfo - -func (m *License) GetName() string { - if m != nil { - return m.Name - } - return "" -} - -func (m *License) GetUrl() string { - if m != nil { - return m.Url - } - return "" -} - -// `ExternalDocumentation` is a representation of OpenAPI v2 specification's -// ExternalDocumentation object. -// -// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#externalDocumentationObject -// -type ExternalDocumentation struct { - // A short description of the target documentation. GFM syntax can be used for - // rich text representation. - Description string `protobuf:"bytes,1,opt,name=description,proto3" json:"description,omitempty"` - // The URL for the target documentation. Value MUST be in the format - // of a URL. - Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *ExternalDocumentation) Reset() { *m = ExternalDocumentation{} } -func (m *ExternalDocumentation) String() string { return proto.CompactTextString(m) } -func (*ExternalDocumentation) ProtoMessage() {} -func (*ExternalDocumentation) Descriptor() ([]byte, []int) { - return fileDescriptor_ba35ad8af024fb48, []int{6} -} - -func (m *ExternalDocumentation) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ExternalDocumentation.Unmarshal(m, b) -} -func (m *ExternalDocumentation) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ExternalDocumentation.Marshal(b, m, deterministic) -} -func (m *ExternalDocumentation) XXX_Merge(src proto.Message) { - xxx_messageInfo_ExternalDocumentation.Merge(m, src) -} -func (m *ExternalDocumentation) XXX_Size() int { - return xxx_messageInfo_ExternalDocumentation.Size(m) -} -func (m *ExternalDocumentation) XXX_DiscardUnknown() { - xxx_messageInfo_ExternalDocumentation.DiscardUnknown(m) -} - -var xxx_messageInfo_ExternalDocumentation proto.InternalMessageInfo - -func (m *ExternalDocumentation) GetDescription() string { - if m != nil { - return m.Description - } - return "" -} - -func (m *ExternalDocumentation) GetUrl() string { - if m != nil { - return m.Url - } - return "" -} - -// `Schema` is a representation of OpenAPI v2 specification's Schema object. -// -// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#schemaObject -// -type Schema struct { - JsonSchema *JSONSchema `protobuf:"bytes,1,opt,name=json_schema,json=jsonSchema,proto3" json:"json_schema,omitempty"` - // Adds support for polymorphism. The discriminator is the schema property - // name that is used to differentiate between other schema that inherit this - // schema. The property name used MUST be defined at this schema and it MUST - // be in the required property list. When used, the value MUST be the name of - // this schema or any schema that inherits it. - Discriminator string `protobuf:"bytes,2,opt,name=discriminator,proto3" json:"discriminator,omitempty"` - // Relevant only for Schema "properties" definitions. Declares the property as - // "read only". This means that it MAY be sent as part of a response but MUST - // NOT be sent as part of the request. Properties marked as readOnly being - // true SHOULD NOT be in the required list of the defined schema. Default - // value is false. - ReadOnly bool `protobuf:"varint,3,opt,name=read_only,json=readOnly,proto3" json:"read_only,omitempty"` - // Additional external documentation for this schema. - ExternalDocs *ExternalDocumentation `protobuf:"bytes,5,opt,name=external_docs,json=externalDocs,proto3" json:"external_docs,omitempty"` - // A free-form property to include an example of an instance for this schema. - Example *any.Any `protobuf:"bytes,6,opt,name=example,proto3" json:"example,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *Schema) Reset() { *m = Schema{} } -func (m *Schema) String() string { return proto.CompactTextString(m) } -func (*Schema) ProtoMessage() {} -func (*Schema) Descriptor() ([]byte, []int) { - return fileDescriptor_ba35ad8af024fb48, []int{7} -} - -func (m *Schema) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Schema.Unmarshal(m, b) -} -func (m *Schema) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Schema.Marshal(b, m, deterministic) -} -func (m *Schema) XXX_Merge(src proto.Message) { - xxx_messageInfo_Schema.Merge(m, src) -} -func (m *Schema) XXX_Size() int { - return xxx_messageInfo_Schema.Size(m) -} -func (m *Schema) XXX_DiscardUnknown() { - xxx_messageInfo_Schema.DiscardUnknown(m) -} - -var xxx_messageInfo_Schema proto.InternalMessageInfo - -func (m *Schema) GetJsonSchema() *JSONSchema { - if m != nil { - return m.JsonSchema - } - return nil -} - -func (m *Schema) GetDiscriminator() string { - if m != nil { - return m.Discriminator - } - return "" -} - -func (m *Schema) GetReadOnly() bool { - if m != nil { - return m.ReadOnly - } - return false -} - -func (m *Schema) GetExternalDocs() *ExternalDocumentation { - if m != nil { - return m.ExternalDocs - } - return nil -} - -func (m *Schema) GetExample() *any.Any { - if m != nil { - return m.Example - } - return nil -} - -// `JSONSchema` represents properties from JSON Schema taken, and as used, in -// the OpenAPI v2 spec. -// -// This includes changes made by OpenAPI v2. -// -// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#schemaObject -// -// See also: https://cswr.github.io/JsonSchema/spec/basic_types/, -// https://github.com/json-schema-org/json-schema-spec/blob/master/schema.json -// -// TODO(ivucica): document fields -type JSONSchema struct { - // Ref is used to define an external reference to include in the message. - // This could be a fully qualified proto message reference, and that type must - // be imported into the protofile. If no message is identified, the Ref will - // be used verbatim in the output. - // For example: - // `ref: ".google.protobuf.Timestamp"`. - Ref string `protobuf:"bytes,3,opt,name=ref,proto3" json:"ref,omitempty"` - // The title of the schema. - Title string `protobuf:"bytes,5,opt,name=title,proto3" json:"title,omitempty"` - // A short description of the schema. - Description string `protobuf:"bytes,6,opt,name=description,proto3" json:"description,omitempty"` - Default string `protobuf:"bytes,7,opt,name=default,proto3" json:"default,omitempty"` - ReadOnly bool `protobuf:"varint,8,opt,name=read_only,json=readOnly,proto3" json:"read_only,omitempty"` - MultipleOf float64 `protobuf:"fixed64,10,opt,name=multiple_of,json=multipleOf,proto3" json:"multiple_of,omitempty"` - // Maximum represents an inclusive upper limit for a numeric instance. The - // value of MUST be a number, - Maximum float64 `protobuf:"fixed64,11,opt,name=maximum,proto3" json:"maximum,omitempty"` - ExclusiveMaximum bool `protobuf:"varint,12,opt,name=exclusive_maximum,json=exclusiveMaximum,proto3" json:"exclusive_maximum,omitempty"` - // minimum represents an inclusive lower limit for a numeric instance. The - // value of MUST be a number, - Minimum float64 `protobuf:"fixed64,13,opt,name=minimum,proto3" json:"minimum,omitempty"` - ExclusiveMinimum bool `protobuf:"varint,14,opt,name=exclusive_minimum,json=exclusiveMinimum,proto3" json:"exclusive_minimum,omitempty"` - MaxLength uint64 `protobuf:"varint,15,opt,name=max_length,json=maxLength,proto3" json:"max_length,omitempty"` - MinLength uint64 `protobuf:"varint,16,opt,name=min_length,json=minLength,proto3" json:"min_length,omitempty"` - Pattern string `protobuf:"bytes,17,opt,name=pattern,proto3" json:"pattern,omitempty"` - MaxItems uint64 `protobuf:"varint,20,opt,name=max_items,json=maxItems,proto3" json:"max_items,omitempty"` - MinItems uint64 `protobuf:"varint,21,opt,name=min_items,json=minItems,proto3" json:"min_items,omitempty"` - UniqueItems bool `protobuf:"varint,22,opt,name=unique_items,json=uniqueItems,proto3" json:"unique_items,omitempty"` - MaxProperties uint64 `protobuf:"varint,24,opt,name=max_properties,json=maxProperties,proto3" json:"max_properties,omitempty"` - MinProperties uint64 `protobuf:"varint,25,opt,name=min_properties,json=minProperties,proto3" json:"min_properties,omitempty"` - Required []string `protobuf:"bytes,26,rep,name=required,proto3" json:"required,omitempty"` - // Items in 'array' must be unique. - Array []string `protobuf:"bytes,34,rep,name=array,proto3" json:"array,omitempty"` - Type []JSONSchema_JSONSchemaSimpleTypes `protobuf:"varint,35,rep,packed,name=type,proto3,enum=grpc.gateway.protoc_gen_swagger.options.JSONSchema_JSONSchemaSimpleTypes" json:"type,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *JSONSchema) Reset() { *m = JSONSchema{} } -func (m *JSONSchema) String() string { return proto.CompactTextString(m) } -func (*JSONSchema) ProtoMessage() {} -func (*JSONSchema) Descriptor() ([]byte, []int) { - return fileDescriptor_ba35ad8af024fb48, []int{8} -} - -func (m *JSONSchema) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_JSONSchema.Unmarshal(m, b) -} -func (m *JSONSchema) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_JSONSchema.Marshal(b, m, deterministic) -} -func (m *JSONSchema) XXX_Merge(src proto.Message) { - xxx_messageInfo_JSONSchema.Merge(m, src) -} -func (m *JSONSchema) XXX_Size() int { - return xxx_messageInfo_JSONSchema.Size(m) -} -func (m *JSONSchema) XXX_DiscardUnknown() { - xxx_messageInfo_JSONSchema.DiscardUnknown(m) -} - -var xxx_messageInfo_JSONSchema proto.InternalMessageInfo - -func (m *JSONSchema) GetRef() string { - if m != nil { - return m.Ref - } - return "" -} - -func (m *JSONSchema) GetTitle() string { - if m != nil { - return m.Title - } - return "" -} - -func (m *JSONSchema) GetDescription() string { - if m != nil { - return m.Description - } - return "" -} - -func (m *JSONSchema) GetDefault() string { - if m != nil { - return m.Default - } - return "" -} - -func (m *JSONSchema) GetReadOnly() bool { - if m != nil { - return m.ReadOnly - } - return false -} - -func (m *JSONSchema) GetMultipleOf() float64 { - if m != nil { - return m.MultipleOf - } - return 0 -} - -func (m *JSONSchema) GetMaximum() float64 { - if m != nil { - return m.Maximum - } - return 0 -} - -func (m *JSONSchema) GetExclusiveMaximum() bool { - if m != nil { - return m.ExclusiveMaximum - } - return false -} - -func (m *JSONSchema) GetMinimum() float64 { - if m != nil { - return m.Minimum - } - return 0 -} - -func (m *JSONSchema) GetExclusiveMinimum() bool { - if m != nil { - return m.ExclusiveMinimum - } - return false -} - -func (m *JSONSchema) GetMaxLength() uint64 { - if m != nil { - return m.MaxLength - } - return 0 -} - -func (m *JSONSchema) GetMinLength() uint64 { - if m != nil { - return m.MinLength - } - return 0 -} - -func (m *JSONSchema) GetPattern() string { - if m != nil { - return m.Pattern - } - return "" -} - -func (m *JSONSchema) GetMaxItems() uint64 { - if m != nil { - return m.MaxItems - } - return 0 -} - -func (m *JSONSchema) GetMinItems() uint64 { - if m != nil { - return m.MinItems - } - return 0 -} - -func (m *JSONSchema) GetUniqueItems() bool { - if m != nil { - return m.UniqueItems - } - return false -} - -func (m *JSONSchema) GetMaxProperties() uint64 { - if m != nil { - return m.MaxProperties - } - return 0 -} - -func (m *JSONSchema) GetMinProperties() uint64 { - if m != nil { - return m.MinProperties - } - return 0 -} - -func (m *JSONSchema) GetRequired() []string { - if m != nil { - return m.Required - } - return nil -} - -func (m *JSONSchema) GetArray() []string { - if m != nil { - return m.Array - } - return nil -} - -func (m *JSONSchema) GetType() []JSONSchema_JSONSchemaSimpleTypes { - if m != nil { - return m.Type - } - return nil -} - -// `Tag` is a representation of OpenAPI v2 specification's Tag object. -// -// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#tagObject -// -type Tag struct { - // A short description for the tag. GFM syntax can be used for rich text - // representation. - Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` - // Additional external documentation for this tag. - ExternalDocs *ExternalDocumentation `protobuf:"bytes,3,opt,name=external_docs,json=externalDocs,proto3" json:"external_docs,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *Tag) Reset() { *m = Tag{} } -func (m *Tag) String() string { return proto.CompactTextString(m) } -func (*Tag) ProtoMessage() {} -func (*Tag) Descriptor() ([]byte, []int) { - return fileDescriptor_ba35ad8af024fb48, []int{9} -} - -func (m *Tag) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Tag.Unmarshal(m, b) -} -func (m *Tag) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Tag.Marshal(b, m, deterministic) -} -func (m *Tag) XXX_Merge(src proto.Message) { - xxx_messageInfo_Tag.Merge(m, src) -} -func (m *Tag) XXX_Size() int { - return xxx_messageInfo_Tag.Size(m) -} -func (m *Tag) XXX_DiscardUnknown() { - xxx_messageInfo_Tag.DiscardUnknown(m) -} - -var xxx_messageInfo_Tag proto.InternalMessageInfo - -func (m *Tag) GetDescription() string { - if m != nil { - return m.Description - } - return "" -} - -func (m *Tag) GetExternalDocs() *ExternalDocumentation { - if m != nil { - return m.ExternalDocs - } - return nil -} - -// `SecurityDefinitions` is a representation of OpenAPI v2 specification's -// Security Definitions object. -// -// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#securityDefinitionsObject -// -// A declaration of the security schemes available to be used in the -// specification. This does not enforce the security schemes on the operations -// and only serves to provide the relevant details for each scheme. -type SecurityDefinitions struct { - // A single security scheme definition, mapping a "name" to the scheme it - // defines. - Security map[string]*SecurityScheme `protobuf:"bytes,1,rep,name=security,proto3" json:"security,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *SecurityDefinitions) Reset() { *m = SecurityDefinitions{} } -func (m *SecurityDefinitions) String() string { return proto.CompactTextString(m) } -func (*SecurityDefinitions) ProtoMessage() {} -func (*SecurityDefinitions) Descriptor() ([]byte, []int) { - return fileDescriptor_ba35ad8af024fb48, []int{10} -} - -func (m *SecurityDefinitions) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SecurityDefinitions.Unmarshal(m, b) -} -func (m *SecurityDefinitions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SecurityDefinitions.Marshal(b, m, deterministic) -} -func (m *SecurityDefinitions) XXX_Merge(src proto.Message) { - xxx_messageInfo_SecurityDefinitions.Merge(m, src) -} -func (m *SecurityDefinitions) XXX_Size() int { - return xxx_messageInfo_SecurityDefinitions.Size(m) -} -func (m *SecurityDefinitions) XXX_DiscardUnknown() { - xxx_messageInfo_SecurityDefinitions.DiscardUnknown(m) -} - -var xxx_messageInfo_SecurityDefinitions proto.InternalMessageInfo - -func (m *SecurityDefinitions) GetSecurity() map[string]*SecurityScheme { - if m != nil { - return m.Security - } - return nil -} - -// `SecurityScheme` is a representation of OpenAPI v2 specification's -// Security Scheme object. -// -// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#securitySchemeObject -// -// Allows the definition of a security scheme that can be used by the -// operations. Supported schemes are basic authentication, an API key (either as -// a header or as a query parameter) and OAuth2's common flows (implicit, -// password, application and access code). -type SecurityScheme struct { - // The type of the security scheme. Valid values are "basic", - // "apiKey" or "oauth2". - Type SecurityScheme_Type `protobuf:"varint,1,opt,name=type,proto3,enum=grpc.gateway.protoc_gen_swagger.options.SecurityScheme_Type" json:"type,omitempty"` - // A short description for security scheme. - Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` - // The name of the header or query parameter to be used. - // Valid for apiKey. - Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` - // The location of the API key. Valid values are "query" or - // "header". - // Valid for apiKey. - In SecurityScheme_In `protobuf:"varint,4,opt,name=in,proto3,enum=grpc.gateway.protoc_gen_swagger.options.SecurityScheme_In" json:"in,omitempty"` - // The flow used by the OAuth2 security scheme. Valid values are - // "implicit", "password", "application" or "accessCode". - // Valid for oauth2. - Flow SecurityScheme_Flow `protobuf:"varint,5,opt,name=flow,proto3,enum=grpc.gateway.protoc_gen_swagger.options.SecurityScheme_Flow" json:"flow,omitempty"` - // The authorization URL to be used for this flow. This SHOULD be in - // the form of a URL. - // Valid for oauth2/implicit and oauth2/accessCode. - AuthorizationUrl string `protobuf:"bytes,6,opt,name=authorization_url,json=authorizationUrl,proto3" json:"authorization_url,omitempty"` - // The token URL to be used for this flow. This SHOULD be in the - // form of a URL. - // Valid for oauth2/password, oauth2/application and oauth2/accessCode. - TokenUrl string `protobuf:"bytes,7,opt,name=token_url,json=tokenUrl,proto3" json:"token_url,omitempty"` - // The available scopes for the OAuth2 security scheme. - // Valid for oauth2. - Scopes *Scopes `protobuf:"bytes,8,opt,name=scopes,proto3" json:"scopes,omitempty"` - Extensions map[string]*_struct.Value `protobuf:"bytes,9,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *SecurityScheme) Reset() { *m = SecurityScheme{} } -func (m *SecurityScheme) String() string { return proto.CompactTextString(m) } -func (*SecurityScheme) ProtoMessage() {} -func (*SecurityScheme) Descriptor() ([]byte, []int) { - return fileDescriptor_ba35ad8af024fb48, []int{11} -} - -func (m *SecurityScheme) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SecurityScheme.Unmarshal(m, b) -} -func (m *SecurityScheme) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SecurityScheme.Marshal(b, m, deterministic) -} -func (m *SecurityScheme) XXX_Merge(src proto.Message) { - xxx_messageInfo_SecurityScheme.Merge(m, src) -} -func (m *SecurityScheme) XXX_Size() int { - return xxx_messageInfo_SecurityScheme.Size(m) -} -func (m *SecurityScheme) XXX_DiscardUnknown() { - xxx_messageInfo_SecurityScheme.DiscardUnknown(m) -} - -var xxx_messageInfo_SecurityScheme proto.InternalMessageInfo - -func (m *SecurityScheme) GetType() SecurityScheme_Type { - if m != nil { - return m.Type - } - return SecurityScheme_TYPE_INVALID -} - -func (m *SecurityScheme) GetDescription() string { - if m != nil { - return m.Description - } - return "" -} - -func (m *SecurityScheme) GetName() string { - if m != nil { - return m.Name - } - return "" -} - -func (m *SecurityScheme) GetIn() SecurityScheme_In { - if m != nil { - return m.In - } - return SecurityScheme_IN_INVALID -} - -func (m *SecurityScheme) GetFlow() SecurityScheme_Flow { - if m != nil { - return m.Flow - } - return SecurityScheme_FLOW_INVALID -} - -func (m *SecurityScheme) GetAuthorizationUrl() string { - if m != nil { - return m.AuthorizationUrl - } - return "" -} - -func (m *SecurityScheme) GetTokenUrl() string { - if m != nil { - return m.TokenUrl - } - return "" -} - -func (m *SecurityScheme) GetScopes() *Scopes { - if m != nil { - return m.Scopes - } - return nil -} - -func (m *SecurityScheme) GetExtensions() map[string]*_struct.Value { - if m != nil { - return m.Extensions - } - return nil -} - -// `SecurityRequirement` is a representation of OpenAPI v2 specification's -// Security Requirement object. -// -// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#securityRequirementObject -// -// Lists the required security schemes to execute this operation. The object can -// have multiple security schemes declared in it which are all required (that -// is, there is a logical AND between the schemes). -// -// The name used for each property MUST correspond to a security scheme -// declared in the Security Definitions. -type SecurityRequirement struct { - // Each name must correspond to a security scheme which is declared in - // the Security Definitions. If the security scheme is of type "oauth2", - // then the value is a list of scope names required for the execution. - // For other security scheme types, the array MUST be empty. - SecurityRequirement map[string]*SecurityRequirement_SecurityRequirementValue `protobuf:"bytes,1,rep,name=security_requirement,json=securityRequirement,proto3" json:"security_requirement,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *SecurityRequirement) Reset() { *m = SecurityRequirement{} } -func (m *SecurityRequirement) String() string { return proto.CompactTextString(m) } -func (*SecurityRequirement) ProtoMessage() {} -func (*SecurityRequirement) Descriptor() ([]byte, []int) { - return fileDescriptor_ba35ad8af024fb48, []int{12} -} - -func (m *SecurityRequirement) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SecurityRequirement.Unmarshal(m, b) -} -func (m *SecurityRequirement) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SecurityRequirement.Marshal(b, m, deterministic) -} -func (m *SecurityRequirement) XXX_Merge(src proto.Message) { - xxx_messageInfo_SecurityRequirement.Merge(m, src) -} -func (m *SecurityRequirement) XXX_Size() int { - return xxx_messageInfo_SecurityRequirement.Size(m) -} -func (m *SecurityRequirement) XXX_DiscardUnknown() { - xxx_messageInfo_SecurityRequirement.DiscardUnknown(m) -} - -var xxx_messageInfo_SecurityRequirement proto.InternalMessageInfo - -func (m *SecurityRequirement) GetSecurityRequirement() map[string]*SecurityRequirement_SecurityRequirementValue { - if m != nil { - return m.SecurityRequirement - } - return nil -} - -// If the security scheme is of type "oauth2", then the value is a list of -// scope names required for the execution. For other security scheme types, -// the array MUST be empty. -type SecurityRequirement_SecurityRequirementValue struct { - Scope []string `protobuf:"bytes,1,rep,name=scope,proto3" json:"scope,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *SecurityRequirement_SecurityRequirementValue) Reset() { - *m = SecurityRequirement_SecurityRequirementValue{} -} -func (m *SecurityRequirement_SecurityRequirementValue) String() string { - return proto.CompactTextString(m) -} -func (*SecurityRequirement_SecurityRequirementValue) ProtoMessage() {} -func (*SecurityRequirement_SecurityRequirementValue) Descriptor() ([]byte, []int) { - return fileDescriptor_ba35ad8af024fb48, []int{12, 0} -} - -func (m *SecurityRequirement_SecurityRequirementValue) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SecurityRequirement_SecurityRequirementValue.Unmarshal(m, b) -} -func (m *SecurityRequirement_SecurityRequirementValue) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SecurityRequirement_SecurityRequirementValue.Marshal(b, m, deterministic) -} -func (m *SecurityRequirement_SecurityRequirementValue) XXX_Merge(src proto.Message) { - xxx_messageInfo_SecurityRequirement_SecurityRequirementValue.Merge(m, src) -} -func (m *SecurityRequirement_SecurityRequirementValue) XXX_Size() int { - return xxx_messageInfo_SecurityRequirement_SecurityRequirementValue.Size(m) -} -func (m *SecurityRequirement_SecurityRequirementValue) XXX_DiscardUnknown() { - xxx_messageInfo_SecurityRequirement_SecurityRequirementValue.DiscardUnknown(m) -} - -var xxx_messageInfo_SecurityRequirement_SecurityRequirementValue proto.InternalMessageInfo - -func (m *SecurityRequirement_SecurityRequirementValue) GetScope() []string { - if m != nil { - return m.Scope - } - return nil -} - -// `Scopes` is a representation of OpenAPI v2 specification's Scopes object. -// -// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#scopesObject -// -// Lists the available scopes for an OAuth2 security scheme. -type Scopes struct { - // Maps between a name of a scope to a short description of it (as the value - // of the property). - Scope map[string]string `protobuf:"bytes,1,rep,name=scope,proto3" json:"scope,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *Scopes) Reset() { *m = Scopes{} } -func (m *Scopes) String() string { return proto.CompactTextString(m) } -func (*Scopes) ProtoMessage() {} -func (*Scopes) Descriptor() ([]byte, []int) { - return fileDescriptor_ba35ad8af024fb48, []int{13} -} - -func (m *Scopes) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Scopes.Unmarshal(m, b) -} -func (m *Scopes) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Scopes.Marshal(b, m, deterministic) -} -func (m *Scopes) XXX_Merge(src proto.Message) { - xxx_messageInfo_Scopes.Merge(m, src) -} -func (m *Scopes) XXX_Size() int { - return xxx_messageInfo_Scopes.Size(m) -} -func (m *Scopes) XXX_DiscardUnknown() { - xxx_messageInfo_Scopes.DiscardUnknown(m) -} - -var xxx_messageInfo_Scopes proto.InternalMessageInfo - -func (m *Scopes) GetScope() map[string]string { - if m != nil { - return m.Scope - } - return nil -} - -func init() { - proto.RegisterEnum("grpc.gateway.protoc_gen_swagger.options.Swagger_SwaggerScheme", Swagger_SwaggerScheme_name, Swagger_SwaggerScheme_value) - proto.RegisterEnum("grpc.gateway.protoc_gen_swagger.options.JSONSchema_JSONSchemaSimpleTypes", JSONSchema_JSONSchemaSimpleTypes_name, JSONSchema_JSONSchemaSimpleTypes_value) - proto.RegisterEnum("grpc.gateway.protoc_gen_swagger.options.SecurityScheme_Type", SecurityScheme_Type_name, SecurityScheme_Type_value) - proto.RegisterEnum("grpc.gateway.protoc_gen_swagger.options.SecurityScheme_In", SecurityScheme_In_name, SecurityScheme_In_value) - proto.RegisterEnum("grpc.gateway.protoc_gen_swagger.options.SecurityScheme_Flow", SecurityScheme_Flow_name, SecurityScheme_Flow_value) - proto.RegisterType((*Swagger)(nil), "grpc.gateway.protoc_gen_swagger.options.Swagger") - proto.RegisterMapType((map[string]*_struct.Value)(nil), "grpc.gateway.protoc_gen_swagger.options.Swagger.ExtensionsEntry") - proto.RegisterMapType((map[string]*Response)(nil), "grpc.gateway.protoc_gen_swagger.options.Swagger.ResponsesEntry") - proto.RegisterType((*Operation)(nil), "grpc.gateway.protoc_gen_swagger.options.Operation") - proto.RegisterMapType((map[string]*_struct.Value)(nil), "grpc.gateway.protoc_gen_swagger.options.Operation.ExtensionsEntry") - proto.RegisterMapType((map[string]*Response)(nil), "grpc.gateway.protoc_gen_swagger.options.Operation.ResponsesEntry") - proto.RegisterType((*Response)(nil), "grpc.gateway.protoc_gen_swagger.options.Response") - proto.RegisterMapType((map[string]string)(nil), "grpc.gateway.protoc_gen_swagger.options.Response.ExamplesEntry") - proto.RegisterMapType((map[string]*_struct.Value)(nil), "grpc.gateway.protoc_gen_swagger.options.Response.ExtensionsEntry") - proto.RegisterType((*Info)(nil), "grpc.gateway.protoc_gen_swagger.options.Info") - proto.RegisterMapType((map[string]*_struct.Value)(nil), "grpc.gateway.protoc_gen_swagger.options.Info.ExtensionsEntry") - proto.RegisterType((*Contact)(nil), "grpc.gateway.protoc_gen_swagger.options.Contact") - proto.RegisterType((*License)(nil), "grpc.gateway.protoc_gen_swagger.options.License") - proto.RegisterType((*ExternalDocumentation)(nil), "grpc.gateway.protoc_gen_swagger.options.ExternalDocumentation") - proto.RegisterType((*Schema)(nil), "grpc.gateway.protoc_gen_swagger.options.Schema") - proto.RegisterType((*JSONSchema)(nil), "grpc.gateway.protoc_gen_swagger.options.JSONSchema") - proto.RegisterType((*Tag)(nil), "grpc.gateway.protoc_gen_swagger.options.Tag") - proto.RegisterType((*SecurityDefinitions)(nil), "grpc.gateway.protoc_gen_swagger.options.SecurityDefinitions") - proto.RegisterMapType((map[string]*SecurityScheme)(nil), "grpc.gateway.protoc_gen_swagger.options.SecurityDefinitions.SecurityEntry") - proto.RegisterType((*SecurityScheme)(nil), "grpc.gateway.protoc_gen_swagger.options.SecurityScheme") - proto.RegisterMapType((map[string]*_struct.Value)(nil), "grpc.gateway.protoc_gen_swagger.options.SecurityScheme.ExtensionsEntry") - proto.RegisterType((*SecurityRequirement)(nil), "grpc.gateway.protoc_gen_swagger.options.SecurityRequirement") - proto.RegisterMapType((map[string]*SecurityRequirement_SecurityRequirementValue)(nil), "grpc.gateway.protoc_gen_swagger.options.SecurityRequirement.SecurityRequirementEntry") - proto.RegisterType((*SecurityRequirement_SecurityRequirementValue)(nil), "grpc.gateway.protoc_gen_swagger.options.SecurityRequirement.SecurityRequirementValue") - proto.RegisterType((*Scopes)(nil), "grpc.gateway.protoc_gen_swagger.options.Scopes") - proto.RegisterMapType((map[string]string)(nil), "grpc.gateway.protoc_gen_swagger.options.Scopes.ScopeEntry") -} - -func init() { - proto.RegisterFile("protoc-gen-swagger/options/openapiv2.proto", fileDescriptor_ba35ad8af024fb48) -} - -var fileDescriptor_ba35ad8af024fb48 = []byte{ - // 1910 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x59, 0x5b, 0x73, 0x1a, 0xd7, - 0x1d, 0xcf, 0xc2, 0x02, 0xcb, 0x1f, 0x81, 0x8f, 0x8f, 0xe5, 0x74, 0x43, 0x6c, 0x57, 0xa1, 0xe9, - 0x54, 0x63, 0xd7, 0x28, 0x51, 0x1e, 0x9a, 0x49, 0xaf, 0x48, 0x22, 0xf2, 0xae, 0x65, 0xa0, 0x0b, - 0x8a, 0xe2, 0x76, 0x3c, 0xdb, 0xd5, 0x72, 0x40, 0x1b, 0xef, 0x85, 0xec, 0x45, 0x12, 0xfd, 0x04, - 0x7d, 0xee, 0xf4, 0x35, 0xdf, 0xa3, 0x0f, 0x7d, 0xea, 0x17, 0x68, 0x3f, 0x4b, 0x3b, 0x7d, 0xef, - 0x9c, 0xcb, 0xc2, 0x22, 0x61, 0x0f, 0xc8, 0x76, 0xfb, 0x90, 0x27, 0xce, 0xff, 0xf6, 0x3b, 0x97, - 0xff, 0xed, 0x9c, 0x05, 0x1e, 0x4e, 0xc2, 0x20, 0x0e, 0xec, 0xc7, 0x63, 0xe2, 0x3f, 0x8e, 0x2e, - 0xac, 0xf1, 0x98, 0x84, 0x3b, 0xc1, 0x24, 0x76, 0x02, 0x3f, 0xda, 0x09, 0x26, 0xc4, 0xb7, 0x26, - 0xce, 0xf9, 0x6e, 0x93, 0x29, 0xe1, 0x9f, 0x8c, 0xc3, 0x89, 0xdd, 0x1c, 0x5b, 0x31, 0xb9, 0xb0, - 0xa6, 0x9c, 0x67, 0x9b, 0x63, 0xe2, 0x9b, 0xc2, 0xb0, 0x29, 0x0c, 0xeb, 0x1f, 0x8c, 0x83, 0x60, - 0xec, 0x92, 0x1d, 0xa6, 0x72, 0x9a, 0x8c, 0x76, 0x2c, 0x5f, 0xe8, 0xd7, 0xef, 0x5d, 0x15, 0x45, - 0x71, 0x98, 0xd8, 0x31, 0x97, 0x36, 0xfe, 0xaa, 0x40, 0xa9, 0xcf, 0xc1, 0xb0, 0x0a, 0x25, 0x81, - 0xab, 0x4a, 0x5b, 0xd2, 0x76, 0xd9, 0x48, 0x49, 0xdc, 0x02, 0xd9, 0xf1, 0x47, 0x81, 0x9a, 0xdb, - 0x92, 0xb6, 0x2b, 0xbb, 0x8f, 0x9b, 0x2b, 0x2e, 0xab, 0xa9, 0xf9, 0xa3, 0xc0, 0x60, 0xa6, 0x18, - 0x83, 0x7c, 0x16, 0x44, 0xb1, 0x9a, 0x67, 0xc8, 0x6c, 0x8c, 0x3f, 0x84, 0xf2, 0xa9, 0x15, 0x11, - 0x73, 0x62, 0xc5, 0x67, 0xaa, 0xcc, 0x04, 0x0a, 0x65, 0xf4, 0xac, 0xf8, 0x0c, 0x7f, 0x0d, 0xa5, - 0xc8, 0x3e, 0x23, 0x1e, 0x89, 0xd4, 0xc2, 0x56, 0x7e, 0xbb, 0xb6, 0xfb, 0xab, 0x95, 0xa7, 0x15, - 0x1b, 0x4a, 0x7f, 0xfb, 0x0c, 0xc6, 0x48, 0xe1, 0x70, 0x1d, 0x14, 0x3b, 0xf0, 0xa3, 0x84, 0x42, - 0x17, 0xb7, 0xf2, 0x74, 0xd6, 0x94, 0xa6, 0xb2, 0x49, 0x18, 0x0c, 0x13, 0x9b, 0x44, 0x6a, 0x89, - 0xcb, 0x52, 0x1a, 0xbf, 0x80, 0x72, 0x48, 0xa2, 0x49, 0xe0, 0x47, 0x24, 0x52, 0x61, 0x2b, 0xbf, - 0x5d, 0xd9, 0xfd, 0xf5, 0xda, 0x6b, 0x32, 0x52, 0x84, 0xb6, 0x1f, 0x87, 0x53, 0x63, 0x8e, 0x88, - 0x03, 0xd8, 0x8c, 0x88, 0x9d, 0x84, 0x4e, 0x3c, 0x35, 0x87, 0x64, 0xe4, 0xf8, 0x0e, 0xb3, 0x54, - 0x2b, 0xec, 0xd0, 0x7f, 0xb1, 0xfa, 0x4c, 0x02, 0xe4, 0x60, 0x8e, 0x61, 0xdc, 0x89, 0xae, 0x33, - 0xf1, 0xd7, 0xa0, 0xa4, 0x6c, 0x75, 0x83, 0x6d, 0x67, 0xfd, 0x49, 0x0c, 0xf2, 0x6d, 0xe2, 0x84, - 0xc4, 0x23, 0x7e, 0x6c, 0xcc, 0xd0, 0xb0, 0x0d, 0x55, 0x72, 0x19, 0x93, 0xd0, 0xb7, 0x5c, 0x73, - 0x18, 0xd8, 0x91, 0x5a, 0x63, 0x7b, 0x58, 0xdd, 0x83, 0x6d, 0x61, 0x7d, 0x10, 0xd8, 0x09, 0xc5, - 0xb6, 0x28, 0xdb, 0xd8, 0x20, 0x73, 0x76, 0x84, 0xff, 0x00, 0x40, 0x69, 0x3f, 0x62, 0xa7, 0x74, - 0x8b, 0x6d, 0xe0, 0x37, 0x6b, 0xfb, 0xa3, 0x3d, 0x83, 0xe0, 0x0e, 0xc9, 0x60, 0xd6, 0x03, 0xa8, - 0x2d, 0xba, 0x0b, 0x23, 0xc8, 0xbf, 0x24, 0x53, 0x91, 0x1e, 0x74, 0x88, 0x0f, 0xa1, 0x70, 0x6e, - 0xb9, 0x09, 0x11, 0xb9, 0xf1, 0xe9, 0xca, 0x0b, 0x48, 0x91, 0x0d, 0x6e, 0xff, 0x45, 0xee, 0x73, - 0xa9, 0x7e, 0x0c, 0xb7, 0xae, 0xac, 0x67, 0xc9, 0x8c, 0x3f, 0x5d, 0x9c, 0xf1, 0xfd, 0x26, 0x4f, - 0xf0, 0x66, 0x9a, 0xe0, 0xcd, 0xaf, 0xa8, 0x34, 0x03, 0xdb, 0xd8, 0x83, 0xea, 0x42, 0x2a, 0xe0, - 0x0a, 0x94, 0x8e, 0x3b, 0x4f, 0x3b, 0xdd, 0x93, 0x0e, 0x7a, 0x0f, 0x2b, 0x20, 0x3f, 0x19, 0x0c, - 0x7a, 0x48, 0xc2, 0x65, 0x28, 0xd0, 0x51, 0x1f, 0xe5, 0x70, 0x11, 0x72, 0x27, 0x7d, 0x94, 0xc7, - 0x25, 0xc8, 0x9f, 0xf4, 0xfb, 0x48, 0xd6, 0x65, 0x45, 0x41, 0x65, 0x5d, 0x56, 0xca, 0x08, 0x74, - 0x59, 0xa9, 0xa2, 0x5a, 0xe3, 0xef, 0x45, 0x28, 0x77, 0x27, 0x24, 0x64, 0xbe, 0xa1, 0xf9, 0x1d, - 0x5b, 0xe3, 0x48, 0x95, 0x58, 0xd2, 0xb0, 0x31, 0x2b, 0x28, 0x89, 0xe7, 0x59, 0xe1, 0x94, 0xad, - 0x95, 0x16, 0x14, 0x4e, 0xe2, 0x2d, 0xa8, 0x0c, 0x49, 0x64, 0x87, 0x0e, 0x3b, 0x0c, 0x51, 0x14, - 0xb2, 0xac, 0xeb, 0x21, 0x24, 0xbf, 0x83, 0x10, 0xfa, 0x08, 0x36, 0x82, 0x74, 0x07, 0xa6, 0x33, - 0x54, 0x0b, 0x7c, 0x1d, 0x33, 0x9e, 0x36, 0xbc, 0x71, 0xb1, 0x30, 0xb3, 0xc5, 0xa2, 0xcc, 0x82, - 0xb3, 0xb5, 0xf2, 0xda, 0x67, 0xc7, 0xfa, 0x9a, 0x72, 0xa1, 0xce, 0xeb, 0x23, 0xb0, 0xb9, 0x67, - 0xf5, 0xed, 0x01, 0xc0, 0x90, 0x4c, 0x42, 0x62, 0x5b, 0x31, 0x19, 0xb2, 0xf2, 0xa1, 0x18, 0x19, - 0xce, 0x3b, 0xcc, 0xfb, 0xd3, 0x85, 0x94, 0xac, 0x32, 0xec, 0xbd, 0x1b, 0xec, 0xfa, 0x7b, 0x90, - 0x94, 0x3c, 0xa1, 0x1a, 0xff, 0xc8, 0x83, 0x92, 0x4e, 0x7a, 0x35, 0x2b, 0xa4, 0xeb, 0x59, 0x71, - 0x08, 0x45, 0xe6, 0x65, 0x4b, 0xcc, 0xb3, 0xb3, 0xba, 0xe3, 0x98, 0x99, 0x21, 0xcc, 0xf1, 0xef, - 0x41, 0x21, 0x97, 0x96, 0x37, 0x71, 0x09, 0xcd, 0xac, 0xf5, 0x5a, 0x59, 0xba, 0xde, 0x66, 0x5b, - 0x20, 0x70, 0x27, 0xcd, 0x00, 0xb1, 0xb5, 0x10, 0x06, 0x85, 0x35, 0x83, 0x3f, 0x03, 0xff, 0xea, - 0x28, 0xf8, 0x39, 0x54, 0x17, 0x66, 0x5f, 0xe2, 0x92, 0xcd, 0xac, 0x4b, 0xca, 0xff, 0x13, 0x8f, - 0xe6, 0x91, 0xdc, 0xf8, 0x67, 0x1e, 0x64, 0x7a, 0xef, 0xa1, 0xf3, 0xc7, 0x4e, 0xec, 0x12, 0x01, - 0xca, 0x89, 0xab, 0x3e, 0xce, 0x5d, 0xf7, 0xf1, 0x36, 0xa0, 0x98, 0x84, 0x5e, 0x64, 0x06, 0x23, - 0x33, 0x22, 0xe1, 0xb9, 0x63, 0x13, 0x51, 0x20, 0x6b, 0x8c, 0xdf, 0x1d, 0xf5, 0x39, 0x17, 0xeb, - 0x50, 0xb2, 0x03, 0x3f, 0xb6, 0xec, 0x58, 0x54, 0xc7, 0x4f, 0x56, 0x3e, 0xe4, 0x7d, 0x6e, 0x67, - 0xa4, 0x00, 0x14, 0xcb, 0x75, 0x6c, 0xe2, 0x47, 0x84, 0x55, 0xc1, 0x75, 0xb0, 0x8e, 0xb8, 0x9d, - 0x91, 0x02, 0xd0, 0xd2, 0x74, 0x4e, 0x42, 0x7a, 0xba, 0x6a, 0x91, 0xd7, 0x7d, 0x41, 0xe2, 0x17, - 0x0b, 0x91, 0x51, 0x62, 0x91, 0xf1, 0xcb, 0xb5, 0xae, 0x93, 0xaf, 0x8d, 0x8a, 0x77, 0xd4, 0x3f, - 0xdb, 0x50, 0x12, 0xe7, 0x45, 0xdb, 0x9c, 0x6f, 0x79, 0xa9, 0x4f, 0xd9, 0x98, 0x4e, 0x91, 0x84, - 0xae, 0x70, 0x25, 0x1d, 0x52, 0xd7, 0x13, 0xcf, 0x72, 0x5c, 0xe1, 0x37, 0x4e, 0x34, 0x76, 0xa0, - 0x24, 0x8e, 0x6a, 0x35, 0x98, 0xc6, 0x53, 0xb8, 0xbb, 0xb4, 0x8b, 0xad, 0x50, 0x28, 0xae, 0x83, - 0xfd, 0x2d, 0x07, 0x45, 0x5e, 0x04, 0xf0, 0x00, 0x2a, 0xdf, 0x44, 0x81, 0x6f, 0x8a, 0x52, 0x22, - 0xb1, 0x73, 0xf8, 0x6c, 0x65, 0x37, 0xe8, 0xfd, 0x6e, 0x47, 0x94, 0x13, 0xa0, 0x38, 0x02, 0xf5, - 0x63, 0xa8, 0x0e, 0x1d, 0xba, 0x02, 0xcf, 0xf1, 0xad, 0x38, 0x08, 0xc5, 0xe4, 0x8b, 0x4c, 0x7a, - 0xe7, 0x0f, 0x89, 0x35, 0x34, 0x03, 0xdf, 0x9d, 0xb2, 0xe3, 0x51, 0x0c, 0x85, 0x32, 0xba, 0xbe, - 0xbb, 0xe4, 0xde, 0x58, 0x78, 0x07, 0x4d, 0xbf, 0x09, 0x25, 0x51, 0xa9, 0x58, 0x74, 0x56, 0x76, - 0x37, 0xaf, 0x45, 0x40, 0xcb, 0x9f, 0x1a, 0xa9, 0x92, 0x2e, 0x2b, 0x32, 0x2a, 0x34, 0xbe, 0x2b, - 0x01, 0xcc, 0x37, 0x4e, 0xcf, 0x37, 0x24, 0x23, 0xe1, 0x5f, 0x3a, 0x9c, 0xa7, 0x7b, 0xe1, 0x35, - 0xe9, 0x5e, 0xbc, 0xee, 0x29, 0x15, 0x4a, 0x43, 0x32, 0xb2, 0x12, 0x37, 0x56, 0x4b, 0x3c, 0x59, - 0x04, 0xb9, 0x78, 0x54, 0xca, 0x95, 0xa3, 0xfa, 0x21, 0x54, 0xbc, 0xc4, 0x8d, 0x9d, 0x89, 0x4b, - 0xcc, 0x60, 0xa4, 0xc2, 0x96, 0xb4, 0x2d, 0x19, 0x90, 0xb2, 0xba, 0x23, 0x8a, 0xeb, 0x59, 0x97, - 0x8e, 0x97, 0x78, 0xec, 0x0a, 0x20, 0x19, 0x29, 0x89, 0x1f, 0xc1, 0x6d, 0x72, 0x69, 0xbb, 0x49, - 0xe4, 0x9c, 0x13, 0x33, 0xd5, 0xd9, 0x60, 0xf8, 0x68, 0x26, 0x78, 0x26, 0x94, 0x29, 0x8c, 0xe3, - 0x33, 0x95, 0xaa, 0x80, 0xe1, 0xe4, 0x15, 0x18, 0xa1, 0x53, 0xbb, 0x0a, 0x23, 0x94, 0xef, 0x03, - 0x78, 0xd6, 0xa5, 0xe9, 0x12, 0x7f, 0x1c, 0x9f, 0xa9, 0xb7, 0xb6, 0xa4, 0x6d, 0xd9, 0x28, 0x7b, - 0xd6, 0xe5, 0x11, 0x63, 0x30, 0xb1, 0xe3, 0xa7, 0x62, 0x24, 0xc4, 0x8e, 0x2f, 0xc4, 0x2a, 0x94, - 0x26, 0x56, 0x4c, 0x7d, 0xa8, 0xde, 0xe6, 0x67, 0x24, 0x48, 0x7a, 0x46, 0x14, 0xd7, 0x89, 0x89, - 0x17, 0xa9, 0x9b, 0xcc, 0x4e, 0xf1, 0xac, 0x4b, 0x8d, 0xd2, 0x4c, 0xe8, 0xf8, 0x42, 0x78, 0x57, - 0x08, 0x1d, 0x9f, 0x0b, 0x3f, 0x82, 0x8d, 0xc4, 0x77, 0xbe, 0x4d, 0x88, 0x90, 0xbf, 0xcf, 0x56, - 0x5e, 0xe1, 0x3c, 0xae, 0xf2, 0x63, 0xa8, 0x51, 0xf0, 0x49, 0x48, 0x2f, 0x84, 0xb1, 0x43, 0x22, - 0x55, 0x65, 0x20, 0x55, 0xcf, 0xba, 0xec, 0xcd, 0x98, 0x4c, 0xcd, 0xf1, 0xb3, 0x6a, 0x1f, 0x08, - 0x35, 0xc7, 0xcf, 0xa8, 0xd5, 0x41, 0x09, 0xf9, 0xad, 0x69, 0xa8, 0xd6, 0xf9, 0x6d, 0x31, 0xa5, - 0x69, 0xf0, 0x58, 0x61, 0x68, 0x4d, 0xd5, 0x06, 0x13, 0x70, 0x02, 0xbf, 0x00, 0x39, 0x9e, 0x4e, - 0x88, 0xfa, 0x23, 0xf6, 0xfe, 0xd5, 0x6e, 0x90, 0xa0, 0x99, 0x61, 0xdf, 0xa1, 0xd1, 0x3c, 0x98, - 0x4e, 0x48, 0x64, 0x30, 0xd8, 0xc6, 0x05, 0xdc, 0x5d, 0x2a, 0x5e, 0x7c, 0x1e, 0x94, 0xa1, 0xd0, - 0x32, 0x8c, 0xd6, 0x73, 0x24, 0x51, 0xfe, 0x5e, 0xb7, 0x7b, 0xd4, 0x6e, 0x75, 0x50, 0x8e, 0x12, - 0x5a, 0x67, 0xd0, 0x3e, 0x6c, 0x1b, 0x28, 0x4f, 0xdf, 0x10, 0x9d, 0xe3, 0xa3, 0x23, 0x24, 0x63, - 0x80, 0x62, 0xe7, 0xf8, 0xd9, 0x5e, 0xdb, 0x40, 0x05, 0x3a, 0xee, 0xee, 0xe9, 0xed, 0xfd, 0x01, - 0x2a, 0xd2, 0x71, 0x7f, 0x60, 0x68, 0x9d, 0x43, 0x54, 0xd2, 0x65, 0x45, 0x42, 0x39, 0x5d, 0x56, - 0x72, 0x28, 0xcf, 0xb3, 0x6b, 0xf6, 0xae, 0xc0, 0xe8, 0x8e, 0x2e, 0x2b, 0x77, 0xd0, 0xa6, 0x2e, - 0x2b, 0x3f, 0x40, 0xaa, 0x2e, 0x2b, 0x1f, 0xa2, 0x7b, 0xba, 0xac, 0xdc, 0x43, 0xf7, 0x75, 0x59, - 0xb9, 0x8f, 0x1e, 0xe8, 0xb2, 0xf2, 0x00, 0x35, 0x74, 0x59, 0xf9, 0x18, 0x3d, 0xd4, 0x65, 0xe5, - 0x21, 0x7a, 0xa4, 0xcb, 0xca, 0x23, 0xd4, 0x6c, 0xfc, 0x59, 0x82, 0xfc, 0xc0, 0x1a, 0xaf, 0xd0, - 0x5f, 0xaf, 0x15, 0x99, 0xfc, 0xdb, 0x2f, 0x32, 0x7c, 0x8b, 0x8d, 0x7f, 0x4b, 0x70, 0x67, 0xc9, - 0x73, 0x1c, 0x8f, 0x32, 0x37, 0x70, 0x89, 0x35, 0x41, 0xfd, 0x4d, 0x9e, 0xf7, 0x33, 0x9e, 0xb8, - 0x88, 0xa5, 0xd8, 0xf5, 0x18, 0xaa, 0x0b, 0xa2, 0x25, 0xdd, 0xf0, 0xd9, 0x62, 0x37, 0xfc, 0xd9, - 0xda, 0xeb, 0x10, 0x5f, 0x57, 0x32, 0xed, 0xf2, 0x3f, 0x45, 0xa8, 0x2d, 0x4a, 0x71, 0x4f, 0x44, - 0x32, 0x9d, 0xb8, 0x76, 0x83, 0xe7, 0x06, 0x87, 0x69, 0xd2, 0xf0, 0xe4, 0xc1, 0xbb, 0x82, 0x9f, - 0xd3, 0x1e, 0x9b, 0xcf, 0xf4, 0x58, 0x1d, 0x72, 0x8e, 0xcf, 0x2e, 0x4b, 0xb5, 0xdd, 0x2f, 0x6e, - 0xba, 0x0a, 0xcd, 0x37, 0x72, 0x8e, 0x4f, 0xf7, 0x34, 0x72, 0x83, 0x0b, 0x56, 0xef, 0xdf, 0x60, - 0x4f, 0x5f, 0xba, 0xc1, 0x85, 0xc1, 0x90, 0x68, 0x45, 0xb5, 0x92, 0xf8, 0x2c, 0x08, 0x9d, 0x3f, - 0xf2, 0x27, 0x29, 0x6d, 0xe1, 0xbc, 0x65, 0xa0, 0x05, 0xc1, 0x71, 0xe8, 0xd2, 0xe2, 0x16, 0x07, - 0x2f, 0x09, 0x57, 0xe2, 0x9d, 0x43, 0x61, 0x0c, 0x2a, 0x64, 0xef, 0x84, 0x60, 0x42, 0x22, 0xd6, - 0x37, 0xd6, 0x7b, 0x27, 0x50, 0x33, 0x43, 0x98, 0xe3, 0xf1, 0xc2, 0x85, 0x8d, 0xbf, 0x63, 0x0f, - 0x6f, 0xba, 0xd5, 0xff, 0xc3, 0xd5, 0xed, 0x29, 0xc8, 0x34, 0x68, 0x30, 0x82, 0x8d, 0xc1, 0xf3, - 0x5e, 0xdb, 0xd4, 0x3a, 0x5f, 0xb5, 0x8e, 0xb4, 0x03, 0xf4, 0x1e, 0xae, 0x01, 0x30, 0xce, 0x5e, - 0xab, 0xaf, 0xed, 0x23, 0x69, 0xa6, 0xd1, 0xea, 0x69, 0xe6, 0xd3, 0xf6, 0x73, 0x94, 0xc3, 0xb7, - 0xa0, 0xc2, 0x38, 0xdd, 0xd6, 0xf1, 0xe0, 0xc9, 0x2e, 0xca, 0x37, 0x3e, 0x85, 0x9c, 0xe6, 0x53, - 0x43, 0xad, 0x93, 0x01, 0xda, 0x00, 0x45, 0xeb, 0x98, 0xbf, 0x3d, 0x6e, 0x1b, 0xb4, 0x46, 0x56, - 0xa1, 0xac, 0x75, 0xcc, 0x27, 0xed, 0xd6, 0x41, 0xdb, 0x40, 0xb9, 0xc6, 0x37, 0x20, 0x53, 0x07, - 0x53, 0xf4, 0x2f, 0x8f, 0xba, 0x27, 0x19, 0xb3, 0xdb, 0x50, 0xe5, 0x9c, 0x67, 0xbd, 0x23, 0x6d, - 0x5f, 0x1b, 0x20, 0x69, 0xc6, 0xea, 0xb5, 0xfa, 0xfd, 0x93, 0xae, 0x71, 0x80, 0x72, 0x78, 0x13, - 0x10, 0x63, 0xb5, 0x7a, 0x54, 0xab, 0x35, 0xd0, 0xba, 0x1d, 0x94, 0x9f, 0x73, 0xf7, 0xf7, 0xdb, - 0xfd, 0xbe, 0xb9, 0xdf, 0x3d, 0x68, 0x23, 0xb9, 0xf1, 0xaf, 0xdc, 0xbc, 0xda, 0x64, 0xde, 0xe7, - 0xf8, 0x4f, 0x52, 0xe6, 0xcb, 0x62, 0x38, 0x17, 0x88, 0xd2, 0x73, 0xfc, 0x26, 0x8f, 0xff, 0x65, - 0x3c, 0xee, 0xdc, 0xd9, 0x27, 0xc7, 0x8c, 0xa4, 0xfe, 0x09, 0xa8, 0x4b, 0x0c, 0x98, 0xd7, 0x68, - 0x0f, 0x64, 0x41, 0x27, 0x3e, 0x21, 0x71, 0xa2, 0xfe, 0x9d, 0xb4, 0xd4, 0xe4, 0x55, 0x11, 0xf2, - 0x72, 0x31, 0x42, 0xde, 0xfa, 0xde, 0xae, 0x05, 0xd8, 0x5f, 0x24, 0x7a, 0xad, 0x66, 0xb9, 0xd2, - 0xcb, 0x6e, 0xa0, 0xb2, 0x4e, 0x7d, 0x61, 0xf6, 0xfc, 0x87, 0x1f, 0x9e, 0xd8, 0xfc, 0xe7, 0x00, - 0x73, 0xe6, 0x3a, 0x4f, 0xdc, 0xbd, 0xfd, 0xdf, 0xb5, 0xc6, 0x4e, 0x7c, 0x96, 0x9c, 0x36, 0xed, - 0xc0, 0xdb, 0xa1, 0x0b, 0x79, 0x4c, 0xec, 0x20, 0x9a, 0x46, 0x31, 0x11, 0xa4, 0x58, 0xd7, 0xce, - 0xab, 0xff, 0x8e, 0x38, 0x2d, 0x32, 0xd9, 0x67, 0xff, 0x0d, 0x00, 0x00, 0xff, 0xff, 0xe3, 0xbc, - 0xdd, 0xdd, 0xb3, 0x18, 0x00, 0x00, -} diff --git a/gateway/runtime/BUILD.bazel b/gateway/runtime/BUILD.bazel index 94bead7..ed32a61 100644 --- a/gateway/runtime/BUILD.bazel +++ b/gateway/runtime/BUILD.bazel @@ -17,15 +17,12 @@ go_library( "@com_github_binchencoder_letsgo//grpc:go_default_library", "@com_github_binchencoder_letsgo//hashring:go_default_library", "@com_github_binchencoder_skylb_api//proto:go_default_library", - "@com_github_golang_protobuf//descriptor:go_default_library_gen", - "@com_github_golang_protobuf//jsonpb:go_default_library_gen", - "@com_github_golang_protobuf//proto:go_default_library", - # "@com_github_grpc_ecosystem_grpc_gateway//internal:go_default_library", + "@com_github_golang_protobuf//ptypes:go_default_library_gen", "@com_github_grpc_ecosystem_grpc_gateway//utilities:go_default_library", - "@com_github_pborman_uuid//:go_default_library", + "@com_github_grpc_ecosystem_grpc_gateway//internal/httprule:go_default_library", + "@com_github_pborman_uuid//:go_default_library", + "@com_github_golang_protobuf//jsonpb:go_default_library_gen", "@go_googleapis//google/api:httpbody_go_proto", - "@io_bazel_rules_go//proto/wkt:any_go_proto", - "@io_bazel_rules_go//proto/wkt:descriptor_go_proto", "@io_bazel_rules_go//proto/wkt:duration_go_proto", "@io_bazel_rules_go//proto/wkt:field_mask_go_proto", "@io_bazel_rules_go//proto/wkt:timestamp_go_proto", @@ -34,7 +31,11 @@ go_library( "@org_golang_google_grpc//grpclog:go_default_library", "@org_golang_google_grpc//metadata:go_default_library", "@org_golang_google_grpc//status:go_default_library", - "@org_golang_google_grpc//:go_default_library", + "@org_golang_google_protobuf//encoding/protojson:go_default_library", + "@org_golang_google_protobuf//proto:go_default_library", + "@org_golang_google_protobuf//reflect/protoreflect:go_default_library", + "@org_golang_google_protobuf//reflect/protoregistry:go_default_library", + "@org_golang_google_grpc//:go_default_library", "@org_golang_x_net//context:go_default_library", ], ) @@ -46,7 +47,6 @@ go_test( "balancer_test.go", "context_test.go", "errors_test.go", - "fieldmask_test.go", "handler_test.go", "hook_test.go", "marshal_httpbodyproto_test.go", @@ -59,25 +59,32 @@ go_test( deps = [ "//examples/proto:go_default_library", "//gateway/internal:go_default_library", + "//gateway/runtime/internal/examplepb:go_default_library", "//httpoptions:go_default_library", "@com_github_binchencoder_letsgo//hashring:go_default_library", "@com_github_binchencoder_skylb_api//proto:go_default_library", - "@com_github_golang_protobuf//proto:go_default_library", - "@com_github_golang_protobuf//ptypes:go_default_library_gen", - # "@com_github_grpc_ecosystem_grpc_gateway//internal:go_default_library", "@com_github_grpc_ecosystem_grpc_gateway//utilities:go_default_library", + "@com_github_grpc_ecosystem_grpc_gateway//runtime/internal/examplepb:go_default_library", + "@com_github_golang_protobuf//ptypes:go_default_library_gen", + "@com_github_golang_protobuf//proto:go_default_library", + "@com_github_google_go_cmp//cmp:go_default_library", + "@com_github_google_go_cmp//cmp/cmpopts:go_default_library", "@go_googleapis//google/api:httpbody_go_proto", "@go_googleapis//google/rpc:errdetails_go_proto", + "@go_googleapis//google/rpc:status_go_proto", "@io_bazel_rules_go//proto/wkt:duration_go_proto", "@io_bazel_rules_go//proto/wkt:empty_go_proto", "@io_bazel_rules_go//proto/wkt:field_mask_go_proto", "@io_bazel_rules_go//proto/wkt:struct_go_proto", "@io_bazel_rules_go//proto/wkt:timestamp_go_proto", "@io_bazel_rules_go//proto/wkt:wrappers_go_proto", - "@org_golang_google_grpc//:go_default_library", "@org_golang_google_grpc//codes:go_default_library", "@org_golang_google_grpc//metadata:go_default_library", "@org_golang_google_grpc//status:go_default_library", - "@org_golang_x_net//context:go_default_library", + "@org_golang_google_protobuf//encoding/protojson:go_default_library", + "@org_golang_google_protobuf//proto:go_default_library", + "@org_golang_google_protobuf//testing/protocmp:go_default_library", + "@org_golang_google_grpc//:go_default_library", + "@org_golang_x_net//context:go_default_library", ], ) diff --git a/gateway/runtime/balancer.go b/gateway/runtime/balancer.go index 29bf5de..0d17ca7 100644 --- a/gateway/runtime/balancer.go +++ b/gateway/runtime/balancer.go @@ -2,13 +2,9 @@ package runtime import ( "context" - "fmt" - "reflect" - "strings" - "github.com/golang/protobuf/proto" "github.com/pborman/uuid" - "google.golang.org/grpc/grpclog" + "google.golang.org/protobuf/proto" options "github.com/binchencoder/ease-gateway/httpoptions" "github.com/binchencoder/letsgo/grpc" @@ -37,7 +33,8 @@ func PreLoadBalance(ctx context.Context, balancer, hashHeyType string, req proto return ctx } else { // Hash key is a proto field. - hashKey := fmt.Sprintf("%v", getProtoFiledValue(req, hashHeyType)) + // hashKey := fmt.Sprintf("%v", getProtoFiledValue(req, hashHeyType)) + hashKey := "" ctx = hashring.WithHashKey(ctx, hashKey) } } @@ -45,37 +42,37 @@ func PreLoadBalance(ctx context.Context, balancer, hashHeyType string, req proto return ctx } -func getProtoFiledValue(msg proto.Message, fieldPathStr string) reflect.Value { - fieldPath := strings.Split(fieldPathStr, ".") - v := reflect.ValueOf(msg).Elem() - for _, fieldName := range fieldPath { - f, _, err := fieldByProtoName(v, fieldName) - if err != nil { - grpclog.Printf("field not found in %T: %s, %v", msg, strings.Join(fieldPath, "."), err) - return reflect.Value{} - } - if !f.IsValid() { - grpclog.Printf("field not found in %T: %s", msg, strings.Join(fieldPath, ".")) - return reflect.Value{} - } +// func getProtoFiledValue(msg proto.Message, fieldPathStr string) reflect.Value { +// fieldPath := strings.Split(fieldPathStr, ".") +// v := reflect.ValueOf(msg).Elem() +// for _, fieldName := range fieldPath { +// f, _, err := fieldByProtoName(v, fieldName) +// if err != nil { +// grpclog.Printf("field not found in %T: %s, %v", msg, strings.Join(fieldPath, "."), err) +// return reflect.Value{} +// } +// if !f.IsValid() { +// grpclog.Printf("field not found in %T: %s", msg, strings.Join(fieldPath, ".")) +// return reflect.Value{} +// } - switch f.Kind() { - case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64, reflect.String, reflect.Uint32, reflect.Uint64: - v = f - case reflect.Ptr: - if f.IsNil() { - grpclog.Printf("field is nil in %T: %s", msg, strings.Join(fieldPath, ".")) - return reflect.Value{} - } - v = f.Elem() - continue - case reflect.Struct: - v = f - continue - default: - grpclog.Printf("unexpected type %s in %T", f.Type(), msg) - return reflect.Value{} - } - } - return v -} +// switch f.Kind() { +// case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64, reflect.String, reflect.Uint32, reflect.Uint64: +// v = f +// case reflect.Ptr: +// if f.IsNil() { +// grpclog.Printf("field is nil in %T: %s", msg, strings.Join(fieldPath, ".")) +// return reflect.Value{} +// } +// v = f.Elem() +// continue +// case reflect.Struct: +// v = f +// continue +// default: +// grpclog.Printf("unexpected type %s in %T", f.Type(), msg) +// return reflect.Value{} +// } +// } +// return v +// } diff --git a/gateway/runtime/balancer_test.go b/gateway/runtime/balancer_test.go index 8b6e4f9..29b50d8 100644 --- a/gateway/runtime/balancer_test.go +++ b/gateway/runtime/balancer_test.go @@ -4,7 +4,8 @@ import ( "context" "testing" - "github.com/golang/protobuf/proto" + pb "github.com/binchencoder/ease-gateway/gateway/runtime/internal/examplepb" + "google.golang.org/protobuf/proto" options "github.com/binchencoder/ease-gateway/httpoptions" "github.com/binchencoder/letsgo/hashring" @@ -13,75 +14,44 @@ import ( const DefaultHashKey = "8daad76a-dbb6-4f95-855d-7cfceb89afa1" type msgA struct { - StringValue string `protobuf:"bytes,1,opt,name=string_value" json:"string_value,omitempty"` + pb proto.Message } -func (ma *msgA) Reset() { *ma = msgA{} } -func (ma *msgA) String() string { return proto.CompactTextString(ma) } -func (*msgA) ProtoMessage() {} - -type msgB struct { - Nested *msgA `protobuf:"bytes,1,opt,name=nested" json:"nested,omitempty"` -} - -func (mb *msgB) Reset() { *mb = msgB{} } -func (mb *msgB) String() string { return proto.CompactTextString(mb) } -func (*msgB) ProtoMessage() {} - -func (mb *msgB) GetNested() *msgA { - if mb != nil { - return mb.Nested - } - return nil -} - -type msgC struct { - Nested *msgB `protobuf:"bytes,1,opt,name=nested" json:"nested,omitempty"` -} - -func (mc *msgC) Reset() { *mc = msgC{} } -func (mc *msgC) String() string { return proto.CompactTextString(mc) } -func (*msgC) ProtoMessage() {} - -func (mc *msgC) GetNested() *msgB { - if mc != nil { - return mc.Nested - } - return nil -} - -func TestGetProtoFiledValue(t *testing.T) { - a := msgA{ - StringValue: "foo", - } - v := getProtoFiledValue(&a, "string_value") - if v.String() != "foo" { - t.Errorf("Expect string %s but got %s", "foo", v.String()) - } - - b := msgB{ - Nested: &a, - } - v = getProtoFiledValue(&b, "nested.string_value") - if v.String() != "foo" { - t.Errorf("Expect string %s but got %s", "foo", v.String()) - } - - c := msgC{ - Nested: &b, - } - v = getProtoFiledValue(&c, "nested.nested.string_value") - if v.String() != "foo" { - t.Errorf("Expect string %s but got %s", "foo", v.String()) - } -} +// func TestGetProtoFiledValue(t *testing.T) { +// a := msgA{ +// StringValue: "foo", +// } +// v := getProtoFiledValue(&a, "string_value") +// if v.String() != "foo" { +// t.Errorf("Expect string %s but got %s", "foo", v.String()) +// } + +// b := msgB{ +// Nested: &a, +// } +// v = getProtoFiledValue(&b, "nested.string_value") +// if v.String() != "foo" { +// t.Errorf("Expect string %s but got %s", "foo", v.String()) +// } + +// c := msgC{ +// Nested: &b, +// } +// v = getProtoFiledValue(&c, "nested.nested.string_value") +// if v.String() != "foo" { +// t.Errorf("Expect string %s but got %s", "foo", v.String()) +// } +// } func TestPreLoadBalance(t *testing.T) { // Generate UUID. req := msgA{ - StringValue: DefaultHashKey, + pb: &pb.Proto3Message{ + StringValue: DefaultHashKey, + }, } - ctx := PreLoadBalance(context.Background(), options.LoadBalancer_CONSISTENT.String(), hashKeyUUID, &req) + + ctx := PreLoadBalance(context.Background(), options.LoadBalancer_CONSISTENT.String(), hashKeyUUID, req.pb) key := hashring.GetHashKeyOrEmpty(ctx) if len(key) != 36 { t.Errorf("Expect getting hash key with length 36s but got %s", key) @@ -89,9 +59,11 @@ func TestPreLoadBalance(t *testing.T) { // Proto field. req = msgA{ - StringValue: DefaultHashKey, + pb: &pb.Proto3Message{ + StringValue: DefaultHashKey, + }, } - ctx = PreLoadBalance(context.Background(), options.LoadBalancer_CONSISTENT.String(), "string_value", &req) + ctx = PreLoadBalance(context.Background(), options.LoadBalancer_CONSISTENT.String(), "string_value", req.pb) key = hashring.GetHashKeyOrEmpty(ctx) if key != DefaultHashKey { t.Errorf("Expect getting hash key %s but got %s", DefaultHashKey, key) diff --git a/gateway/runtime/context.go b/gateway/runtime/context.go index 07673f3..bb52a37 100644 --- a/gateway/runtime/context.go +++ b/gateway/runtime/context.go @@ -41,6 +41,8 @@ var ( DefaultContextTimeout = 0 * time.Second ) +type rpcMethodKey struct{} + func decodeBinHeader(v string) ([]byte, error) { if len(v)%4 == 0 { // Input was padded, or padding was not necessary. @@ -56,8 +58,8 @@ At a minimum, the RemoteAddr is included in the fashion of "X-Forwarded-For", except that the forwarded destination is not another HTTP service but rather a gRPC service. */ -func AnnotateContext(ctx context.Context, mux *ServeMux, req *http.Request) (context.Context, error) { - ctx, md, err := annotateContext(ctx, mux, req) +func AnnotateContext(ctx context.Context, mux *ServeMux, req *http.Request, rpcMethodName string) (context.Context, error) { + ctx, md, err := annotateContext(ctx, mux, req, rpcMethodName) if err != nil { return nil, err } @@ -70,8 +72,8 @@ func AnnotateContext(ctx context.Context, mux *ServeMux, req *http.Request) (con // AnnotateIncomingContext adds context information such as metadata from the request. // Attach metadata as incoming context. -func AnnotateIncomingContext(ctx context.Context, mux *ServeMux, req *http.Request) (context.Context, error) { - ctx, md, err := annotateContext(ctx, mux, req) +func AnnotateIncomingContext(ctx context.Context, mux *ServeMux, req *http.Request, rpcMethodName string) (context.Context, error) { + ctx, md, err := annotateContext(ctx, mux, req, rpcMethodName) if err != nil { return nil, err } @@ -82,7 +84,8 @@ func AnnotateIncomingContext(ctx context.Context, mux *ServeMux, req *http.Reque return metadata.NewIncomingContext(ctx, md), nil } -func annotateContext(ctx context.Context, mux *ServeMux, req *http.Request) (context.Context, metadata.MD, error) { +func annotateContext(ctx context.Context, mux *ServeMux, req *http.Request, rpcMethodName string) (context.Context, metadata.MD, error) { + ctx = withRPCMethod(ctx, rpcMethodName) var pairs []string timeout := DefaultContextTimeout if tm := req.Header.Get(metadataGrpcTimeout); tm != "" { @@ -234,3 +237,21 @@ func isPermanentHTTPHeader(hdr string) bool { } return false } + +// RPCMethod returns the method string for the server context. The returned +// string is in the format of "/package.service/method". +func RPCMethod(ctx context.Context) (string, bool) { + m := ctx.Value(rpcMethodKey{}) + if m == nil { + return "", false + } + ms, ok := m.(string) + if !ok { + return "", false + } + return ms, true +} + +func withRPCMethod(ctx context.Context, rpcMethodName string) context.Context { + return context.WithValue(ctx, rpcMethodKey{}, rpcMethodName) +} diff --git a/gateway/runtime/context_test.go b/gateway/runtime/context_test.go index b092938..b618f60 100644 --- a/gateway/runtime/context_test.go +++ b/gateway/runtime/context_test.go @@ -8,6 +8,7 @@ import ( "testing" "time" + // "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" "github.com/binchencoder/ease-gateway/gateway/runtime" "google.golang.org/grpc/metadata" ) @@ -18,13 +19,13 @@ const ( func TestAnnotateContext_WorksWithEmpty(t *testing.T) { ctx := context.Background() - + expectedRPCName := "/example.Example/Example" request, err := http.NewRequest("GET", "http://www.example.com", nil) if err != nil { t.Fatalf("http.NewRequest(%q, %q, nil) failed with %v; want success", "GET", "http://www.example.com", err) } request.Header.Add("Some-Irrelevant-Header", "some value") - annotated, err := runtime.AnnotateContext(ctx, runtime.NewServeMux(), request) + annotated, err := runtime.AnnotateContext(ctx, runtime.NewServeMux(), request, expectedRPCName) if err != nil { t.Errorf("runtime.AnnotateContext(ctx, %#v) failed with %v; want success", request, err) return @@ -37,6 +38,7 @@ func TestAnnotateContext_WorksWithEmpty(t *testing.T) { func TestAnnotateContext_ForwardsGrpcMetadata(t *testing.T) { ctx := context.Background() + expectedRPCName := "/example.Example/Example" request, err := http.NewRequest("GET", "http://www.example.com", nil) if err != nil { t.Fatalf("http.NewRequest(%q, %q, nil) failed with %v; want success", "GET", "http://www.example.com", err) @@ -46,7 +48,7 @@ func TestAnnotateContext_ForwardsGrpcMetadata(t *testing.T) { request.Header.Add("Grpc-Metadata-Foo-BAZ", "Value2") request.Header.Add("Grpc-Metadata-foo-bAz", "Value3") request.Header.Add("Authorization", "Token 1234567890") - annotated, err := runtime.AnnotateContext(ctx, runtime.NewServeMux(), request) + annotated, err := runtime.AnnotateContext(ctx, runtime.NewServeMux(), request, expectedRPCName) if err != nil { t.Errorf("runtime.AnnotateContext(ctx, %#v) failed with %v; want success", request, err) return @@ -67,10 +69,16 @@ func TestAnnotateContext_ForwardsGrpcMetadata(t *testing.T) { if got, want := md["authorization"], []string{"Token 1234567890"}; !reflect.DeepEqual(got, want) { t.Errorf(`md["authorization"] = %q want %q`, got, want) } + if m, ok := runtime.RPCMethod(annotated); !ok { + t.Errorf("runtime.RPCMethod(annotated) failed with no value; want %s", expectedRPCName) + } else if m != expectedRPCName { + t.Errorf("runtime.RPCMethod(annotated) failed with %s; want %s", m, expectedRPCName) + } } func TestAnnotateContext_ForwardGrpcBinaryMetadata(t *testing.T) { ctx := context.Background() + expectedRPCName := "/example.Example/Example" request, err := http.NewRequest("GET", "http://www.example.com", nil) if err != nil { t.Fatalf("http.NewRequest(%q, %q, nil) failed with %v; want success", "GET", "http://www.example.com", err) @@ -79,7 +87,7 @@ func TestAnnotateContext_ForwardGrpcBinaryMetadata(t *testing.T) { binData := []byte("\x00test-binary-data") request.Header.Add("Grpc-Metadata-Test-Bin", base64.StdEncoding.EncodeToString(binData)) - annotated, err := runtime.AnnotateContext(ctx, runtime.NewServeMux(), request) + annotated, err := runtime.AnnotateContext(ctx, runtime.NewServeMux(), request, expectedRPCName) if err != nil { t.Errorf("runtime.AnnotateContext(ctx, %#v) failed with %v; want success", request, err) return @@ -91,10 +99,16 @@ func TestAnnotateContext_ForwardGrpcBinaryMetadata(t *testing.T) { if got, want := md["test-bin"], []string{string(binData)}; !reflect.DeepEqual(got, want) { t.Errorf(`md["test-bin"] = %q want %q`, got, want) } + if m, ok := runtime.RPCMethod(annotated); !ok { + t.Errorf("runtime.RPCMethod(annotated) failed with no value; want %s", expectedRPCName) + } else if m != expectedRPCName { + t.Errorf("runtime.RPCMethod(annotated) failed with %s; want %s", m, expectedRPCName) + } } func TestAnnotateContext_XForwardedFor(t *testing.T) { ctx := context.Background() + expectedRPCName := "/example.Example/Example" request, err := http.NewRequest("GET", "http://bar.foo.example.com", nil) if err != nil { t.Fatalf("http.NewRequest(%q, %q, nil) failed with %v; want success", "GET", "http://bar.foo.example.com", err) @@ -102,7 +116,7 @@ func TestAnnotateContext_XForwardedFor(t *testing.T) { request.Header.Add("X-Forwarded-For", "192.0.2.100") // client request.RemoteAddr = "192.0.2.200:12345" // proxy - annotated, err := runtime.AnnotateContext(ctx, runtime.NewServeMux(), request) + annotated, err := runtime.AnnotateContext(ctx, runtime.NewServeMux(), request, expectedRPCName) if err != nil { t.Errorf("runtime.AnnotateContext(ctx, %#v) failed with %v; want success", request, err) return @@ -118,15 +132,21 @@ func TestAnnotateContext_XForwardedFor(t *testing.T) { if got, want := md["x-forwarded-for"], []string{"192.0.2.100, 192.0.2.200"}; !reflect.DeepEqual(got, want) { t.Errorf(`md["x-forwarded-for"] = %v want %v`, got, want) } + if m, ok := runtime.RPCMethod(annotated); !ok { + t.Errorf("runtime.RPCMethod(annotated) failed with no value; want %s", expectedRPCName) + } else if m != expectedRPCName { + t.Errorf("runtime.RPCMethod(annotated) failed with %s; want %s", m, expectedRPCName) + } } func TestAnnotateContext_SupportsTimeouts(t *testing.T) { ctx := context.Background() + expectedRPCName := "/example.Example/Example" request, err := http.NewRequest("GET", "http://example.com", nil) if err != nil { t.Fatalf(`http.NewRequest("GET", "http://example.com", nil failed with %v; want success`, err) } - annotated, err := runtime.AnnotateContext(ctx, runtime.NewServeMux(), request) + annotated, err := runtime.AnnotateContext(ctx, runtime.NewServeMux(), request, expectedRPCName) if err != nil { t.Errorf("runtime.AnnotateContext(ctx, %#v) failed with %v; want success", request, err) return @@ -138,7 +158,7 @@ func TestAnnotateContext_SupportsTimeouts(t *testing.T) { const acceptableError = 50 * time.Millisecond runtime.DefaultContextTimeout = 10 * time.Second - annotated, err = runtime.AnnotateContext(ctx, runtime.NewServeMux(), request) + annotated, err = runtime.AnnotateContext(ctx, runtime.NewServeMux(), request, expectedRPCName) if err != nil { t.Errorf("runtime.AnnotateContext(ctx, %#v) failed with %v; want success", request, err) return @@ -147,8 +167,8 @@ func TestAnnotateContext_SupportsTimeouts(t *testing.T) { if !ok { t.Errorf("annotated.Deadline() = _, false; want _, true") } - if got, want := deadline.Sub(time.Now()), runtime.DefaultContextTimeout; got-want > acceptableError || got-want < -acceptableError { - t.Errorf("deadline.Sub(time.Now()) = %v; want %v; with error %v", got, want, acceptableError) + if got, want := time.Until(deadline), runtime.DefaultContextTimeout; got-want > acceptableError || got-want < -acceptableError { + t.Errorf("time.Until(deadline) = %v; want %v; with error %v", got, want, acceptableError) } for _, spec := range []struct { @@ -181,7 +201,7 @@ func TestAnnotateContext_SupportsTimeouts(t *testing.T) { }, } { request.Header.Set("Grpc-Timeout", spec.timeout) - annotated, err = runtime.AnnotateContext(ctx, runtime.NewServeMux(), request) + annotated, err = runtime.AnnotateContext(ctx, runtime.NewServeMux(), request, expectedRPCName) if err != nil { t.Errorf("runtime.AnnotateContext(ctx, %#v) failed with %v; want success", request, err) return @@ -190,8 +210,13 @@ func TestAnnotateContext_SupportsTimeouts(t *testing.T) { if !ok { t.Errorf("annotated.Deadline() = _, false; want _, true; timeout = %q", spec.timeout) } - if got, want := deadline.Sub(time.Now()), spec.want; got-want > acceptableError || got-want < -acceptableError { - t.Errorf("deadline.Sub(time.Now()) = %v; want %v; with error %v; timeout= %q", got, want, acceptableError, spec.timeout) + if got, want := time.Until(deadline), spec.want; got-want > acceptableError || got-want < -acceptableError { + t.Errorf("time.Until(deadline) = %v; want %v; with error %v; timeout= %q", got, want, acceptableError, spec.timeout) + } + if m, ok := runtime.RPCMethod(annotated); !ok { + t.Errorf("runtime.RPCMethod(annotated) failed with no value; want %s", expectedRPCName) + } else if m != expectedRPCName { + t.Errorf("runtime.RPCMethod(annotated) failed with %s; want %s", m, expectedRPCName) } } } @@ -199,11 +224,12 @@ func TestAnnotateContext_SupportsCustomAnnotators(t *testing.T) { md1 := func(context.Context, *http.Request) metadata.MD { return metadata.New(map[string]string{"foo": "bar"}) } md2 := func(context.Context, *http.Request) metadata.MD { return metadata.New(map[string]string{"baz": "qux"}) } expected := metadata.New(map[string]string{"foo": "bar", "baz": "qux"}) + expectedRPCName := "/example.Example/Example" request, err := http.NewRequest("GET", "http://example.com", nil) if err != nil { t.Fatalf(`http.NewRequest("GET", "http://example.com", nil failed with %v; want success`, err) } - annotated, err := runtime.AnnotateContext(context.Background(), runtime.NewServeMux(runtime.WithMetadata(md1), runtime.WithMetadata(md2)), request) + annotated, err := runtime.AnnotateContext(context.Background(), runtime.NewServeMux(runtime.WithMetadata(md1), runtime.WithMetadata(md2)), request, expectedRPCName) if err != nil { t.Errorf("runtime.AnnotateContext(ctx, %#v) failed with %v; want success", request, err) return @@ -214,17 +240,22 @@ func TestAnnotateContext_SupportsCustomAnnotators(t *testing.T) { t.Errorf("metadata.MD[%s] = %v; want %v", key, a, e) } } + if m, ok := runtime.RPCMethod(annotated); !ok { + t.Errorf("runtime.RPCMethod(annotated) failed with no value; want %s", expectedRPCName) + } else if m != expectedRPCName { + t.Errorf("runtime.RPCMethod(annotated) failed with %s; want %s", m, expectedRPCName) + } } func TestAnnotateIncomingContext_WorksWithEmpty(t *testing.T) { ctx := context.Background() - + expectedRPCName := "/example.Example/Example" request, err := http.NewRequest("GET", "http://www.example.com", nil) if err != nil { t.Fatalf("http.NewRequest(%q, %q, nil) failed with %v; want success", "GET", "http://www.example.com", err) } request.Header.Add("Some-Irrelevant-Header", "some value") - annotated, err := runtime.AnnotateIncomingContext(ctx, runtime.NewServeMux(), request) + annotated, err := runtime.AnnotateIncomingContext(ctx, runtime.NewServeMux(), request, expectedRPCName) if err != nil { t.Errorf("runtime.AnnotateIncomingContext(ctx, %#v) failed with %v; want success", request, err) return @@ -233,10 +264,16 @@ func TestAnnotateIncomingContext_WorksWithEmpty(t *testing.T) { if !ok || len(md) != emptyForwardMetaCount { t.Errorf("Expected %d metadata items in context; got %v", emptyForwardMetaCount, md) } + if m, ok := runtime.RPCMethod(annotated); !ok { + t.Errorf("runtime.RPCMethod(annotated) failed with no value; want %s", expectedRPCName) + } else if m != expectedRPCName { + t.Errorf("runtime.RPCMethod(annotated) failed with %s; want %s", m, expectedRPCName) + } } func TestAnnotateIncomingContext_ForwardsGrpcMetadata(t *testing.T) { ctx := context.Background() + expectedRPCName := "/example.Example/Example" request, err := http.NewRequest("GET", "http://www.example.com", nil) if err != nil { t.Fatalf("http.NewRequest(%q, %q, nil) failed with %v; want success", "GET", "http://www.example.com", err) @@ -246,7 +283,7 @@ func TestAnnotateIncomingContext_ForwardsGrpcMetadata(t *testing.T) { request.Header.Add("Grpc-Metadata-Foo-BAZ", "Value2") request.Header.Add("Grpc-Metadata-foo-bAz", "Value3") request.Header.Add("Authorization", "Token 1234567890") - annotated, err := runtime.AnnotateIncomingContext(ctx, runtime.NewServeMux(), request) + annotated, err := runtime.AnnotateIncomingContext(ctx, runtime.NewServeMux(), request, expectedRPCName) if err != nil { t.Errorf("runtime.AnnotateIncomingContext(ctx, %#v) failed with %v; want success", request, err) return @@ -267,10 +304,16 @@ func TestAnnotateIncomingContext_ForwardsGrpcMetadata(t *testing.T) { if got, want := md["authorization"], []string{"Token 1234567890"}; !reflect.DeepEqual(got, want) { t.Errorf(`md["authorization"] = %q want %q`, got, want) } + if m, ok := runtime.RPCMethod(annotated); !ok { + t.Errorf("runtime.RPCMethod(annotated) failed with no value; want %s", expectedRPCName) + } else if m != expectedRPCName { + t.Errorf("runtime.RPCMethod(annotated) failed with %s; want %s", m, expectedRPCName) + } } func TestAnnotateIncomingContext_ForwardGrpcBinaryMetadata(t *testing.T) { ctx := context.Background() + expectedRPCName := "/example.Example/Example" request, err := http.NewRequest("GET", "http://www.example.com", nil) if err != nil { t.Fatalf("http.NewRequest(%q, %q, nil) failed with %v; want success", "GET", "http://www.example.com", err) @@ -279,7 +322,7 @@ func TestAnnotateIncomingContext_ForwardGrpcBinaryMetadata(t *testing.T) { binData := []byte("\x00test-binary-data") request.Header.Add("Grpc-Metadata-Test-Bin", base64.StdEncoding.EncodeToString(binData)) - annotated, err := runtime.AnnotateIncomingContext(ctx, runtime.NewServeMux(), request) + annotated, err := runtime.AnnotateIncomingContext(ctx, runtime.NewServeMux(), request, expectedRPCName) if err != nil { t.Errorf("runtime.AnnotateIncomingContext(ctx, %#v) failed with %v; want success", request, err) return @@ -291,10 +334,16 @@ func TestAnnotateIncomingContext_ForwardGrpcBinaryMetadata(t *testing.T) { if got, want := md["test-bin"], []string{string(binData)}; !reflect.DeepEqual(got, want) { t.Errorf(`md["test-bin"] = %q want %q`, got, want) } + if m, ok := runtime.RPCMethod(annotated); !ok { + t.Errorf("runtime.RPCMethod(annotated) failed with no value; want %s", expectedRPCName) + } else if m != expectedRPCName { + t.Errorf("runtime.RPCMethod(annotated) failed with %s; want %s", m, expectedRPCName) + } } func TestAnnotateIncomingContext_XForwardedFor(t *testing.T) { ctx := context.Background() + expectedRPCName := "/example.Example/Example" request, err := http.NewRequest("GET", "http://bar.foo.example.com", nil) if err != nil { t.Fatalf("http.NewRequest(%q, %q, nil) failed with %v; want success", "GET", "http://bar.foo.example.com", err) @@ -302,7 +351,7 @@ func TestAnnotateIncomingContext_XForwardedFor(t *testing.T) { request.Header.Add("X-Forwarded-For", "192.0.2.100") // client request.RemoteAddr = "192.0.2.200:12345" // proxy - annotated, err := runtime.AnnotateIncomingContext(ctx, runtime.NewServeMux(), request) + annotated, err := runtime.AnnotateIncomingContext(ctx, runtime.NewServeMux(), request, expectedRPCName) if err != nil { t.Errorf("runtime.AnnotateIncomingContext(ctx, %#v) failed with %v; want success", request, err) return @@ -318,18 +367,23 @@ func TestAnnotateIncomingContext_XForwardedFor(t *testing.T) { if got, want := md["x-forwarded-for"], []string{"192.0.2.100, 192.0.2.200"}; !reflect.DeepEqual(got, want) { t.Errorf(`md["x-forwarded-for"] = %v want %v`, got, want) } + if m, ok := runtime.RPCMethod(annotated); !ok { + t.Errorf("runtime.RPCMethod(annotated) failed with no value; want %s", expectedRPCName) + } else if m != expectedRPCName { + t.Errorf("runtime.RPCMethod(annotated) failed with %s; want %s", m, expectedRPCName) + } } func TestAnnotateIncomingContext_SupportsTimeouts(t *testing.T) { // While run all test, TestAnnotateContext_SupportsTimeouts() will change the DefaultContextTimeout, so reset it to zero. runtime.DefaultContextTimeout = 0 * time.Second - + expectedRPCName := "/example.Example/Example" ctx := context.Background() request, err := http.NewRequest("GET", "http://example.com", nil) if err != nil { t.Fatalf(`http.NewRequest("GET", "http://example.com", nil failed with %v; want success`, err) } - annotated, err := runtime.AnnotateIncomingContext(ctx, runtime.NewServeMux(), request) + annotated, err := runtime.AnnotateIncomingContext(ctx, runtime.NewServeMux(), request, expectedRPCName) if err != nil { t.Errorf("runtime.AnnotateIncomingContext(ctx, %#v) failed with %v; want success", request, err) return @@ -341,7 +395,7 @@ func TestAnnotateIncomingContext_SupportsTimeouts(t *testing.T) { const acceptableError = 50 * time.Millisecond runtime.DefaultContextTimeout = 10 * time.Second - annotated, err = runtime.AnnotateIncomingContext(ctx, runtime.NewServeMux(), request) + annotated, err = runtime.AnnotateIncomingContext(ctx, runtime.NewServeMux(), request, expectedRPCName) if err != nil { t.Errorf("runtime.AnnotateIncomingContext(ctx, %#v) failed with %v; want success", request, err) return @@ -350,8 +404,8 @@ func TestAnnotateIncomingContext_SupportsTimeouts(t *testing.T) { if !ok { t.Errorf("annotated.Deadline() = _, false; want _, true") } - if got, want := deadline.Sub(time.Now()), runtime.DefaultContextTimeout; got-want > acceptableError || got-want < -acceptableError { - t.Errorf("deadline.Sub(time.Now()) = %v; want %v; with error %v", got, want, acceptableError) + if got, want := time.Until(deadline), runtime.DefaultContextTimeout; got-want > acceptableError || got-want < -acceptableError { + t.Errorf("time.Until(deadline) = %v; want %v; with error %v", got, want, acceptableError) } for _, spec := range []struct { @@ -384,7 +438,7 @@ func TestAnnotateIncomingContext_SupportsTimeouts(t *testing.T) { }, } { request.Header.Set("Grpc-Timeout", spec.timeout) - annotated, err = runtime.AnnotateIncomingContext(ctx, runtime.NewServeMux(), request) + annotated, err = runtime.AnnotateIncomingContext(ctx, runtime.NewServeMux(), request, expectedRPCName) if err != nil { t.Errorf("runtime.AnnotateIncomingContext(ctx, %#v) failed with %v; want success", request, err) return @@ -393,8 +447,13 @@ func TestAnnotateIncomingContext_SupportsTimeouts(t *testing.T) { if !ok { t.Errorf("annotated.Deadline() = _, false; want _, true; timeout = %q", spec.timeout) } - if got, want := deadline.Sub(time.Now()), spec.want; got-want > acceptableError || got-want < -acceptableError { - t.Errorf("deadline.Sub(time.Now()) = %v; want %v; with error %v; timeout= %q", got, want, acceptableError, spec.timeout) + if got, want := time.Until(deadline), spec.want; got-want > acceptableError || got-want < -acceptableError { + t.Errorf("time.Until(deadline) = %v; want %v; with error %v; timeout= %q", got, want, acceptableError, spec.timeout) + } + if m, ok := runtime.RPCMethod(annotated); !ok { + t.Errorf("runtime.RPCMethod(annotated) failed with no value; want %s", expectedRPCName) + } else if m != expectedRPCName { + t.Errorf("runtime.RPCMethod(annotated) failed with %s; want %s", m, expectedRPCName) } } } @@ -402,11 +461,12 @@ func TestAnnotateIncomingContext_SupportsCustomAnnotators(t *testing.T) { md1 := func(context.Context, *http.Request) metadata.MD { return metadata.New(map[string]string{"foo": "bar"}) } md2 := func(context.Context, *http.Request) metadata.MD { return metadata.New(map[string]string{"baz": "qux"}) } expected := metadata.New(map[string]string{"foo": "bar", "baz": "qux"}) + expectedRPCName := "/example.Example/Example" request, err := http.NewRequest("GET", "http://example.com", nil) if err != nil { t.Fatalf(`http.NewRequest("GET", "http://example.com", nil failed with %v; want success`, err) } - annotated, err := runtime.AnnotateIncomingContext(context.Background(), runtime.NewServeMux(runtime.WithMetadata(md1), runtime.WithMetadata(md2)), request) + annotated, err := runtime.AnnotateIncomingContext(context.Background(), runtime.NewServeMux(runtime.WithMetadata(md1), runtime.WithMetadata(md2)), request, expectedRPCName) if err != nil { t.Errorf("runtime.AnnotateIncomingContext(ctx, %#v) failed with %v; want success", request, err) return @@ -417,4 +477,9 @@ func TestAnnotateIncomingContext_SupportsCustomAnnotators(t *testing.T) { t.Errorf("metadata.MD[%s] = %v; want %v", key, a, e) } } + if m, ok := runtime.RPCMethod(annotated); !ok { + t.Errorf("runtime.RPCMethod(annotated) failed with no value; want %s", expectedRPCName) + } else if m != expectedRPCName { + t.Errorf("runtime.RPCMethod(annotated) failed with %s; want %s", m, expectedRPCName) + } } diff --git a/gateway/runtime/convert.go b/gateway/runtime/convert.go index 2c27934..e122dd3 100644 --- a/gateway/runtime/convert.go +++ b/gateway/runtime/convert.go @@ -6,10 +6,10 @@ import ( "strconv" "strings" - "github.com/golang/protobuf/jsonpb" - "github.com/golang/protobuf/ptypes/duration" - "github.com/golang/protobuf/ptypes/timestamp" - "github.com/golang/protobuf/ptypes/wrappers" + durationpb "github.com/golang/protobuf/ptypes/duration" + timestamppb "github.com/golang/protobuf/ptypes/timestamp" + wrapperspb "github.com/golang/protobuf/ptypes/wrappers" + "google.golang.org/protobuf/encoding/protojson" ) // String just returns the given string. @@ -205,9 +205,10 @@ func BytesSlice(val, sep string) ([][]byte, error) { } // Timestamp converts the given RFC3339 formatted string into a timestamp.Timestamp. -func Timestamp(val string) (*timestamp.Timestamp, error) { - var r timestamp.Timestamp - err := jsonpb.UnmarshalString(val, &r) +func Timestamp(val string) (*timestamppb.Timestamp, error) { + var r timestamppb.Timestamp + unmarshaler := &protojson.UnmarshalOptions{} + err := unmarshaler.Unmarshal([]byte(val), &r) if err != nil { return nil, err } @@ -215,9 +216,10 @@ func Timestamp(val string) (*timestamp.Timestamp, error) { } // Duration converts the given string into a timestamp.Duration. -func Duration(val string) (*duration.Duration, error) { - var r duration.Duration - err := jsonpb.UnmarshalString(val, &r) +func Duration(val string) (*durationpb.Duration, error) { + var r durationpb.Duration + unmarshaler := &protojson.UnmarshalOptions{} + err := unmarshaler.Unmarshal([]byte(val), &r) if err != nil { return nil, err } @@ -265,54 +267,54 @@ func EnumSlice(val, sep string, enumValMap map[string]int32) ([]int32, error) { */ // StringValue well-known type support as wrapper around string type -func StringValue(val string) (*wrappers.StringValue, error) { - return &wrappers.StringValue{Value: val}, nil +func StringValue(val string) (*wrapperspb.StringValue, error) { + return &wrapperspb.StringValue{Value: val}, nil } // FloatValue well-known type support as wrapper around float32 type -func FloatValue(val string) (*wrappers.FloatValue, error) { +func FloatValue(val string) (*wrapperspb.FloatValue, error) { parsedVal, err := Float32(val) - return &wrappers.FloatValue{Value: parsedVal}, err + return &wrapperspb.FloatValue{Value: parsedVal}, err } // DoubleValue well-known type support as wrapper around float64 type -func DoubleValue(val string) (*wrappers.DoubleValue, error) { +func DoubleValue(val string) (*wrapperspb.DoubleValue, error) { parsedVal, err := Float64(val) - return &wrappers.DoubleValue{Value: parsedVal}, err + return &wrapperspb.DoubleValue{Value: parsedVal}, err } // BoolValue well-known type support as wrapper around bool type -func BoolValue(val string) (*wrappers.BoolValue, error) { +func BoolValue(val string) (*wrapperspb.BoolValue, error) { parsedVal, err := Bool(val) - return &wrappers.BoolValue{Value: parsedVal}, err + return &wrapperspb.BoolValue{Value: parsedVal}, err } // Int32Value well-known type support as wrapper around int32 type -func Int32Value(val string) (*wrappers.Int32Value, error) { +func Int32Value(val string) (*wrapperspb.Int32Value, error) { parsedVal, err := Int32(val) - return &wrappers.Int32Value{Value: parsedVal}, err + return &wrapperspb.Int32Value{Value: parsedVal}, err } // UInt32Value well-known type support as wrapper around uint32 type -func UInt32Value(val string) (*wrappers.UInt32Value, error) { +func UInt32Value(val string) (*wrapperspb.UInt32Value, error) { parsedVal, err := Uint32(val) - return &wrappers.UInt32Value{Value: parsedVal}, err + return &wrapperspb.UInt32Value{Value: parsedVal}, err } // Int64Value well-known type support as wrapper around int64 type -func Int64Value(val string) (*wrappers.Int64Value, error) { +func Int64Value(val string) (*wrapperspb.Int64Value, error) { parsedVal, err := Int64(val) - return &wrappers.Int64Value{Value: parsedVal}, err + return &wrapperspb.Int64Value{Value: parsedVal}, err } // UInt64Value well-known type support as wrapper around uint64 type -func UInt64Value(val string) (*wrappers.UInt64Value, error) { +func UInt64Value(val string) (*wrapperspb.UInt64Value, error) { parsedVal, err := Uint64(val) - return &wrappers.UInt64Value{Value: parsedVal}, err + return &wrapperspb.UInt64Value{Value: parsedVal}, err } // BytesValue well-known type support as wrapper around bytes[] type -func BytesValue(val string) (*wrappers.BytesValue, error) { +func BytesValue(val string) (*wrapperspb.BytesValue, error) { parsedVal, err := Bytes(val) - return &wrappers.BytesValue{Value: parsedVal}, err + return &wrapperspb.BytesValue{Value: parsedVal}, err } diff --git a/gateway/runtime/convert_test.go b/gateway/runtime/convert_test.go index 307e8c7..2c95fa1 100644 --- a/gateway/runtime/convert_test.go +++ b/gateway/runtime/convert_test.go @@ -1,71 +1,60 @@ package runtime_test import ( - "encoding/json" - "fmt" - "reflect" "testing" - "github.com/golang/protobuf/proto" - "github.com/golang/protobuf/ptypes/duration" - "github.com/golang/protobuf/ptypes/timestamp" + durationpb "github.com/golang/protobuf/ptypes/duration" + timestamppb "github.com/golang/protobuf/ptypes/timestamp" + // "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" "github.com/binchencoder/ease-gateway/gateway/runtime" + "google.golang.org/protobuf/proto" ) func TestConvertTimestamp(t *testing.T) { specs := []struct { name string input string - output *timestamp.Timestamp - wanterr error + output *timestamppb.Timestamp + wanterr bool }{ { name: "a valid RFC3339 timestamp", input: `"2016-05-10T10:19:13.123Z"`, - output: ×tamp.Timestamp{ + output: ×tamppb.Timestamp{ Seconds: 1462875553, Nanos: 123000000, }, - wanterr: nil, + wanterr: false, }, { name: "invalid timestamp", input: `"05-10-2016T10:19:13.123Z"`, output: nil, - wanterr: fmt.Errorf(`bad Timestamp: parsing time "05-10-2016T10:19:13.123Z" as "2006-01-02T15:04:05.999999999Z07:00": cannot parse "0-2016T10:19:13.123Z" as "2006"`), + wanterr: true, }, { - name: "JSON number", - input: "123", - output: nil, - wanterr: &json.UnmarshalTypeError{ - Value: "number", - Type: reflect.TypeOf("123"), - Offset: 3, - }, + name: "JSON number", + input: "123", + output: nil, + wanterr: true, }, { - name: "JSON bool", - input: "true", - output: nil, - wanterr: &json.UnmarshalTypeError{ - Value: "bool", - Type: reflect.TypeOf("123"), - Offset: 4, - }, + name: "JSON bool", + input: "true", + output: nil, + wanterr: true, }, } for _, spec := range specs { t.Run(spec.name, func(t *testing.T) { ts, err := runtime.Timestamp(spec.input) - if spec.wanterr != nil { - if !reflect.DeepEqual(err, spec.wanterr) { - t.Errorf("got unexpected error\n%#v\nexpected\n%#v", err, spec.wanterr) - } - return - } - if !proto.Equal(ts, spec.output) { + switch { + case err != nil && !spec.wanterr: + t.Errorf("got unexpected error\n%#v", err) + case err == nil && spec.wanterr: + t.Errorf("did not error when expecte") + case !proto.Equal(ts, spec.output): t.Errorf( "when testing %s; got\n%#v\nexpected\n%#v", spec.name, @@ -81,56 +70,47 @@ func TestConvertDuration(t *testing.T) { specs := []struct { name string input string - output *duration.Duration - wanterr error + output *durationpb.Duration + wanterr bool }{ { name: "a valid duration", input: `"123.456s"`, - output: &duration.Duration{ + output: &durationpb.Duration{ Seconds: 123, Nanos: 456000000, }, - wanterr: nil, + wanterr: false, }, { name: "invalid duration", input: `"123years"`, output: nil, - wanterr: fmt.Errorf(`bad Duration: time: unknown unit years in duration 123years`), + wanterr: true, }, { - name: "JSON number", - input: "123", - output: nil, - wanterr: &json.UnmarshalTypeError{ - Value: "number", - Type: reflect.TypeOf("123"), - Offset: 3, - }, + name: "JSON number", + input: "123", + output: nil, + wanterr: true, }, { - name: "JSON bool", - input: "true", - output: nil, - wanterr: &json.UnmarshalTypeError{ - Value: "bool", - Type: reflect.TypeOf("123"), - Offset: 4, - }, + name: "JSON bool", + input: "true", + output: nil, + wanterr: true, }, } for _, spec := range specs { t.Run(spec.name, func(t *testing.T) { ts, err := runtime.Duration(spec.input) - if spec.wanterr != nil { - if !reflect.DeepEqual(err, spec.wanterr) { - t.Errorf("got unexpected error\n%#v\nexpected\n%#v", err, spec.wanterr) - } - return - } - if !proto.Equal(ts, spec.output) { + switch { + case err != nil && !spec.wanterr: + t.Errorf("got unexpected error\n%#v", err) + case err == nil && spec.wanterr: + t.Errorf("did not error when expecte") + case !proto.Equal(ts, spec.output): t.Errorf( "when testing %s; got\n%#v\nexpected\n%#v", spec.name, diff --git a/gateway/runtime/errors.go b/gateway/runtime/errors.go index 704128d..ed7603d 100644 --- a/gateway/runtime/errors.go +++ b/gateway/runtime/errors.go @@ -7,6 +7,7 @@ import ( "strings" "github.com/golang/protobuf/jsonpb" + "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/grpclog" @@ -16,6 +17,12 @@ import ( fpb "github.com/binchencoder/gateway-proto/frontend" ) +// ErrorHandlerFunc is the signature used to configure error handling. +type ErrorHandlerFunc func(context.Context, *ServeMux, Marshaler, http.ResponseWriter, *http.Request, error) + +// StreamErrorHandlerFunc is the signature used to configure stream error handling. +type StreamErrorHandlerFunc func(context.Context, error) *status.Status + // HTTPStatusFromCode converts a gRPC error code into the corresponding HTTP response status. // See: https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto func HTTPStatusFromCode(code codes.Code) int { @@ -61,78 +68,27 @@ func HTTPStatusFromCode(code codes.Code) int { return http.StatusInternalServerError } -var ( - // HTTPError replies to the request with an error. - // - // HTTPError is called: - // - From generated per-endpoint gateway handler code, when calling the backend results in an error. - // - From gateway runtime code, when forwarding the response message results in an error. - // - // The default value for HTTPError calls the custom error handler configured on the ServeMux via the - // WithProtoErrorHandler serve option if that option was used, calling GlobalHTTPErrorHandler otherwise. - // - // To customize the error handling of a particular ServeMux instance, use the WithProtoErrorHandler - // serve option. - // - // To customize the error format for all ServeMux instances not using the WithProtoErrorHandler serve - // option, set GlobalHTTPErrorHandler to a custom function. - // - // Setting this variable directly to customize error format is deprecated. - HTTPError = MuxOrGlobalHTTPError - - // GlobalHTTPErrorHandler is the HTTPError handler for all ServeMux instances not using the - // WithProtoErrorHandler serve option. - // - // You can set a custom function to this variable to customize error format. - GlobalHTTPErrorHandler = DefaultHTTPError - - // OtherErrorHandler handles gateway errors from parsing and routing client requests for all - // ServeMux instances not using the WithProtoErrorHandler serve option. - // - // It returns the following error codes: StatusMethodNotAllowed StatusNotFound StatusBadRequest - // - // To customize parsing and routing error handling of a particular ServeMux instance, use the - // WithProtoErrorHandler serve option. - // - // To customize parsing and routing error handling of all ServeMux instances not using the - // WithProtoErrorHandler serve option, set a custom function to this variable. - OtherErrorHandler = DefaultOtherErrorHandler -) - -// MuxOrGlobalHTTPError uses the mux-configured error handler, falling back to GlobalErrorHandler. -func MuxOrGlobalHTTPError(ctx context.Context, mux *ServeMux, marshaler Marshaler, w http.ResponseWriter, r *http.Request, err error) { - if mux.protoErrorHandler != nil { - mux.protoErrorHandler(ctx, mux, marshaler, w, r, err) - } else { - GlobalHTTPErrorHandler(ctx, mux, marshaler, w, r, err) - } +// HTTPError uses the mux-configured error handler. +func HTTPError(ctx context.Context, mux *ServeMux, marshaler Marshaler, w http.ResponseWriter, r *http.Request, err error) { + mux.errorHandler(ctx, mux, marshaler, w, r, err) } -// DefaultHTTPError is the default implementation of HTTPError. -// If "err" is an error from gRPC system, the function replies with the status code mapped by HTTPStatusFromCode. +// DefaultHTTPErrorHandler is the default error handler. +// If "err" is a gRPC Status, the function replies with the status code mapped by HTTPStatusFromCode. // If otherwise, it replies with http.StatusInternalServerError. // -// The response body returned by this function is a JSON object, -// which contains a member whose key is "error" and whose value is err.Error(). -func DefaultHTTPError(ctx context.Context, mux *ServeMux, marshaler Marshaler, w http.ResponseWriter, r *http.Request, err error) { - const fallback = `{"error": "failed to marshal error message"}` +// The response body written by this function is a Status message marshaled by the Marshaler. +func DefaultHTTPErrorHandler(ctx context.Context, mux *ServeMux, marshaler Marshaler, w http.ResponseWriter, r *http.Request, err error) { + // return Internal when Marshal failed + const fallback = `{"code": 13, "message": "failed to marshal error message"}` - s, ok := status.FromError(err) - if !ok { - s = status.New(codes.Unknown, err.Error()) - } + s := status.Convert(err) + pb := s.Proto() w.Header().Del("Trailer") w.Header().Del("Transfer-Encoding") - contentType := marshaler.ContentType() - // Check marshaler on run time in order to keep backwards compatibility - // An interface param needs to be added to the ContentType() function on - // the Marshal interface to be able to remove this check - if typeMarshaler, ok := marshaler.(contentTypeMarshaler); ok { - pb := s.Proto() - contentType = typeMarshaler.ContentTypeFromMessage(pb) - } + contentType := marshaler.ContentType(pb) w.Header().Set("Content-Type", contentType) e := fpb.Error{} @@ -189,8 +145,6 @@ func DefaultHTTPError(ctx context.Context, mux *ServeMux, marshaler Marshaler, w } } -// DefaultOtherErrorHandler is the default implementation of OtherErrorHandler. -// It simply writes a string representation of the given error into "w". -func DefaultOtherErrorHandler(w http.ResponseWriter, _ *http.Request, msg string, code int) { - http.Error(w, msg, code) +func DefaultStreamErrorHandler(_ context.Context, err error) *status.Status { + return status.Convert(err) } diff --git a/gateway/runtime/errors_test.go b/gateway/runtime/errors_test.go index d1589b7..7f91013 100644 --- a/gateway/runtime/errors_test.go +++ b/gateway/runtime/errors_test.go @@ -2,15 +2,17 @@ package runtime_test import ( "context" - "encoding/json" "fmt" "net/http" "net/http/httptest" + "strconv" "strings" "testing" + // "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" "github.com/binchencoder/ease-gateway/gateway/runtime" "google.golang.org/genproto/googleapis/rpc/errdetails" + statuspb "google.golang.org/genproto/googleapis/rpc/status" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) @@ -22,7 +24,7 @@ func TestDefaultHTTPError(t *testing.T) { &errdetails.PreconditionFailure{}, ) - for _, spec := range []struct { + for i, spec := range []struct { err error status int msg string @@ -60,43 +62,39 @@ func TestDefaultHTTPError(t *testing.T) { msg: "example error", }, } { - w := httptest.NewRecorder() - req, _ := http.NewRequest("", "", nil) // Pass in an empty request to match the signature - runtime.DefaultHTTPError(ctx, &runtime.ServeMux{}, &runtime.JSONPb{}, w, req, spec.err) + t.Run(strconv.Itoa(i), func(t *testing.T) { + w := httptest.NewRecorder() + req, _ := http.NewRequest("", "", nil) // Pass in an empty request to match the signature + mux := runtime.NewServeMux() + marshaler := &runtime.JSONPb{} + runtime.HTTPError(ctx, mux, marshaler, w, req, spec.err) - if got, want := w.Header().Get("Content-Type"), "application/json"; got != want { - t.Errorf(`w.Header().Get("Content-Type") = %q; want %q; on spec.err=%v`, got, want, spec.err) - } - if got, want := w.Code, spec.status; got != want { - t.Errorf("w.Code = %d; want %d", got, want) - } - - body := make(map[string]interface{}) - if err := json.Unmarshal(w.Body.Bytes(), &body); err != nil { - t.Errorf("json.Unmarshal(%q, &body) failed with %v; want success", w.Body.Bytes(), err) - continue - } - - if got, want := body["error"].(string), spec.msg; !strings.Contains(got, want) { - t.Errorf(`body["error"] = %q; want %q; on spec.err=%v`, got, want, spec.err) - } - if got, want := body["message"].(string), spec.msg; !strings.Contains(got, want) { - t.Errorf(`body["message"] = %q; want %q; on spec.err=%v`, got, want, spec.err) - } + if got, want := w.Header().Get("Content-Type"), "application/json"; got != want { + t.Errorf(`w.Header().Get("Content-Type") = %q; want %q; on spec.err=%v`, got, want, spec.err) + } + if got, want := w.Code, spec.status; got != want { + t.Errorf("w.Code = %d; want %d", got, want) + } - if spec.details != "" { - details, ok := body["details"].([]interface{}) - if !ok { - t.Errorf(`body["details"] = %T; want %T`, body["details"], []interface{}{}) - continue + var st statuspb.Status + if err := marshaler.Unmarshal(w.Body.Bytes(), &st); err != nil { + t.Errorf("marshaler.Unmarshal(%q, &body) failed with %v; want success", w.Body.Bytes(), err) + return } - if len(details) != 1 { - t.Errorf(`len(body["details"]) = %v; want 1`, len(details)) - continue + + if got, want := st.Message, spec.msg; !strings.Contains(got, want) { + t.Errorf(`st.Message = %q; want %q; on spec.err=%v`, got, want, spec.err) } - if details[0].(map[string]interface{})["@type"] != spec.details { - t.Errorf(`details.@type = %s; want %s`, details[0].(map[string]interface{})["@type"], spec.details) + + if spec.details != "" { + if len(st.Details) != 1 { + t.Errorf(`len(st.Details) = %v; want 1`, len(st.Details)) + return + } + if st.Details[0].TypeUrl != spec.details { + t.Errorf(`details.type_url = %s; want %s`, st.Details[0].TypeUrl, spec.details) + } } - } + }) } } diff --git a/gateway/runtime/fieldmask.go b/gateway/runtime/fieldmask.go index 341aad5..5cd931a 100644 --- a/gateway/runtime/fieldmask.go +++ b/gateway/runtime/fieldmask.go @@ -2,42 +2,29 @@ package runtime import ( "encoding/json" + "fmt" "io" "strings" - descriptor2 "github.com/golang/protobuf/descriptor" - "github.com/golang/protobuf/protoc-gen-go/descriptor" "google.golang.org/genproto/protobuf/field_mask" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/reflect/protoreflect" ) -func translateName(name string, md *descriptor.DescriptorProto) (string, *descriptor.DescriptorProto) { - // TODO - should really gate this with a test that the marshaller has used json names - if md != nil { - for _, f := range md.Field { - if f.JsonName != nil && f.Name != nil && *f.JsonName == name { - var subType *descriptor.DescriptorProto - - // If the field has a TypeName then we retrieve the nested type for translating the embedded message names. - if f.TypeName != nil { - typeSplit := strings.Split(*f.TypeName, ".") - typeName := typeSplit[len(typeSplit)-1] - for _, t := range md.NestedType { - if typeName == *t.Name { - subType = t - } - } - } - return *f.Name, subType - } - } +func getFieldByName(fields protoreflect.FieldDescriptors, name string) protoreflect.FieldDescriptor { + fd := fields.ByName(protoreflect.Name(name)) + if fd != nil { + return fd } - return name, nil + + return fields.ByJSONName(name) } // FieldMaskFromRequestBody creates a FieldMask printing all complete paths from the JSON body. -func FieldMaskFromRequestBody(r io.Reader, md *descriptor.DescriptorProto) (*field_mask.FieldMask, error) { +func FieldMaskFromRequestBody(r io.Reader, msg proto.Message) (*field_mask.FieldMask, error) { fm := &field_mask.FieldMask{} var root interface{} + if err := json.NewDecoder(r).Decode(&root); err != nil { if err == io.EOF { return fm, nil @@ -45,27 +32,59 @@ func FieldMaskFromRequestBody(r io.Reader, md *descriptor.DescriptorProto) (*fie return nil, err } - queue := []fieldMaskPathItem{{node: root, md: md}} + queue := []fieldMaskPathItem{{node: root, msg: msg.ProtoReflect()}} + var repeatedChild *fieldMaskPathItem for len(queue) > 0 { // dequeue an item item := queue[0] queue = queue[1:] - if m, ok := item.node.(map[string]interface{}); ok { + m, ok := item.node.(map[string]interface{}) + switch { + case ok: // if the item is an object, then enqueue all of its children for k, v := range m { - protoName, subMd := translateName(k, item.md) - if subMsg, ok := v.(descriptor2.Message); ok { - _, subMd = descriptor2.ForMessage(subMsg) + if item.msg == nil { + return nil, fmt.Errorf("JSON structure did not match request type") + } + + fd := getFieldByName(item.msg.Descriptor().Fields(), k) + if fd == nil { + return nil, fmt.Errorf("could not find field %q in %q", k, item.msg.Descriptor().FullName()) + } + child := fieldMaskPathItem{ + path: append(item.path, string(fd.FullName().Name())), + node: v, + } + switch { + case fd.IsList(), fd.IsMap(): + if repeatedChild != nil { + // This is implied by the rule that any repeated fields must be + // last in the paths. + // Ref: https://github.com/protocolbuffers/protobuf/blob/6b0ff74ecf63e26c7315f6745de36aff66deb59d/src/google/protobuf/field_mask.proto#L85-L86 + return nil, fmt.Errorf("only one repeated value is allowed per field_mask") + } + repeatedChild = &child + // Don't add to paths until the end + case fd.Message() != nil: + child.msg = item.msg.Get(fd).Message() + fallthrough + default: + queue = append(queue, child) } - queue = append(queue, fieldMaskPathItem{path: append(item.path, protoName), node: v, md: subMd}) } - } else if len(item.path) > 0 { + case len(item.path) > 0: // otherwise, it's a leaf node so print its path fm.Paths = append(fm.Paths, strings.Join(item.path, ".")) } } + // Add any repeated fields last, as per + // https://github.com/protocolbuffers/protobuf/blob/6b0ff74ecf63e26c7315f6745de36aff66deb59d/src/google/protobuf/field_mask.proto#L85-L86 + if repeatedChild != nil { + fm.Paths = append(fm.Paths, strings.Join(repeatedChild.path, ".")) + } + return fm, nil } @@ -77,6 +96,6 @@ type fieldMaskPathItem struct { // a generic decoded json object the current item to inspect for further path extraction node interface{} - // descriptor for parent message - md *descriptor.DescriptorProto + // parent message + msg protoreflect.Message } diff --git a/gateway/runtime/fieldmask_test.go b/gateway/runtime/fieldmask_test.go deleted file mode 100644 index 7a5ddaa..0000000 --- a/gateway/runtime/fieldmask_test.go +++ /dev/null @@ -1,151 +0,0 @@ -package runtime - -import ( - "bytes" - "fmt" - "testing" - - "google.golang.org/genproto/protobuf/field_mask" -) - -func fieldMasksEqual(fm1, fm2 *field_mask.FieldMask) bool { - if fm1 == nil && fm2 == nil { - return true - } - if fm1 == nil || fm2 == nil { - return false - } - if len(fm1.GetPaths()) != len(fm2.GetPaths()) { - return false - } - - paths := make(map[string]bool) - for _, path := range fm1.GetPaths() { - paths[path] = true - } - for _, path := range fm2.GetPaths() { - if _, ok := paths[path]; !ok { - return false - } - } - - return true -} - -func newFieldMask(paths ...string) *field_mask.FieldMask { - return &field_mask.FieldMask{Paths: paths} -} - -func fieldMaskString(fm *field_mask.FieldMask) string { - if fm == nil { - return "" - } - return fmt.Sprintf("%v", fm.GetPaths()) -} - -func TestFieldMaskFromRequestBody(t *testing.T) { - for _, tc := range []struct { - name string - input string - expected *field_mask.FieldMask - expectedErr error - }{ - {name: "empty", expected: newFieldMask()}, - {name: "simple", input: `{"foo":1, "bar":"baz"}`, expected: newFieldMask("foo", "bar")}, - {name: "nested", input: `{"foo": {"bar":1, "baz": 2}, "qux": 3}`, expected: newFieldMask("foo.bar", "foo.baz", "qux")}, - {name: "canonical", input: `{"f": {"b": {"d": 1, "x": 2}, "c": 1}}`, expected: newFieldMask("f.b.d", "f.b.x", "f.c")}, - } { - t.Run(tc.name, func(t *testing.T) { - actual, err := FieldMaskFromRequestBody(bytes.NewReader([]byte(tc.input)), nil) - if !fieldMasksEqual(actual, tc.expected) { - t.Errorf("want %v; got %v", fieldMaskString(tc.expected), fieldMaskString(actual)) - } - if err != tc.expectedErr { - t.Errorf("want %v; got %v", tc.expectedErr, err) - } - }) - } -} - -// avoid compiler optimising benchmark away -var result *field_mask.FieldMask - -func BenchmarkABEFieldMaskFromRequestBody(b *testing.B) { - input := `{` + - `"single_nested": {"name": "bar",` + - ` "amount": 10,` + - ` "ok": "TRUE"},` + - `"uuid": "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7",` + - `"nested": [{"name": "bar",` + - ` "amount": 10},` + - ` {"name": "baz",` + - ` "amount": 20}],` + - `"float_value": 1.5,` + - `"double_value": 2.5,` + - `"int64_value": 4294967296,` + - `"uint64_value": 9223372036854775807,` + - `"int32_value": -2147483648,` + - `"fixed64_value": 9223372036854775807,` + - `"fixed32_value": 4294967295,` + - `"bool_value": true,` + - `"string_value": "strprefix/foo",` + - `"bytes_value": "132456",` + - `"uint32_value": 4294967295,` + - `"enum_value": "ONE",` + - `"path_enum_value": "DEF",` + - `"nested_path_enum_value": "JKL",` + - `"sfixed32_value": 2147483647,` + - `"sfixed64_value": -4611686018427387904,` + - `"sint32_value": 2147483647,` + - `"sint64_value": 4611686018427387903,` + - `"repeated_string_value": ["a", "b", "c"],` + - `"oneof_value": {"oneof_string":"x"},` + - `"map_value": {"a": "ONE",` + - ` "b": "ZERO"},` + - `"mapped_string_value": {"a": "x",` + - ` "b": "y"},` + - `"mapped_nested_value": {"a": {"name": "x", "amount": 1},` + - ` "b": {"name": "y", "amount": 2}},` + - `"nonConventionalNameValue": "camelCase",` + - `"timestamp_value": "2016-05-10T10:19:13.123Z",` + - `"repeated_enum_value": ["ONE", "ZERO"],` + - `"repeated_enum_annotation": ["ONE", "ZERO"],` + - `"enum_value_annotation": "ONE",` + - `"repeated_string_annotation": ["a", "b"],` + - `"repeated_nested_annotation": [{"name": "hoge",` + - ` "amount": 10},` + - ` {"name": "fuga",` + - ` "amount": 20}],` + - `"nested_annotation": {"name": "hoge",` + - ` "amount": 10},` + - `"int64_override_type": 12345` + - `}` - var r *field_mask.FieldMask - var err error - for i := 0; i < b.N; i++ { - r, err = FieldMaskFromRequestBody(bytes.NewReader([]byte(input)), nil) - } - if err != nil { - b.Error(err) - } - result = r -} - -func BenchmarkNonStandardFieldMaskFromRequestBody(b *testing.B) { - input := `{` + - `"id": "foo",` + - `"Num": 2,` + - `"line_num": 3,` + - `"langIdent": "bar",` + - `"STATUS": "baz"` + - `}` - var r *field_mask.FieldMask - var err error - for i := 0; i < b.N; i++ { - r, err = FieldMaskFromRequestBody(bytes.NewReader([]byte(input)), nil) - } - if err != nil { - b.Error(err) - } - result = r -} diff --git a/gateway/runtime/handler.go b/gateway/runtime/handler.go index 7c0f67c..2628c2b 100644 --- a/gateway/runtime/handler.go +++ b/gateway/runtime/handler.go @@ -2,20 +2,18 @@ package runtime import ( "context" - "errors" "fmt" "io" "net/http" "net/textproto" - // "github.com/grpc-ecosystem/grpc-gateway/internal" - "github.com/binchencoder/ease-gateway/gateway/internal" - "github.com/golang/protobuf/proto" + "google.golang.org/genproto/googleapis/api/httpbody" + "google.golang.org/grpc/codes" "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/proto" ) -var errEmptyResponse = errors.New("empty response") - // ForwardResponseStream forwards the stream from gRPC server to REST client. func ForwardResponseStream(ctx context.Context, mux *ServeMux, marshaler Marshaler, w http.ResponseWriter, req *http.Request, recv func() (proto.Message, error), opts ...func(context.Context, http.ResponseWriter, proto.Message) error) { f, ok := w.(http.Flusher) @@ -34,7 +32,6 @@ func ForwardResponseStream(ctx context.Context, mux *ServeMux, marshaler Marshal handleForwardResponseServerMetadata(w, mux, md) w.Header().Set("Transfer-Encoding", "chunked") - w.Header().Set("Content-Type", marshaler.ContentType()) if err := handleForwardResponseOptions(ctx, w, nil, opts); err != nil { HTTPError(ctx, mux, marshaler, w, req, err) return @@ -62,10 +59,17 @@ func ForwardResponseStream(ctx context.Context, mux *ServeMux, marshaler Marshal return } + if !wroteHeader { + w.Header().Set("Content-Type", marshaler.ContentType(resp)) + } + var buf []byte + httpBody, isHTTPBody := resp.(*httpbody.HttpBody) switch { case resp == nil: - buf, err = marshaler.Marshal(errorChunk(streamError(ctx, mux.streamErrorHandler, errEmptyResponse))) + buf, err = marshaler.Marshal(errorChunk(status.New(codes.Internal, "empty response"))) + case isHTTPBody: + buf = httpBody.GetData() default: result := map[string]interface{}{"result": resp} if rb, ok := resp.(responseBody); ok { @@ -135,13 +139,7 @@ func ForwardResponseMessage(ctx context.Context, mux *ServeMux, marshaler Marsha handleForwardResponseServerMetadata(w, mux, md) handleForwardResponseTrailerHeader(w, md) - contentType := marshaler.ContentType() - // Check marshaler on run time in order to keep backwards compatibility - // An interface param needs to be added to the ContentType() function on - // the Marshal interface to be able to remove this check - if typeMarshaler, ok := marshaler.(contentTypeMarshaler); ok { - contentType = typeMarshaler.ContentTypeFromMessage(resp) - } + contentType := marshaler.ContentType(resp) w.Header().Set("Content-Type", contentType) if err := handleForwardResponseOptions(ctx, w, resp, opts); err != nil { @@ -182,11 +180,11 @@ func handleForwardResponseOptions(ctx context.Context, w http.ResponseWriter, re } func handleForwardResponseStreamError(ctx context.Context, wroteHeader bool, marshaler Marshaler, w http.ResponseWriter, req *http.Request, mux *ServeMux, err error) { - serr := streamError(ctx, mux.streamErrorHandler, err) + st := mux.streamErrorHandler(ctx, err) if !wroteHeader { - w.WriteHeader(int(serr.HttpCode)) + w.WriteHeader(HTTPStatusFromCode(st.Code())) } - buf, merr := marshaler.Marshal(errorChunk(serr)) + buf, merr := marshaler.Marshal(errorChunk(st)) if merr != nil { grpclog.Infof("Failed to marshal an error: %v", merr) return @@ -197,17 +195,6 @@ func handleForwardResponseStreamError(ctx context.Context, wroteHeader bool, mar } } -// streamError returns the payload for the final message in a response stream -// that represents the given err. -func streamError(ctx context.Context, errHandler StreamErrorHandlerFunc, err error) *StreamError { - serr := errHandler(ctx, err) - if serr != nil { - return serr - } - // TODO: log about misbehaving stream error handler? - return DefaultHTTPStreamErrorHandler(ctx, err) -} - -func errorChunk(err *StreamError) map[string]proto.Message { - return map[string]proto.Message{"error": (*internal.StreamError)(err)} +func errorChunk(st *status.Status) map[string]proto.Message { + return map[string]proto.Message{"error": st.Proto()} } diff --git a/gateway/runtime/handler_test.go b/gateway/runtime/handler_test.go index c9edcfd..e4e9768 100644 --- a/gateway/runtime/handler_test.go +++ b/gateway/runtime/handler_test.go @@ -8,13 +8,13 @@ import ( "net/http/httptest" "testing" - pb "github.com/binchencoder/ease-gateway/examples/proto" - // "github.com/grpc-ecosystem/grpc-gateway/internal" - "github.com/binchencoder/ease-gateway/gateway/internal" + // "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" "github.com/binchencoder/ease-gateway/gateway/runtime" - "github.com/golang/protobuf/proto" + // pb "github.com/grpc-ecosystem/grpc-gateway/v2/runtime/internal/examplepb" + pb "github.com/binchencoder/ease-gateway/examples/proto" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + "google.golang.org/protobuf/proto" ) type fakeReponseBodyWrapper struct { @@ -119,16 +119,9 @@ func TestForwardResponseStream(t *testing.T) { // Skip non-stream errors t.Skip("checking error encodings") } - st, _ := status.FromError(msg.err) - httpCode := runtime.HTTPStatusFromCode(st.Code()) + st := status.Convert(msg.err) b, err := marshaler.Marshal(map[string]proto.Message{ - "error": &internal.StreamError{ - GrpcCode: int32(st.Code()), - HttpCode: int32(httpCode), - Message: st.Message(), - HttpStatus: http.StatusText(httpCode), - Details: st.Proto().GetDetails(), - }, + "error": st.Proto(), }) if err != nil { t.Errorf("marshaler.Marshal() failed %v", err) @@ -175,12 +168,11 @@ type CustomMarshaler struct { m *runtime.JSONPb } -func (c *CustomMarshaler) Marshal(v interface{}) ([]byte, error) { return c.m.Marshal(v) } -func (c *CustomMarshaler) Unmarshal(data []byte, v interface{}) error { return c.m.Unmarshal(data, v) } -func (c *CustomMarshaler) NewDecoder(r io.Reader) runtime.Decoder { return c.m.NewDecoder(r) } -func (c *CustomMarshaler) NewEncoder(w io.Writer) runtime.Encoder { return c.m.NewEncoder(w) } -func (c *CustomMarshaler) ContentType() string { return c.m.ContentType() } -func (c *CustomMarshaler) ContentTypeFromMessage(v interface{}) string { return "Custom-Content-Type" } +func (c *CustomMarshaler) Marshal(v interface{}) ([]byte, error) { return c.m.Marshal(v) } +func (c *CustomMarshaler) Unmarshal(data []byte, v interface{}) error { return c.m.Unmarshal(data, v) } +func (c *CustomMarshaler) NewDecoder(r io.Reader) runtime.Decoder { return c.m.NewDecoder(r) } +func (c *CustomMarshaler) NewEncoder(w io.Writer) runtime.Encoder { return c.m.NewEncoder(w) } +func (c *CustomMarshaler) ContentType(v interface{}) string { return "Custom-Content-Type" } func TestForwardResponseStreamCustomMarshaler(t *testing.T) { type msg struct { diff --git a/gateway/runtime/hook.go b/gateway/runtime/hook.go index 8db1721..784018f 100644 --- a/gateway/runtime/hook.go +++ b/gateway/runtime/hook.go @@ -3,8 +3,8 @@ package runtime import ( "net/http" - "github.com/golang/protobuf/proto" "golang.org/x/net/context" + "google.golang.org/protobuf/proto" pb "github.com/binchencoder/skylb-api/proto" ) diff --git a/gateway/runtime/hook_test.go b/gateway/runtime/hook_test.go index 4040e28..9541752 100755 --- a/gateway/runtime/hook_test.go +++ b/gateway/runtime/hook_test.go @@ -4,8 +4,8 @@ import ( "net/http" "testing" - "github.com/golang/protobuf/proto" "golang.org/x/net/context" + "google.golang.org/protobuf/proto" ) type GatewayServiceHookFake struct { diff --git a/gateway/runtime/internal/examplepb/BUILD.bazel b/gateway/runtime/internal/examplepb/BUILD.bazel new file mode 100644 index 0000000..dbd8d9a --- /dev/null +++ b/gateway/runtime/internal/examplepb/BUILD.bazel @@ -0,0 +1,39 @@ +load("@rules_proto//proto:defs.bzl", "proto_library") +load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") + +# gazelle:exclude non_standard_names_grpc.pb.go + +package(default_visibility = ["//visibility:public"]) + +proto_library( + name = "examplepb_proto", + srcs = [ + "proto3.proto", + ], + deps = [ + "@com_google_protobuf//:duration_proto", + "@com_google_protobuf//:empty_proto", + "@com_google_protobuf//:field_mask_proto", + "@com_google_protobuf//:timestamp_proto", + "@com_google_protobuf//:wrappers_proto", + "@go_googleapis//google/api:annotations_proto", + ], +) + +go_proto_library( + name = "examplepb_go_proto", + compilers = [ + "//:go_apiv2", + "//:go_grpc", + ], + importpath = "github.com/binchencoder/ease-gateway/gateway/runtime/internal/examplepb", + proto = ":examplepb_proto", + deps = ["@go_googleapis//google/api:annotations_go_proto"], +) + +go_library( + name = "go_default_library", + embed = [":examplepb_go_proto"], + importpath = "github.com/binchencoder/ease-gateway/gateway/runtime/internal/examplepb", +) diff --git a/gateway/runtime/internal/examplepb/proto3.pb.go b/gateway/runtime/internal/examplepb/proto3.pb.go new file mode 100644 index 0000000..023c967 --- /dev/null +++ b/gateway/runtime/internal/examplepb/proto3.pb.go @@ -0,0 +1,886 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.23.0 +// protoc v3.12.3 +// source: gateway/runtime/internal/examplepb/proto3.proto + +package examplepb + +import ( + proto "github.com/golang/protobuf/proto" + duration "github.com/golang/protobuf/ptypes/duration" + timestamp "github.com/golang/protobuf/ptypes/timestamp" + wrappers "github.com/golang/protobuf/ptypes/wrappers" + field_mask "google.golang.org/genproto/protobuf/field_mask" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// This is a compile-time assertion that a sufficiently up-to-date version +// of the legacy proto package is being used. +const _ = proto.ProtoPackageIsVersion4 + +type EnumValue int32 + +const ( + EnumValue_X EnumValue = 0 + EnumValue_Y EnumValue = 1 + EnumValue_Z EnumValue = 2 +) + +// Enum value maps for EnumValue. +var ( + EnumValue_name = map[int32]string{ + 0: "X", + 1: "Y", + 2: "Z", + } + EnumValue_value = map[string]int32{ + "X": 0, + "Y": 1, + "Z": 2, + } +) + +func (x EnumValue) Enum() *EnumValue { + p := new(EnumValue) + *p = x + return p +} + +func (x EnumValue) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (EnumValue) Descriptor() protoreflect.EnumDescriptor { + return file_gateway_runtime_internal_examplepb_proto3_proto_enumTypes[0].Descriptor() +} + +func (EnumValue) Type() protoreflect.EnumType { + return &file_gateway_runtime_internal_examplepb_proto3_proto_enumTypes[0] +} + +func (x EnumValue) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use EnumValue.Descriptor instead. +func (EnumValue) EnumDescriptor() ([]byte, []int) { + return file_gateway_runtime_internal_examplepb_proto3_proto_rawDescGZIP(), []int{0} +} + +type Proto3Message struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Next number: 46 + Nested *Proto3Message `protobuf:"bytes,41,opt,name=nested,proto3" json:"nested,omitempty"` + FloatValue float32 `protobuf:"fixed32,42,opt,name=float_value,json=floatValue,proto3" json:"float_value,omitempty"` + DoubleValue float64 `protobuf:"fixed64,43,opt,name=double_value,json=doubleValue,proto3" json:"double_value,omitempty"` + Int64Value int64 `protobuf:"varint,3,opt,name=int64_value,json=int64Value,proto3" json:"int64_value,omitempty"` + Int32Value int32 `protobuf:"varint,4,opt,name=int32_value,json=int32Value,proto3" json:"int32_value,omitempty"` + Uint64Value uint64 `protobuf:"varint,5,opt,name=uint64_value,json=uint64Value,proto3" json:"uint64_value,omitempty"` + Uint32Value uint32 `protobuf:"varint,6,opt,name=uint32_value,json=uint32Value,proto3" json:"uint32_value,omitempty"` + BoolValue bool `protobuf:"varint,7,opt,name=bool_value,json=boolValue,proto3" json:"bool_value,omitempty"` + StringValue string `protobuf:"bytes,8,opt,name=string_value,json=stringValue,proto3" json:"string_value,omitempty"` + BytesValue []byte `protobuf:"bytes,9,opt,name=bytes_value,json=bytesValue,proto3" json:"bytes_value,omitempty"` + RepeatedValue []string `protobuf:"bytes,10,rep,name=repeated_value,json=repeatedValue,proto3" json:"repeated_value,omitempty"` + RepeatedMessage []*wrappers.UInt64Value `protobuf:"bytes,44,rep,name=repeated_message,json=repeatedMessage,proto3" json:"repeated_message,omitempty"` + EnumValue EnumValue `protobuf:"varint,11,opt,name=enum_value,json=enumValue,proto3,enum=ease.gateway.runtime.internal.examplepb.EnumValue" json:"enum_value,omitempty"` + RepeatedEnum []EnumValue `protobuf:"varint,12,rep,packed,name=repeated_enum,json=repeatedEnum,proto3,enum=ease.gateway.runtime.internal.examplepb.EnumValue" json:"repeated_enum,omitempty"` + TimestampValue *timestamp.Timestamp `protobuf:"bytes,13,opt,name=timestamp_value,json=timestampValue,proto3" json:"timestamp_value,omitempty"` + DurationValue *duration.Duration `protobuf:"bytes,14,opt,name=duration_value,json=durationValue,proto3" json:"duration_value,omitempty"` + FieldmaskValue *field_mask.FieldMask `protobuf:"bytes,15,opt,name=fieldmask_value,json=fieldmaskValue,proto3" json:"fieldmask_value,omitempty"` + // Types that are assignable to OneofValue: + // *Proto3Message_OneofBoolValue + // *Proto3Message_OneofStringValue + OneofValue isProto3Message_OneofValue `protobuf_oneof:"oneof_value"` + WrapperDoubleValue *wrappers.DoubleValue `protobuf:"bytes,17,opt,name=wrapper_double_value,json=wrapperDoubleValue,proto3" json:"wrapper_double_value,omitempty"` + WrapperFloatValue *wrappers.FloatValue `protobuf:"bytes,18,opt,name=wrapper_float_value,json=wrapperFloatValue,proto3" json:"wrapper_float_value,omitempty"` + WrapperInt64Value *wrappers.Int64Value `protobuf:"bytes,19,opt,name=wrapper_int64_value,json=wrapperInt64Value,proto3" json:"wrapper_int64_value,omitempty"` + WrapperInt32Value *wrappers.Int32Value `protobuf:"bytes,20,opt,name=wrapper_int32_value,json=wrapperInt32Value,proto3" json:"wrapper_int32_value,omitempty"` + WrapperUInt64Value *wrappers.UInt64Value `protobuf:"bytes,21,opt,name=wrapper_u_int64_value,json=wrapperUInt64Value,proto3" json:"wrapper_u_int64_value,omitempty"` + WrapperUInt32Value *wrappers.UInt32Value `protobuf:"bytes,22,opt,name=wrapper_u_int32_value,json=wrapperUInt32Value,proto3" json:"wrapper_u_int32_value,omitempty"` + WrapperBoolValue *wrappers.BoolValue `protobuf:"bytes,23,opt,name=wrapper_bool_value,json=wrapperBoolValue,proto3" json:"wrapper_bool_value,omitempty"` + WrapperStringValue *wrappers.StringValue `protobuf:"bytes,24,opt,name=wrapper_string_value,json=wrapperStringValue,proto3" json:"wrapper_string_value,omitempty"` + WrapperBytesValue *wrappers.BytesValue `protobuf:"bytes,25,opt,name=wrapper_bytes_value,json=wrapperBytesValue,proto3" json:"wrapper_bytes_value,omitempty"` + MapValue map[string]string `protobuf:"bytes,26,rep,name=map_value,json=mapValue,proto3" json:"map_value,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + MapValue2 map[string]int32 `protobuf:"bytes,27,rep,name=map_value2,json=mapValue2,proto3" json:"map_value2,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` + MapValue3 map[int32]string `protobuf:"bytes,28,rep,name=map_value3,json=mapValue3,proto3" json:"map_value3,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + MapValue4 map[string]int64 `protobuf:"bytes,29,rep,name=map_value4,json=mapValue4,proto3" json:"map_value4,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` + MapValue5 map[int64]string `protobuf:"bytes,30,rep,name=map_value5,json=mapValue5,proto3" json:"map_value5,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + MapValue6 map[string]uint32 `protobuf:"bytes,31,rep,name=map_value6,json=mapValue6,proto3" json:"map_value6,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` + MapValue7 map[uint32]string `protobuf:"bytes,32,rep,name=map_value7,json=mapValue7,proto3" json:"map_value7,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + MapValue8 map[string]uint64 `protobuf:"bytes,33,rep,name=map_value8,json=mapValue8,proto3" json:"map_value8,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` + MapValue9 map[uint64]string `protobuf:"bytes,34,rep,name=map_value9,json=mapValue9,proto3" json:"map_value9,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + MapValue10 map[string]float32 `protobuf:"bytes,35,rep,name=map_value10,json=mapValue10,proto3" json:"map_value10,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"fixed32,2,opt,name=value,proto3"` + MapValue12 map[string]float64 `protobuf:"bytes,37,rep,name=map_value12,json=mapValue12,proto3" json:"map_value12,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"fixed64,2,opt,name=value,proto3"` + MapValue14 map[string]bool `protobuf:"bytes,39,rep,name=map_value14,json=mapValue14,proto3" json:"map_value14,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` + MapValue15 map[bool]string `protobuf:"bytes,40,rep,name=map_value15,json=mapValue15,proto3" json:"map_value15,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + MapValue16 map[string]*wrappers.UInt64Value `protobuf:"bytes,45,rep,name=map_value16,json=mapValue16,proto3" json:"map_value16,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *Proto3Message) Reset() { + *x = Proto3Message{} + if protoimpl.UnsafeEnabled { + mi := &file_gateway_runtime_internal_examplepb_proto3_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Proto3Message) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Proto3Message) ProtoMessage() {} + +func (x *Proto3Message) ProtoReflect() protoreflect.Message { + mi := &file_gateway_runtime_internal_examplepb_proto3_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Proto3Message.ProtoReflect.Descriptor instead. +func (*Proto3Message) Descriptor() ([]byte, []int) { + return file_gateway_runtime_internal_examplepb_proto3_proto_rawDescGZIP(), []int{0} +} + +func (x *Proto3Message) GetNested() *Proto3Message { + if x != nil { + return x.Nested + } + return nil +} + +func (x *Proto3Message) GetFloatValue() float32 { + if x != nil { + return x.FloatValue + } + return 0 +} + +func (x *Proto3Message) GetDoubleValue() float64 { + if x != nil { + return x.DoubleValue + } + return 0 +} + +func (x *Proto3Message) GetInt64Value() int64 { + if x != nil { + return x.Int64Value + } + return 0 +} + +func (x *Proto3Message) GetInt32Value() int32 { + if x != nil { + return x.Int32Value + } + return 0 +} + +func (x *Proto3Message) GetUint64Value() uint64 { + if x != nil { + return x.Uint64Value + } + return 0 +} + +func (x *Proto3Message) GetUint32Value() uint32 { + if x != nil { + return x.Uint32Value + } + return 0 +} + +func (x *Proto3Message) GetBoolValue() bool { + if x != nil { + return x.BoolValue + } + return false +} + +func (x *Proto3Message) GetStringValue() string { + if x != nil { + return x.StringValue + } + return "" +} + +func (x *Proto3Message) GetBytesValue() []byte { + if x != nil { + return x.BytesValue + } + return nil +} + +func (x *Proto3Message) GetRepeatedValue() []string { + if x != nil { + return x.RepeatedValue + } + return nil +} + +func (x *Proto3Message) GetRepeatedMessage() []*wrappers.UInt64Value { + if x != nil { + return x.RepeatedMessage + } + return nil +} + +func (x *Proto3Message) GetEnumValue() EnumValue { + if x != nil { + return x.EnumValue + } + return EnumValue_X +} + +func (x *Proto3Message) GetRepeatedEnum() []EnumValue { + if x != nil { + return x.RepeatedEnum + } + return nil +} + +func (x *Proto3Message) GetTimestampValue() *timestamp.Timestamp { + if x != nil { + return x.TimestampValue + } + return nil +} + +func (x *Proto3Message) GetDurationValue() *duration.Duration { + if x != nil { + return x.DurationValue + } + return nil +} + +func (x *Proto3Message) GetFieldmaskValue() *field_mask.FieldMask { + if x != nil { + return x.FieldmaskValue + } + return nil +} + +func (m *Proto3Message) GetOneofValue() isProto3Message_OneofValue { + if m != nil { + return m.OneofValue + } + return nil +} + +func (x *Proto3Message) GetOneofBoolValue() bool { + if x, ok := x.GetOneofValue().(*Proto3Message_OneofBoolValue); ok { + return x.OneofBoolValue + } + return false +} + +func (x *Proto3Message) GetOneofStringValue() string { + if x, ok := x.GetOneofValue().(*Proto3Message_OneofStringValue); ok { + return x.OneofStringValue + } + return "" +} + +func (x *Proto3Message) GetWrapperDoubleValue() *wrappers.DoubleValue { + if x != nil { + return x.WrapperDoubleValue + } + return nil +} + +func (x *Proto3Message) GetWrapperFloatValue() *wrappers.FloatValue { + if x != nil { + return x.WrapperFloatValue + } + return nil +} + +func (x *Proto3Message) GetWrapperInt64Value() *wrappers.Int64Value { + if x != nil { + return x.WrapperInt64Value + } + return nil +} + +func (x *Proto3Message) GetWrapperInt32Value() *wrappers.Int32Value { + if x != nil { + return x.WrapperInt32Value + } + return nil +} + +func (x *Proto3Message) GetWrapperUInt64Value() *wrappers.UInt64Value { + if x != nil { + return x.WrapperUInt64Value + } + return nil +} + +func (x *Proto3Message) GetWrapperUInt32Value() *wrappers.UInt32Value { + if x != nil { + return x.WrapperUInt32Value + } + return nil +} + +func (x *Proto3Message) GetWrapperBoolValue() *wrappers.BoolValue { + if x != nil { + return x.WrapperBoolValue + } + return nil +} + +func (x *Proto3Message) GetWrapperStringValue() *wrappers.StringValue { + if x != nil { + return x.WrapperStringValue + } + return nil +} + +func (x *Proto3Message) GetWrapperBytesValue() *wrappers.BytesValue { + if x != nil { + return x.WrapperBytesValue + } + return nil +} + +func (x *Proto3Message) GetMapValue() map[string]string { + if x != nil { + return x.MapValue + } + return nil +} + +func (x *Proto3Message) GetMapValue2() map[string]int32 { + if x != nil { + return x.MapValue2 + } + return nil +} + +func (x *Proto3Message) GetMapValue3() map[int32]string { + if x != nil { + return x.MapValue3 + } + return nil +} + +func (x *Proto3Message) GetMapValue4() map[string]int64 { + if x != nil { + return x.MapValue4 + } + return nil +} + +func (x *Proto3Message) GetMapValue5() map[int64]string { + if x != nil { + return x.MapValue5 + } + return nil +} + +func (x *Proto3Message) GetMapValue6() map[string]uint32 { + if x != nil { + return x.MapValue6 + } + return nil +} + +func (x *Proto3Message) GetMapValue7() map[uint32]string { + if x != nil { + return x.MapValue7 + } + return nil +} + +func (x *Proto3Message) GetMapValue8() map[string]uint64 { + if x != nil { + return x.MapValue8 + } + return nil +} + +func (x *Proto3Message) GetMapValue9() map[uint64]string { + if x != nil { + return x.MapValue9 + } + return nil +} + +func (x *Proto3Message) GetMapValue10() map[string]float32 { + if x != nil { + return x.MapValue10 + } + return nil +} + +func (x *Proto3Message) GetMapValue12() map[string]float64 { + if x != nil { + return x.MapValue12 + } + return nil +} + +func (x *Proto3Message) GetMapValue14() map[string]bool { + if x != nil { + return x.MapValue14 + } + return nil +} + +func (x *Proto3Message) GetMapValue15() map[bool]string { + if x != nil { + return x.MapValue15 + } + return nil +} + +func (x *Proto3Message) GetMapValue16() map[string]*wrappers.UInt64Value { + if x != nil { + return x.MapValue16 + } + return nil +} + +type isProto3Message_OneofValue interface { + isProto3Message_OneofValue() +} + +type Proto3Message_OneofBoolValue struct { + OneofBoolValue bool `protobuf:"varint,1,opt,name=oneof_bool_value,json=oneofBoolValue,proto3,oneof"` +} + +type Proto3Message_OneofStringValue struct { + OneofStringValue string `protobuf:"bytes,2,opt,name=oneof_string_value,json=oneofStringValue,proto3,oneof"` +} + +func (*Proto3Message_OneofBoolValue) isProto3Message_OneofValue() {} + +func (*Proto3Message_OneofStringValue) isProto3Message_OneofValue() {} + +var File_gateway_runtime_internal_examplepb_proto3_proto protoreflect.FileDescriptor + +var file_gateway_runtime_internal_examplepb_proto3_proto_rawDesc = []byte{ + 0x0a, 0x2f, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2f, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, + 0x65, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, + 0x6c, 0x65, 0x70, 0x62, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x12, 0x27, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, + 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, + 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x75, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x20, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x66, 0x69, 0x65, 0x6c, + 0x64, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x77, + 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc7, 0x1f, + 0x0a, 0x0d, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x4e, 0x0a, 0x06, 0x6e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x18, 0x29, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x36, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, + 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, + 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x06, 0x6e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x12, + 0x1f, 0x0a, 0x0b, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x2a, + 0x20, 0x01, 0x28, 0x02, 0x52, 0x0a, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0x2b, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0b, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x56, 0x61, + 0x6c, 0x75, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x5f, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x56, + 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x5f, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x69, 0x6e, 0x74, 0x33, 0x32, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x75, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x5f, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x75, 0x69, 0x6e, + 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x75, 0x69, 0x6e, 0x74, + 0x33, 0x32, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, + 0x75, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x62, + 0x6f, 0x6f, 0x6c, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x09, 0x62, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x74, + 0x72, 0x69, 0x6e, 0x67, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0b, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1f, 0x0a, + 0x0b, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x09, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x0a, 0x62, 0x79, 0x74, 0x65, 0x73, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x25, + 0x0a, 0x0e, 0x72, 0x65, 0x70, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0x0a, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x72, 0x65, 0x70, 0x65, 0x61, 0x74, 0x65, 0x64, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x47, 0x0a, 0x10, 0x72, 0x65, 0x70, 0x65, 0x61, 0x74, 0x65, + 0x64, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x2c, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0f, 0x72, + 0x65, 0x70, 0x65, 0x61, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x51, + 0x0a, 0x0a, 0x65, 0x6e, 0x75, 0x6d, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x0b, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x32, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, + 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, + 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x45, 0x6e, 0x75, + 0x6d, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x09, 0x65, 0x6e, 0x75, 0x6d, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x12, 0x57, 0x0a, 0x0d, 0x72, 0x65, 0x70, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x65, 0x6e, + 0x75, 0x6d, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x32, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, + 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, + 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, + 0x70, 0x62, 0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0c, 0x72, 0x65, + 0x70, 0x65, 0x61, 0x74, 0x65, 0x64, 0x45, 0x6e, 0x75, 0x6d, 0x12, 0x43, 0x0a, 0x0f, 0x74, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x0d, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, + 0x0e, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, + 0x40, 0x0a, 0x0e, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x0d, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x12, 0x43, 0x0a, 0x0f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x6d, 0x61, 0x73, 0x6b, 0x5f, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, + 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x52, 0x0e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x6d, 0x61, 0x73, + 0x6b, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x2a, 0x0a, 0x10, 0x6f, 0x6e, 0x65, 0x6f, 0x66, 0x5f, + 0x62, 0x6f, 0x6f, 0x6c, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, + 0x48, 0x00, 0x52, 0x0e, 0x6f, 0x6e, 0x65, 0x6f, 0x66, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x12, 0x2e, 0x0a, 0x12, 0x6f, 0x6e, 0x65, 0x6f, 0x66, 0x5f, 0x73, 0x74, 0x72, 0x69, + 0x6e, 0x67, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, + 0x52, 0x10, 0x6f, 0x6e, 0x65, 0x6f, 0x66, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x12, 0x4e, 0x0a, 0x14, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x5f, 0x64, 0x6f, + 0x75, 0x62, 0x6c, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x44, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x12, + 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x44, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x12, 0x4b, 0x0a, 0x13, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x5f, 0x66, 0x6c, + 0x6f, 0x61, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x11, 0x77, 0x72, + 0x61, 0x70, 0x70, 0x65, 0x72, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, + 0x4b, 0x0a, 0x13, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x74, 0x36, 0x34, + 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, + 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x11, 0x77, 0x72, 0x61, 0x70, 0x70, + 0x65, 0x72, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x4b, 0x0a, 0x13, + 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x5f, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, 0x6e, 0x74, 0x33, + 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x11, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x49, + 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x4f, 0x0a, 0x15, 0x77, 0x72, 0x61, + 0x70, 0x70, 0x65, 0x72, 0x5f, 0x75, 0x5f, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x5f, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x36, + 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x12, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x55, + 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x4f, 0x0a, 0x15, 0x77, 0x72, + 0x61, 0x70, 0x70, 0x65, 0x72, 0x5f, 0x75, 0x5f, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x5f, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, + 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x12, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, + 0x55, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x48, 0x0a, 0x12, 0x77, + 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x5f, 0x62, 0x6f, 0x6f, 0x6c, 0x5f, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x18, 0x17, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, + 0x6c, 0x75, 0x65, 0x52, 0x10, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x42, 0x6f, 0x6f, 0x6c, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x4e, 0x0a, 0x14, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, + 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x18, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x52, 0x12, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x4b, 0x0a, 0x13, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, + 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x19, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x79, 0x74, 0x65, 0x73, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, + 0x11, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x42, 0x79, 0x74, 0x65, 0x73, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x12, 0x61, 0x0a, 0x09, 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0x1a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x44, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, + 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, + 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, + 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, + 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x61, 0x70, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x64, 0x0a, 0x0a, 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x32, 0x18, 0x1b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x65, 0x61, 0x73, 0x65, + 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, + 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, + 0x65, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x2e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x32, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x52, 0x09, 0x6d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x32, 0x12, 0x64, 0x0a, 0x0a, 0x6d, + 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x33, 0x18, 0x1c, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x45, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, + 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, + 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x33, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x6d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x33, 0x12, 0x64, 0x0a, 0x0a, 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x34, 0x18, + 0x1d, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, + 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, + 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, + 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, + 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x34, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x6d, 0x61, + 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x34, 0x12, 0x64, 0x0a, 0x0a, 0x6d, 0x61, 0x70, 0x5f, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x35, 0x18, 0x1e, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x65, 0x61, + 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, + 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x35, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x52, 0x09, 0x6d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x35, 0x12, 0x64, 0x0a, + 0x0a, 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x36, 0x18, 0x1f, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x45, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, + 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, + 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x74, + 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x36, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x6d, 0x61, 0x70, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x36, 0x12, 0x64, 0x0a, 0x0a, 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x37, 0x18, 0x20, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, + 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, + 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, + 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, + 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x37, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, + 0x6d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x37, 0x12, 0x64, 0x0a, 0x0a, 0x6d, 0x61, 0x70, + 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x38, 0x18, 0x21, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, + 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, + 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x65, 0x78, + 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x38, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x6d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x38, 0x12, + 0x64, 0x0a, 0x0a, 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x39, 0x18, 0x22, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, + 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, 0x72, + 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, 0x56, + 0x61, 0x6c, 0x75, 0x65, 0x39, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x6d, 0x61, 0x70, 0x56, + 0x61, 0x6c, 0x75, 0x65, 0x39, 0x12, 0x67, 0x0a, 0x0b, 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x31, 0x30, 0x18, 0x23, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x46, 0x2e, 0x65, 0x61, 0x73, + 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, + 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, + 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x30, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x52, 0x0a, 0x6d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x30, 0x12, 0x67, + 0x0a, 0x0b, 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x32, 0x18, 0x25, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x46, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, + 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, 0x72, + 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, 0x56, + 0x61, 0x6c, 0x75, 0x65, 0x31, 0x32, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x6d, 0x61, 0x70, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x32, 0x12, 0x67, 0x0a, 0x0b, 0x6d, 0x61, 0x70, 0x5f, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x31, 0x34, 0x18, 0x27, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x46, 0x2e, 0x65, + 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, + 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, + 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x34, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x6d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x34, + 0x12, 0x67, 0x0a, 0x0b, 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x35, 0x18, + 0x28, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x46, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, + 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, + 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, + 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, + 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x35, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x6d, + 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x35, 0x12, 0x67, 0x0a, 0x0b, 0x6d, 0x61, 0x70, + 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x36, 0x18, 0x2d, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x46, + 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, + 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x65, + 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, + 0x36, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x6d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x31, 0x36, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, + 0x3c, 0x0a, 0x0e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x32, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, + 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3c, 0x0a, + 0x0e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x33, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, + 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x6b, 0x65, + 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3c, 0x0a, 0x0e, 0x4d, + 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x34, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, + 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, + 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3c, 0x0a, 0x0e, 0x4d, 0x61, 0x70, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x35, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, + 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3c, 0x0a, 0x0e, 0x4d, 0x61, 0x70, 0x56, 0x61, + 0x6c, 0x75, 0x65, 0x36, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3c, 0x0a, 0x0e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x37, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, + 0x02, 0x38, 0x01, 0x1a, 0x3c, 0x0a, 0x0e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x38, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, + 0x01, 0x1a, 0x3c, 0x0a, 0x0e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x39, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, + 0x3d, 0x0a, 0x0f, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x30, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x02, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3d, + 0x0a, 0x0f, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x32, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, + 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x01, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3d, 0x0a, + 0x0f, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x34, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, + 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3d, 0x0a, 0x0f, + 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x35, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, + 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x6b, 0x65, + 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x5b, 0x0a, 0x0f, 0x4d, + 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x36, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, + 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, + 0x12, 0x32, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x0d, 0x0a, 0x0b, 0x6f, 0x6e, 0x65, 0x6f, + 0x66, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2a, 0x20, 0x0a, 0x09, 0x45, 0x6e, 0x75, 0x6d, 0x56, + 0x61, 0x6c, 0x75, 0x65, 0x12, 0x05, 0x0a, 0x01, 0x58, 0x10, 0x00, 0x12, 0x05, 0x0a, 0x01, 0x59, + 0x10, 0x01, 0x12, 0x05, 0x0a, 0x01, 0x5a, 0x10, 0x02, 0x42, 0x49, 0x5a, 0x47, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x69, 0x6e, 0x63, 0x68, 0x65, 0x6e, 0x63, + 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x65, 0x61, 0x73, 0x65, 0x2d, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, + 0x79, 0x2f, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2f, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, + 0x65, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, + 0x6c, 0x65, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_gateway_runtime_internal_examplepb_proto3_proto_rawDescOnce sync.Once + file_gateway_runtime_internal_examplepb_proto3_proto_rawDescData = file_gateway_runtime_internal_examplepb_proto3_proto_rawDesc +) + +func file_gateway_runtime_internal_examplepb_proto3_proto_rawDescGZIP() []byte { + file_gateway_runtime_internal_examplepb_proto3_proto_rawDescOnce.Do(func() { + file_gateway_runtime_internal_examplepb_proto3_proto_rawDescData = protoimpl.X.CompressGZIP(file_gateway_runtime_internal_examplepb_proto3_proto_rawDescData) + }) + return file_gateway_runtime_internal_examplepb_proto3_proto_rawDescData +} + +var file_gateway_runtime_internal_examplepb_proto3_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_gateway_runtime_internal_examplepb_proto3_proto_msgTypes = make([]protoimpl.MessageInfo, 15) +var file_gateway_runtime_internal_examplepb_proto3_proto_goTypes = []interface{}{ + (EnumValue)(0), // 0: ease.gateway.runtime.internal.examplepb.EnumValue + (*Proto3Message)(nil), // 1: ease.gateway.runtime.internal.examplepb.Proto3Message + nil, // 2: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValueEntry + nil, // 3: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue2Entry + nil, // 4: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue3Entry + nil, // 5: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue4Entry + nil, // 6: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue5Entry + nil, // 7: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue6Entry + nil, // 8: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue7Entry + nil, // 9: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue8Entry + nil, // 10: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue9Entry + nil, // 11: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue10Entry + nil, // 12: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue12Entry + nil, // 13: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue14Entry + nil, // 14: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue15Entry + nil, // 15: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue16Entry + (*wrappers.UInt64Value)(nil), // 16: google.protobuf.UInt64Value + (*timestamp.Timestamp)(nil), // 17: google.protobuf.Timestamp + (*duration.Duration)(nil), // 18: google.protobuf.Duration + (*field_mask.FieldMask)(nil), // 19: google.protobuf.FieldMask + (*wrappers.DoubleValue)(nil), // 20: google.protobuf.DoubleValue + (*wrappers.FloatValue)(nil), // 21: google.protobuf.FloatValue + (*wrappers.Int64Value)(nil), // 22: google.protobuf.Int64Value + (*wrappers.Int32Value)(nil), // 23: google.protobuf.Int32Value + (*wrappers.UInt32Value)(nil), // 24: google.protobuf.UInt32Value + (*wrappers.BoolValue)(nil), // 25: google.protobuf.BoolValue + (*wrappers.StringValue)(nil), // 26: google.protobuf.StringValue + (*wrappers.BytesValue)(nil), // 27: google.protobuf.BytesValue +} +var file_gateway_runtime_internal_examplepb_proto3_proto_depIdxs = []int32{ + 1, // 0: ease.gateway.runtime.internal.examplepb.Proto3Message.nested:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message + 16, // 1: ease.gateway.runtime.internal.examplepb.Proto3Message.repeated_message:type_name -> google.protobuf.UInt64Value + 0, // 2: ease.gateway.runtime.internal.examplepb.Proto3Message.enum_value:type_name -> ease.gateway.runtime.internal.examplepb.EnumValue + 0, // 3: ease.gateway.runtime.internal.examplepb.Proto3Message.repeated_enum:type_name -> ease.gateway.runtime.internal.examplepb.EnumValue + 17, // 4: ease.gateway.runtime.internal.examplepb.Proto3Message.timestamp_value:type_name -> google.protobuf.Timestamp + 18, // 5: ease.gateway.runtime.internal.examplepb.Proto3Message.duration_value:type_name -> google.protobuf.Duration + 19, // 6: ease.gateway.runtime.internal.examplepb.Proto3Message.fieldmask_value:type_name -> google.protobuf.FieldMask + 20, // 7: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_double_value:type_name -> google.protobuf.DoubleValue + 21, // 8: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_float_value:type_name -> google.protobuf.FloatValue + 22, // 9: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_int64_value:type_name -> google.protobuf.Int64Value + 23, // 10: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_int32_value:type_name -> google.protobuf.Int32Value + 16, // 11: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_u_int64_value:type_name -> google.protobuf.UInt64Value + 24, // 12: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_u_int32_value:type_name -> google.protobuf.UInt32Value + 25, // 13: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_bool_value:type_name -> google.protobuf.BoolValue + 26, // 14: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_string_value:type_name -> google.protobuf.StringValue + 27, // 15: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_bytes_value:type_name -> google.protobuf.BytesValue + 2, // 16: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValueEntry + 3, // 17: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value2:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue2Entry + 4, // 18: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value3:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue3Entry + 5, // 19: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value4:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue4Entry + 6, // 20: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value5:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue5Entry + 7, // 21: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value6:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue6Entry + 8, // 22: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value7:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue7Entry + 9, // 23: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value8:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue8Entry + 10, // 24: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value9:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue9Entry + 11, // 25: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value10:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue10Entry + 12, // 26: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value12:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue12Entry + 13, // 27: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value14:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue14Entry + 14, // 28: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value15:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue15Entry + 15, // 29: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value16:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue16Entry + 16, // 30: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue16Entry.value:type_name -> google.protobuf.UInt64Value + 31, // [31:31] is the sub-list for method output_type + 31, // [31:31] is the sub-list for method input_type + 31, // [31:31] is the sub-list for extension type_name + 31, // [31:31] is the sub-list for extension extendee + 0, // [0:31] is the sub-list for field type_name +} + +func init() { file_gateway_runtime_internal_examplepb_proto3_proto_init() } +func file_gateway_runtime_internal_examplepb_proto3_proto_init() { + if File_gateway_runtime_internal_examplepb_proto3_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_gateway_runtime_internal_examplepb_proto3_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Proto3Message); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_gateway_runtime_internal_examplepb_proto3_proto_msgTypes[0].OneofWrappers = []interface{}{ + (*Proto3Message_OneofBoolValue)(nil), + (*Proto3Message_OneofStringValue)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_gateway_runtime_internal_examplepb_proto3_proto_rawDesc, + NumEnums: 1, + NumMessages: 15, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_gateway_runtime_internal_examplepb_proto3_proto_goTypes, + DependencyIndexes: file_gateway_runtime_internal_examplepb_proto3_proto_depIdxs, + EnumInfos: file_gateway_runtime_internal_examplepb_proto3_proto_enumTypes, + MessageInfos: file_gateway_runtime_internal_examplepb_proto3_proto_msgTypes, + }.Build() + File_gateway_runtime_internal_examplepb_proto3_proto = out.File + file_gateway_runtime_internal_examplepb_proto3_proto_rawDesc = nil + file_gateway_runtime_internal_examplepb_proto3_proto_goTypes = nil + file_gateway_runtime_internal_examplepb_proto3_proto_depIdxs = nil +} diff --git a/gateway/runtime/internal/examplepb/proto3.proto b/gateway/runtime/internal/examplepb/proto3.proto new file mode 100644 index 0000000..a81fc4d --- /dev/null +++ b/gateway/runtime/internal/examplepb/proto3.proto @@ -0,0 +1,64 @@ +syntax = "proto3"; + +package ease.gateway.runtime.internal.examplepb; + +option go_package = "github.com/binchencoder/ease-gateway/gateway/runtime/internal/examplepb"; + +import "google/protobuf/duration.proto"; +import "google/protobuf/field_mask.proto"; +import "google/protobuf/timestamp.proto"; +import "google/protobuf/wrappers.proto"; + +message Proto3Message { + // Next number: 46 + Proto3Message nested = 41; + float float_value = 42; + double double_value = 43; + int64 int64_value = 3; + int32 int32_value = 4; + uint64 uint64_value = 5; + uint32 uint32_value = 6; + bool bool_value = 7; + string string_value = 8; + bytes bytes_value = 9; + repeated string repeated_value = 10; + repeated google.protobuf.UInt64Value repeated_message = 44; + EnumValue enum_value = 11; + repeated EnumValue repeated_enum = 12; + google.protobuf.Timestamp timestamp_value = 13; + google.protobuf.Duration duration_value = 14; + google.protobuf.FieldMask fieldmask_value = 15; + oneof oneof_value { + bool oneof_bool_value = 1; + string oneof_string_value = 2; + } + google.protobuf.DoubleValue wrapper_double_value = 17; + google.protobuf.FloatValue wrapper_float_value = 18; + google.protobuf.Int64Value wrapper_int64_value = 19; + google.protobuf.Int32Value wrapper_int32_value = 20; + google.protobuf.UInt64Value wrapper_u_int64_value = 21; + google.protobuf.UInt32Value wrapper_u_int32_value = 22; + google.protobuf.BoolValue wrapper_bool_value = 23; + google.protobuf.StringValue wrapper_string_value = 24; + google.protobuf.BytesValue wrapper_bytes_value = 25; + map map_value = 26; + map map_value2 = 27; + map map_value3 = 28; + map map_value4 = 29; + map map_value5 = 30; + map map_value6 = 31; + map map_value7 = 32; + map map_value8 = 33; + map map_value9 = 34; + map map_value10 = 35; + map map_value12 = 37; + map map_value14 = 39; + map map_value15 = 40; + map map_value16 = 45; +} + +enum EnumValue { + X = 0; + Y = 1; + Z = 2; +} diff --git a/gateway/runtime/marshal_httpbodyproto.go b/gateway/runtime/marshal_httpbodyproto.go index 525b033..b86135c 100644 --- a/gateway/runtime/marshal_httpbodyproto.go +++ b/gateway/runtime/marshal_httpbodyproto.go @@ -4,13 +4,6 @@ import ( "google.golang.org/genproto/googleapis/api/httpbody" ) -// SetHTTPBodyMarshaler overwrite the default marshaler with the HTTPBodyMarshaler -func SetHTTPBodyMarshaler(serveMux *ServeMux) { - serveMux.marshalers.mimeMap[MIMEWildcard] = &HTTPBodyMarshaler{ - Marshaler: &JSONPb{OrigName: true}, - } -} - // HTTPBodyMarshaler is a Marshaler which supports marshaling of a // google.api.HttpBody message as the full response body if it is // the actual message used as the response. If not, then this will @@ -19,18 +12,14 @@ type HTTPBodyMarshaler struct { Marshaler } -// ContentType implementation to keep backwards compatibility with marshal interface -func (h *HTTPBodyMarshaler) ContentType() string { - return h.ContentTypeFromMessage(nil) -} - -// ContentTypeFromMessage in case v is a google.api.HttpBody message it returns -// its specified content type otherwise fall back to the default Marshaler. -func (h *HTTPBodyMarshaler) ContentTypeFromMessage(v interface{}) string { +// ContentType returns its specified content type in case v is a +// google.api.HttpBody message, otherwise it will fall back to the default Marshalers +// content type. +func (h *HTTPBodyMarshaler) ContentType(v interface{}) string { if httpBody, ok := v.(*httpbody.HttpBody); ok { return httpBody.GetContentType() } - return h.Marshaler.ContentType() + return h.Marshaler.ContentType(v) } // Marshal marshals "v" by returning the body bytes if v is a diff --git a/gateway/runtime/marshal_httpbodyproto_test.go b/gateway/runtime/marshal_httpbodyproto_test.go index 4bcd358..dbfbadb 100644 --- a/gateway/runtime/marshal_httpbodyproto_test.go +++ b/gateway/runtime/marshal_httpbodyproto_test.go @@ -4,25 +4,29 @@ import ( "bytes" "testing" + // "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" "github.com/binchencoder/ease-gateway/gateway/runtime" "google.golang.org/genproto/googleapis/api/httpbody" + "google.golang.org/protobuf/encoding/protojson" ) func TestHTTPBodyContentType(t *testing.T) { m := runtime.HTTPBodyMarshaler{ &runtime.JSONPb{ - OrigName: true, + MarshalOptions: protojson.MarshalOptions{ + UseProtoNames: true, + }, }, } expected := "CustomContentType" message := &httpbody.HttpBody{ ContentType: expected, } - res := m.ContentType() + res := m.ContentType(nil) if res != "application/json" { t.Errorf("content type not equal (%q, %q)", res, expected) } - res = m.ContentTypeFromMessage(message) + res = m.ContentType(message) if res != expected { t.Errorf("content type not equal (%q, %q)", res, expected) } @@ -31,7 +35,9 @@ func TestHTTPBodyContentType(t *testing.T) { func TestHTTPBodyMarshal(t *testing.T) { m := runtime.HTTPBodyMarshaler{ &runtime.JSONPb{ - OrigName: true, + MarshalOptions: protojson.MarshalOptions{ + UseProtoNames: true, + }, }, } expected := []byte("Some test") diff --git a/gateway/runtime/marshal_json.go b/gateway/runtime/marshal_json.go index f9d3a58..d6aa825 100644 --- a/gateway/runtime/marshal_json.go +++ b/gateway/runtime/marshal_json.go @@ -15,7 +15,7 @@ import ( type JSONBuiltin struct{} // ContentType always Returns "application/json". -func (*JSONBuiltin) ContentType() string { +func (*JSONBuiltin) ContentType(_ interface{}) string { return "application/json" } diff --git a/gateway/runtime/marshal_json_test.go b/gateway/runtime/marshal_json_test.go index e7610ce..f13c0b1 100644 --- a/gateway/runtime/marshal_json_test.go +++ b/gateway/runtime/marshal_json_test.go @@ -7,32 +7,33 @@ import ( "strings" "testing" - "github.com/golang/protobuf/proto" - "github.com/golang/protobuf/ptypes/empty" - structpb "github.com/golang/protobuf/ptypes/struct" - "github.com/golang/protobuf/ptypes/timestamp" - "github.com/golang/protobuf/ptypes/wrappers" - "github.com/grpc-ecosystem/grpc-gateway/runtime" - "github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb" + emptypb "github.com/golang/protobuf/ptypes/empty" + timestamppb "github.com/golang/protobuf/ptypes/timestamp" + wrapperspb "github.com/golang/protobuf/ptypes/wrappers" + "github.com/google/go-cmp/cmp" + "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" + "github.com/grpc-ecosystem/grpc-gateway/v2/runtime/internal/examplepb" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/testing/protocmp" ) func TestJSONBuiltinMarshal(t *testing.T) { var m runtime.JSONBuiltin - msg := examplepb.SimpleMessage{ + msg := &examplepb.SimpleMessage{ Id: "foo", } - buf, err := m.Marshal(&msg) + buf, err := m.Marshal(msg) if err != nil { - t.Errorf("m.Marshal(%v) failed with %v; want success", &msg, err) + t.Errorf("m.Marshal(%v) failed with %v; want success", msg, err) } - var got examplepb.SimpleMessage - if err := json.Unmarshal(buf, &got); err != nil { - t.Errorf("json.Unmarshal(%q, &got) failed with %v; want success", buf, err) + got := new(examplepb.SimpleMessage) + if err := json.Unmarshal(buf, got); err != nil { + t.Errorf("json.Unmarshal(%q, got) failed with %v; want success", buf, err) } - if want := msg; !reflect.DeepEqual(got, want) { - t.Errorf("got = %v; want %v", &got, &want) + if diff := cmp.Diff(got, msg, protocmp.Transform()); diff != "" { + t.Error(diff) } } @@ -65,19 +66,19 @@ func TestJSONBuiltinMarshalFieldKnownErrors(t *testing.T) { func TestJSONBuiltinsnmarshal(t *testing.T) { var ( m runtime.JSONBuiltin - got examplepb.SimpleMessage + got = new(examplepb.SimpleMessage) data = []byte(`{"id": "foo"}`) ) - if err := m.Unmarshal(data, &got); err != nil { - t.Errorf("m.Unmarshal(%q, &got) failed with %v; want success", data, err) + if err := m.Unmarshal(data, got); err != nil { + t.Errorf("m.Unmarshal(%q, got) failed with %v; want success", data, err) } - want := examplepb.SimpleMessage{ + want := &examplepb.SimpleMessage{ Id: "foo", } - if !reflect.DeepEqual(got, want) { - t.Errorf("got = %v; want = %v", &got, &want) + if diff := cmp.Diff(got, want, protocmp.Transform()); diff != "" { + t.Errorf(diff) } } @@ -89,8 +90,9 @@ func TestJSONBuiltinUnmarshalField(t *testing.T) { t.Errorf("m.Unmarshal(%q, dest) failed with %v; want success", fixt.json, err) } - if got, want := dest.Elem().Interface(), fixt.data; !reflect.DeepEqual(got, want) { - t.Errorf("got = %#v; want = %#v; input = %q", got, want, fixt.json) + got, want := dest.Elem().Interface(), fixt.data + if diff := cmp.Diff(got, want, protocmp.Transform()); diff != "" { + t.Error(diff) } } } @@ -115,22 +117,22 @@ func TestJSONBuiltinUnmarshalFieldKnownErrors(t *testing.T) { func TestJSONBuiltinEncoder(t *testing.T) { var m runtime.JSONBuiltin - msg := examplepb.SimpleMessage{ + msg := &examplepb.SimpleMessage{ Id: "foo", } var buf bytes.Buffer enc := m.NewEncoder(&buf) - if err := enc.Encode(&msg); err != nil { - t.Errorf("enc.Encode(%v) failed with %v; want success", &msg, err) + if err := enc.Encode(msg); err != nil { + t.Errorf("enc.Encode(%v) failed with %v; want success", msg, err) } - var got examplepb.SimpleMessage - if err := json.Unmarshal(buf.Bytes(), &got); err != nil { - t.Errorf("json.Unmarshal(%q, &got) failed with %v; want success", buf.String(), err) + got := new(examplepb.SimpleMessage) + if err := json.Unmarshal(buf.Bytes(), got); err != nil { + t.Errorf("json.Unmarshal(%q, got) failed with %v; want success", buf.String(), err) } - if want := msg; !reflect.DeepEqual(got, want) { - t.Errorf("got = %v; want %v", &got, &want) + if diff := cmp.Diff(got, msg, protocmp.Transform()); diff != "" { + t.Error(diff) } } @@ -152,21 +154,21 @@ func TestJSONBuiltinEncoderFields(t *testing.T) { func TestJSONBuiltinDecoder(t *testing.T) { var ( m runtime.JSONBuiltin - got examplepb.SimpleMessage + got = new(examplepb.SimpleMessage) data = `{"id": "foo"}` ) r := strings.NewReader(data) dec := m.NewDecoder(r) - if err := dec.Decode(&got); err != nil { - t.Errorf("m.Unmarshal(&got) failed with %v; want success", err) + if err := dec.Decode(got); err != nil { + t.Errorf("m.Unmarshal(got) failed with %v; want success", err) } - want := examplepb.SimpleMessage{ + want := &examplepb.SimpleMessage{ Id: "foo", } - if !reflect.DeepEqual(got, want) { - t.Errorf("got = %v; want = %v", &got, &want) + if diff := cmp.Diff(got, want, protocmp.Transform()); diff != "" { + t.Errorf("got = %v; want = %v", got, want) } } @@ -180,8 +182,9 @@ func TestJSONBuiltinDecoderFields(t *testing.T) { t.Errorf("dec.Decode(dest) failed with %v; want success; data = %q", err, fixt.json) } - if got, want := dest.Elem().Interface(), fixt.data; !reflect.DeepEqual(got, want) { - t.Errorf("got = %v; want = %v; input = %q", got, want, fixt.json) + got, want := dest.Elem().Interface(), fixt.data + if diff := cmp.Diff(got, want, protocmp.Transform()); diff != "" { + t.Error(diff) } } } @@ -210,7 +213,7 @@ var ( {data: true, json: "true"}, {data: proto.Bool(true), json: "true"}, {data: (*string)(nil), json: "null"}, - {data: new(empty.Empty), json: "{}"}, + {data: new(emptypb.Empty), json: "{}"}, {data: examplepb.NumericEnum_ONE, json: "1"}, {data: nil, json: "null"}, {data: (*string)(nil), json: "null"}, @@ -238,23 +241,15 @@ var ( json: `"abc"`, }, { - data: ×tamp.Timestamp{ + data: ×tamppb.Timestamp{ Seconds: 1462875553, Nanos: 123000000, }, json: `"2016-05-10T10:19:13.123Z"`, }, { - data: &wrappers.Int32Value{Value: 123}, + data: &wrapperspb.Int32Value{Value: 123}, json: "123", }, - { - data: &structpb.Value{ - Kind: &structpb.Value_StringValue{ - StringValue: "abc", - }, - }, - json: `"abc"`, - }, } ) diff --git a/gateway/runtime/marshal_jsonpb.go b/gateway/runtime/marshal_jsonpb.go index f0de351..38ac3dd 100644 --- a/gateway/runtime/marshal_jsonpb.go +++ b/gateway/runtime/marshal_jsonpb.go @@ -7,20 +7,23 @@ import ( "io" "reflect" - "github.com/golang/protobuf/jsonpb" - "github.com/golang/protobuf/proto" + "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) // JSONPb is a Marshaler which marshals/unmarshals into/from JSON -// with the "github.com/golang/protobuf/jsonpb". -// It supports fully functionality of protobuf unlike JSONBuiltin. +// with the "google.golang.org/protobuf/encoding/protojson" marshaler. +// It supports the full functionality of protobuf unlike JSONBuiltin. // // The NewDecoder method returns a DecoderWrapper, so the underlying // *json.Decoder methods can be used. -type JSONPb jsonpb.Marshaler +type JSONPb struct { + protojson.MarshalOptions + protojson.UnmarshalOptions +} // ContentType always returns "application/json". -func (*JSONPb) ContentType() string { +func (*JSONPb) ContentType(_ interface{}) string { return "application/json" } @@ -47,7 +50,13 @@ func (j *JSONPb) marshalTo(w io.Writer, v interface{}) error { _, err = w.Write(buf) return err } - return (*jsonpb.Marshaler)(j).Marshal(w, p) + b, err := j.MarshalOptions.Marshal(p) + if err != nil { + return err + } + + _, err = w.Write(b) + return err } var ( @@ -56,8 +65,8 @@ var ( ) // marshalNonProto marshals a non-message field of a protobuf message. -// This function does not correctly marshals arbitrary data structure into JSON, -// but it is only capable of marshaling non-message field values of protobuf, +// This function does not correctly marshal arbitrary data structures into JSON, +// it is only capable of marshaling non-message field values of protobuf, // i.e. primitive types, enums; pointers to primitives or enums; maps from // integer/string types to primitives/enums/pointers to messages. func (j *JSONPb) marshalNonProtoField(v interface{}) ([]byte, error) { @@ -74,7 +83,7 @@ func (j *JSONPb) marshalNonProtoField(v interface{}) ([]byte, error) { if rv.Kind() == reflect.Slice { if rv.IsNil() { - if j.EmitDefaults { + if j.EmitUnpopulated { return []byte("[]"), nil } return []byte("null"), nil @@ -93,7 +102,7 @@ func (j *JSONPb) marshalNonProtoField(v interface{}) ([]byte, error) { return nil, err } } - if err = (*jsonpb.Marshaler)(j).Marshal(&buf, rv.Index(i).Interface().(proto.Message)); err != nil { + if err = j.marshalTo(&buf, rv.Index(i).Interface().(proto.Message)); err != nil { return nil, err } } @@ -120,7 +129,7 @@ func (j *JSONPb) marshalNonProtoField(v interface{}) ([]byte, error) { } return json.Marshal(m) } - if enum, ok := rv.Interface().(protoEnum); ok && !j.EnumsAsInts { + if enum, ok := rv.Interface().(protoEnum); ok && !j.UseEnumNumbers { return json.Marshal(enum.String()) } return json.Marshal(rv.Interface()) @@ -128,25 +137,29 @@ func (j *JSONPb) marshalNonProtoField(v interface{}) ([]byte, error) { // Unmarshal unmarshals JSON "data" into "v" func (j *JSONPb) Unmarshal(data []byte, v interface{}) error { - return unmarshalJSONPb(data, v) + return unmarshalJSONPb(data, j.UnmarshalOptions, v) } // NewDecoder returns a Decoder which reads JSON stream from "r". func (j *JSONPb) NewDecoder(r io.Reader) Decoder { d := json.NewDecoder(r) - return DecoderWrapper{Decoder: d} + return DecoderWrapper{ + Decoder: d, + UnmarshalOptions: j.UnmarshalOptions, + } } // DecoderWrapper is a wrapper around a *json.Decoder that adds // support for protos to the Decode method. type DecoderWrapper struct { *json.Decoder + protojson.UnmarshalOptions } // Decode wraps the embedded decoder's Decode method to support // protos using a jsonpb.Unmarshaler. func (d DecoderWrapper) Decode(v interface{}) error { - return decodeJSONPb(d.Decoder, v) + return decodeJSONPb(d.Decoder, d.UnmarshalOptions, v) } // NewEncoder returns an Encoder which writes JSON stream into "w". @@ -162,21 +175,28 @@ func (j *JSONPb) NewEncoder(w io.Writer) Encoder { }) } -func unmarshalJSONPb(data []byte, v interface{}) error { +func unmarshalJSONPb(data []byte, unmarshaler protojson.UnmarshalOptions, v interface{}) error { d := json.NewDecoder(bytes.NewReader(data)) - return decodeJSONPb(d, v) + return decodeJSONPb(d, unmarshaler, v) } -func decodeJSONPb(d *json.Decoder, v interface{}) error { +func decodeJSONPb(d *json.Decoder, unmarshaler protojson.UnmarshalOptions, v interface{}) error { p, ok := v.(proto.Message) if !ok { - return decodeNonProtoField(d, v) + return decodeNonProtoField(d, unmarshaler, v) + } + + // Decode into bytes for marshalling + var b json.RawMessage + err := d.Decode(&b) + if err != nil { + return err } - unmarshaler := &jsonpb.Unmarshaler{AllowUnknownFields: allowUnknownFields} - return unmarshaler.UnmarshalNext(d, p) + + return unmarshaler.Unmarshal([]byte(b), p) } -func decodeNonProtoField(d *json.Decoder, v interface{}) error { +func decodeNonProtoField(d *json.Decoder, unmarshaler protojson.UnmarshalOptions, v interface{}) error { rv := reflect.ValueOf(v) if rv.Kind() != reflect.Ptr { return fmt.Errorf("%T is not a pointer", v) @@ -186,8 +206,14 @@ func decodeNonProtoField(d *json.Decoder, v interface{}) error { rv.Set(reflect.New(rv.Type().Elem())) } if rv.Type().ConvertibleTo(typeProtoMessage) { - unmarshaler := &jsonpb.Unmarshaler{AllowUnknownFields: allowUnknownFields} - return unmarshaler.UnmarshalNext(d, rv.Interface().(proto.Message)) + // Decode into bytes for marshalling + var b json.RawMessage + err := d.Decode(&b) + if err != nil { + return err + } + + return unmarshaler.Unmarshal([]byte(b), rv.Interface().(proto.Message)) } rv = rv.Elem() } @@ -211,24 +237,41 @@ func decodeNonProtoField(d *json.Decoder, v interface{}) error { } bk := result[0] bv := reflect.New(rv.Type().Elem()) - if err := unmarshalJSONPb([]byte(*v), bv.Interface()); err != nil { + if err := unmarshalJSONPb([]byte(*v), unmarshaler, bv.Interface()); err != nil { return err } rv.SetMapIndex(bk, bv.Elem()) } return nil } + if rv.Kind() == reflect.Slice { + var sl []json.RawMessage + if err := d.Decode(&sl); err != nil { + return err + } + if sl != nil { + rv.Set(reflect.MakeSlice(rv.Type(), 0, 0)) + } + for _, item := range sl { + bv := reflect.New(rv.Type().Elem()) + if err := unmarshalJSONPb([]byte(item), unmarshaler, bv.Interface()); err != nil { + return err + } + rv.Set(reflect.Append(rv, bv.Elem())) + } + return nil + } if _, ok := rv.Interface().(protoEnum); ok { var repr interface{} if err := d.Decode(&repr); err != nil { return err } - switch repr.(type) { + switch v := repr.(type) { case string: // TODO(yugui) Should use proto.StructProperties? return fmt.Errorf("unmarshaling of symbolic enum %q not supported: %T", repr, rv.Interface()) case float64: - rv.Set(reflect.ValueOf(int32(repr.(float64))).Convert(rv.Type())) + rv.Set(reflect.ValueOf(int32(v)).Convert(rv.Type())) return nil default: return fmt.Errorf("cannot assign %#v into Go type %T", repr, rv.Interface()) @@ -249,14 +292,16 @@ func (j *JSONPb) Delimiter() []byte { return []byte("\n") } -// allowUnknownFields helps not to return an error when the destination -// is a struct and the input contains object keys which do not match any -// non-ignored, exported fields in the destination. -var allowUnknownFields = true - -// DisallowUnknownFields enables option in decoder (unmarshaller) to -// return an error when it finds an unknown field. This function must be -// called before using the JSON marshaller. -func DisallowUnknownFields() { - allowUnknownFields = false -} +var ( + convFromType = map[reflect.Kind]reflect.Value{ + reflect.String: reflect.ValueOf(String), + reflect.Bool: reflect.ValueOf(Bool), + reflect.Float64: reflect.ValueOf(Float64), + reflect.Float32: reflect.ValueOf(Float32), + reflect.Int64: reflect.ValueOf(Int64), + reflect.Int32: reflect.ValueOf(Int32), + reflect.Uint64: reflect.ValueOf(Uint64), + reflect.Uint32: reflect.ValueOf(Uint32), + reflect.Slice: reflect.ValueOf(Bytes), + } +) diff --git a/gateway/runtime/marshal_jsonpb_test.go b/gateway/runtime/marshal_jsonpb_test.go index 19d5bc8..e508562 100644 --- a/gateway/runtime/marshal_jsonpb_test.go +++ b/gateway/runtime/marshal_jsonpb_test.go @@ -7,15 +7,17 @@ import ( "strings" "testing" - "github.com/golang/protobuf/jsonpb" - "github.com/golang/protobuf/proto" - "github.com/golang/protobuf/ptypes/duration" - "github.com/golang/protobuf/ptypes/empty" + durationpb "github.com/golang/protobuf/ptypes/duration" + emptypb "github.com/golang/protobuf/ptypes/empty" structpb "github.com/golang/protobuf/ptypes/struct" - "github.com/golang/protobuf/ptypes/timestamp" - "github.com/golang/protobuf/ptypes/wrappers" - "github.com/grpc-ecosystem/grpc-gateway/runtime" - "github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb" + timestamppb "github.com/golang/protobuf/ptypes/timestamp" + wrapperspb "github.com/golang/protobuf/ptypes/wrappers" + "github.com/google/go-cmp/cmp" + "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" + "github.com/grpc-ecosystem/grpc-gateway/v2/runtime/internal/examplepb" + "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/testing/protocmp" ) func TestJSONPbMarshal(t *testing.T) { @@ -25,7 +27,7 @@ func TestJSONPbMarshal(t *testing.T) { MappedStringValue: map[string]string{}, MappedNestedValue: map[string]*examplepb.ABitOfEverything_Nested{}, RepeatedEnumValue: []examplepb.NumericEnum{}, - TimestampValue: ×tamp.Timestamp{}, + TimestampValue: ×tamppb.Timestamp{}, Uuid: "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", Nested: []*examplepb.ABitOfEverything_Nested{ { @@ -50,16 +52,13 @@ func TestJSONPbMarshal(t *testing.T) { } for i, spec := range []struct { - enumsAsInts, emitDefaults bool - indent string - origName bool - verifier func(json string) + useEnumNumbers, emitUnpopulated bool + indent string + useProtoNames bool + verifier func(json string) }{ { verifier: func(json string) { - if strings.ContainsAny(json, " \t\r\n") { - t.Errorf("strings.ContainsAny(%q, %q) = true; want false", json, " \t\r\n") - } if !strings.Contains(json, "ONE") { t.Errorf(`strings.Contains(%q, "ONE") = false; want true`, json) } @@ -69,7 +68,7 @@ func TestJSONPbMarshal(t *testing.T) { }, }, { - enumsAsInts: true, + useEnumNumbers: true, verifier: func(json string) { if strings.Contains(json, "ONE") { t.Errorf(`strings.Contains(%q, "ONE") = true; want false`, json) @@ -77,7 +76,7 @@ func TestJSONPbMarshal(t *testing.T) { }, }, { - emitDefaults: true, + emitUnpopulated: true, verifier: func(json string) { if want := `"sfixed32Value"`; !strings.Contains(json, want) { t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want) @@ -93,7 +92,7 @@ func TestJSONPbMarshal(t *testing.T) { }, }, { - origName: true, + useProtoNames: true, verifier: func(json string) { if want := "uint64_value"; !strings.Contains(json, want) { t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want) @@ -101,33 +100,38 @@ func TestJSONPbMarshal(t *testing.T) { }, }, } { - m := runtime.JSONPb{ - EnumsAsInts: spec.enumsAsInts, - EmitDefaults: spec.emitDefaults, - Indent: spec.indent, - OrigName: spec.origName, - } - buf, err := m.Marshal(&msg) - if err != nil { - t.Errorf("m.Marshal(%v) failed with %v; want success; spec=%v", &msg, err, spec) - } + t.Run(strconv.Itoa(i), func(t *testing.T) { + m := runtime.JSONPb{ + MarshalOptions: protojson.MarshalOptions{ + EmitUnpopulated: spec.emitUnpopulated, + Indent: spec.indent, + UseProtoNames: spec.useProtoNames, + UseEnumNumbers: spec.useEnumNumbers, + }, + } + buf, err := m.Marshal(&msg) + if err != nil { + t.Errorf("m.Marshal(%v) failed with %v; want success; spec=%v", &msg, err, spec) + } - var got examplepb.ABitOfEverything - if err := jsonpb.UnmarshalString(string(buf), &got); err != nil { - t.Errorf("jsonpb.UnmarshalString(%q, &got) failed with %v; want success; spec=%v", string(buf), err, spec) - } - if want := msg; !reflect.DeepEqual(got, want) { - t.Errorf("case %d: got = %v; want %v; spec=%v", i, &got, &want, spec) - } - if spec.verifier != nil { - spec.verifier(string(buf)) - } + var got examplepb.ABitOfEverything + unmarshaler := &protojson.UnmarshalOptions{} + if err = unmarshaler.Unmarshal(buf, &got); err != nil { + t.Errorf("jsonpb.UnmarshalString(%q, &got) failed with %v; want success; spec=%v", string(buf), err, spec) + } + if diff := cmp.Diff(&got, &msg, protocmp.Transform()); diff != "" { + t.Errorf("case %d: spec=%v; %s", i, spec, diff) + } + if spec.verifier != nil { + spec.verifier(string(buf)) + } + }) } } func TestJSONPbMarshalFields(t *testing.T) { var m runtime.JSONPb - m.EnumsAsInts = true // builtin fixtures include an enum, expected to be marshaled as int + m.UseEnumNumbers = true // builtin fixtures include an enum, expected to be marshaled as int for _, spec := range builtinFieldFixtures { buf, err := m.Marshal(spec.data) if err != nil { @@ -138,7 +142,7 @@ func TestJSONPbMarshalFields(t *testing.T) { } } - m.EnumsAsInts = false + m.UseEnumNumbers = false buf, err := m.Marshal(examplepb.NumericEnum_ONE) if err != nil { t.Errorf("m.Marshal(%#v) failed with %v; want success", examplepb.NumericEnum_ONE, err) @@ -217,8 +221,8 @@ func TestJSONPbUnmarshal(t *testing.T) { }, } - if !reflect.DeepEqual(got, want) { - t.Errorf("case %d: got = %v; want = %v", i, &got, &want) + if diff := cmp.Diff(&got, &want, protocmp.Transform()); diff != "" { + t.Errorf("case %d: %s", i, diff) } } } @@ -234,8 +238,8 @@ func TestJSONPbUnmarshalFields(t *testing.T) { if err := m.Unmarshal([]byte(fixt.json), dest.Interface()); err != nil { t.Errorf("m.Unmarshal(%q, %T) failed with %v; want success", fixt.json, dest.Interface(), err) } - if got, want := dest.Elem().Interface(), fixt.data; !reflect.DeepEqual(got, want) { - t.Errorf("dest = %#v; want %#v; input = %v", got, want, fixt.json) + if diff := cmp.Diff(dest.Elem().Interface(), fixt.data, protocmp.Transform()); diff != "" { + t.Errorf("dest = %#v; want %#v; input = %v", dest.Elem().Interface(), fixt.data, fixt.json) } } } @@ -247,7 +251,7 @@ func TestJSONPbEncoder(t *testing.T) { MappedStringValue: map[string]string{}, MappedNestedValue: map[string]*examplepb.ABitOfEverything_Nested{}, RepeatedEnumValue: []examplepb.NumericEnum{}, - TimestampValue: ×tamp.Timestamp{}, + TimestampValue: ×tamppb.Timestamp{}, Uuid: "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", Nested: []*examplepb.ABitOfEverything_Nested{ { @@ -271,19 +275,13 @@ func TestJSONPbEncoder(t *testing.T) { } for i, spec := range []struct { - enumsAsInts, emitDefaults bool - indent string - origName bool - verifier func(json string) + useEnumNumbers, emitUnpopulated bool + indent string + useProtoNames bool + verifier func(json string) }{ { verifier: func(json string) { - // remove trailing delimiter before verifying - json = strings.TrimSuffix(json, "\n") - - if strings.ContainsAny(json, " \t\r\n") { - t.Errorf("strings.ContainsAny(%q, %q) = true; want false", json, " \t\r\n") - } if !strings.Contains(json, "ONE") { t.Errorf(`strings.Contains(%q, "ONE") = false; want true`, json) } @@ -293,7 +291,7 @@ func TestJSONPbEncoder(t *testing.T) { }, }, { - enumsAsInts: true, + useEnumNumbers: true, verifier: func(json string) { if strings.Contains(json, "ONE") { t.Errorf(`strings.Contains(%q, "ONE") = true; want false`, json) @@ -301,7 +299,7 @@ func TestJSONPbEncoder(t *testing.T) { }, }, { - emitDefaults: true, + emitUnpopulated: true, verifier: func(json string) { if want := `"sfixed32Value"`; !strings.Contains(json, want) { t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want) @@ -317,7 +315,7 @@ func TestJSONPbEncoder(t *testing.T) { }, }, { - origName: true, + useProtoNames: true, verifier: func(json string) { if want := "uint64_value"; !strings.Contains(json, want) { t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want) @@ -326,10 +324,12 @@ func TestJSONPbEncoder(t *testing.T) { }, } { m := runtime.JSONPb{ - EnumsAsInts: spec.enumsAsInts, - EmitDefaults: spec.emitDefaults, - Indent: spec.indent, - OrigName: spec.origName, + MarshalOptions: protojson.MarshalOptions{ + EmitUnpopulated: spec.emitUnpopulated, + Indent: spec.indent, + UseProtoNames: spec.useProtoNames, + UseEnumNumbers: spec.useEnumNumbers, + }, } var buf bytes.Buffer @@ -339,11 +339,12 @@ func TestJSONPbEncoder(t *testing.T) { } var got examplepb.ABitOfEverything - if err := jsonpb.UnmarshalString(buf.String(), &got); err != nil { + unmarshaler := &protojson.UnmarshalOptions{} + if err := unmarshaler.Unmarshal(buf.Bytes(), &got); err != nil { t.Errorf("jsonpb.UnmarshalString(%q, &got) failed with %v; want success; spec=%v", buf.String(), err, spec) } - if want := msg; !reflect.DeepEqual(got, want) { - t.Errorf("case %d: got = %v; want %v; spec=%v", i, &got, &want, spec) + if diff := cmp.Diff(&got, &msg, protocmp.Transform()); diff != "" { + t.Errorf("case %d: %s", i, diff) } if spec.verifier != nil { spec.verifier(buf.String()) @@ -364,7 +365,7 @@ func TestJSONPbEncoderFields(t *testing.T) { } } - m.EnumsAsInts = true + m.UseEnumNumbers = true buf, err := m.Marshal(examplepb.NumericEnum_ONE) if err != nil { t.Errorf("m.Marshal(%#v) failed with %v; want success", examplepb.NumericEnum_ONE, err) @@ -444,8 +445,8 @@ func TestJSONPbDecoder(t *testing.T) { "b": examplepb.NumericEnum_ZERO, }, } - if !reflect.DeepEqual(got, want) { - t.Errorf("got = %v; want = %v; data = %v", &got, &want, data) + if diff := cmp.Diff(&got, &want, protocmp.Transform()); diff != "" { + t.Errorf("data %q: %s", data, diff) } } } @@ -470,7 +471,11 @@ func TestJSONPbDecoderFields(t *testing.T) { func TestJSONPbDecoderUnknownField(t *testing.T) { var ( - m runtime.JSONPb + m = runtime.JSONPb{ + UnmarshalOptions: protojson.UnmarshalOptions{ + DiscardUnknown: false, + }, + } got examplepb.ABitOfEverything ) data := `{ @@ -478,8 +483,6 @@ func TestJSONPbDecoderUnknownField(t *testing.T) { "unknownField": "111" }` - runtime.DisallowUnknownFields() - r := strings.NewReader(data) dec := m.NewDecoder(r) if err := dec.Decode(&got); err == nil { @@ -548,26 +551,23 @@ var ( json: `{"true":{"id":"foo"}}`, }, { - data: &duration.Duration{ + data: &durationpb.Duration{ Seconds: 123, Nanos: 456000000, }, json: `"123.456s"`, }, { - data: ×tamp.Timestamp{ + data: ×tamppb.Timestamp{ Seconds: 1462875553, Nanos: 123000000, }, json: `"2016-05-10T10:19:13.123Z"`, }, { - data: new(empty.Empty), + data: new(emptypb.Empty), json: "{}", }, - - // TODO(yugui) Enable unmarshaling of the following examples - // once jsonpb supports them. { data: &structpb.Value{ Kind: new(structpb.Value_NullValue), @@ -617,31 +617,31 @@ var ( }, { - data: &wrappers.BoolValue{Value: true}, + data: &wrapperspb.BoolValue{Value: true}, json: "true", }, { - data: &wrappers.DoubleValue{Value: 123.456}, + data: &wrapperspb.DoubleValue{Value: 123.456}, json: "123.456", }, { - data: &wrappers.FloatValue{Value: 123.456}, + data: &wrapperspb.FloatValue{Value: 123.456}, json: "123.456", }, { - data: &wrappers.Int32Value{Value: -123}, + data: &wrapperspb.Int32Value{Value: -123}, json: "-123", }, { - data: &wrappers.Int64Value{Value: -123}, + data: &wrapperspb.Int64Value{Value: -123}, json: `"-123"`, }, { - data: &wrappers.UInt32Value{Value: 123}, + data: &wrapperspb.UInt32Value{Value: 123}, json: "123", }, { - data: &wrappers.UInt64Value{Value: 123}, + data: &wrapperspb.UInt64Value{Value: 123}, json: `"123"`, }, // TODO(yugui) Add other well-known types once jsonpb supports them @@ -649,144 +649,210 @@ var ( ) func TestJSONPbMarshalResponseBodies(t *testing.T) { + marshaler := &runtime.JSONPb{} for i, spec := range []struct { - input interface{} - emitDefaults bool - verifier func(json string) + input interface{} + emitUnpopulated bool + verifier func(*testing.T, interface{}, []byte) }{ { input: &examplepb.ResponseBodyOut{ Response: &examplepb.ResponseBodyOut_Response{Data: "abcdef"}, }, - verifier: func(json string) { - expected := `{"response":{"data":"abcdef"}}` - if json != expected { - t.Errorf("json not equal (%q, %q)", json, expected) + verifier: func(t *testing.T, input interface{}, json []byte) { + var out examplepb.ResponseBodyOut + err := marshaler.Unmarshal(json, &out) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + diff := cmp.Diff(input, &out, protocmp.Transform()) + if diff != "" { + t.Errorf("json not equal:\n%s", diff) } }, }, { - emitDefaults: true, - input: &examplepb.ResponseBodyOut{}, - verifier: func(json string) { - expected := `{"response":null}` - if json != expected { - t.Errorf("json not equal (%q, %q)", json, expected) + emitUnpopulated: true, + input: &examplepb.ResponseBodyOut{}, + verifier: func(t *testing.T, input interface{}, json []byte) { + var out examplepb.ResponseBodyOut + err := marshaler.Unmarshal(json, &out) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + diff := cmp.Diff(input, &out, protocmp.Transform()) + if diff != "" { + t.Errorf("json not equal:\n%s", diff) } }, }, { input: &examplepb.RepeatedResponseBodyOut_Response{}, - verifier: func(json string) { - expected := `{}` - if json != expected { - t.Errorf("json not equal (%q, %q)", json, expected) + verifier: func(t *testing.T, input interface{}, json []byte) { + var out examplepb.RepeatedResponseBodyOut_Response + err := marshaler.Unmarshal(json, &out) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + diff := cmp.Diff(input, &out, protocmp.Transform()) + if diff != "" { + t.Errorf("json not equal:\n%s", diff) } }, }, { - emitDefaults: true, - input: &examplepb.RepeatedResponseBodyOut_Response{}, - verifier: func(json string) { - expected := `{"data":"","type":"UNKNOWN"}` - if json != expected { - t.Errorf("json not equal (%q, %q)", json, expected) + emitUnpopulated: true, + input: &examplepb.RepeatedResponseBodyOut_Response{}, + verifier: func(t *testing.T, input interface{}, json []byte) { + var out examplepb.RepeatedResponseBodyOut_Response + err := marshaler.Unmarshal(json, &out) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + diff := cmp.Diff(input, &out, protocmp.Transform()) + if diff != "" { + t.Errorf("json not equal:\n%s", diff) } }, }, { input: ([]*examplepb.RepeatedResponseBodyOut_Response)(nil), - verifier: func(json string) { - expected := `null` - if json != expected { - t.Errorf("json not equal (%q, %q)", json, expected) + verifier: func(t *testing.T, input interface{}, json []byte) { + var out []*examplepb.RepeatedResponseBodyOut_Response + err := marshaler.Unmarshal(json, &out) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + diff := cmp.Diff(input, out, protocmp.Transform()) + if diff != "" { + t.Errorf("json not equal:\n%s", diff) } }, }, { - emitDefaults: true, - input: ([]*examplepb.RepeatedResponseBodyOut_Response)(nil), - verifier: func(json string) { - expected := `[]` - if json != expected { - t.Errorf("json not equal (%q, %q)", json, expected) + emitUnpopulated: true, + input: ([]*examplepb.RepeatedResponseBodyOut_Response)(nil), + verifier: func(t *testing.T, _ interface{}, json []byte) { + var out []*examplepb.RepeatedResponseBodyOut_Response + err := marshaler.Unmarshal(json, &out) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + diff := cmp.Diff([]*examplepb.RepeatedResponseBodyOut_Response{}, out, protocmp.Transform()) + if diff != "" { + t.Errorf("json not equal:\n%s", diff) } }, }, { input: []*examplepb.RepeatedResponseBodyOut_Response{}, - verifier: func(json string) { - expected := `[]` - if json != expected { - t.Errorf("json not equal (%q, %q)", json, expected) + verifier: func(t *testing.T, input interface{}, json []byte) { + var out []*examplepb.RepeatedResponseBodyOut_Response + err := marshaler.Unmarshal(json, &out) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + diff := cmp.Diff(input, out, protocmp.Transform()) + if diff != "" { + t.Errorf("json not equal:\n%s", diff) } }, }, { input: []string{"something"}, - verifier: func(json string) { - expected := `["something"]` - if json != expected { - t.Errorf("json not equal (%q, %q)", json, expected) + verifier: func(t *testing.T, input interface{}, json []byte) { + var out []string + err := marshaler.Unmarshal(json, &out) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + diff := cmp.Diff(input, out, protocmp.Transform()) + if diff != "" { + t.Errorf("json not equal:\n%s", diff) } }, }, { input: []string{}, - verifier: func(json string) { - expected := `[]` - if json != expected { - t.Errorf("json not equal (%q, %q)", json, expected) + verifier: func(t *testing.T, input interface{}, json []byte) { + var out []string + err := marshaler.Unmarshal(json, &out) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + diff := cmp.Diff(input, out, protocmp.Transform()) + if diff != "" { + t.Errorf("json not equal:\n%s", diff) } }, }, { input: ([]string)(nil), - verifier: func(json string) { - expected := `null` - if json != expected { - t.Errorf("json not equal (%q, %q)", json, expected) + verifier: func(t *testing.T, input interface{}, json []byte) { + var out []string + err := marshaler.Unmarshal(json, &out) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + diff := cmp.Diff(input, out, protocmp.Transform()) + if diff != "" { + t.Errorf("json not equal:\n%s", diff) } }, }, { - emitDefaults: true, - input: ([]string)(nil), - verifier: func(json string) { - expected := `[]` - if json != expected { - t.Errorf("json not equal (%q, %q)", json, expected) + emitUnpopulated: true, + input: ([]string)(nil), + verifier: func(t *testing.T, _ interface{}, json []byte) { + var out []string + err := marshaler.Unmarshal(json, &out) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + diff := cmp.Diff([]string{}, out, protocmp.Transform()) + if diff != "" { + t.Errorf("json not equal:\n%s", diff) } }, }, { input: []*examplepb.RepeatedResponseBodyOut_Response{ - &examplepb.RepeatedResponseBodyOut_Response{}, - &examplepb.RepeatedResponseBodyOut_Response{ + {}, + { Data: "abc", Type: examplepb.RepeatedResponseBodyOut_Response_A, }, }, - verifier: func(json string) { - expected := `[{},{"data":"abc","type":"A"}]` - if json != expected { - t.Errorf("json not equal (%q, %q)", json, expected) + verifier: func(t *testing.T, input interface{}, json []byte) { + var out []*examplepb.RepeatedResponseBodyOut_Response + err := marshaler.Unmarshal(json, &out) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + diff := cmp.Diff(input, out, protocmp.Transform()) + if diff != "" { + t.Errorf("json not equal:\n%s", diff) } }, }, { - emitDefaults: true, + emitUnpopulated: true, input: []*examplepb.RepeatedResponseBodyOut_Response{ - &examplepb.RepeatedResponseBodyOut_Response{}, - &examplepb.RepeatedResponseBodyOut_Response{ + {}, + { Data: "abc", Type: examplepb.RepeatedResponseBodyOut_Response_B, }, }, - verifier: func(json string) { - expected := `[{"data":"","type":"UNKNOWN"},{"data":"abc","type":"B"}]` - if json != expected { - t.Errorf("json not equal (%q, %q)", json, expected) + verifier: func(t *testing.T, input interface{}, json []byte) { + var out []*examplepb.RepeatedResponseBodyOut_Response + err := marshaler.Unmarshal(json, &out) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + diff := cmp.Diff(input, out, protocmp.Transform()) + if diff != "" { + t.Errorf("json not equal:\n%s", diff) } }, }, @@ -794,7 +860,9 @@ func TestJSONPbMarshalResponseBodies(t *testing.T) { t.Run(strconv.Itoa(i), func(t *testing.T) { m := runtime.JSONPb{ - EmitDefaults: spec.emitDefaults, + MarshalOptions: protojson.MarshalOptions{ + EmitUnpopulated: spec.emitUnpopulated, + }, } val := spec.input buf, err := m.Marshal(val) @@ -802,7 +870,7 @@ func TestJSONPbMarshalResponseBodies(t *testing.T) { t.Errorf("m.Marshal(%v) failed with %v; want success; spec=%v", val, err, spec) } if spec.verifier != nil { - spec.verifier(string(buf)) + spec.verifier(t, spec.input, buf) } }) } diff --git a/gateway/runtime/marshal_proto.go b/gateway/runtime/marshal_proto.go index f65d1a2..007f8f1 100644 --- a/gateway/runtime/marshal_proto.go +++ b/gateway/runtime/marshal_proto.go @@ -4,15 +4,16 @@ import ( "io" "errors" - "github.com/golang/protobuf/proto" "io/ioutil" + + "google.golang.org/protobuf/proto" ) // ProtoMarshaller is a Marshaller which marshals/unmarshals into/from serialize proto bytes type ProtoMarshaller struct{} // ContentType always returns "application/octet-stream". -func (*ProtoMarshaller) ContentType() string { +func (*ProtoMarshaller) ContentType(_ interface{}) string { return "application/octet-stream" } diff --git a/gateway/runtime/marshal_proto_test.go b/gateway/runtime/marshal_proto_test.go index d653aca..df156ac 100644 --- a/gateway/runtime/marshal_proto_test.go +++ b/gateway/runtime/marshal_proto_test.go @@ -4,10 +4,10 @@ import ( "bytes" "testing" - "github.com/golang/protobuf/proto" - "github.com/golang/protobuf/ptypes/timestamp" - "github.com/grpc-ecosystem/grpc-gateway/runtime" - "github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb" + timestamppb "github.com/golang/protobuf/ptypes/timestamp" + "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" + "github.com/grpc-ecosystem/grpc-gateway/v2/runtime/internal/examplepb" + "google.golang.org/protobuf/proto" ) var message = &examplepb.ABitOfEverything{ @@ -16,7 +16,7 @@ var message = &examplepb.ABitOfEverything{ MappedStringValue: nil, MappedNestedValue: nil, RepeatedEnumValue: nil, - TimestampValue: ×tamp.Timestamp{}, + TimestampValue: ×tamppb.Timestamp{}, Uuid: "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", Nested: []*examplepb.ABitOfEverything_Nested{ { diff --git a/gateway/runtime/marshaler.go b/gateway/runtime/marshaler.go index 4615329..2c0d25f 100644 --- a/gateway/runtime/marshaler.go +++ b/gateway/runtime/marshaler.go @@ -16,14 +16,9 @@ type Marshaler interface { // NewEncoder returns an Encoder which writes bytes sequence into "w". NewEncoder(w io.Writer) Encoder // ContentType returns the Content-Type which this marshaler is responsible for. - ContentType() string -} - -// Marshalers that implement contentTypeMarshaler will have their ContentTypeFromMessage method called -// to set the Content-Type header on the response -type contentTypeMarshaler interface { - // ContentTypeFromMessage returns the Content-Type this marshaler produces from the provided message - ContentTypeFromMessage(v interface{}) string + // The parameter describes the type which is being marshalled, which can sometimes + // affect the content type returned. + ContentType(v interface{}) string } // Decoder decodes a byte sequence diff --git a/gateway/runtime/marshaler_registry.go b/gateway/runtime/marshaler_registry.go index ae673e3..a714de0 100644 --- a/gateway/runtime/marshaler_registry.go +++ b/gateway/runtime/marshaler_registry.go @@ -6,6 +6,7 @@ import ( "net/http" "google.golang.org/grpc/grpclog" + "google.golang.org/protobuf/encoding/protojson" ) // MIMEWildcard is the fallback MIME type used for requests which do not match @@ -16,9 +17,15 @@ var ( acceptHeader = http.CanonicalHeaderKey("Accept") contentTypeHeader = http.CanonicalHeaderKey("Content-Type") - defaultMarshaler = &JSONPb{ - OrigName: true, - EnumsAsInts: true, + defaultMarshaler = &HTTPBodyMarshaler{ + Marshaler: &JSONPb{ + MarshalOptions: protojson.MarshalOptions{ + EmitUnpopulated: true, + }, + UnmarshalOptions: protojson.UnmarshalOptions{ + DiscardUnknown: true, + }, + }, } ) diff --git a/gateway/runtime/marshaler_registry_test.go b/gateway/runtime/marshaler_registry_test.go index 70bbea5..36028d2 100644 --- a/gateway/runtime/marshaler_registry_test.go +++ b/gateway/runtime/marshaler_registry_test.go @@ -7,6 +7,7 @@ import ( "net/http" "testing" + // "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" "github.com/binchencoder/ease-gateway/gateway/runtime" ) @@ -21,11 +22,11 @@ func TestMarshalerForRequest(t *testing.T) { r.Header.Set("Accept", "application/x-out") r.Header.Set("Content-Type", "application/x-in") in, out := runtime.MarshalerForRequest(mux, r) - if _, ok := in.(*runtime.JSONPb); !ok { - t.Errorf("in = %#v; want a runtime.JSONPb", in) + if _, ok := in.(*runtime.HTTPBodyMarshaler); !ok { + t.Errorf("in = %#v; want a runtime.HTTPBodyMarshaler", in) } - if _, ok := out.(*runtime.JSONPb); !ok { - t.Errorf("out = %#v; want a runtime.JSONPb", in) + if _, ok := out.(*runtime.HTTPBodyMarshaler); !ok { + t.Errorf("out = %#v; want a runtime.HTTPBodyMarshaler", in) } marshalers := []dummyMarshaler{0, 1, 2} @@ -93,7 +94,7 @@ func TestMarshalerForRequest(t *testing.T) { type dummyMarshaler int -func (dummyMarshaler) ContentType() string { return "" } +func (dummyMarshaler) ContentType(_ interface{}) string { return "" } func (dummyMarshaler) Marshal(interface{}) ([]byte, error) { return nil, errors.New("not implemented") } diff --git a/gateway/runtime/mux.go b/gateway/runtime/mux.go index 9a0171f..ebfbae7 100644 --- a/gateway/runtime/mux.go +++ b/gateway/runtime/mux.go @@ -6,26 +6,19 @@ import ( "net/http" "net/textproto" "strings" - - "github.com/golang/protobuf/proto" + + "github.com/grpc-ecosystem/grpc-gateway/v2/internal/httprule" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" - + "google.golang.org/protobuf/proto" + "github.com/binchencoder/gateway-proto/data" ) // A HandlerFunc handles a specific pair of path pattern and HTTP method. type HandlerFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request, pathParams map[string]string) -// ErrUnknownURI is the error supplied to a custom ProtoErrorHandlerFunc when -// a request is received with a URI path that does not match any registered -// service method. -// -// Since gRPC servers return an "Unimplemented" code for requests with an -// unrecognized URI path, this error also has a gRPC "Unimplemented" code. -var ErrUnknownURI = status.Error(codes.Unimplemented, http.StatusText(http.StatusNotImplemented)) - // ServeMux is a request multiplexer for grpc-gateway. // It matches http requests to patterns and invokes the corresponding handler. type ServeMux struct { @@ -36,10 +29,9 @@ type ServeMux struct { incomingHeaderMatcher HeaderMatcherFunc outgoingHeaderMatcher HeaderMatcherFunc metadataAnnotators []func(context.Context, *http.Request) metadata.MD + errorHandler ErrorHandlerFunc streamErrorHandler StreamErrorHandlerFunc - protoErrorHandler ProtoErrorHandlerFunc disablePathLengthFallback bool - lastMatchWins bool } // ServeMuxOption is an option that can be given to a ServeMux on construction. @@ -58,7 +50,7 @@ func WithForwardResponseOption(forwardResponseOption func(context.Context, http. } // SetQueryParameterParser sets the query parameter parser, used to populate message from query parameters. -// Configuring this will mean the generated swagger output is no longer correct, and it should be +// Configuring this will mean the generated OpenAPI output is no longer correct, and it should be // done with careful consideration. func SetQueryParameterParser(queryParameterParser QueryParameterParser) ServeMuxOption { return func(serveMux *ServeMux) { @@ -113,21 +105,12 @@ func WithMetadata(annotator func(context.Context, *http.Request) metadata.MD) Se } } -// WithProtoErrorHandler returns a ServeMuxOption for configuring a custom error handler. +// WithErrorHandler returns a ServeMuxOption for configuring a custom error handler. // -// This can be used to handle an error as general proto message defined by gRPC. -// When this option is used, the mux uses the configured error handler instead of HTTPError and -// OtherErrorHandler. -func WithProtoErrorHandler(fn ProtoErrorHandlerFunc) ServeMuxOption { - return func(serveMux *ServeMux) { - serveMux.protoErrorHandler = fn - } -} - -// WithDisablePathLengthFallback returns a ServeMuxOption for disable path length fallback. -func WithDisablePathLengthFallback() ServeMuxOption { +// This can be used to configure a custom error response. +func WithErrorHandler(fn ErrorHandlerFunc) ServeMuxOption { return func(serveMux *ServeMux) { - serveMux.disablePathLengthFallback = true + serveMux.errorHandler = fn } } @@ -136,7 +119,7 @@ func WithDisablePathLengthFallback() ServeMuxOption { // calls. // // For stream errors that occur before any response has been written, the mux's -// ProtoErrorHandler will be invoked. However, once data has been written, the errors must +// ErrorHandler will be invoked. However, once data has been written, the errors must // be handled differently: they must be included in the response body. The response body's // final message will include the error details returned by the stream error handler. func WithStreamErrorHandler(fn StreamErrorHandlerFunc) ServeMuxOption { @@ -145,12 +128,10 @@ func WithStreamErrorHandler(fn StreamErrorHandlerFunc) ServeMuxOption { } } -// WithLastMatchWins returns a ServeMuxOption that will enable "last -// match wins" behavior, where if multiple path patterns match a -// request path, the last one defined in the .proto file will be used. -func WithLastMatchWins() ServeMuxOption { +// WithDisablePathLengthFallback returns a ServeMuxOption for disable path length fallback. +func WithDisablePathLengthFallback() ServeMuxOption { return func(serveMux *ServeMux) { - serveMux.lastMatchWins = true + serveMux.disablePathLengthFallback = true } } @@ -160,25 +141,14 @@ func NewServeMux(opts ...ServeMuxOption) *ServeMux { handlers: make(map[string][]handler), forwardResponseOptions: make([]func(context.Context, http.ResponseWriter, proto.Message) error, 0), marshalers: makeMarshalerMIMERegistry(), - streamErrorHandler: DefaultHTTPStreamErrorHandler, + errorHandler: DefaultHTTPErrorHandler, + streamErrorHandler: DefaultStreamErrorHandler, } for _, opt := range opts { opt(serveMux) } - if serveMux.protoErrorHandler != nil { - HTTPError = serveMux.protoErrorHandler - // OtherErrorHandler is no longer used when protoErrorHandler is set. - // Overwritten by a special error handler to return Unknown. - OtherErrorHandler = func(w http.ResponseWriter, r *http.Request, _ string, _ int) { - ctx := context.Background() - _, outboundMarshaler := MarshalerForRequest(serveMux, r) - sterr := status.Error(codes.Unknown, "unexpected use of OtherErrorHandler") - serveMux.protoErrorHandler(ctx, serveMux, outboundMarshaler, w, r, sterr) - } - } - if serveMux.incomingHeaderMatcher == nil { serveMux.incomingHeaderMatcher = DefaultHeaderMatcher } @@ -194,45 +164,52 @@ func NewServeMux(opts ...ServeMuxOption) *ServeMux { // Handle associates "h" to the pair of HTTP method and path pattern. func (s *ServeMux) Handle(meth string, pat Pattern, sid data.ServiceId, h HandlerFunc) { - if s.lastMatchWins { - s.handlers[meth] = append([]handler{handler{pat: pat, h: h, serviceId: sid}}, s.handlers[meth]...) - } else { - s.handlers[meth] = append(s.handlers[meth], handler{pat: pat, h: h, serviceId: sid}) + s.handlers[meth] = append([]handler{handler{pat: pat, h: h, serviceId: sid}}, s.handlers[meth]...) +} + +// HandlePath allows users to configure custom path handlers. +// refer: https://grpc-ecosystem.github.io/grpc-gateway/docs/inject_router.html +func (s *ServeMux) HandlePath(meth string, pathPattern string, sid data.ServiceId, h HandlerFunc) error { + compiler, err := httprule.Parse(pathPattern) + if err != nil { + return fmt.Errorf("parsing path pattern: %w", err) } + tp := compiler.Compile() + pattern, err := NewPattern(tp.Version, tp.OpCodes, tp.Pool, tp.Verb) + if err != nil { + return fmt.Errorf("creating new pattern: %w", err) + } + s.Handle(meth, pattern, sid, h) + return nil } // ServeHTTP dispatches the request to the first handler whose pattern matches to r.Method and r.Path. func (s *ServeMux) ServeHTTP(w http.ResponseWriter, r *http.Request) { ctx, err := RequestReceived(w, r) if err != nil { - DefaultHTTPError(ctx, nil, &JSONBuiltin{}, w, r, err) + DefaultHTTPErrorHandler(ctx, nil, &JSONBuiltin{}, w, r, err) return } path := r.URL.Path if !strings.HasPrefix(path, "/") { - if s.protoErrorHandler != nil { - _, outboundMarshaler := MarshalerForRequest(s, r) - sterr := status.Error(codes.InvalidArgument, http.StatusText(http.StatusBadRequest)) - s.protoErrorHandler(ctx, s, outboundMarshaler, w, r, sterr) - } else { - OtherErrorHandler(w, r, http.StatusText(http.StatusBadRequest), http.StatusBadRequest) - } + _, outboundMarshaler := MarshalerForRequest(s, r) + sterr := status.Error(codes.InvalidArgument, http.StatusText(http.StatusBadRequest)) + s.errorHandler(ctx, s, outboundMarshaler, w, r, sterr) return } components := strings.Split(path[1:], "/") l := len(components) var verb string - if idx := strings.LastIndex(components[l-1], ":"); idx == 0 { - if s.protoErrorHandler != nil { - _, outboundMarshaler := MarshalerForRequest(s, r) - s.protoErrorHandler(ctx, s, outboundMarshaler, w, r, ErrUnknownURI) - } else { - OtherErrorHandler(w, r, http.StatusText(http.StatusNotFound), http.StatusNotFound) - } + idx := strings.LastIndex(components[l-1], ":") + if idx == 0 { + _, outboundMarshaler := MarshalerForRequest(s, r) + sterr := status.Error(codes.NotFound, http.StatusText(http.StatusNotFound)) + s.errorHandler(ctx, s, outboundMarshaler, w, r, sterr) return - } else if idx > 0 { + } + if idx > 0 { c := components[l-1] components[l-1], verb = c[:idx], c[idx+1:] } @@ -240,13 +217,9 @@ func (s *ServeMux) ServeHTTP(w http.ResponseWriter, r *http.Request) { if override := r.Header.Get("X-HTTP-Method-Override"); override != "" && s.isPathLengthFallback(r) { r.Method = strings.ToUpper(override) if err := r.ParseForm(); err != nil { - if s.protoErrorHandler != nil { - _, outboundMarshaler := MarshalerForRequest(s, r) - sterr := status.Error(codes.InvalidArgument, err.Error()) - s.protoErrorHandler(ctx, s, outboundMarshaler, w, r, sterr) - } else { - OtherErrorHandler(w, r, err.Error(), http.StatusBadRequest) - } + _, outboundMarshaler := MarshalerForRequest(s, r) + sterr := status.Error(codes.InvalidArgument, err.Error()) + s.errorHandler(ctx, s, outboundMarshaler, w, r, sterr) return } } @@ -260,7 +233,7 @@ func (s *ServeMux) ServeHTTP(w http.ResponseWriter, r *http.Request) { } // lookup other methods to handle fallback from GET to POST and - // to determine if it is MethodNotAllowed or NotFound. + // to determine if it is NotImplemented or NotFound. for m, handlers := range s.handlers { if m == r.Method { continue @@ -273,34 +246,25 @@ func (s *ServeMux) ServeHTTP(w http.ResponseWriter, r *http.Request) { // X-HTTP-Method-Override is optional. Always allow fallback to POST. if s.isPathLengthFallback(r) { if err := r.ParseForm(); err != nil { - if s.protoErrorHandler != nil { - _, outboundMarshaler := MarshalerForRequest(s, r) - sterr := status.Error(codes.InvalidArgument, err.Error()) - s.protoErrorHandler(ctx, s, outboundMarshaler, w, r, sterr) - } else { - OtherErrorHandler(w, r, err.Error(), http.StatusBadRequest) - } + _, outboundMarshaler := MarshalerForRequest(s, r) + sterr := status.Error(codes.InvalidArgument, err.Error()) + s.errorHandler(ctx, s, outboundMarshaler, w, r, sterr) return } h.h(ctx, w, r, pathParams) return } - if s.protoErrorHandler != nil { - _, outboundMarshaler := MarshalerForRequest(s, r) - s.protoErrorHandler(ctx, s, outboundMarshaler, w, r, ErrUnknownURI) - } else { - OtherErrorHandler(w, r, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed) - } + _, outboundMarshaler := MarshalerForRequest(s, r) + // codes.Unimplemented is the closes we have to MethodNotAllowed + sterr := status.Error(codes.Unimplemented, http.StatusText(http.StatusNotImplemented)) + s.errorHandler(ctx, s, outboundMarshaler, w, r, sterr) return } } - if s.protoErrorHandler != nil { - _, outboundMarshaler := MarshalerForRequest(s, r) - s.protoErrorHandler(ctx, s, outboundMarshaler, w, r, ErrUnknownURI) - } else { - OtherErrorHandler(w, r, http.StatusText(http.StatusNotFound), http.StatusNotFound) - } + _, outboundMarshaler := MarshalerForRequest(s, r) + sterr := status.Error(codes.NotFound, http.StatusText(http.StatusNotFound)) + s.errorHandler(ctx, s, outboundMarshaler, w, r, sterr) } // GetForwardResponseOptions returns the ForwardResponseOptions associated with this ServeMux. diff --git a/gateway/runtime/mux_test.go b/gateway/runtime/mux_test.go index fa4e3c2..7218376 100644 --- a/gateway/runtime/mux_test.go +++ b/gateway/runtime/mux_test.go @@ -6,12 +6,12 @@ import ( "fmt" "net/http" "net/http/httptest" + "strconv" "testing" + // "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" "github.com/binchencoder/ease-gateway/gateway/runtime" - "github.com/grpc-ecosystem/grpc-gateway/utilities" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" + "github.com/grpc-ecosystem/grpc-gateway/v2/utilities" ) func TestMuxServeHTTP(t *testing.T) { @@ -21,9 +21,8 @@ func TestMuxServeHTTP(t *testing.T) { pool []string verb string } - for _, spec := range []struct { - patterns []stubPattern - patternOpts []runtime.PatternOpt + for i, spec := range []struct { + patterns []stubPattern reqMethod string reqPath string @@ -33,8 +32,6 @@ func TestMuxServeHTTP(t *testing.T) { respContent string disablePathLengthFallback bool - errHandler runtime.ProtoErrorHandlerFunc - muxOpts []runtime.ServeMuxOption }{ { patterns: nil, @@ -71,12 +68,12 @@ func TestMuxServeHTTP(t *testing.T) { patterns: []stubPattern{ { method: "GET", - ops: []int{int(utilities.OpLitPush), 0}, - pool: []string{"foo"}, + ops: []int{int(utilities.OpPush), 0}, }, { method: "GET", - ops: []int{int(utilities.OpPush), 0}, + ops: []int{int(utilities.OpLitPush), 0}, + pool: []string{"foo"}, }, }, reqMethod: "GET", @@ -112,7 +109,7 @@ func TestMuxServeHTTP(t *testing.T) { }, reqMethod: "DELETE", reqPath: "/foo", - respStatus: http.StatusMethodNotAllowed, + respStatus: http.StatusNotImplemented, }, { patterns: []stubPattern{ @@ -143,8 +140,7 @@ func TestMuxServeHTTP(t *testing.T) { headers: map[string]string{ "Content-Type": "application/x-www-form-urlencoded", }, - respStatus: http.StatusMethodNotAllowed, - respContent: "Method Not Allowed\n", + respStatus: http.StatusNotImplemented, disablePathLengthFallback: true, }, { @@ -204,7 +200,7 @@ func TestMuxServeHTTP(t *testing.T) { headers: map[string]string{ "Content-Type": "application/json", }, - respStatus: http.StatusMethodNotAllowed, + respStatus: http.StatusNotImplemented, }, { patterns: []stubPattern{ @@ -245,38 +241,6 @@ func TestMuxServeHTTP(t *testing.T) { respStatus: http.StatusOK, respContent: "GET /foo/{id=*}:verb", }, - { - // mux identifying invalid path results in 'Not Found' status - // (with custom handler looking for ErrUnknownURI) - patterns: []stubPattern{ - { - method: "GET", - ops: []int{int(utilities.OpLitPush), 0}, - pool: []string{"unimplemented"}, - }, - }, - reqMethod: "GET", - reqPath: "/foobar", - respStatus: http.StatusNotFound, - respContent: "GET /foobar", - errHandler: unknownPathIs404, - }, - { - // server returning unimplemented results in 'Not Implemented' code - // even when using custom error handler - patterns: []stubPattern{ - { - method: "GET", - ops: []int{int(utilities.OpLitPush), 0}, - pool: []string{"unimplemented"}, - }, - }, - reqMethod: "GET", - reqPath: "/unimplemented", - respStatus: http.StatusNotImplemented, - respContent: `GET /unimplemented`, - errHandler: unknownPathIs404, - }, { patterns: []stubPattern{ { @@ -285,9 +249,8 @@ func TestMuxServeHTTP(t *testing.T) { pool: []string{"foo", "id"}, }, }, - patternOpts: []runtime.PatternOpt{runtime.AssumeColonVerbOpt(false)}, - reqMethod: "GET", - reqPath: "/foo/bar", + reqMethod: "GET", + reqPath: "/foo/bar", headers: map[string]string{ "Content-Type": "application/json", }, @@ -302,9 +265,8 @@ func TestMuxServeHTTP(t *testing.T) { pool: []string{"foo", "id"}, }, }, - patternOpts: []runtime.PatternOpt{runtime.AssumeColonVerbOpt(false)}, - reqMethod: "GET", - reqPath: "/foo/bar:123", + reqMethod: "GET", + reqPath: "/foo/bar:123", headers: map[string]string{ "Content-Type": "application/json", }, @@ -325,75 +287,54 @@ func TestMuxServeHTTP(t *testing.T) { verb: "verb", }, }, - patternOpts: []runtime.PatternOpt{runtime.AssumeColonVerbOpt(false)}, - reqMethod: "POST", - reqPath: "/foo/bar:verb", + reqMethod: "POST", + reqPath: "/foo/bar:verb", headers: map[string]string{ "Content-Type": "application/json", }, respStatus: http.StatusOK, respContent: "POST /foo/{id=*}:verb", - muxOpts: []runtime.ServeMuxOption{runtime.WithLastMatchWins()}, }, } { - opts := spec.muxOpts - if spec.disablePathLengthFallback { - opts = append(opts, runtime.WithDisablePathLengthFallback()) - } - if spec.errHandler != nil { - opts = append(opts, runtime.WithProtoErrorHandler(spec.errHandler)) - } - mux := runtime.NewServeMux(opts...) - for _, p := range spec.patterns { - func(p stubPattern) { - pat, err := runtime.NewPattern(1, p.ops, p.pool, p.verb, spec.patternOpts...) - if err != nil { - t.Fatalf("runtime.NewPattern(1, %#v, %#v, %q) failed with %v; want success", p.ops, p.pool, p.verb, err) - } - mux.Handle(p.method, pat, 1 /* sid */, func(ctx context.Context, w http.ResponseWriter, r *http.Request, pathParams map[string]string) { - if r.URL.Path == "/unimplemented" { - // simulate method returning "unimplemented" error - _, m := runtime.MarshalerForRequest(mux, r) - runtime.HTTPError(r.Context(), mux, m, w, r, status.Error(codes.Unimplemented, http.StatusText(http.StatusNotImplemented))) - w.WriteHeader(http.StatusNotImplemented) - return + t.Run(strconv.Itoa(i), func(t *testing.T) { + var opts []runtime.ServeMuxOption + if spec.disablePathLengthFallback { + opts = append(opts, runtime.WithDisablePathLengthFallback()) + } + mux := runtime.NewServeMux(opts...) + for _, p := range spec.patterns { + func(p stubPattern) { + pat, err := runtime.NewPattern(1, p.ops, p.pool, p.verb) + if err != nil { + t.Fatalf("runtime.NewPattern(1, %#v, %#v, %q) failed with %v; want success", p.ops, p.pool, p.verb, err) } - fmt.Fprintf(w, "%s %s", p.method, pat.String()) - }) - }(p) - } - - url := fmt.Sprintf("http://host.example%s", spec.reqPath) - r, err := http.NewRequest(spec.reqMethod, url, bytes.NewReader(nil)) - if err != nil { - t.Fatalf("http.NewRequest(%q, %q, nil) failed with %v; want success", spec.reqMethod, url, err) - } - for name, value := range spec.headers { - r.Header.Set(name, value) - } - w := httptest.NewRecorder() - mux.ServeHTTP(w, r) + mux.Handle(p.method, pat, 1 /* sid */, func(ctx context.Context, w http.ResponseWriter, r *http.Request, pathParams map[string]string) { + fmt.Fprintf(w, "%s %s", p.method, pat.String()) + }) + }(p) + } - if got, want := w.Code, spec.respStatus; got != want { - t.Errorf("w.Code = %d; want %d; patterns=%v; req=%v", got, want, spec.patterns, r) - } - if spec.respContent != "" { - if got, want := w.Body.String(), spec.respContent; got != want { - t.Errorf("w.Body = %q; want %q; patterns=%v; req=%v", got, want, spec.patterns, r) + url := fmt.Sprintf("http://host.example%s", spec.reqPath) + r, err := http.NewRequest(spec.reqMethod, url, bytes.NewReader(nil)) + if err != nil { + t.Fatalf("http.NewRequest(%q, %q, nil) failed with %v; want success", spec.reqMethod, url, err) } - } - } -} + for name, value := range spec.headers { + r.Header.Set(name, value) + } + w := httptest.NewRecorder() + mux.ServeHTTP(w, r) -func unknownPathIs404(ctx context.Context, mux *runtime.ServeMux, m runtime.Marshaler, w http.ResponseWriter, r *http.Request, err error) { - if err == runtime.ErrUnknownURI { - w.WriteHeader(http.StatusNotFound) - } else { - c := status.Convert(err).Code() - w.WriteHeader(runtime.HTTPStatusFromCode(c)) + if got, want := w.Code, spec.respStatus; got != want { + t.Errorf("w.Code = %d; want %d; patterns=%v; req=%v", got, want, spec.patterns, r) + } + if spec.respContent != "" { + if got, want := w.Body.String(), spec.respContent; got != want { + t.Errorf("w.Body = %q; want %q; patterns=%v; req=%v", got, want, spec.patterns, r) + } + } + }) } - - fmt.Fprintf(w, "%s %s", r.Method, r.URL.Path) } var defaultHeaderMatcherTests = []struct { @@ -435,3 +376,55 @@ func TestDefaultHeaderMatcher(t *testing.T) { }) } } + + + +var defaultRouteMatcherTests = []struct { + name string + method string + path string + valid bool +}{ + { + "Simple Endpoint", + "GET", + "/v1/{bucket}/do:action", + true, + }, + { + "Complex Endpoint", + "POST", + "/v1/b/{bucket_name=buckets/*}/o/{name}", + true, + }, + { + "Wildcard Endpoint", + "GET", + "/v1/endpoint/*", + true, + }, + { + "Invalid Endpoint", + "POST", + "v1/b/:name/do", + false, + }, +} + +func TestServeMux_HandlePath(t *testing.T) { + mux := runtime.NewServeMux() + testFn := func(ctx context.Context, w http.ResponseWriter, r *http.Request, pathParams map[string]string) { + } + for _, tt := range defaultRouteMatcherTests { + t.Run(tt.name, func(t *testing.T) { + err := mux.HandlePath(tt.method, tt.path, 1 /* sid */, testFn) + if tt.valid && err != nil { + t.Errorf("The route %v with method %v and path %v invalid, got %v", tt.name, tt.method, tt.path, err) + } + if !tt.valid && err == nil { + t.Errorf("The route %v with method %v and path %v should be invalid", tt.name, tt.method, tt.path) + } + }) + } + +} \ No newline at end of file diff --git a/gateway/runtime/pattern.go b/gateway/runtime/pattern.go index 0905369..f319664 100644 --- a/gateway/runtime/pattern.go +++ b/gateway/runtime/pattern.go @@ -5,7 +5,7 @@ import ( "fmt" "strings" - "github.com/grpc-ecosystem/grpc-gateway/utilities" + "github.com/grpc-ecosystem/grpc-gateway/v2/utilities" "google.golang.org/grpc/grpclog" ) @@ -21,7 +21,8 @@ type op struct { operand int } -// Pattern is a template pattern of http request paths defined in github.com/googleapis/googleapis/google/api/http.proto. +// Pattern is a template pattern of http request paths defined in +// https://github.com/googleapis/googleapis/blob/master/google/api/http.proto type Pattern struct { // ops is a list of operations ops []op @@ -35,31 +36,14 @@ type Pattern struct { tailLen int // verb is the VERB part of the path pattern. It is empty if the pattern does not have VERB part. verb string - // assumeColonVerb indicates whether a path suffix after a final - // colon may only be interpreted as a verb. - assumeColonVerb bool } -type patternOptions struct { - assumeColonVerb bool -} - -// PatternOpt is an option for creating Patterns. -type PatternOpt func(*patternOptions) - // NewPattern returns a new Pattern from the given definition values. // "ops" is a sequence of op codes. "pool" is a constant pool. // "verb" is the verb part of the pattern. It is empty if the pattern does not have the part. // "version" must be 1 for now. // It returns an error if the given definition is invalid. -func NewPattern(version int, ops []int, pool []string, verb string, opts ...PatternOpt) (Pattern, error) { - options := patternOptions{ - assumeColonVerb: true, - } - for _, o := range opts { - o(&options) - } - +func NewPattern(version int, ops []int, pool []string, verb string) (Pattern, error) { if version != 1 { grpclog.Infof("unsupported version: %d", version) return Pattern{}, ErrInvalidPattern @@ -111,7 +95,7 @@ func NewPattern(version int, ops []int, pool []string, verb string, opts ...Patt } stack -= op.operand if stack < 0 { - grpclog.Print("stack underflow") + grpclog.Info("stack underflow") return Pattern{}, ErrInvalidPattern } stack++ @@ -139,13 +123,12 @@ func NewPattern(version int, ops []int, pool []string, verb string, opts ...Patt typedOps = append(typedOps, op) } return Pattern{ - ops: typedOps, - pool: pool, - vars: vars, - stacksize: maxstack, - tailLen: tailLen, - verb: verb, - assumeColonVerb: options.assumeColonVerb, + ops: typedOps, + pool: pool, + vars: vars, + stacksize: maxstack, + tailLen: tailLen, + verb: verb, }, nil } @@ -162,7 +145,7 @@ func MustPattern(p Pattern, err error) Pattern { // If otherwise, the function returns an error. func (p Pattern) Match(components []string, verb string) (map[string]string, error) { if p.verb != verb { - if p.assumeColonVerb || p.verb != "" { + if p.verb != "" { return nil, ErrNotMatch } if len(components) == 0 { @@ -252,11 +235,3 @@ func (p Pattern) String() string { } return "/" + segs } - -// AssumeColonVerbOpt indicates whether a path suffix after a final -// colon may only be interpreted as a verb. -func AssumeColonVerbOpt(val bool) PatternOpt { - return PatternOpt(func(o *patternOptions) { - o.assumeColonVerb = val - }) -} diff --git a/gateway/runtime/pattern_test.go b/gateway/runtime/pattern_test.go index 8f5a664..1b856a5 100644 --- a/gateway/runtime/pattern_test.go +++ b/gateway/runtime/pattern_test.go @@ -6,7 +6,7 @@ import ( "strings" "testing" - "github.com/grpc-ecosystem/grpc-gateway/utilities" + "github.com/grpc-ecosystem/grpc-gateway/v2/utilities" ) const ( diff --git a/gateway/runtime/proto2_convert.go b/gateway/runtime/proto2_convert.go index a3151e2..d549407 100644 --- a/gateway/runtime/proto2_convert.go +++ b/gateway/runtime/proto2_convert.go @@ -1,7 +1,7 @@ package runtime import ( - "github.com/golang/protobuf/proto" + "google.golang.org/protobuf/proto" ) // StringP returns a pointer to a string whose pointee is same as the given string value. diff --git a/gateway/runtime/proto_errors.go b/gateway/runtime/proto_errors.go deleted file mode 100644 index 96fa398..0000000 --- a/gateway/runtime/proto_errors.go +++ /dev/null @@ -1,107 +0,0 @@ -package runtime - -import ( - "context" - "io" - "net/http" - - // "github.com/grpc-ecosystem/grpc-gateway/internal" - "github.com/binchencoder/ease-gateway/gateway/internal" - "github.com/golang/protobuf/ptypes/any" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/grpclog" - "google.golang.org/grpc/status" -) - -// StreamErrorHandlerFunc accepts an error as a gRPC error generated via status package and translates it into a -// a proto struct used to represent error at the end of a stream. -type StreamErrorHandlerFunc func(context.Context, error) *StreamError - -// StreamError is the payload for the final message in a server stream in the event that the server returns an -// error after a response message has already been sent. -type StreamError internal.StreamError - -// ProtoErrorHandlerFunc handles the error as a gRPC error generated via status package and replies to the request. -type ProtoErrorHandlerFunc func(context.Context, *ServeMux, Marshaler, http.ResponseWriter, *http.Request, error) - -var _ ProtoErrorHandlerFunc = DefaultHTTPProtoErrorHandler - -// DefaultHTTPProtoErrorHandler is an implementation of HTTPError. -// If "err" is an error from gRPC system, the function replies with the status code mapped by HTTPStatusFromCode. -// If otherwise, it replies with http.StatusInternalServerError. -// -// The response body returned by this function is a Status message marshaled by a Marshaler. -// -// Do not set this function to HTTPError variable directly, use WithProtoErrorHandler option instead. -func DefaultHTTPProtoErrorHandler(ctx context.Context, mux *ServeMux, marshaler Marshaler, w http.ResponseWriter, _ *http.Request, err error) { - // return Internal when Marshal failed - const fallback = `{"code": 13, "message": "failed to marshal error message"}` - - s, ok := status.FromError(err) - if !ok { - s = status.New(codes.Unknown, err.Error()) - } - - w.Header().Del("Trailer") - - contentType := marshaler.ContentType() - // Check marshaler on run time in order to keep backwards compatibility - // An interface param needs to be added to the ContentType() function on - // the Marshal interface to be able to remove this check - if typeMarshaler, ok := marshaler.(contentTypeMarshaler); ok { - pb := s.Proto() - contentType = typeMarshaler.ContentTypeFromMessage(pb) - } - w.Header().Set("Content-Type", contentType) - - buf, merr := marshaler.Marshal(s.Proto()) - if merr != nil { - grpclog.Infof("Failed to marshal error message %q: %v", s.Proto(), merr) - w.WriteHeader(http.StatusInternalServerError) - if _, err := io.WriteString(w, fallback); err != nil { - grpclog.Infof("Failed to write response: %v", err) - } - return - } - - md, ok := ServerMetadataFromContext(ctx) - if !ok { - grpclog.Infof("Failed to extract ServerMetadata from context") - } - - handleForwardResponseServerMetadata(w, mux, md) - handleForwardResponseTrailerHeader(w, md) - st := HTTPStatusFromCode(s.Code()) - w.WriteHeader(st) - if _, err := w.Write(buf); err != nil { - grpclog.Infof("Failed to write response: %v", err) - } - - handleForwardResponseTrailer(w, md) -} - -// DefaultHTTPStreamErrorHandler converts the given err into a *StreamError via -// default logic. -// -// It extracts the gRPC status from err if possible. The fields of the status are -// used to populate the returned StreamError, and the HTTP status code is derived -// from the gRPC code via HTTPStatusFromCode. If the given err does not contain a -// gRPC status, an "Unknown" gRPC code is used and "Internal Server Error" HTTP code. -func DefaultHTTPStreamErrorHandler(_ context.Context, err error) *StreamError { - grpcCode := codes.Unknown - grpcMessage := err.Error() - var grpcDetails []*any.Any - if s, ok := status.FromError(err); ok { - grpcCode = s.Code() - grpcMessage = s.Message() - grpcDetails = s.Proto().GetDetails() - } - httpCode := HTTPStatusFromCode(grpcCode) - return &StreamError{ - GrpcCode: int32(grpcCode), - HttpCode: int32(httpCode), - Message: grpcMessage, - HttpStatus: http.StatusText(httpCode), - Details: grpcDetails, - } -} diff --git a/gateway/runtime/query.go b/gateway/runtime/query.go index ba66842..9a9f3d3 100644 --- a/gateway/runtime/query.go +++ b/gateway/runtime/query.go @@ -2,20 +2,25 @@ package runtime import ( "encoding/base64" + "errors" "fmt" "net/url" - "reflect" "regexp" "strconv" "strings" "time" - "github.com/golang/protobuf/proto" - "github.com/grpc-ecosystem/grpc-gateway/utilities" + "github.com/golang/protobuf/ptypes" + wrapperspb "github.com/golang/protobuf/ptypes/wrappers" + "github.com/grpc-ecosystem/grpc-gateway/v2/utilities" + "google.golang.org/genproto/protobuf/field_mask" "google.golang.org/grpc/grpclog" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/reflect/protoreflect" + "google.golang.org/protobuf/reflect/protoregistry" ) -var valuesKeyRegexp = regexp.MustCompile("^(.*)\\[(.*)\\]$") +var valuesKeyRegexp = regexp.MustCompile(`^(.*)\[(.*)\]$`) var currentQueryParser QueryParameterParser = &defaultQueryParser{} @@ -45,7 +50,7 @@ func (*defaultQueryParser) Parse(msg proto.Message, values url.Values, filter *u if filter.HasCommonPrefix(fieldPath) { continue } - if err := populateFieldValueFromPath(msg, fieldPath, values); err != nil { + if err := populateFieldValueFromPath(msg.ProtoReflect(), fieldPath, values); err != nil { return err } } @@ -53,354 +58,274 @@ func (*defaultQueryParser) Parse(msg proto.Message, values url.Values, filter *u } // PopulateFieldFromPath sets a value in a nested Protobuf structure. -// It instantiates missing protobuf fields as it goes. func PopulateFieldFromPath(msg proto.Message, fieldPathString string, value string) error { fieldPath := strings.Split(fieldPathString, ".") - return populateFieldValueFromPath(msg, fieldPath, []string{value}) + return populateFieldValueFromPath(msg.ProtoReflect(), fieldPath, []string{value}) } -func populateFieldValueFromPath(msg proto.Message, fieldPath []string, values []string) error { - m := reflect.ValueOf(msg) - if m.Kind() != reflect.Ptr { - return fmt.Errorf("unexpected type %T: %v", msg, msg) +func populateFieldValueFromPath(msgValue protoreflect.Message, fieldPath []string, values []string) error { + if len(fieldPath) < 1 { + return errors.New("no field path") + } + if len(values) < 1 { + return errors.New("no value provided") } - var props *proto.Properties - m = m.Elem() - for i, fieldName := range fieldPath { - isLast := i == len(fieldPath)-1 - if !isLast && m.Kind() != reflect.Struct { - return fmt.Errorf("non-aggregate type in the mid of path: %s", strings.Join(fieldPath, ".")) - } - var f reflect.Value - var err error - f, props, err = fieldByProtoName(m, fieldName) - if err != nil { - return err - } else if !f.IsValid() { - grpclog.Infof("field not found in %T: %s", msg, strings.Join(fieldPath, ".")) - return nil - } - switch f.Kind() { - case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64, reflect.String, reflect.Uint32, reflect.Uint64: - if !isLast { - return fmt.Errorf("unexpected nested field %s in %s", fieldPath[i+1], strings.Join(fieldPath[:i+1], ".")) - } - m = f - case reflect.Slice: - if !isLast { - return fmt.Errorf("unexpected repeated field in %s", strings.Join(fieldPath, ".")) - } - // Handle []byte - if f.Type().Elem().Kind() == reflect.Uint8 { - m = f - break - } - return populateRepeatedField(f, values, props) - case reflect.Ptr: - if f.IsNil() { - m = reflect.New(f.Type().Elem()) - f.Set(m.Convert(f.Type())) - } - m = f.Elem() - continue - case reflect.Struct: - m = f - continue - case reflect.Map: - if !isLast { - return fmt.Errorf("unexpected nested field %s in %s", fieldPath[i+1], strings.Join(fieldPath[:i+1], ".")) + var fieldDescriptor protoreflect.FieldDescriptor + for i, fieldName := range fieldPath { + fields := msgValue.Descriptor().Fields() + + // Get field by name + fieldDescriptor = fields.ByName(protoreflect.Name(fieldName)) + if fieldDescriptor == nil { + fieldDescriptor = fields.ByJSONName(fieldName) + if fieldDescriptor == nil { + // We're not returning an error here because this could just be + // an extra query parameter that isn't part of the request. + grpclog.Infof("field not found in %q: %q", msgValue.Descriptor().FullName(), strings.Join(fieldPath, ".")) + return nil } - return populateMapField(f, values, props) - default: - return fmt.Errorf("unexpected type %s in %T", f.Type(), msg) } - } - switch len(values) { - case 0: - return fmt.Errorf("no value of field: %s", strings.Join(fieldPath, ".")) - case 1: - default: - grpclog.Infof("too many field values: %s", strings.Join(fieldPath, ".")) - } - return populateField(m, values[0], props) -} -// fieldByProtoName looks up a field whose corresponding protobuf field name is "name". -// "m" must be a struct value. It returns zero reflect.Value if no such field found. -func fieldByProtoName(m reflect.Value, name string) (reflect.Value, *proto.Properties, error) { - props := proto.GetProperties(m.Type()) + // If this is the last element, we're done + if i == len(fieldPath)-1 { + break + } - // look up field name in oneof map - for _, op := range props.OneofTypes { - if name == op.Prop.OrigName || name == op.Prop.JSONName { - v := reflect.New(op.Type.Elem()) - field := m.Field(op.Field) - if !field.IsNil() { - return reflect.Value{}, nil, fmt.Errorf("field already set for %s oneof", props.Prop[op.Field].OrigName) - } - field.Set(v) - return v.Elem().Field(0), op.Prop, nil + // Only singular message fields are allowed + if fieldDescriptor.Message() == nil || fieldDescriptor.Cardinality() == protoreflect.Repeated { + return fmt.Errorf("invalid path: %q is not a message", fieldName) } + + // Get the nested message + msgValue = msgValue.Mutable(fieldDescriptor).Message() } - for _, p := range props.Prop { - if p.OrigName == name { - return m.FieldByName(p.Name), p, nil - } - if p.JSONName == name { - return m.FieldByName(p.Name), p, nil + // Check if oneof already set + if of := fieldDescriptor.ContainingOneof(); of != nil { + if f := msgValue.WhichOneof(of); f != nil { + return fmt.Errorf("field already set for oneof %q", of.FullName().Name()) } } - return reflect.Value{}, nil, nil -} -func populateMapField(f reflect.Value, values []string, props *proto.Properties) error { - if len(values) != 2 { - return fmt.Errorf("more than one value provided for key %s in map %s", values[0], props.Name) + switch { + case fieldDescriptor.IsList(): + return populateRepeatedField(fieldDescriptor, msgValue.Mutable(fieldDescriptor).List(), values) + case fieldDescriptor.IsMap(): + return populateMapField(fieldDescriptor, msgValue.Mutable(fieldDescriptor).Map(), values) } - key, value := values[0], values[1] - keyType := f.Type().Key() - valueType := f.Type().Elem() - if f.IsNil() { - f.Set(reflect.MakeMap(f.Type())) + if len(values) > 1 { + return fmt.Errorf("too many values for field %q: %s", fieldDescriptor.FullName().Name(), strings.Join(values, ", ")) } - keyConv, ok := convFromType[keyType.Kind()] - if !ok { - return fmt.Errorf("unsupported key type %s in map %s", keyType, props.Name) - } - valueConv, ok := convFromType[valueType.Kind()] - if !ok { - return fmt.Errorf("unsupported value type %s in map %s", valueType, props.Name) - } + return populateField(fieldDescriptor, msgValue, values[0]) +} - keyV := keyConv.Call([]reflect.Value{reflect.ValueOf(key)}) - if err := keyV[1].Interface(); err != nil { - return err.(error) - } - valueV := valueConv.Call([]reflect.Value{reflect.ValueOf(value)}) - if err := valueV[1].Interface(); err != nil { - return err.(error) +func populateField(fieldDescriptor protoreflect.FieldDescriptor, msgValue protoreflect.Message, value string) error { + v, err := parseField(fieldDescriptor, value) + if err != nil { + return fmt.Errorf("parsing field %q: %w", fieldDescriptor.FullName().Name(), err) } - f.SetMapIndex(keyV[0].Convert(keyType), valueV[0].Convert(valueType)) - + msgValue.Set(fieldDescriptor, v) return nil } -func populateRepeatedField(f reflect.Value, values []string, props *proto.Properties) error { - elemType := f.Type().Elem() +func populateRepeatedField(fieldDescriptor protoreflect.FieldDescriptor, list protoreflect.List, values []string) error { + for _, value := range values { + v, err := parseField(fieldDescriptor, value) + if err != nil { + return fmt.Errorf("parsing list %q: %w", fieldDescriptor.FullName().Name(), err) + } + list.Append(v) + } - // is the destination field a slice of an enumeration type? - if enumValMap := proto.EnumValueMap(props.Enum); enumValMap != nil { - return populateFieldEnumRepeated(f, values, enumValMap) + return nil +} + +func populateMapField(fieldDescriptor protoreflect.FieldDescriptor, mp protoreflect.Map, values []string) error { + if len(values) != 2 { + return fmt.Errorf("more than one value provided for key %q in map %q", values[0], fieldDescriptor.FullName()) } - conv, ok := convFromType[elemType.Kind()] - if !ok { - return fmt.Errorf("unsupported field type %s", elemType) + key, err := parseField(fieldDescriptor.MapKey(), values[0]) + if err != nil { + return fmt.Errorf("parsing map key %q: %w", fieldDescriptor.FullName().Name(), err) } - f.Set(reflect.MakeSlice(f.Type(), len(values), len(values)).Convert(f.Type())) - for i, v := range values { - result := conv.Call([]reflect.Value{reflect.ValueOf(v)}) - if err := result[1].Interface(); err != nil { - return err.(error) - } - f.Index(i).Set(result[0].Convert(f.Index(i).Type())) + + value, err := parseField(fieldDescriptor.MapValue(), values[1]) + if err != nil { + return fmt.Errorf("parsing map value %q: %w", fieldDescriptor.FullName().Name(), err) } + + mp.Set(key.MapKey(), value) + return nil } -func populateField(f reflect.Value, value string, props *proto.Properties) error { - i := f.Addr().Interface() - - // Handle protobuf well known types - var name string - switch m := i.(type) { - case interface{ XXX_WellKnownType() string }: - name = m.XXX_WellKnownType() - case proto.Message: - const wktPrefix = "google.protobuf." - if fullName := proto.MessageName(m); strings.HasPrefix(fullName, wktPrefix) { - name = fullName[len(wktPrefix):] +func parseField(fieldDescriptor protoreflect.FieldDescriptor, value string) (protoreflect.Value, error) { + switch fieldDescriptor.Kind() { + case protoreflect.BoolKind: + v, err := strconv.ParseBool(value) + if err != nil { + return protoreflect.Value{}, err + } + return protoreflect.ValueOfBool(v), nil + case protoreflect.EnumKind: + enum, err := protoregistry.GlobalTypes.FindEnumByName(fieldDescriptor.Enum().FullName()) + switch { + case errors.Is(err, protoregistry.NotFound): + return protoreflect.Value{}, fmt.Errorf("enum %q is not registered", fieldDescriptor.Enum().FullName()) + case err != nil: + return protoreflect.Value{}, fmt.Errorf("failed to look up enum: %w", err) + } + // Look for enum by name + v := enum.Descriptor().Values().ByName(protoreflect.Name(value)) + if v == nil { + i, err := strconv.Atoi(value) + if err != nil { + return protoreflect.Value{}, fmt.Errorf("%q is not a valid value", value) + } + // Look for enum by number + v = enum.Descriptor().Values().ByNumber(protoreflect.EnumNumber(i)) + if v == nil { + return protoreflect.Value{}, fmt.Errorf("%q is not a valid value", value) + } + } + return protoreflect.ValueOfEnum(v.Number()), nil + case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind: + v, err := strconv.ParseInt(value, 10, 32) + if err != nil { + return protoreflect.Value{}, err + } + return protoreflect.ValueOfInt32(int32(v)), nil + case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind: + v, err := strconv.ParseInt(value, 10, 64) + if err != nil { + return protoreflect.Value{}, err } + return protoreflect.ValueOfInt64(v), nil + case protoreflect.Uint32Kind, protoreflect.Fixed32Kind: + v, err := strconv.ParseUint(value, 10, 32) + if err != nil { + return protoreflect.Value{}, err + } + return protoreflect.ValueOfUint32(uint32(v)), nil + case protoreflect.Uint64Kind, protoreflect.Fixed64Kind: + v, err := strconv.ParseUint(value, 10, 64) + if err != nil { + return protoreflect.Value{}, err + } + return protoreflect.ValueOfUint64(v), nil + case protoreflect.FloatKind: + v, err := strconv.ParseFloat(value, 32) + if err != nil { + return protoreflect.Value{}, err + } + return protoreflect.ValueOfFloat32(float32(v)), nil + case protoreflect.DoubleKind: + v, err := strconv.ParseFloat(value, 64) + if err != nil { + return protoreflect.Value{}, err + } + return protoreflect.ValueOfFloat64(v), nil + case protoreflect.StringKind: + return protoreflect.ValueOfString(value), nil + case protoreflect.BytesKind: + v, err := base64.StdEncoding.DecodeString(value) + if err != nil { + return protoreflect.Value{}, err + } + return protoreflect.ValueOfBytes(v), nil + case protoreflect.MessageKind, protoreflect.GroupKind: + return parseMessage(fieldDescriptor.Message(), value) + default: + panic(fmt.Sprintf("unknown field kind: %v", fieldDescriptor.Kind())) } - switch name { - case "Timestamp": +} + +func parseMessage(msgDescriptor protoreflect.MessageDescriptor, value string) (protoreflect.Value, error) { + var msg proto.Message + switch msgDescriptor.FullName() { + case "google.protobuf.Timestamp": if value == "null" { - f.FieldByName("Seconds").SetInt(0) - f.FieldByName("Nanos").SetInt(0) - return nil + break } - t, err := time.Parse(time.RFC3339Nano, value) if err != nil { - return fmt.Errorf("bad Timestamp: %v", err) + return protoreflect.Value{}, err + } + msg, err = ptypes.TimestampProto(t) + if err != nil { + return protoreflect.Value{}, err } - f.FieldByName("Seconds").SetInt(int64(t.Unix())) - f.FieldByName("Nanos").SetInt(int64(t.Nanosecond())) - return nil - case "Duration": + case "google.protobuf.Duration": if value == "null" { - f.FieldByName("Seconds").SetInt(0) - f.FieldByName("Nanos").SetInt(0) - return nil + break } d, err := time.ParseDuration(value) if err != nil { - return fmt.Errorf("bad Duration: %v", err) + return protoreflect.Value{}, err } - - ns := d.Nanoseconds() - s := ns / 1e9 - ns %= 1e9 - f.FieldByName("Seconds").SetInt(s) - f.FieldByName("Nanos").SetInt(ns) - return nil - case "DoubleValue": - fallthrough - case "FloatValue": - float64Val, err := strconv.ParseFloat(value, 64) + msg = ptypes.DurationProto(d) + case "google.protobuf.DoubleValue": + v, err := strconv.ParseFloat(value, 64) if err != nil { - return fmt.Errorf("bad DoubleValue: %s", value) + return protoreflect.Value{}, err } - f.FieldByName("Value").SetFloat(float64Val) - return nil - case "Int64Value": - fallthrough - case "Int32Value": - int64Val, err := strconv.ParseInt(value, 10, 64) + msg = &wrapperspb.DoubleValue{Value: v} + case "google.protobuf.FloatValue": + v, err := strconv.ParseFloat(value, 32) if err != nil { - return fmt.Errorf("bad DoubleValue: %s", value) + return protoreflect.Value{}, err } - f.FieldByName("Value").SetInt(int64Val) - return nil - case "UInt64Value": - fallthrough - case "UInt32Value": - uint64Val, err := strconv.ParseUint(value, 10, 64) + msg = &wrapperspb.FloatValue{Value: float32(v)} + case "google.protobuf.Int64Value": + v, err := strconv.ParseInt(value, 10, 64) if err != nil { - return fmt.Errorf("bad DoubleValue: %s", value) + return protoreflect.Value{}, err } - f.FieldByName("Value").SetUint(uint64Val) - return nil - case "BoolValue": - if value == "true" { - f.FieldByName("Value").SetBool(true) - } else if value == "false" { - f.FieldByName("Value").SetBool(false) - } else { - return fmt.Errorf("bad BoolValue: %s", value) - } - return nil - case "StringValue": - f.FieldByName("Value").SetString(value) - return nil - case "BytesValue": - bytesVal, err := base64.StdEncoding.DecodeString(value) + msg = &wrapperspb.Int64Value{Value: v} + case "google.protobuf.Int32Value": + v, err := strconv.ParseInt(value, 10, 32) if err != nil { - return fmt.Errorf("bad BytesValue: %s", value) - } - f.FieldByName("Value").SetBytes(bytesVal) - return nil - case "FieldMask": - p := f.FieldByName("Paths") - for _, v := range strings.Split(value, ",") { - if v != "" { - p.Set(reflect.Append(p, reflect.ValueOf(v))) - } + return protoreflect.Value{}, err } - return nil - } - - // Handle Time and Duration stdlib types - switch t := i.(type) { - case *time.Time: - pt, err := time.Parse(time.RFC3339Nano, value) + msg = &wrapperspb.Int32Value{Value: int32(v)} + case "google.protobuf.UInt64Value": + v, err := strconv.ParseUint(value, 10, 64) if err != nil { - return fmt.Errorf("bad Timestamp: %v", err) + return protoreflect.Value{}, err } - *t = pt - return nil - case *time.Duration: - d, err := time.ParseDuration(value) + msg = &wrapperspb.UInt64Value{Value: v} + case "google.protobuf.UInt32Value": + v, err := strconv.ParseUint(value, 10, 32) if err != nil { - return fmt.Errorf("bad Duration: %v", err) + return protoreflect.Value{}, err } - *t = d - return nil - } - - // is the destination field an enumeration type? - if enumValMap := proto.EnumValueMap(props.Enum); enumValMap != nil { - return populateFieldEnum(f, value, enumValMap) - } - - conv, ok := convFromType[f.Kind()] - if !ok { - return fmt.Errorf("field type %T is not supported in query parameters", i) - } - result := conv.Call([]reflect.Value{reflect.ValueOf(value)}) - if err := result[1].Interface(); err != nil { - return err.(error) - } - f.Set(result[0].Convert(f.Type())) - return nil -} - -func convertEnum(value string, t reflect.Type, enumValMap map[string]int32) (reflect.Value, error) { - // see if it's an enumeration string - if enumVal, ok := enumValMap[value]; ok { - return reflect.ValueOf(enumVal).Convert(t), nil - } - - // check for an integer that matches an enumeration value - eVal, err := strconv.Atoi(value) - if err != nil { - return reflect.Value{}, fmt.Errorf("%s is not a valid %s", value, t) - } - for _, v := range enumValMap { - if v == int32(eVal) { - return reflect.ValueOf(eVal).Convert(t), nil + msg = &wrapperspb.UInt32Value{Value: uint32(v)} + case "google.protobuf.BoolValue": + v, err := strconv.ParseBool(value) + if err != nil { + return protoreflect.Value{}, err } - } - return reflect.Value{}, fmt.Errorf("%s is not a valid %s", value, t) -} - -func populateFieldEnum(f reflect.Value, value string, enumValMap map[string]int32) error { - cval, err := convertEnum(value, f.Type(), enumValMap) - if err != nil { - return err - } - f.Set(cval) - return nil -} - -func populateFieldEnumRepeated(f reflect.Value, values []string, enumValMap map[string]int32) error { - elemType := f.Type().Elem() - f.Set(reflect.MakeSlice(f.Type(), len(values), len(values)).Convert(f.Type())) - for i, v := range values { - result, err := convertEnum(v, elemType, enumValMap) + msg = &wrapperspb.BoolValue{Value: v} + case "google.protobuf.StringValue": + msg = &wrapperspb.StringValue{Value: value} + case "google.protobuf.BytesValue": + v, err := base64.StdEncoding.DecodeString(value) if err != nil { - return err + return protoreflect.Value{}, err } - f.Index(i).Set(result) + msg = &wrapperspb.BytesValue{Value: v} + case "google.protobuf.FieldMask": + fm := &field_mask.FieldMask{} + fm.Paths = append(fm.Paths, strings.Split(value, ",")...) + msg = fm + default: + return protoreflect.Value{}, fmt.Errorf("unsupported message type: %q", string(msgDescriptor.FullName())) } - return nil -} -var ( - convFromType = map[reflect.Kind]reflect.Value{ - reflect.String: reflect.ValueOf(String), - reflect.Bool: reflect.ValueOf(Bool), - reflect.Float64: reflect.ValueOf(Float64), - reflect.Float32: reflect.ValueOf(Float32), - reflect.Int64: reflect.ValueOf(Int64), - reflect.Int32: reflect.ValueOf(Int32), - reflect.Uint64: reflect.ValueOf(Uint64), - reflect.Uint32: reflect.ValueOf(Uint32), - reflect.Slice: reflect.ValueOf(Bytes), - } -) + return protoreflect.ValueOfMessage(msg.ProtoReflect()), nil +} diff --git a/gateway/runtime/query_test.go b/gateway/runtime/query_test.go index 732541a..ee6667a 100644 --- a/gateway/runtime/query_test.go +++ b/gateway/runtime/query_test.go @@ -2,21 +2,21 @@ package runtime_test import ( "errors" - "fmt" "net/url" - "reflect" + "strconv" "testing" "time" - "github.com/golang/protobuf/proto" "github.com/golang/protobuf/ptypes" - "github.com/golang/protobuf/ptypes/duration" - "github.com/golang/protobuf/ptypes/timestamp" - "github.com/golang/protobuf/ptypes/wrappers" - "github.com/grpc-ecosystem/grpc-gateway/utilities" - "google.golang.org/genproto/protobuf/field_mask" - + wrapperspb "github.com/golang/protobuf/ptypes/wrappers" + "github.com/google/go-cmp/cmp" + // "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" "github.com/binchencoder/ease-gateway/gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/v2/runtime/internal/examplepb" + "github.com/grpc-ecosystem/grpc-gateway/v2/utilities" + "google.golang.org/genproto/protobuf/field_mask" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/testing/protocmp" ) func BenchmarkPopulateQueryParameters(b *testing.B) { @@ -28,7 +28,7 @@ func BenchmarkPopulateQueryParameters(b *testing.B) { fieldmaskStr := "float_value,double_value" - msg := &proto3Message{} + msg := &examplepb.Proto3Message{} values := url.Values{ "float_value": {"1.5"}, "double_value": {"2.5"}, @@ -98,7 +98,7 @@ func TestPopulateParameters(t *testing.T) { fieldmaskStr := "float_value,double_value" fieldmaskPb := &field_mask.FieldMask{Paths: []string{"float_value", "double_value"}} - for _, spec := range []struct { + for i, spec := range []struct { values url.Values filter *utilities.DoubleArray want proto.Message @@ -116,6 +116,7 @@ func TestPopulateParameters(t *testing.T) { "string_value": {"str"}, "bytes_value": {"Ynl0ZXM="}, "repeated_value": {"a", "b", "c"}, + "repeated_message": {"1", "2", "3"}, "enum_value": {"1"}, "repeated_enum": {"1", "2", "0"}, "timestamp_value": {timeStr}, @@ -149,9 +150,10 @@ func TestPopulateParameters(t *testing.T) { "map_value13[2.5]": {"value"}, "map_value14[key]": {"true"}, "map_value15[true]": {"value"}, + "map_value16[key]": {"2"}, }, filter: utilities.NewDoubleArray(nil), - want: &proto3Message{ + want: &examplepb.Proto3Message{ FloatValue: 1.5, DoubleValue: 2.5, Int64Value: -1, @@ -162,20 +164,21 @@ func TestPopulateParameters(t *testing.T) { StringValue: "str", BytesValue: []byte("bytes"), RepeatedValue: []string{"a", "b", "c"}, - EnumValue: EnumValue_Y, - RepeatedEnum: []EnumValue{EnumValue_Y, EnumValue_Z, EnumValue_X}, + RepeatedMessage: []*wrapperspb.UInt64Value{{Value: 1}, {Value: 2}, {Value: 3}}, + EnumValue: examplepb.EnumValue_Y, + RepeatedEnum: []examplepb.EnumValue{examplepb.EnumValue_Y, examplepb.EnumValue_Z, examplepb.EnumValue_X}, TimestampValue: timePb, DurationValue: durationPb, - FieldMaskValue: fieldmaskPb, - WrapperFloatValue: &wrappers.FloatValue{Value: 1.5}, - WrapperDoubleValue: &wrappers.DoubleValue{Value: 2.5}, - WrapperInt64Value: &wrappers.Int64Value{Value: -1}, - WrapperInt32Value: &wrappers.Int32Value{Value: -2}, - WrapperUInt64Value: &wrappers.UInt64Value{Value: 3}, - WrapperUInt32Value: &wrappers.UInt32Value{Value: 4}, - WrapperBoolValue: &wrappers.BoolValue{Value: true}, - WrapperStringValue: &wrappers.StringValue{Value: "str"}, - WrapperBytesValue: &wrappers.BytesValue{Value: []byte("bytes")}, + FieldmaskValue: fieldmaskPb, + WrapperFloatValue: &wrapperspb.FloatValue{Value: 1.5}, + WrapperDoubleValue: &wrapperspb.DoubleValue{Value: 2.5}, + WrapperInt64Value: &wrapperspb.Int64Value{Value: -1}, + WrapperInt32Value: &wrapperspb.Int32Value{Value: -2}, + WrapperUInt64Value: &wrapperspb.UInt64Value{Value: 3}, + WrapperUInt32Value: &wrapperspb.UInt32Value{Value: 4}, + WrapperBoolValue: &wrapperspb.BoolValue{Value: true}, + WrapperStringValue: &wrapperspb.StringValue{Value: "str"}, + WrapperBytesValue: &wrapperspb.BytesValue{Value: []byte("bytes")}, MapValue: map[string]string{ "key": "value", "second": "bar", @@ -192,11 +195,10 @@ func TestPopulateParameters(t *testing.T) { MapValue8: map[string]uint64{"key": 4}, MapValue9: map[uint64]string{4: "value"}, MapValue10: map[string]float32{"key": 1.5}, - MapValue11: map[float32]string{1.5: "value"}, MapValue12: map[string]float64{"key": 2.5}, - MapValue13: map[float64]string{2.5: "value"}, MapValue14: map[string]bool{"key": true}, MapValue15: map[bool]string{true: "value"}, + MapValue16: map[string]*wrapperspb.UInt64Value{"key": {Value: 2}}, }, }, { @@ -227,7 +229,7 @@ func TestPopulateParameters(t *testing.T) { "wrapperBytesValue": {"Ynl0ZXM="}, }, filter: utilities.NewDoubleArray(nil), - want: &proto3Message{ + want: &examplepb.Proto3Message{ FloatValue: 1.5, DoubleValue: 2.5, Int64Value: -1, @@ -238,31 +240,31 @@ func TestPopulateParameters(t *testing.T) { StringValue: "str", BytesValue: []byte("bytes"), RepeatedValue: []string{"a", "b", "c"}, - EnumValue: EnumValue_Y, - RepeatedEnum: []EnumValue{EnumValue_Y, EnumValue_Z, EnumValue_X}, + EnumValue: examplepb.EnumValue_Y, + RepeatedEnum: []examplepb.EnumValue{examplepb.EnumValue_Y, examplepb.EnumValue_Z, examplepb.EnumValue_X}, TimestampValue: timePb, DurationValue: durationPb, - FieldMaskValue: fieldmaskPb, - WrapperFloatValue: &wrappers.FloatValue{Value: 1.5}, - WrapperDoubleValue: &wrappers.DoubleValue{Value: 2.5}, - WrapperInt64Value: &wrappers.Int64Value{Value: -1}, - WrapperInt32Value: &wrappers.Int32Value{Value: -2}, - WrapperUInt64Value: &wrappers.UInt64Value{Value: 3}, - WrapperUInt32Value: &wrappers.UInt32Value{Value: 4}, - WrapperBoolValue: &wrappers.BoolValue{Value: true}, - WrapperStringValue: &wrappers.StringValue{Value: "str"}, - WrapperBytesValue: &wrappers.BytesValue{Value: []byte("bytes")}, + FieldmaskValue: fieldmaskPb, + WrapperFloatValue: &wrapperspb.FloatValue{Value: 1.5}, + WrapperDoubleValue: &wrapperspb.DoubleValue{Value: 2.5}, + WrapperInt64Value: &wrapperspb.Int64Value{Value: -1}, + WrapperInt32Value: &wrapperspb.Int32Value{Value: -2}, + WrapperUInt64Value: &wrapperspb.UInt64Value{Value: 3}, + WrapperUInt32Value: &wrapperspb.UInt32Value{Value: 4}, + WrapperBoolValue: &wrapperspb.BoolValue{Value: true}, + WrapperStringValue: &wrapperspb.StringValue{Value: "str"}, + WrapperBytesValue: &wrapperspb.BytesValue{Value: []byte("bytes")}, }, }, { values: url.Values{ - "enum_value": {"EnumValue_Z"}, - "repeated_enum": {"EnumValue_X", "2", "0"}, + "enum_value": {"Z"}, + "repeated_enum": {"X", "2", "0"}, }, filter: utilities.NewDoubleArray(nil), - want: &proto3Message{ - EnumValue: EnumValue_Z, - RepeatedEnum: []EnumValue{EnumValue_X, EnumValue_Z, EnumValue_X}, + want: &examplepb.Proto3Message{ + EnumValue: examplepb.EnumValue_Z, + RepeatedEnum: []examplepb.EnumValue{examplepb.EnumValue_X, examplepb.EnumValue_Z, examplepb.EnumValue_X}, }, }, { @@ -276,11 +278,9 @@ func TestPopulateParameters(t *testing.T) { "bool_value": {"true"}, "string_value": {"str"}, "repeated_value": {"a", "b", "c"}, - "enum_value": {"1"}, - "repeated_enum": {"1", "2", "0"}, }, filter: utilities.NewDoubleArray(nil), - want: &proto2Message{ + want: &examplepb.Proto2Message{ FloatValue: proto.Float32(1.5), DoubleValue: proto.Float64(2.5), Int64Value: proto.Int64(-1), @@ -290,8 +290,6 @@ func TestPopulateParameters(t *testing.T) { BoolValue: proto.Bool(true), StringValue: proto.String("str"), RepeatedValue: []string{"a", "b", "c"}, - EnumValue: EnumValue_Y, - RepeatedEnum: []EnumValue{EnumValue_Y, EnumValue_Z, EnumValue_X}, }, }, { @@ -305,11 +303,9 @@ func TestPopulateParameters(t *testing.T) { "boolValue": {"true"}, "stringValue": {"str"}, "repeatedValue": {"a", "b", "c"}, - "enumValue": {"1"}, - "repeatedEnum": {"1", "2", "0"}, }, filter: utilities.NewDoubleArray(nil), - want: &proto2Message{ + want: &examplepb.Proto2Message{ FloatValue: proto.Float32(1.5), DoubleValue: proto.Float64(2.5), Int64Value: proto.Int64(-1), @@ -319,8 +315,6 @@ func TestPopulateParameters(t *testing.T) { BoolValue: proto.Bool(true), StringValue: proto.String("str"), RepeatedValue: []string{"a", "b", "c"}, - EnumValue: EnumValue_Y, - RepeatedEnum: []EnumValue{EnumValue_Y, EnumValue_Z, EnumValue_X}, }, }, { @@ -329,47 +323,36 @@ func TestPopulateParameters(t *testing.T) { "nested.nested.nested.string_value": {"s"}, "nested.nested.string_value": {"t"}, "nested.string_value": {"u"}, - "nested_non_null.string_value": {"v"}, "nested.nested.map_value[first]": {"foo"}, "nested.nested.map_value[second]": {"bar"}, }, filter: utilities.NewDoubleArray(nil), - want: &proto3Message{ - Nested: &proto2Message{ - Nested: &proto3Message{ + want: &examplepb.Proto3Message{ + Nested: &examplepb.Proto3Message{ + Nested: &examplepb.Proto3Message{ MapValue: map[string]string{ "first": "foo", "second": "bar", }, - Nested: &proto2Message{ + Nested: &examplepb.Proto3Message{ RepeatedValue: []string{"a", "b", "c"}, - StringValue: proto.String("s"), + StringValue: "s", }, StringValue: "t", }, - StringValue: proto.String("u"), - }, - NestedNonNull: proto2Message{ - StringValue: proto.String("v"), + StringValue: "u", }, }, }, - { - values: url.Values{ - "uint64_value": {"1", "2", "3", "4", "5"}, - }, - filter: utilities.NewDoubleArray(nil), - want: &proto3Message{ - Uint64Value: 1, - }, - }, { values: url.Values{ "oneof_string_value": {"foobar"}, }, filter: utilities.NewDoubleArray(nil), - want: &proto3Message{ - OneofValue: &proto3Message_OneofStringValue{"foobar"}, + want: &examplepb.Proto3Message{ + OneofValue: &examplepb.Proto3Message_OneofStringValue{ + OneofStringValue: "foobar", + }, }, }, { @@ -377,8 +360,10 @@ func TestPopulateParameters(t *testing.T) { "oneofStringValue": {"foobar"}, }, filter: utilities.NewDoubleArray(nil), - want: &proto3Message{ - OneofValue: &proto3Message_OneofStringValue{"foobar"}, + want: &examplepb.Proto3Message{ + OneofValue: &examplepb.Proto3Message_OneofStringValue{ + OneofStringValue: "foobar", + }, }, }, { @@ -386,8 +371,10 @@ func TestPopulateParameters(t *testing.T) { "oneof_bool_value": {"true"}, }, filter: utilities.NewDoubleArray(nil), - want: &proto3Message{ - OneofValue: &proto3Message_OneofBoolValue{true}, + want: &examplepb.Proto3Message{ + OneofValue: &examplepb.Proto3Message_OneofBoolValue{ + OneofBoolValue: true, + }, }, }, { @@ -397,72 +384,46 @@ func TestPopulateParameters(t *testing.T) { "oneof_string_value": {"foobar"}, }, filter: utilities.NewDoubleArray(nil), - want: &proto3Message{}, - wanterr: errors.New("field already set for oneof_value oneof"), + want: &examplepb.Proto3Message{}, + wanterr: errors.New("field already set for oneof \"oneof_value\""), }, - } { - msg := proto.Clone(spec.want) - msg.Reset() - err := runtime.PopulateQueryParameters(msg, spec.values, spec.filter) - if spec.wanterr != nil { - if !reflect.DeepEqual(err, spec.wanterr) { - t.Errorf("runtime.PopulateQueryParameters(msg, %v, %v) failed with %v; want error %v", spec.values, spec.filter, err, spec.wanterr) - } - continue - } - - if err != nil { - t.Errorf("runtime.PopulateQueryParameters(msg, %v, %v) failed with %v; want success", spec.values, spec.filter, err) - continue - } - if got, want := msg, spec.want; !proto.Equal(got, want) { - t.Errorf("runtime.PopulateQueryParameters(msg, %v, %v = %v; want %v", spec.values, spec.filter, got, want) - } - } -} - -func TestPopulateParametersWithNativeTypes(t *testing.T) { - timeT := time.Date(2016, time.December, 15, 12, 23, 32, 49, time.UTC) - timeStr := timeT.Format(time.RFC3339Nano) - - durationT := 13 * time.Hour - durationStr := durationT.String() - - for _, spec := range []struct { - values url.Values - want *nativeProto3Message - }{ { + // Error when there are too many values values: url.Values{ - "native_timestamp_value": {timeStr}, - "native_duration_value": {durationStr}, - }, - want: &nativeProto3Message{ - NativeTimeValue: &timeT, - NativeDurationValue: &durationT, + "uint64_value": {"1", "2"}, }, + filter: utilities.NewDoubleArray(nil), + want: &examplepb.Proto3Message{}, + wanterr: errors.New("too many values for field \"uint64_value\": 1, 2"), }, { + // Error when dereferencing a list of messages values: url.Values{ - "nativeTimestampValue": {timeStr}, - "nativeDurationValue": {durationStr}, - }, - want: &nativeProto3Message{ - NativeTimeValue: &timeT, - NativeDurationValue: &durationT, + "repeated_message.value": {"1"}, }, + filter: utilities.NewDoubleArray(nil), + want: &examplepb.Proto3Message{}, + wanterr: errors.New("invalid path: \"repeated_message\" is not a message"), }, } { - msg := new(nativeProto3Message) - err := runtime.PopulateQueryParameters(msg, spec.values, utilities.NewDoubleArray(nil)) + t.Run(strconv.Itoa(i), func(t *testing.T) { + msg := spec.want.ProtoReflect().New().Interface() + err := runtime.PopulateQueryParameters(msg, spec.values, spec.filter) + if spec.wanterr != nil { + if err == nil || err.Error() != spec.wanterr.Error() { + t.Errorf("runtime.PopulateQueryParameters(msg, %v, %v) failed with %q; want error %q", spec.values, spec.filter, err, spec.wanterr) + } + return + } - if err != nil { - t.Errorf("runtime.PopulateQueryParameters(msg, %v, utilities.NewDoubleArray(nil)) failed with %v; want success", spec.values, err) - continue - } - if got, want := msg, spec.want; !proto.Equal(got, want) { - t.Errorf("runtime.PopulateQueryParameters(msg, %v, utilities.NewDoubleArray(nil)) = %v; want %v", spec.values, got, want) - } + if err != nil { + t.Errorf("runtime.PopulateQueryParameters(msg, %v, %v) failed with %v; want success", spec.values, spec.filter, err) + return + } + if diff := cmp.Diff(spec.want, msg, protocmp.Transform()); diff != "" { + t.Errorf("runtime.PopulateQueryParameters(msg, %v, %v): %s", spec.values, spec.filter, diff) + } + }) } } @@ -481,7 +442,7 @@ func TestPopulateParametersWithFilters(t *testing.T) { filter: utilities.NewDoubleArray([][]string{ {"bool_value"}, {"repeated_value"}, }), - want: &proto3Message{ + want: &examplepb.Proto3Message{ StringValue: "str", }, }, @@ -495,7 +456,7 @@ func TestPopulateParametersWithFilters(t *testing.T) { filter: utilities.NewDoubleArray([][]string{ {"nested"}, }), - want: &proto3Message{ + want: &examplepb.Proto3Message{ StringValue: "str", }, }, @@ -509,9 +470,9 @@ func TestPopulateParametersWithFilters(t *testing.T) { filter: utilities.NewDoubleArray([][]string{ {"nested", "nested"}, }), - want: &proto3Message{ - Nested: &proto2Message{ - StringValue: proto.String("str"), + want: &examplepb.Proto3Message{ + Nested: &examplepb.Proto3Message{ + StringValue: "str", }, StringValue: "str", }, @@ -526,10 +487,10 @@ func TestPopulateParametersWithFilters(t *testing.T) { filter: utilities.NewDoubleArray([][]string{ {"nested", "nested", "string_value"}, }), - want: &proto3Message{ - Nested: &proto2Message{ - StringValue: proto.String("str"), - Nested: &proto3Message{ + want: &examplepb.Proto3Message{ + Nested: &examplepb.Proto3Message{ + StringValue: "str", + Nested: &examplepb.Proto3Message{ BoolValue: true, }, }, @@ -537,8 +498,7 @@ func TestPopulateParametersWithFilters(t *testing.T) { }, }, } { - msg := proto.Clone(spec.want) - msg.Reset() + msg := spec.want.ProtoReflect().New().Interface() err := runtime.PopulateQueryParameters(msg, spec.values, spec.filter) if err != nil { t.Errorf("runtime.PoplateQueryParameters(msg, %v, %v) failed with %v; want success", spec.values, spec.filter, err) @@ -557,376 +517,94 @@ func TestPopulateQueryParametersWithInvalidNestedParameters(t *testing.T) { filter *utilities.DoubleArray }{ { - msg: &proto3Message{}, + msg: &examplepb.Proto3Message{}, values: url.Values{ "float_value.nested": {"test"}, }, filter: utilities.NewDoubleArray(nil), }, { - msg: &proto3Message{}, + msg: &examplepb.Proto3Message{}, values: url.Values{ "double_value.nested": {"test"}, }, filter: utilities.NewDoubleArray(nil), }, { - msg: &proto3Message{}, + msg: &examplepb.Proto3Message{}, values: url.Values{ "int64_value.nested": {"test"}, }, filter: utilities.NewDoubleArray(nil), }, { - msg: &proto3Message{}, + msg: &examplepb.Proto3Message{}, values: url.Values{ "int32_value.nested": {"test"}, }, filter: utilities.NewDoubleArray(nil), }, { - msg: &proto3Message{}, + msg: &examplepb.Proto3Message{}, values: url.Values{ "uint64_value.nested": {"test"}, }, filter: utilities.NewDoubleArray(nil), }, { - msg: &proto3Message{}, + msg: &examplepb.Proto3Message{}, values: url.Values{ "uint32_value.nested": {"test"}, }, filter: utilities.NewDoubleArray(nil), }, { - msg: &proto3Message{}, + msg: &examplepb.Proto3Message{}, values: url.Values{ "bool_value.nested": {"test"}, }, filter: utilities.NewDoubleArray(nil), }, { - msg: &proto3Message{}, + msg: &examplepb.Proto3Message{}, values: url.Values{ "string_value.nested": {"test"}, }, filter: utilities.NewDoubleArray(nil), }, { - msg: &proto3Message{}, + msg: &examplepb.Proto3Message{}, values: url.Values{ "repeated_value.nested": {"test"}, }, filter: utilities.NewDoubleArray(nil), }, { - msg: &proto3Message{}, + msg: &examplepb.Proto3Message{}, values: url.Values{ "enum_value.nested": {"test"}, }, filter: utilities.NewDoubleArray(nil), }, { - msg: &proto3Message{}, + msg: &examplepb.Proto3Message{}, values: url.Values{ "enum_value.nested": {"test"}, }, filter: utilities.NewDoubleArray(nil), }, { - msg: &proto3Message{}, + msg: &examplepb.Proto3Message{}, values: url.Values{ "repeated_enum.nested": {"test"}, }, filter: utilities.NewDoubleArray(nil), }, } { - spec.msg.Reset() + spec.msg = spec.msg.ProtoReflect().New().Interface() err := runtime.PopulateQueryParameters(spec.msg, spec.values, spec.filter) if err == nil { t.Errorf("runtime.PopulateQueryParameters(msg, %v, %v) did not fail; want error", spec.values, spec.filter) } } } - -type proto3Message struct { - Nested *proto2Message `protobuf:"bytes,1,opt,name=nested,json=nested" json:"nested,omitempty"` - NestedNonNull proto2Message `protobuf:"bytes,15,opt,name=nested_non_null,json=nestedNonNull" json:"nested_non_null,omitempty"` - FloatValue float32 `protobuf:"fixed32,2,opt,name=float_value,json=floatValue" json:"float_value,omitempty"` - DoubleValue float64 `protobuf:"fixed64,3,opt,name=double_value,json=doubleValue" json:"double_value,omitempty"` - Int64Value int64 `protobuf:"varint,4,opt,name=int64_value,json=int64Value" json:"int64_value,omitempty"` - Int32Value int32 `protobuf:"varint,5,opt,name=int32_value,json=int32Value" json:"int32_value,omitempty"` - Uint64Value uint64 `protobuf:"varint,6,opt,name=uint64_value,json=uint64Value" json:"uint64_value,omitempty"` - Uint32Value uint32 `protobuf:"varint,7,opt,name=uint32_value,json=uint32Value" json:"uint32_value,omitempty"` - BoolValue bool `protobuf:"varint,8,opt,name=bool_value,json=boolValue" json:"bool_value,omitempty"` - StringValue string `protobuf:"bytes,9,opt,name=string_value,json=stringValue" json:"string_value,omitempty"` - BytesValue []byte `protobuf:"bytes,25,opt,name=bytes_value,json=bytesValue" json:"bytes_value,omitempty"` - RepeatedValue []string `protobuf:"bytes,10,rep,name=repeated_value,json=repeatedValue" json:"repeated_value,omitempty"` - EnumValue EnumValue `protobuf:"varint,11,opt,name=enum_value,json=enumValue,enum=runtime_test_api.EnumValue" json:"enum_value,omitempty"` - RepeatedEnum []EnumValue `protobuf:"varint,12,rep,packed,name=repeated_enum,json=repeatedEnum,enum=runtime_test_api.EnumValue" json:"repeated_enum,omitempty"` - TimestampValue *timestamp.Timestamp `protobuf:"bytes,16,opt,name=timestamp_value,json=timestampValue" json:"timestamp_value,omitempty"` - DurationValue *duration.Duration `protobuf:"bytes,42,opt,name=duration_value,json=durationValue" json:"duration_value,omitempty"` - FieldMaskValue *field_mask.FieldMask `protobuf:"bytes,27,opt,name=fieldmask_value,json=fieldmaskValue" json:"fieldmask_value,omitempty"` - OneofValue proto3Message_OneofValue `protobuf_oneof:"oneof_value"` - WrapperDoubleValue *wrappers.DoubleValue `protobuf:"bytes,17,opt,name=wrapper_double_value,json=wrapperDoubleValue" json:"wrapper_double_value,omitempty"` - WrapperFloatValue *wrappers.FloatValue `protobuf:"bytes,18,opt,name=wrapper_float_value,json=wrapperFloatValue" json:"wrapper_float_value,omitempty"` - WrapperInt64Value *wrappers.Int64Value `protobuf:"bytes,19,opt,name=wrapper_int64_value,json=wrapperInt64Value" json:"wrapper_int64_value,omitempty"` - WrapperInt32Value *wrappers.Int32Value `protobuf:"bytes,20,opt,name=wrapper_int32_value,json=wrapperInt32Value" json:"wrapper_int32_value,omitempty"` - WrapperUInt64Value *wrappers.UInt64Value `protobuf:"bytes,21,opt,name=wrapper_u_int64_value,json=wrapperUInt64Value" json:"wrapper_u_int64_value,omitempty"` - WrapperUInt32Value *wrappers.UInt32Value `protobuf:"bytes,22,opt,name=wrapper_u_int32_value,json=wrapperUInt32Value" json:"wrapper_u_int32_value,omitempty"` - WrapperBoolValue *wrappers.BoolValue `protobuf:"bytes,23,opt,name=wrapper_bool_value,json=wrapperBoolValue" json:"wrapper_bool_value,omitempty"` - WrapperStringValue *wrappers.StringValue `protobuf:"bytes,24,opt,name=wrapper_string_value,json=wrapperStringValue" json:"wrapper_string_value,omitempty"` - WrapperBytesValue *wrappers.BytesValue `protobuf:"bytes,26,opt,name=wrapper_bytes_value,json=wrapperBytesValue" json:"wrapper_bytes_value,omitempty"` - MapValue map[string]string `protobuf:"bytes,27,opt,name=map_value,json=mapValue" json:"map_value,omitempty"` - MapValue2 map[string]int32 `protobuf:"bytes,28,opt,name=map_value2,json=mapValue2" json:"map_value2,omitempty"` - MapValue3 map[int32]string `protobuf:"bytes,29,opt,name=map_value3,json=mapValue3" json:"map_value3,omitempty"` - MapValue4 map[string]int64 `protobuf:"bytes,30,opt,name=map_value4,json=mapValue4" json:"map_value4,omitempty"` - MapValue5 map[int64]string `protobuf:"bytes,31,opt,name=map_value5,json=mapValue5" json:"map_value5,omitempty"` - MapValue6 map[string]uint32 `protobuf:"bytes,32,opt,name=map_value6,json=mapValue6" json:"map_value6,omitempty"` - MapValue7 map[uint32]string `protobuf:"bytes,33,opt,name=map_value7,json=mapValue7" json:"map_value7,omitempty"` - MapValue8 map[string]uint64 `protobuf:"bytes,34,opt,name=map_value8,json=mapValue8" json:"map_value8,omitempty"` - MapValue9 map[uint64]string `protobuf:"bytes,35,opt,name=map_value9,json=mapValue9" json:"map_value9,omitempty"` - MapValue10 map[string]float32 `protobuf:"bytes,36,opt,name=map_value10,json=mapValue10" json:"map_value10,omitempty"` - MapValue11 map[float32]string `protobuf:"bytes,37,opt,name=map_value11,json=mapValue11" json:"map_value11,omitempty"` - MapValue12 map[string]float64 `protobuf:"bytes,38,opt,name=map_value12,json=mapValue12" json:"map_value12,omitempty"` - MapValue13 map[float64]string `protobuf:"bytes,39,opt,name=map_value13,json=mapValue13" json:"map_value13,omitempty"` - MapValue14 map[string]bool `protobuf:"bytes,40,opt,name=map_value14,json=mapValue14" json:"map_value14,omitempty"` - MapValue15 map[bool]string `protobuf:"bytes,41,opt,name=map_value15,json=mapValue15" json:"map_value15,omitempty"` -} - -func (m *proto3Message) Reset() { *m = proto3Message{} } -func (m *proto3Message) String() string { return proto.CompactTextString(m) } -func (*proto3Message) ProtoMessage() {} - -func (m *proto3Message) GetNested() *proto2Message { - if m != nil { - return m.Nested - } - return nil -} - -type proto3Message_OneofValue interface { - proto3Message_OneofValue() -} - -type proto3Message_OneofBoolValue struct { - OneofBoolValue bool `protobuf:"varint,13,opt,name=oneof_bool_value,json=oneofBoolValue,oneof"` -} -type proto3Message_OneofStringValue struct { - OneofStringValue string `protobuf:"bytes,14,opt,name=oneof_string_value,json=oneofStringValue,oneof"` -} - -func (*proto3Message_OneofBoolValue) proto3Message_OneofValue() {} -func (*proto3Message_OneofStringValue) proto3Message_OneofValue() {} - -func (m *proto3Message) GetOneofValue() proto3Message_OneofValue { - if m != nil { - return m.OneofValue - } - return nil -} - -func (m *proto3Message) GetOneofBoolValue() bool { - if x, ok := m.GetOneofValue().(*proto3Message_OneofBoolValue); ok { - return x.OneofBoolValue - } - return false -} - -func (m *proto3Message) GetOneofStringValue() string { - if x, ok := m.GetOneofValue().(*proto3Message_OneofStringValue); ok { - return x.OneofStringValue - } - return "" -} - -// XXX_OneofFuncs is for the internal use of the proto package. -func (*proto3Message) 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 _proto3Message_OneofMarshaler, _proto3Message_OneofUnmarshaler, _proto3Message_OneofSizer, []interface{}{ - (*proto3Message_OneofBoolValue)(nil), - (*proto3Message_OneofStringValue)(nil), - } -} - -func _proto3Message_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { - m := msg.(*proto3Message) - // oneof_value - switch x := m.OneofValue.(type) { - case *proto3Message_OneofBoolValue: - t := uint64(0) - if x.OneofBoolValue { - t = 1 - } - b.EncodeVarint(13<<3 | proto.WireVarint) - b.EncodeVarint(t) - case *proto3Message_OneofStringValue: - b.EncodeVarint(14<<3 | proto.WireBytes) - b.EncodeStringBytes(x.OneofStringValue) - case nil: - default: - return fmt.Errorf("proto3Message.OneofValue has unexpected type %T", x) - } - return nil -} - -func _proto3Message_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { - m := msg.(*proto3Message) - switch tag { - case 14: // oneof_value.oneof_bool_value - if wire != proto.WireVarint { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeVarint() - m.OneofValue = &proto3Message_OneofBoolValue{x != 0} - return true, err - case 15: // oneof_value.oneof_string_value - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeStringBytes() - m.OneofValue = &proto3Message_OneofStringValue{x} - return true, err - default: - return false, nil - } -} - -func _proto3Message_OneofSizer(msg proto.Message) (n int) { - m := msg.(*proto3Message) - // oneof_value - switch x := m.OneofValue.(type) { - case *proto3Message_OneofBoolValue: - n += proto.SizeVarint(14<<3 | proto.WireVarint) - n += 1 - case *proto3Message_OneofStringValue: - n += proto.SizeVarint(15<<3 | proto.WireBytes) - n += proto.SizeVarint(uint64(len(x.OneofStringValue))) - n += len(x.OneofStringValue) - case nil: - default: - panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) - } - return n -} - -type nativeProto3Message struct { - NativeTimeValue *time.Time `protobuf:"bytes,1,opt,name=native_timestamp_value,json=nativeTimestampValue" json:"native_timestamp_value,omitempty"` - NativeDurationValue *time.Duration `protobuf:"bytes,2,opt,name=native_duration_value,json=nativeDurationValue" json:"native_duration_value,omitempty"` -} - -func (m *nativeProto3Message) Reset() { *m = nativeProto3Message{} } -func (m *nativeProto3Message) String() string { return proto.CompactTextString(m) } -func (*nativeProto3Message) ProtoMessage() {} - -type proto2Message struct { - Nested *proto3Message `protobuf:"bytes,1,opt,name=nested,json=nested" json:"nested,omitempty"` - FloatValue *float32 `protobuf:"fixed32,2,opt,name=float_value,json=floatValue" json:"float_value,omitempty"` - DoubleValue *float64 `protobuf:"fixed64,3,opt,name=double_value,json=doubleValue" json:"double_value,omitempty"` - Int64Value *int64 `protobuf:"varint,4,opt,name=int64_value,json=int64Value" json:"int64_value,omitempty"` - Int32Value *int32 `protobuf:"varint,5,opt,name=int32_value,json=int32Value" json:"int32_value,omitempty"` - Uint64Value *uint64 `protobuf:"varint,6,opt,name=uint64_value,json=uint64Value" json:"uint64_value,omitempty"` - Uint32Value *uint32 `protobuf:"varint,7,opt,name=uint32_value,json=uint32Value" json:"uint32_value,omitempty"` - BoolValue *bool `protobuf:"varint,8,opt,name=bool_value,json=boolValue" json:"bool_value,omitempty"` - StringValue *string `protobuf:"bytes,9,opt,name=string_value,json=stringValue" json:"string_value,omitempty"` - RepeatedValue []string `protobuf:"bytes,10,rep,name=repeated_value,json=repeatedValue" json:"repeated_value,omitempty"` - EnumValue EnumValue `protobuf:"varint,11,opt,name=enum_value,json=enumValue,enum=runtime_test_api.EnumValue" json:"enum_value,omitempty"` - RepeatedEnum []EnumValue `protobuf:"varint,12,rep,packed,name=repeated_enum,json=repeatedEnum,enum=runtime_test_api.EnumValue" json:"repeated_enum,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *proto2Message) Reset() { *m = proto2Message{} } -func (m *proto2Message) String() string { return proto.CompactTextString(m) } -func (*proto2Message) ProtoMessage() {} - -func (m *proto2Message) GetNested() *proto3Message { - if m != nil { - return m.Nested - } - return nil -} - -func (m *proto2Message) GetFloatValue() float32 { - if m != nil && m.FloatValue != nil { - return *m.FloatValue - } - return 0 -} - -func (m *proto2Message) GetDoubleValue() float64 { - if m != nil && m.DoubleValue != nil { - return *m.DoubleValue - } - return 0 -} - -func (m *proto2Message) GetInt64Value() int64 { - if m != nil && m.Int64Value != nil { - return *m.Int64Value - } - return 0 -} - -func (m *proto2Message) GetInt32Value() int32 { - if m != nil && m.Int32Value != nil { - return *m.Int32Value - } - return 0 -} - -func (m *proto2Message) GetUint64Value() uint64 { - if m != nil && m.Uint64Value != nil { - return *m.Uint64Value - } - return 0 -} - -func (m *proto2Message) GetUint32Value() uint32 { - if m != nil && m.Uint32Value != nil { - return *m.Uint32Value - } - return 0 -} - -func (m *proto2Message) GetBoolValue() bool { - if m != nil && m.BoolValue != nil { - return *m.BoolValue - } - return false -} - -func (m *proto2Message) GetStringValue() string { - if m != nil && m.StringValue != nil { - return *m.StringValue - } - return "" -} - -func (m *proto2Message) GetRepeatedValue() []string { - if m != nil { - return m.RepeatedValue - } - return nil -} - -type EnumValue int32 - -const ( - EnumValue_X EnumValue = 0 - EnumValue_Y EnumValue = 1 - EnumValue_Z EnumValue = 2 -) - -var EnumValue_name = map[int32]string{ - 0: "EnumValue_X", - 1: "EnumValue_Y", - 2: "EnumValue_Z", -} -var EnumValue_value = map[string]int32{ - "EnumValue_X": 0, - "EnumValue_Y": 1, - "EnumValue_Z": 2, -} - -func init() { - proto.RegisterEnum("runtime_test_api.EnumValue", EnumValue_name, EnumValue_value) -} diff --git a/go.mod b/go.mod index e9dda22..36af499 100644 --- a/go.mod +++ b/go.mod @@ -9,15 +9,17 @@ require ( github.com/fatih/color v1.9.0 github.com/ghodss/yaml v1.0.0 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b - github.com/golang/protobuf v1.4.2 + github.com/golang/protobuf v1.4.3 + github.com/google/go-cmp v0.5.2 github.com/grpc-ecosystem/grpc-gateway v1.14.6 + github.com/grpc-ecosystem/grpc-gateway/v2 v2.0.1 github.com/klauspost/compress v1.10.10 github.com/pborman/uuid v1.2.0 github.com/prometheus/client_golang v1.7.1 - golang.org/x/net v0.0.0-20200625001655-4c5254603344 - google.golang.org/genproto v0.0.0-20200702021140-07506425bd67 - google.golang.org/grpc v1.30.0 - google.golang.org/protobuf v1.24.0 + golang.org/x/net v0.0.0-20200822124328-c89045814202 + google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154 + google.golang.org/grpc v1.33.1 + google.golang.org/protobuf v1.25.0 ) replace ( diff --git a/go.sum b/go.sum index a979252..b810a75 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,38 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= @@ -46,6 +78,9 @@ github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QH github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= @@ -81,6 +116,9 @@ github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.10.0 h1:dXFJfIHVvUcpSgDOV+Ne6t7jXri8Tfv2uOLHUZ2XNuo= @@ -98,11 +136,21 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekf github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= @@ -111,6 +159,8 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -119,11 +169,29 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= @@ -138,6 +206,9 @@ github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t github.com/grpc-ecosystem/grpc-gateway v1.12.1/go.mod h1:8XEsbTttt/W+VvjtQhLACqCisSPWTxCZ7sBRjU6iH9c= github.com/grpc-ecosystem/grpc-gateway v1.14.6 h1:8ERzHx8aj1Sc47mu9n/AksaKCSWrMchFtkdrS4BIj5o= github.com/grpc-ecosystem/grpc-gateway v1.14.6/go.mod h1:zdiPV4Yse/1gnckTHtghG4GkDEdKCRJduHpTxT3/jcw= +github.com/grpc-ecosystem/grpc-gateway v1.15.2 h1:HC+hWRWf+v5zTMPyoaYTKIJih+4sd4XRWmj0qlG87Co= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.0.1 h1:X2vfSnm1WC8HEo0MBHZg2TcuDUHJj6kd1TmEAQncnSA= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.0.1/go.mod h1:oVMjMN64nzEcepv1kdZKgx1qNYt4Ro0Gqefiq2JWdis= github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 h1:MJG/KsmcqMwFAkh8mTnAwhyKoB+sTAnY4CACC110tbU= github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw= github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= @@ -162,6 +233,7 @@ github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2p github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= @@ -170,6 +242,8 @@ github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCV github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= @@ -316,13 +390,20 @@ github.com/uber/jaeger-lib v2.2.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6 github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -337,18 +418,41 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -361,22 +465,46 @@ golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201026091529-146b70c837a4 h1:awiuzyrRjJDb+OXi9ceHO3SDxVoN3JER57mhtqkdQBs= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -387,22 +515,47 @@ golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM/fAoGlaiiHYiFYdm80= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642 h1:B6caxRw+hozq68X2MY7jEpZh/cr4/aHLv9xU8Kkadrw= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -410,38 +563,120 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200103221440-774c71fcf114 h1:DnSr2mCsxyCE6ZgIkmcWUQY2R5cH/6wL7eIxEmQOMSE= golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= google.golang.org/genproto v0.0.0-20190927181202-20e1ac93f88c/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200624020401-64a14ca9d1ad/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200702021140-07506425bd67 h1:4BC1C1i30F3MZeiIO6y6IIo4DxrtOwITK87bQl3lhFA= google.golang.org/genproto v0.0.0-20200702021140-07506425bd67/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154 h1:bFFRpT+e8JJVY7lMMfvezL1ZIwqiwmPl2bsE2yx4HqM= +google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= @@ -451,9 +686,14 @@ google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8 google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0 h1:M5a8xTlYTxwMn5ZFkwhRabsygDY5G8TYLyQDBxJNAxE= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1 h1:DGeFlSan2f+WEtCERJ4J9GJWk15TxUi8QGagfI87Xyc= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.0.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/grpc/examples v0.0.0-20200630190442-3de8449f8555 h1:B6/wMqTY7mM93BBu0wfiO67B9+bcv4oQQsdrcijjfzA= google.golang.org/grpc/examples v0.0.0-20200630190442-3de8449f8555/go.mod h1:5j1uub0jRGhRiSghIlrThmBUgcgLXOVJQ/l1getT4uo= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= @@ -466,6 +706,8 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -490,8 +732,15 @@ gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclp gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= upper.io/db.v3 v3.7.1+incompatible h1:GiK/NmDUClH3LrZd54qj5OQsz8brGFv652QXyRXtg2U= diff --git a/httpoptions/annotations.pb.go b/httpoptions/annotations.pb.go old mode 100755 new mode 100644 index 73842ca..75acf02 --- a/httpoptions/annotations.pb.go +++ b/httpoptions/annotations.pb.go @@ -1,614 +1,1035 @@ +// Copyright (c) 2015, Google 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. + +// See `https://github.com/googleapis/googleapis/blob/master/google/api/annotations.proto` + // Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.23.0 +// protoc v3.12.3 // source: httpoptions/annotations.proto package ease_api import ( - fmt "fmt" - data "github.com/binchencoder/gateway-proto/data" + data "data" + _ "frontend" proto "github.com/golang/protobuf/proto" descriptor "github.com/golang/protobuf/protoc-gen-go/descriptor" - math "math" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" ) -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) -// 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.ProtoPackageIsVersion3 // please upgrade the proto package +// This is a compile-time assertion that a sufficiently up-to-date version +// of the legacy proto package is being used. +const _ = proto.ProtoPackageIsVersion4 +// Api regist gateway. type ApiSourceType int32 const ( - ApiSourceType_EASE_GATEWAY ApiSourceType = 0 - ApiSourceType_OPEN_GATEWAY ApiSourceType = 1 + ApiSourceType_EASE_GATEWAY ApiSourceType = 0 // ease-gateway apis. + ApiSourceType_OPEN_GATEWAY ApiSourceType = 1 // open-gateway open apis. ) -var ApiSourceType_name = map[int32]string{ - 0: "EASE_GATEWAY", - 1: "OPEN_GATEWAY", -} +// Enum value maps for ApiSourceType. +var ( + ApiSourceType_name = map[int32]string{ + 0: "EASE_GATEWAY", + 1: "OPEN_GATEWAY", + } + ApiSourceType_value = map[string]int32{ + "EASE_GATEWAY": 0, + "OPEN_GATEWAY": 1, + } +) -var ApiSourceType_value = map[string]int32{ - "EASE_GATEWAY": 0, - "OPEN_GATEWAY": 1, +func (x ApiSourceType) Enum() *ApiSourceType { + p := new(ApiSourceType) + *p = x + return p } func (x ApiSourceType) String() string { - return proto.EnumName(ApiSourceType_name, int32(x)) + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ApiSourceType) Descriptor() protoreflect.EnumDescriptor { + return file_httpoptions_annotations_proto_enumTypes[0].Descriptor() +} + +func (ApiSourceType) Type() protoreflect.EnumType { + return &file_httpoptions_annotations_proto_enumTypes[0] +} + +func (x ApiSourceType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) } +// Deprecated: Use ApiSourceType.Descriptor instead. func (ApiSourceType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_1be5d6cda9fc6cfe, []int{0} + return file_httpoptions_annotations_proto_rawDescGZIP(), []int{0} } +// Auth token type. type AuthTokenType int32 const ( - AuthTokenType_EASE_AUTH_TOKEN AuthTokenType = 0 - AuthTokenType_BASE_ACCESS_TOKEN AuthTokenType = 1 + AuthTokenType_EASE_AUTH_TOKEN AuthTokenType = 0 // ease gateway auth type. + AuthTokenType_BASE_ACCESS_TOKEN AuthTokenType = 1 // open platform baseAccessToken. ) -var AuthTokenType_name = map[int32]string{ - 0: "EASE_AUTH_TOKEN", - 1: "BASE_ACCESS_TOKEN", -} +// Enum value maps for AuthTokenType. +var ( + AuthTokenType_name = map[int32]string{ + 0: "EASE_AUTH_TOKEN", + 1: "BASE_ACCESS_TOKEN", + } + AuthTokenType_value = map[string]int32{ + "EASE_AUTH_TOKEN": 0, + "BASE_ACCESS_TOKEN": 1, + } +) -var AuthTokenType_value = map[string]int32{ - "EASE_AUTH_TOKEN": 0, - "BASE_ACCESS_TOKEN": 1, +func (x AuthTokenType) Enum() *AuthTokenType { + p := new(AuthTokenType) + *p = x + return p } func (x AuthTokenType) String() string { - return proto.EnumName(AuthTokenType_name, int32(x)) + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (AuthTokenType) Descriptor() protoreflect.EnumDescriptor { + return file_httpoptions_annotations_proto_enumTypes[1].Descriptor() +} + +func (AuthTokenType) Type() protoreflect.EnumType { + return &file_httpoptions_annotations_proto_enumTypes[1] +} + +func (x AuthTokenType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) } +// Deprecated: Use AuthTokenType.Descriptor instead. func (AuthTokenType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_1be5d6cda9fc6cfe, []int{1} + return file_httpoptions_annotations_proto_rawDescGZIP(), []int{1} } +// Specified source Type. type SpecSourceType int32 const ( - SpecSourceType_UNSPECIFIED SpecSourceType = 0 - SpecSourceType_WEB SpecSourceType = 1 + SpecSourceType_UNSPECIFIED SpecSourceType = 0 // use the value of x-source about header. + SpecSourceType_WEB SpecSourceType = 1 // specify x-source as "web". ) -var SpecSourceType_name = map[int32]string{ - 0: "UNSPECIFIED", - 1: "WEB", -} +// Enum value maps for SpecSourceType. +var ( + SpecSourceType_name = map[int32]string{ + 0: "UNSPECIFIED", + 1: "WEB", + } + SpecSourceType_value = map[string]int32{ + "UNSPECIFIED": 0, + "WEB": 1, + } +) -var SpecSourceType_value = map[string]int32{ - "UNSPECIFIED": 0, - "WEB": 1, +func (x SpecSourceType) Enum() *SpecSourceType { + p := new(SpecSourceType) + *p = x + return p } func (x SpecSourceType) String() string { - return proto.EnumName(SpecSourceType_name, int32(x)) + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (SpecSourceType) Descriptor() protoreflect.EnumDescriptor { + return file_httpoptions_annotations_proto_enumTypes[2].Descriptor() +} + +func (SpecSourceType) Type() protoreflect.EnumType { + return &file_httpoptions_annotations_proto_enumTypes[2] } +func (x SpecSourceType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use SpecSourceType.Descriptor instead. func (SpecSourceType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_1be5d6cda9fc6cfe, []int{2} + return file_httpoptions_annotations_proto_rawDescGZIP(), []int{2} } +// The load balancer enums. type LoadBalancer int32 const ( LoadBalancer_ROUND_ROBIN LoadBalancer = 0 - LoadBalancer_CONSISTENT LoadBalancer = 1 + LoadBalancer_CONSISTENT LoadBalancer = 1 // Consistent hashing. ) -var LoadBalancer_name = map[int32]string{ - 0: "ROUND_ROBIN", - 1: "CONSISTENT", -} +// Enum value maps for LoadBalancer. +var ( + LoadBalancer_name = map[int32]string{ + 0: "ROUND_ROBIN", + 1: "CONSISTENT", + } + LoadBalancer_value = map[string]int32{ + "ROUND_ROBIN": 0, + "CONSISTENT": 1, + } +) -var LoadBalancer_value = map[string]int32{ - "ROUND_ROBIN": 0, - "CONSISTENT": 1, +func (x LoadBalancer) Enum() *LoadBalancer { + p := new(LoadBalancer) + *p = x + return p } func (x LoadBalancer) String() string { - return proto.EnumName(LoadBalancer_name, int32(x)) + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (LoadBalancer) Descriptor() protoreflect.EnumDescriptor { + return file_httpoptions_annotations_proto_enumTypes[3].Descriptor() } +func (LoadBalancer) Type() protoreflect.EnumType { + return &file_httpoptions_annotations_proto_enumTypes[3] +} + +func (x LoadBalancer) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use LoadBalancer.Descriptor instead. func (LoadBalancer) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_1be5d6cda9fc6cfe, []int{3} + return file_httpoptions_annotations_proto_rawDescGZIP(), []int{3} } +// The opertaion type. type OperatorType int32 const ( OperatorType_OPERATOR_TYPE_UNKNOWN OperatorType = 0 - OperatorType_GT OperatorType = 1 - OperatorType_LT OperatorType = 2 - OperatorType_EQ OperatorType = 3 - OperatorType_MATCH OperatorType = 4 - OperatorType_NON_NIL OperatorType = 5 - OperatorType_LEN_GT OperatorType = 6 - OperatorType_LEN_LT OperatorType = 7 - OperatorType_LEN_EQ OperatorType = 8 + OperatorType_GT OperatorType = 1 // Greater than + OperatorType_LT OperatorType = 2 // Less than + OperatorType_EQ OperatorType = 3 // Equals + OperatorType_MATCH OperatorType = 4 // String pattern match. + OperatorType_NON_NIL OperatorType = 5 // Not nil + OperatorType_LEN_GT OperatorType = 6 // String length great than + OperatorType_LEN_LT OperatorType = 7 // String length less than + OperatorType_LEN_EQ OperatorType = 8 // String length equals +) + +// Enum value maps for OperatorType. +var ( + OperatorType_name = map[int32]string{ + 0: "OPERATOR_TYPE_UNKNOWN", + 1: "GT", + 2: "LT", + 3: "EQ", + 4: "MATCH", + 5: "NON_NIL", + 6: "LEN_GT", + 7: "LEN_LT", + 8: "LEN_EQ", + } + OperatorType_value = map[string]int32{ + "OPERATOR_TYPE_UNKNOWN": 0, + "GT": 1, + "LT": 2, + "EQ": 3, + "MATCH": 4, + "NON_NIL": 5, + "LEN_GT": 6, + "LEN_LT": 7, + "LEN_EQ": 8, + } ) -var OperatorType_name = map[int32]string{ - 0: "OPERATOR_TYPE_UNKNOWN", - 1: "GT", - 2: "LT", - 3: "EQ", - 4: "MATCH", - 5: "NON_NIL", - 6: "LEN_GT", - 7: "LEN_LT", - 8: "LEN_EQ", -} - -var OperatorType_value = map[string]int32{ - "OPERATOR_TYPE_UNKNOWN": 0, - "GT": 1, - "LT": 2, - "EQ": 3, - "MATCH": 4, - "NON_NIL": 5, - "LEN_GT": 6, - "LEN_LT": 7, - "LEN_EQ": 8, +func (x OperatorType) Enum() *OperatorType { + p := new(OperatorType) + *p = x + return p } func (x OperatorType) String() string { - return proto.EnumName(OperatorType_name, int32(x)) + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (OperatorType) Descriptor() protoreflect.EnumDescriptor { + return file_httpoptions_annotations_proto_enumTypes[4].Descriptor() +} + +func (OperatorType) Type() protoreflect.EnumType { + return &file_httpoptions_annotations_proto_enumTypes[4] +} + +func (x OperatorType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) } +// Deprecated: Use OperatorType.Descriptor instead. func (OperatorType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_1be5d6cda9fc6cfe, []int{4} + return file_httpoptions_annotations_proto_rawDescGZIP(), []int{4} } +// The supported function type list type FunctionType int32 const ( FunctionType_FUNCTION_TYPE_UNKNOWN FunctionType = 0 - FunctionType_TRIM FunctionType = 1 + FunctionType_TRIM FunctionType = 1 // String trim. ) -var FunctionType_name = map[int32]string{ - 0: "FUNCTION_TYPE_UNKNOWN", - 1: "TRIM", -} +// Enum value maps for FunctionType. +var ( + FunctionType_name = map[int32]string{ + 0: "FUNCTION_TYPE_UNKNOWN", + 1: "TRIM", + } + FunctionType_value = map[string]int32{ + "FUNCTION_TYPE_UNKNOWN": 0, + "TRIM": 1, + } +) -var FunctionType_value = map[string]int32{ - "FUNCTION_TYPE_UNKNOWN": 0, - "TRIM": 1, +func (x FunctionType) Enum() *FunctionType { + p := new(FunctionType) + *p = x + return p } func (x FunctionType) String() string { - return proto.EnumName(FunctionType_name, int32(x)) + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (FunctionType) Descriptor() protoreflect.EnumDescriptor { + return file_httpoptions_annotations_proto_enumTypes[5].Descriptor() +} + +func (FunctionType) Type() protoreflect.EnumType { + return &file_httpoptions_annotations_proto_enumTypes[5] } +func (x FunctionType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use FunctionType.Descriptor instead. func (FunctionType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_1be5d6cda9fc6cfe, []int{5} + return file_httpoptions_annotations_proto_rawDescGZIP(), []int{5} } +// ValueType is the type of the field. type ValueType int32 const ( ValueType_VALUE_TYPE_UNKNOWN ValueType = 0 - ValueType_NUMBER ValueType = 1 - ValueType_STRING ValueType = 2 + ValueType_NUMBER ValueType = 1 // Represent all number type like int,real + ValueType_STRING ValueType = 2 // String ValueType_OBJ ValueType = 3 ) -var ValueType_name = map[int32]string{ - 0: "VALUE_TYPE_UNKNOWN", - 1: "NUMBER", - 2: "STRING", - 3: "OBJ", -} +// Enum value maps for ValueType. +var ( + ValueType_name = map[int32]string{ + 0: "VALUE_TYPE_UNKNOWN", + 1: "NUMBER", + 2: "STRING", + 3: "OBJ", + } + ValueType_value = map[string]int32{ + "VALUE_TYPE_UNKNOWN": 0, + "NUMBER": 1, + "STRING": 2, + "OBJ": 3, + } +) -var ValueType_value = map[string]int32{ - "VALUE_TYPE_UNKNOWN": 0, - "NUMBER": 1, - "STRING": 2, - "OBJ": 3, +func (x ValueType) Enum() *ValueType { + p := new(ValueType) + *p = x + return p } func (x ValueType) String() string { - return proto.EnumName(ValueType_name, int32(x)) + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) } -func (ValueType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_1be5d6cda9fc6cfe, []int{6} +func (ValueType) Descriptor() protoreflect.EnumDescriptor { + return file_httpoptions_annotations_proto_enumTypes[6].Descriptor() } -type ApiMethod struct { - LoginNotRequired bool `protobuf:"varint,1,opt,name=login_not_required,json=loginNotRequired,proto3" json:"login_not_required,omitempty"` - ClientSignRequired bool `protobuf:"varint,2,opt,name=client_sign_required,json=clientSignRequired,proto3" json:"client_sign_required,omitempty"` - HashKey string `protobuf:"bytes,3,opt,name=hash_key,json=hashKey,proto3" json:"hash_key,omitempty"` - IsThirdParty bool `protobuf:"varint,4,opt,name=is_third_party,json=isThirdParty,proto3" json:"is_third_party,omitempty"` - Timeout string `protobuf:"bytes,5,opt,name=timeout,proto3" json:"timeout,omitempty"` - ApiSource ApiSourceType `protobuf:"varint,6,opt,name=api_source,json=apiSource,proto3,enum=ease.api.ApiSourceType" json:"api_source,omitempty"` - TokenType AuthTokenType `protobuf:"varint,7,opt,name=token_type,json=tokenType,proto3,enum=ease.api.AuthTokenType" json:"token_type,omitempty"` - SpecSourceType SpecSourceType `protobuf:"varint,8,opt,name=spec_source_type,json=specSourceType,proto3,enum=ease.api.SpecSourceType" json:"spec_source_type,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *ApiMethod) Reset() { *m = ApiMethod{} } -func (m *ApiMethod) String() string { return proto.CompactTextString(m) } -func (*ApiMethod) ProtoMessage() {} -func (*ApiMethod) Descriptor() ([]byte, []int) { - return fileDescriptor_1be5d6cda9fc6cfe, []int{0} +func (ValueType) Type() protoreflect.EnumType { + return &file_httpoptions_annotations_proto_enumTypes[6] } -func (m *ApiMethod) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ApiMethod.Unmarshal(m, b) +func (x ValueType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) } -func (m *ApiMethod) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ApiMethod.Marshal(b, m, deterministic) + +// Deprecated: Use ValueType.Descriptor instead. +func (ValueType) EnumDescriptor() ([]byte, []int) { + return file_httpoptions_annotations_proto_rawDescGZIP(), []int{6} } -func (m *ApiMethod) XXX_Merge(src proto.Message) { - xxx_messageInfo_ApiMethod.Merge(m, src) + +// The api method. +type ApiMethod struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + LoginNotRequired bool `protobuf:"varint,1,opt,name=login_not_required,json=loginNotRequired,proto3" json:"login_not_required,omitempty"` + ClientSignRequired bool `protobuf:"varint,2,opt,name=client_sign_required,json=clientSignRequired,proto3" json:"client_sign_required,omitempty"` + // Used only for CONSISTENT load balancer. + // Can take the following formats: + // - "field.field.field": hash key from a proto field. + // - "@uuid": generated UUID as hash key. + // - "@session": hash key from session (session sticky). + HashKey string `protobuf:"bytes,3,opt,name=hash_key,json=hashKey,proto3" json:"hash_key,omitempty"` + // If the client of this call come from third party. + // When this field is true, gateway will not check + // X-Source. + IsThirdParty bool `protobuf:"varint,4,opt,name=is_third_party,json=isThirdParty,proto3" json:"is_third_party,omitempty"` + // Used to call the GRPC service timeout. + // duration string, such as "300ms", "1m30s". + Timeout string `protobuf:"bytes,5,opt,name=timeout,proto3" json:"timeout,omitempty"` + // Api regist gateway. + ApiSource ApiSourceType `protobuf:"varint,6,opt,name=api_source,json=apiSource,proto3,enum=ease.api.ApiSourceType" json:"api_source,omitempty"` + // Auth token type. + TokenType AuthTokenType `protobuf:"varint,7,opt,name=token_type,json=tokenType,proto3,enum=ease.api.AuthTokenType" json:"token_type,omitempty"` + // Specified source Type. + SpecSourceType SpecSourceType `protobuf:"varint,8,opt,name=spec_source_type,json=specSourceType,proto3,enum=ease.api.SpecSourceType" json:"spec_source_type,omitempty"` +} + +func (x *ApiMethod) Reset() { + *x = ApiMethod{} + if protoimpl.UnsafeEnabled { + mi := &file_httpoptions_annotations_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *ApiMethod) XXX_Size() int { - return xxx_messageInfo_ApiMethod.Size(m) + +func (x *ApiMethod) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *ApiMethod) XXX_DiscardUnknown() { - xxx_messageInfo_ApiMethod.DiscardUnknown(m) + +func (*ApiMethod) ProtoMessage() {} + +func (x *ApiMethod) ProtoReflect() protoreflect.Message { + mi := &file_httpoptions_annotations_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_ApiMethod proto.InternalMessageInfo +// Deprecated: Use ApiMethod.ProtoReflect.Descriptor instead. +func (*ApiMethod) Descriptor() ([]byte, []int) { + return file_httpoptions_annotations_proto_rawDescGZIP(), []int{0} +} -func (m *ApiMethod) GetLoginNotRequired() bool { - if m != nil { - return m.LoginNotRequired +func (x *ApiMethod) GetLoginNotRequired() bool { + if x != nil { + return x.LoginNotRequired } return false } -func (m *ApiMethod) GetClientSignRequired() bool { - if m != nil { - return m.ClientSignRequired +func (x *ApiMethod) GetClientSignRequired() bool { + if x != nil { + return x.ClientSignRequired } return false } -func (m *ApiMethod) GetHashKey() string { - if m != nil { - return m.HashKey +func (x *ApiMethod) GetHashKey() string { + if x != nil { + return x.HashKey } return "" } -func (m *ApiMethod) GetIsThirdParty() bool { - if m != nil { - return m.IsThirdParty +func (x *ApiMethod) GetIsThirdParty() bool { + if x != nil { + return x.IsThirdParty } return false } -func (m *ApiMethod) GetTimeout() string { - if m != nil { - return m.Timeout +func (x *ApiMethod) GetTimeout() string { + if x != nil { + return x.Timeout } return "" } -func (m *ApiMethod) GetApiSource() ApiSourceType { - if m != nil { - return m.ApiSource +func (x *ApiMethod) GetApiSource() ApiSourceType { + if x != nil { + return x.ApiSource } return ApiSourceType_EASE_GATEWAY } -func (m *ApiMethod) GetTokenType() AuthTokenType { - if m != nil { - return m.TokenType +func (x *ApiMethod) GetTokenType() AuthTokenType { + if x != nil { + return x.TokenType } return AuthTokenType_EASE_AUTH_TOKEN } -func (m *ApiMethod) GetSpecSourceType() SpecSourceType { - if m != nil { - return m.SpecSourceType +func (x *ApiMethod) GetSpecSourceType() SpecSourceType { + if x != nil { + return x.SpecSourceType } return SpecSourceType_UNSPECIFIED } +// The service spec used for skylb/vexillary type ServiceSpec struct { - ServiceId data.ServiceId `protobuf:"varint,1,opt,name=service_id,json=serviceId,proto3,enum=data.ServiceId" json:"service_id,omitempty"` - PortName string `protobuf:"bytes,2,opt,name=port_name,json=portName,proto3" json:"port_name,omitempty"` - Namespace string `protobuf:"bytes,3,opt,name=namespace,proto3" json:"namespace,omitempty"` - GenController bool `protobuf:"varint,4,opt,name=gen_controller,json=genController,proto3" json:"gen_controller,omitempty"` - Balancer LoadBalancer `protobuf:"varint,5,opt,name=balancer,proto3,enum=ease.api.LoadBalancer" json:"balancer,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *ServiceSpec) Reset() { *m = ServiceSpec{} } -func (m *ServiceSpec) String() string { return proto.CompactTextString(m) } -func (*ServiceSpec) ProtoMessage() {} -func (*ServiceSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_1be5d6cda9fc6cfe, []int{1} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The identity of the service. + ServiceId data.ServiceId `protobuf:"varint,1,opt,name=service_id,json=serviceId,proto3,enum=data.ServiceId" json:"service_id,omitempty"` + // For skylb integration. + PortName string `protobuf:"bytes,2,opt,name=port_name,json=portName,proto3" json:"port_name,omitempty"` + Namespace string `protobuf:"bytes,3,opt,name=namespace,proto3" json:"namespace,omitempty"` + GenController bool `protobuf:"varint,4,opt,name=gen_controller,json=genController,proto3" json:"gen_controller,omitempty"` + Balancer LoadBalancer `protobuf:"varint,5,opt,name=balancer,proto3,enum=ease.api.LoadBalancer" json:"balancer,omitempty"` +} + +func (x *ServiceSpec) Reset() { + *x = ServiceSpec{} + if protoimpl.UnsafeEnabled { + mi := &file_httpoptions_annotations_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *ServiceSpec) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ServiceSpec.Unmarshal(m, b) -} -func (m *ServiceSpec) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ServiceSpec.Marshal(b, m, deterministic) -} -func (m *ServiceSpec) XXX_Merge(src proto.Message) { - xxx_messageInfo_ServiceSpec.Merge(m, src) +func (x *ServiceSpec) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *ServiceSpec) XXX_Size() int { - return xxx_messageInfo_ServiceSpec.Size(m) -} -func (m *ServiceSpec) XXX_DiscardUnknown() { - xxx_messageInfo_ServiceSpec.DiscardUnknown(m) + +func (*ServiceSpec) ProtoMessage() {} + +func (x *ServiceSpec) ProtoReflect() protoreflect.Message { + mi := &file_httpoptions_annotations_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_ServiceSpec proto.InternalMessageInfo +// Deprecated: Use ServiceSpec.ProtoReflect.Descriptor instead. +func (*ServiceSpec) Descriptor() ([]byte, []int) { + return file_httpoptions_annotations_proto_rawDescGZIP(), []int{1} +} -func (m *ServiceSpec) GetServiceId() data.ServiceId { - if m != nil { - return m.ServiceId +func (x *ServiceSpec) GetServiceId() data.ServiceId { + if x != nil { + return x.ServiceId } return data.ServiceId_SERVICE_NONE } -func (m *ServiceSpec) GetPortName() string { - if m != nil { - return m.PortName +func (x *ServiceSpec) GetPortName() string { + if x != nil { + return x.PortName } return "" } -func (m *ServiceSpec) GetNamespace() string { - if m != nil { - return m.Namespace +func (x *ServiceSpec) GetNamespace() string { + if x != nil { + return x.Namespace } return "" } -func (m *ServiceSpec) GetGenController() bool { - if m != nil { - return m.GenController +func (x *ServiceSpec) GetGenController() bool { + if x != nil { + return x.GenController } return false } -func (m *ServiceSpec) GetBalancer() LoadBalancer { - if m != nil { - return m.Balancer +func (x *ServiceSpec) GetBalancer() LoadBalancer { + if x != nil { + return x.Balancer } return LoadBalancer_ROUND_ROBIN } +// ValidationRule defines the rule to validate the input value. type ValidationRule struct { - Operator OperatorType `protobuf:"varint,1,opt,name=operator,proto3,enum=ease.api.OperatorType" json:"operator,omitempty"` - Type ValueType `protobuf:"varint,2,opt,name=type,proto3,enum=ease.api.ValueType" json:"type,omitempty"` - Value string `protobuf:"bytes,3,opt,name=value,proto3" json:"value,omitempty"` - Function FunctionType `protobuf:"varint,4,opt,name=function,proto3,enum=ease.api.FunctionType" json:"function,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *ValidationRule) Reset() { *m = ValidationRule{} } -func (m *ValidationRule) String() string { return proto.CompactTextString(m) } -func (*ValidationRule) ProtoMessage() {} -func (*ValidationRule) Descriptor() ([]byte, []int) { - return fileDescriptor_1be5d6cda9fc6cfe, []int{2} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Operator OperatorType `protobuf:"varint,1,opt,name=operator,proto3,enum=ease.api.OperatorType" json:"operator,omitempty"` + Type ValueType `protobuf:"varint,2,opt,name=type,proto3,enum=ease.api.ValueType" json:"type,omitempty"` + Value string `protobuf:"bytes,3,opt,name=value,proto3" json:"value,omitempty"` + Function FunctionType `protobuf:"varint,4,opt,name=function,proto3,enum=ease.api.FunctionType" json:"function,omitempty"` +} + +func (x *ValidationRule) Reset() { + *x = ValidationRule{} + if protoimpl.UnsafeEnabled { + mi := &file_httpoptions_annotations_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *ValidationRule) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ValidationRule.Unmarshal(m, b) -} -func (m *ValidationRule) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ValidationRule.Marshal(b, m, deterministic) -} -func (m *ValidationRule) XXX_Merge(src proto.Message) { - xxx_messageInfo_ValidationRule.Merge(m, src) -} -func (m *ValidationRule) XXX_Size() int { - return xxx_messageInfo_ValidationRule.Size(m) +func (x *ValidationRule) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *ValidationRule) XXX_DiscardUnknown() { - xxx_messageInfo_ValidationRule.DiscardUnknown(m) + +func (*ValidationRule) ProtoMessage() {} + +func (x *ValidationRule) ProtoReflect() protoreflect.Message { + mi := &file_httpoptions_annotations_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_ValidationRule proto.InternalMessageInfo +// Deprecated: Use ValidationRule.ProtoReflect.Descriptor instead. +func (*ValidationRule) Descriptor() ([]byte, []int) { + return file_httpoptions_annotations_proto_rawDescGZIP(), []int{2} +} -func (m *ValidationRule) GetOperator() OperatorType { - if m != nil { - return m.Operator +func (x *ValidationRule) GetOperator() OperatorType { + if x != nil { + return x.Operator } return OperatorType_OPERATOR_TYPE_UNKNOWN } -func (m *ValidationRule) GetType() ValueType { - if m != nil { - return m.Type +func (x *ValidationRule) GetType() ValueType { + if x != nil { + return x.Type } return ValueType_VALUE_TYPE_UNKNOWN } -func (m *ValidationRule) GetValue() string { - if m != nil { - return m.Value +func (x *ValidationRule) GetValue() string { + if x != nil { + return x.Value } return "" } -func (m *ValidationRule) GetFunction() FunctionType { - if m != nil { - return m.Function +func (x *ValidationRule) GetFunction() FunctionType { + if x != nil { + return x.Function } return FunctionType_FUNCTION_TYPE_UNKNOWN } +// ValidationRules holds a list of validation rules. type ValidationRules struct { - Rules []*ValidationRule `protobuf:"bytes,1,rep,name=rules,proto3" json:"rules,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -func (m *ValidationRules) Reset() { *m = ValidationRules{} } -func (m *ValidationRules) String() string { return proto.CompactTextString(m) } -func (*ValidationRules) ProtoMessage() {} -func (*ValidationRules) Descriptor() ([]byte, []int) { - return fileDescriptor_1be5d6cda9fc6cfe, []int{3} + Rules []*ValidationRule `protobuf:"bytes,1,rep,name=rules,proto3" json:"rules,omitempty"` } -func (m *ValidationRules) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ValidationRules.Unmarshal(m, b) -} -func (m *ValidationRules) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ValidationRules.Marshal(b, m, deterministic) -} -func (m *ValidationRules) XXX_Merge(src proto.Message) { - xxx_messageInfo_ValidationRules.Merge(m, src) +func (x *ValidationRules) Reset() { + *x = ValidationRules{} + if protoimpl.UnsafeEnabled { + mi := &file_httpoptions_annotations_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *ValidationRules) XXX_Size() int { - return xxx_messageInfo_ValidationRules.Size(m) + +func (x *ValidationRules) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *ValidationRules) XXX_DiscardUnknown() { - xxx_messageInfo_ValidationRules.DiscardUnknown(m) + +func (*ValidationRules) ProtoMessage() {} + +func (x *ValidationRules) ProtoReflect() protoreflect.Message { + mi := &file_httpoptions_annotations_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_ValidationRules proto.InternalMessageInfo +// Deprecated: Use ValidationRules.ProtoReflect.Descriptor instead. +func (*ValidationRules) Descriptor() ([]byte, []int) { + return file_httpoptions_annotations_proto_rawDescGZIP(), []int{3} +} -func (m *ValidationRules) GetRules() []*ValidationRule { - if m != nil { - return m.Rules +func (x *ValidationRules) GetRules() []*ValidationRule { + if x != nil { + return x.Rules } return nil } -var E_Http = &proto.ExtensionDesc{ - ExtendedType: (*descriptor.MethodOptions)(nil), - ExtensionType: (*HttpRule)(nil), - Field: 108345, - Name: "ease.api.http", - Tag: "bytes,108345,opt,name=http", - Filename: "httpoptions/annotations.proto", -} - -var E_Method = &proto.ExtensionDesc{ - ExtendedType: (*descriptor.MethodOptions)(nil), - ExtensionType: (*ApiMethod)(nil), - Field: 108361, - Name: "ease.api.method", - Tag: "bytes,108361,opt,name=method", - Filename: "httpoptions/annotations.proto", -} - -var E_ServiceSpec = &proto.ExtensionDesc{ - ExtendedType: (*descriptor.ServiceOptions)(nil), - ExtensionType: (*ServiceSpec)(nil), - Field: 108349, - Name: "ease.api.service_spec", - Tag: "bytes,108349,opt,name=service_spec", - Filename: "httpoptions/annotations.proto", -} - -var E_Rules = &proto.ExtensionDesc{ - ExtendedType: (*descriptor.FieldOptions)(nil), - ExtensionType: (*ValidationRules)(nil), - Field: 108102, - Name: "ease.api.rules", - Tag: "bytes,108102,opt,name=rules", - Filename: "httpoptions/annotations.proto", -} - -func init() { - proto.RegisterEnum("ease.api.ApiSourceType", ApiSourceType_name, ApiSourceType_value) - proto.RegisterEnum("ease.api.AuthTokenType", AuthTokenType_name, AuthTokenType_value) - proto.RegisterEnum("ease.api.SpecSourceType", SpecSourceType_name, SpecSourceType_value) - proto.RegisterEnum("ease.api.LoadBalancer", LoadBalancer_name, LoadBalancer_value) - proto.RegisterEnum("ease.api.OperatorType", OperatorType_name, OperatorType_value) - proto.RegisterEnum("ease.api.FunctionType", FunctionType_name, FunctionType_value) - proto.RegisterEnum("ease.api.ValueType", ValueType_name, ValueType_value) - proto.RegisterType((*ApiMethod)(nil), "ease.api.ApiMethod") - proto.RegisterType((*ServiceSpec)(nil), "ease.api.ServiceSpec") - proto.RegisterType((*ValidationRule)(nil), "ease.api.ValidationRule") - proto.RegisterType((*ValidationRules)(nil), "ease.api.ValidationRules") - proto.RegisterExtension(E_Http) - proto.RegisterExtension(E_Method) - proto.RegisterExtension(E_ServiceSpec) - proto.RegisterExtension(E_Rules) -} - -func init() { proto.RegisterFile("httpoptions/annotations.proto", fileDescriptor_1be5d6cda9fc6cfe) } - -var fileDescriptor_1be5d6cda9fc6cfe = []byte{ - // 966 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x55, 0x4d, 0x6f, 0xe3, 0x54, - 0x17, 0xae, 0xd3, 0x34, 0x1f, 0x27, 0x69, 0x7a, 0xdf, 0xdb, 0x69, 0x5f, 0x77, 0x60, 0x20, 0xaa, - 0x40, 0x94, 0x08, 0x39, 0x28, 0x95, 0x58, 0x94, 0x95, 0x93, 0xba, 0xad, 0x69, 0x62, 0x67, 0x6c, - 0xa7, 0xd5, 0x88, 0x85, 0xe5, 0x3a, 0x77, 0x12, 0x6b, 0x1c, 0x5f, 0x63, 0xdf, 0x8c, 0x94, 0x05, - 0x7f, 0x86, 0x3f, 0x81, 0x58, 0xb0, 0x45, 0x42, 0x42, 0x6c, 0xf8, 0x37, 0xac, 0xd0, 0xbd, 0xb6, - 0xf3, 0x31, 0x15, 0x62, 0x13, 0x9f, 0xf3, 0x9c, 0xe7, 0x3c, 0xc7, 0xf7, 0xdc, 0xe3, 0x13, 0x78, - 0x35, 0x67, 0x2c, 0xa6, 0x31, 0x0b, 0x68, 0x94, 0x76, 0xbd, 0x28, 0xa2, 0xcc, 0x13, 0xb6, 0x12, - 0x27, 0x94, 0x51, 0x5c, 0x23, 0x5e, 0x4a, 0x14, 0x2f, 0x0e, 0x5e, 0xb6, 0x67, 0x94, 0xce, 0x42, - 0xd2, 0x15, 0xf8, 0xd3, 0xf2, 0x6d, 0x77, 0x4a, 0x52, 0x3f, 0x09, 0x62, 0x46, 0x93, 0x8c, 0xfb, - 0xf2, 0x74, 0x5b, 0x8a, 0xdb, 0x39, 0x7e, 0x34, 0xf5, 0x98, 0xd7, 0xe5, 0x3f, 0x19, 0x70, 0xfe, - 0x77, 0x09, 0xea, 0x6a, 0x1c, 0x8c, 0x08, 0x9b, 0xd3, 0x29, 0xfe, 0x0a, 0x70, 0x48, 0x67, 0x41, - 0xe4, 0x46, 0x94, 0xb9, 0x09, 0xf9, 0x61, 0x19, 0x24, 0x64, 0x2a, 0x4b, 0x6d, 0xe9, 0xa2, 0x66, - 0x21, 0x11, 0x31, 0x28, 0xb3, 0x72, 0x1c, 0x7f, 0x0d, 0x2f, 0xfc, 0x30, 0x20, 0x11, 0x73, 0xd3, - 0x60, 0x16, 0x6d, 0xf8, 0x25, 0xc1, 0xc7, 0x59, 0xcc, 0x0e, 0x66, 0xd1, 0x3a, 0xe3, 0x0c, 0x6a, - 0x73, 0x2f, 0x9d, 0xbb, 0xef, 0xc8, 0x4a, 0xde, 0x6f, 0x4b, 0x17, 0x75, 0xab, 0xca, 0xfd, 0x7b, - 0xb2, 0xc2, 0x9f, 0x41, 0x2b, 0x48, 0x5d, 0x36, 0x0f, 0x92, 0xa9, 0x1b, 0x7b, 0x09, 0x5b, 0xc9, - 0x65, 0x21, 0xd3, 0x0c, 0x52, 0x87, 0x83, 0x63, 0x8e, 0x61, 0x19, 0xaa, 0x2c, 0x58, 0x10, 0xba, - 0x64, 0xf2, 0x41, 0x96, 0x9f, 0xbb, 0xf8, 0x1b, 0x00, 0x2f, 0x0e, 0xdc, 0x94, 0x2e, 0x13, 0x9f, - 0xc8, 0x95, 0xb6, 0x74, 0xd1, 0xea, 0xfd, 0x5f, 0x29, 0x5a, 0xa6, 0xa8, 0x71, 0x60, 0x8b, 0x90, - 0xb3, 0x8a, 0x89, 0x55, 0xf7, 0x0a, 0x97, 0xe7, 0x31, 0xfa, 0x8e, 0x44, 0x2e, 0x5b, 0xc5, 0x44, - 0xae, 0x3e, 0xcb, 0x5b, 0xb2, 0xb9, 0xc3, 0xe3, 0x59, 0x1e, 0x2b, 0x4c, 0xdc, 0x07, 0x94, 0xc6, - 0xc4, 0xcf, 0x0b, 0x66, 0xd9, 0x35, 0x91, 0x2d, 0x6f, 0xb2, 0xed, 0x98, 0xf8, 0x5b, 0x65, 0x5b, - 0xe9, 0x8e, 0x7f, 0xfe, 0x97, 0x04, 0x0d, 0x9b, 0x24, 0xef, 0x03, 0x9f, 0x70, 0x26, 0x56, 0x00, - 0xd2, 0xcc, 0x75, 0x83, 0xac, 0xed, 0xad, 0xde, 0x91, 0x22, 0x6e, 0x2b, 0xa7, 0xe9, 0x53, 0xab, - 0x9e, 0x16, 0x26, 0xfe, 0x08, 0xea, 0x31, 0x4d, 0x98, 0x1b, 0x79, 0x0b, 0x22, 0xba, 0x5e, 0xb7, - 0x6a, 0x1c, 0x30, 0xbc, 0x05, 0xc1, 0x1f, 0x43, 0x9d, 0xe3, 0x69, 0xec, 0xf9, 0x24, 0x6f, 0xf6, - 0x06, 0xc0, 0x9f, 0x43, 0x6b, 0x46, 0x22, 0xd7, 0xa7, 0x11, 0x4b, 0x68, 0x18, 0x92, 0x24, 0x6f, - 0xf7, 0xe1, 0x8c, 0x44, 0x83, 0x35, 0x88, 0x7b, 0x50, 0x7b, 0xf2, 0x42, 0x2f, 0xf2, 0x49, 0x22, - 0x1a, 0xde, 0xea, 0x9d, 0x6e, 0x4e, 0x37, 0xa4, 0xde, 0xb4, 0x9f, 0x47, 0xad, 0x35, 0xef, 0xfc, - 0x67, 0x09, 0x5a, 0x0f, 0x5e, 0x18, 0x4c, 0xc5, 0xf4, 0x5a, 0xcb, 0x90, 0x70, 0x19, 0x1a, 0x93, - 0xc4, 0x63, 0x34, 0xc9, 0x8f, 0xb5, 0x25, 0x63, 0xe6, 0x11, 0xd1, 0xa2, 0x35, 0x0f, 0x7f, 0x01, - 0x65, 0xd1, 0xd4, 0x92, 0xe0, 0x1f, 0x6f, 0xf8, 0x0f, 0x5e, 0xb8, 0xcc, 0xfa, 0x29, 0x08, 0xf8, - 0x05, 0x1c, 0xbc, 0xe7, 0x50, 0x7e, 0xc8, 0xcc, 0xe1, 0x25, 0xdf, 0x2e, 0x23, 0x9f, 0xbf, 0x82, - 0x38, 0xda, 0x4e, 0xc9, 0x9b, 0x3c, 0x92, 0x95, 0x2c, 0x78, 0xe7, 0x2a, 0x1c, 0xed, 0xbe, 0x78, - 0x8a, 0x15, 0x38, 0x48, 0xb8, 0x21, 0x4b, 0xed, 0xfd, 0x8b, 0xc6, 0xf6, 0xdd, 0xee, 0x32, 0xad, - 0x8c, 0xd6, 0xb9, 0x84, 0xc3, 0x9d, 0x51, 0xc3, 0x08, 0x9a, 0x9a, 0x6a, 0x6b, 0xee, 0xad, 0xea, - 0x68, 0x8f, 0xea, 0x1b, 0xb4, 0xc7, 0x11, 0x73, 0xac, 0x19, 0x6b, 0x44, 0xea, 0x7c, 0x0b, 0x87, - 0x3b, 0x73, 0x86, 0x8f, 0xe1, 0x48, 0x24, 0xa9, 0x13, 0xe7, 0xce, 0x75, 0xcc, 0x7b, 0xcd, 0x40, - 0x7b, 0xf8, 0x04, 0xfe, 0xd7, 0x17, 0xe0, 0x60, 0xa0, 0xd9, 0x76, 0x0e, 0x4b, 0x9d, 0x0e, 0xb4, - 0x76, 0xc7, 0x0c, 0x1f, 0x41, 0x63, 0x62, 0xd8, 0x63, 0x6d, 0xa0, 0xdf, 0xe8, 0xda, 0x35, 0xda, - 0xc3, 0x55, 0xd8, 0x7f, 0xd4, 0xfa, 0x48, 0xea, 0x74, 0xa1, 0xb9, 0x7d, 0x69, 0x9c, 0x69, 0x99, - 0x13, 0xe3, 0xda, 0xb5, 0xcc, 0xbe, 0xce, 0x6b, 0xb4, 0x00, 0x06, 0xa6, 0x61, 0xeb, 0xb6, 0xa3, - 0x19, 0x0e, 0x92, 0x3a, 0x3f, 0x42, 0x73, 0xfb, 0x7a, 0xf0, 0x19, 0x9c, 0x98, 0x63, 0xcd, 0x52, - 0x1d, 0xd3, 0x72, 0x9d, 0x37, 0x63, 0xcd, 0x9d, 0x18, 0xf7, 0x86, 0xf9, 0xc8, 0x53, 0x2b, 0x50, - 0xba, 0x75, 0x90, 0xc4, 0x9f, 0x43, 0x07, 0x95, 0xf8, 0x53, 0x7b, 0x8d, 0xf6, 0x71, 0x1d, 0x0e, - 0x46, 0xaa, 0x33, 0xb8, 0x43, 0x65, 0xdc, 0x80, 0xaa, 0x61, 0x1a, 0xae, 0xa1, 0x0f, 0xd1, 0x01, - 0x06, 0xa8, 0x0c, 0x79, 0x17, 0x1c, 0x54, 0x29, 0xec, 0xa1, 0x83, 0xaa, 0x85, 0xad, 0xbd, 0x46, - 0xb5, 0xce, 0x25, 0x34, 0xb7, 0xaf, 0x8a, 0x97, 0xbf, 0x99, 0x18, 0x03, 0x47, 0x37, 0x8d, 0x0f, - 0xcb, 0xd7, 0xa0, 0xec, 0x58, 0xfa, 0x08, 0x49, 0x9d, 0x6b, 0xa8, 0xaf, 0x47, 0x04, 0x9f, 0x02, - 0x7e, 0x50, 0x87, 0x13, 0xed, 0x43, 0x3a, 0x40, 0xc5, 0x98, 0x8c, 0xfa, 0x9a, 0x85, 0x24, 0x6e, - 0xdb, 0x8e, 0xa5, 0x1b, 0xb7, 0xa8, 0xc4, 0x5b, 0x65, 0xf6, 0xbf, 0x43, 0xfb, 0x57, 0x77, 0x50, - 0xe6, 0x7b, 0x13, 0x7f, 0xa2, 0x64, 0xcb, 0x56, 0x29, 0x96, 0xad, 0x92, 0xed, 0x4a, 0x33, 0x5b, - 0xae, 0xf2, 0x2f, 0x7f, 0xf2, 0x5d, 0xd3, 0xe8, 0xe1, 0xcd, 0x64, 0xdc, 0x31, 0x16, 0x8b, 0x99, - 0x10, 0x0a, 0x57, 0x23, 0xa8, 0x2c, 0xb2, 0xf5, 0xfa, 0x5f, 0x5a, 0xbf, 0xe7, 0x5a, 0xc7, 0x3b, - 0x7b, 0x2b, 0xe3, 0x58, 0xb9, 0xc8, 0xd5, 0xf7, 0xd0, 0x2c, 0x96, 0x04, 0x5f, 0x27, 0xf8, 0xd3, - 0x67, 0xa2, 0xf9, 0xae, 0x28, 0x54, 0x7f, 0xcd, 0x55, 0x4f, 0xb6, 0xf6, 0xd2, 0x66, 0xe9, 0x58, - 0x8d, 0x74, 0xe3, 0x5c, 0x8d, 0xf3, 0x71, 0xc7, 0xaf, 0x9e, 0xa9, 0xde, 0x04, 0x24, 0x5c, 0xbf, - 0xe9, 0x6f, 0x7f, 0x64, 0x9a, 0x67, 0xff, 0xf6, 0x3d, 0xa4, 0xf9, 0x07, 0xd1, 0xff, 0x12, 0x9a, - 0x3e, 0x5d, 0xac, 0x69, 0x7d, 0xa4, 0x6e, 0xfe, 0xd8, 0xc6, 0x5c, 0x7b, 0x2c, 0xfd, 0x54, 0x2a, - 0x6b, 0xea, 0x58, 0x7f, 0xaa, 0x88, 0x5a, 0x97, 0xff, 0x04, 0x00, 0x00, 0xff, 0xff, 0x31, 0x32, - 0xc5, 0x86, 0x08, 0x07, 0x00, 0x00, +var file_httpoptions_annotations_proto_extTypes = []protoimpl.ExtensionInfo{ + { + ExtendedType: (*descriptor.MethodOptions)(nil), + ExtensionType: (*HttpRule)(nil), + Field: 108345, + Name: "ease.api.http", + Tag: "bytes,108345,opt,name=http", + Filename: "httpoptions/annotations.proto", + }, + { + ExtendedType: (*descriptor.MethodOptions)(nil), + ExtensionType: (*ApiMethod)(nil), + Field: 108361, + Name: "ease.api.method", + Tag: "bytes,108361,opt,name=method", + Filename: "httpoptions/annotations.proto", + }, + { + ExtendedType: (*descriptor.ServiceOptions)(nil), + ExtensionType: (*ServiceSpec)(nil), + Field: 108349, + Name: "ease.api.service_spec", + Tag: "bytes,108349,opt,name=service_spec", + Filename: "httpoptions/annotations.proto", + }, + { + ExtendedType: (*descriptor.FieldOptions)(nil), + ExtensionType: (*ValidationRules)(nil), + Field: 108102, + Name: "ease.api.rules", + Tag: "bytes,108102,opt,name=rules", + Filename: "httpoptions/annotations.proto", + }, +} + +// Extension fields to descriptor.MethodOptions. +var ( + // See `HttpRule`. + // + // optional ease.api.HttpRule http = 108345; + E_Http = &file_httpoptions_annotations_proto_extTypes[0] + // optional ease.api.ApiMethod method = 108361; + E_Method = &file_httpoptions_annotations_proto_extTypes[1] +) + +// Extension fields to descriptor.ServiceOptions. +var ( + // optional ease.api.ServiceSpec service_spec = 108349; + E_ServiceSpec = &file_httpoptions_annotations_proto_extTypes[2] +) + +// Extension fields to descriptor.FieldOptions. +var ( + // The validation rules, if there are more than + // one rules, validtion will pass only if all + // the rules are complied (AND). + // + // optional ease.api.ValidationRules rules = 108102; + E_Rules = &file_httpoptions_annotations_proto_extTypes[3] +) + +var File_httpoptions_annotations_proto protoreflect.FileDescriptor + +var file_httpoptions_annotations_proto_rawDesc = []byte{ + 0x0a, 0x1d, 0x68, 0x74, 0x74, 0x70, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x61, 0x6e, + 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, + 0x08, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x1a, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x65, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x16, 0x68, 0x74, 0x74, + 0x70, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x68, 0x74, 0x74, 0x70, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x1a, 0x0f, 0x64, 0x61, 0x74, 0x61, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x14, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x2f, 0x65, + 0x72, 0x72, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xfa, 0x02, 0x0a, 0x09, 0x41, + 0x70, 0x69, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x2c, 0x0a, 0x12, 0x6c, 0x6f, 0x67, 0x69, + 0x6e, 0x5f, 0x6e, 0x6f, 0x74, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x4e, 0x6f, 0x74, 0x52, 0x65, + 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0x30, 0x0a, 0x14, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x69, 0x67, 0x6e, + 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x68, 0x61, 0x73, 0x68, + 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x68, 0x61, 0x73, 0x68, + 0x4b, 0x65, 0x79, 0x12, 0x24, 0x0a, 0x0e, 0x69, 0x73, 0x5f, 0x74, 0x68, 0x69, 0x72, 0x64, 0x5f, + 0x70, 0x61, 0x72, 0x74, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x69, 0x73, 0x54, + 0x68, 0x69, 0x72, 0x64, 0x50, 0x61, 0x72, 0x74, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x69, 0x6d, + 0x65, 0x6f, 0x75, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, + 0x6f, 0x75, 0x74, 0x12, 0x36, 0x0a, 0x0a, 0x61, 0x70, 0x69, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x61, + 0x70, 0x69, 0x2e, 0x41, 0x70, 0x69, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, + 0x52, 0x09, 0x61, 0x70, 0x69, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x36, 0x0a, 0x0a, 0x74, + 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, + 0x17, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x54, + 0x6f, 0x6b, 0x65, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x09, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x54, + 0x79, 0x70, 0x65, 0x12, 0x42, 0x0a, 0x10, 0x73, 0x70, 0x65, 0x63, 0x5f, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x18, 0x2e, + 0x65, 0x61, 0x73, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x70, 0x65, 0x63, 0x53, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0e, 0x73, 0x70, 0x65, 0x63, 0x53, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x22, 0xd3, 0x01, 0x0a, 0x0b, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x12, 0x2e, 0x0a, 0x0a, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x64, 0x61, + 0x74, 0x61, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x52, 0x09, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x5f, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6f, 0x72, 0x74, + 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, + 0x63, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x67, 0x65, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, + 0x6c, 0x6c, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x67, 0x65, 0x6e, 0x43, + 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x12, 0x32, 0x0a, 0x08, 0x62, 0x61, 0x6c, + 0x61, 0x6e, 0x63, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x16, 0x2e, 0x65, 0x61, + 0x73, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x6f, 0x61, 0x64, 0x42, 0x61, 0x6c, 0x61, 0x6e, + 0x63, 0x65, 0x72, 0x52, 0x08, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x22, 0xb7, 0x01, + 0x0a, 0x0e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x75, 0x6c, 0x65, + 0x12, 0x32, 0x0a, 0x08, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x16, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4f, 0x70, + 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x54, 0x79, 0x70, 0x65, 0x52, 0x08, 0x6f, 0x70, 0x65, 0x72, + 0x61, 0x74, 0x6f, 0x72, 0x12, 0x27, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x13, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x56, 0x61, + 0x6c, 0x75, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x12, 0x32, 0x0a, 0x08, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x16, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x61, 0x70, 0x69, + 0x2e, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x08, 0x66, + 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x41, 0x0a, 0x0f, 0x56, 0x61, 0x6c, 0x69, 0x64, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x2e, 0x0a, 0x05, 0x72, 0x75, + 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x65, 0x61, 0x73, 0x65, + 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x75, 0x6c, 0x65, 0x52, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x2a, 0x33, 0x0a, 0x0d, 0x41, 0x70, + 0x69, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x45, + 0x41, 0x53, 0x45, 0x5f, 0x47, 0x41, 0x54, 0x45, 0x57, 0x41, 0x59, 0x10, 0x00, 0x12, 0x10, 0x0a, + 0x0c, 0x4f, 0x50, 0x45, 0x4e, 0x5f, 0x47, 0x41, 0x54, 0x45, 0x57, 0x41, 0x59, 0x10, 0x01, 0x2a, + 0x3b, 0x0a, 0x0d, 0x41, 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x54, 0x79, 0x70, 0x65, + 0x12, 0x13, 0x0a, 0x0f, 0x45, 0x41, 0x53, 0x45, 0x5f, 0x41, 0x55, 0x54, 0x48, 0x5f, 0x54, 0x4f, + 0x4b, 0x45, 0x4e, 0x10, 0x00, 0x12, 0x15, 0x0a, 0x11, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x41, 0x43, + 0x43, 0x45, 0x53, 0x53, 0x5f, 0x54, 0x4f, 0x4b, 0x45, 0x4e, 0x10, 0x01, 0x2a, 0x2a, 0x0a, 0x0e, + 0x53, 0x70, 0x65, 0x63, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0f, + 0x0a, 0x0b, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, + 0x07, 0x0a, 0x03, 0x57, 0x45, 0x42, 0x10, 0x01, 0x2a, 0x2f, 0x0a, 0x0c, 0x4c, 0x6f, 0x61, 0x64, + 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x12, 0x0f, 0x0a, 0x0b, 0x52, 0x4f, 0x55, 0x4e, + 0x44, 0x5f, 0x52, 0x4f, 0x42, 0x49, 0x4e, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x43, 0x4f, 0x4e, + 0x53, 0x49, 0x53, 0x54, 0x45, 0x4e, 0x54, 0x10, 0x01, 0x2a, 0x7d, 0x0a, 0x0c, 0x4f, 0x70, 0x65, + 0x72, 0x61, 0x74, 0x6f, 0x72, 0x54, 0x79, 0x70, 0x65, 0x12, 0x19, 0x0a, 0x15, 0x4f, 0x50, 0x45, + 0x52, 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, + 0x57, 0x4e, 0x10, 0x00, 0x12, 0x06, 0x0a, 0x02, 0x47, 0x54, 0x10, 0x01, 0x12, 0x06, 0x0a, 0x02, + 0x4c, 0x54, 0x10, 0x02, 0x12, 0x06, 0x0a, 0x02, 0x45, 0x51, 0x10, 0x03, 0x12, 0x09, 0x0a, 0x05, + 0x4d, 0x41, 0x54, 0x43, 0x48, 0x10, 0x04, 0x12, 0x0b, 0x0a, 0x07, 0x4e, 0x4f, 0x4e, 0x5f, 0x4e, + 0x49, 0x4c, 0x10, 0x05, 0x12, 0x0a, 0x0a, 0x06, 0x4c, 0x45, 0x4e, 0x5f, 0x47, 0x54, 0x10, 0x06, + 0x12, 0x0a, 0x0a, 0x06, 0x4c, 0x45, 0x4e, 0x5f, 0x4c, 0x54, 0x10, 0x07, 0x12, 0x0a, 0x0a, 0x06, + 0x4c, 0x45, 0x4e, 0x5f, 0x45, 0x51, 0x10, 0x08, 0x2a, 0x33, 0x0a, 0x0c, 0x46, 0x75, 0x6e, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x19, 0x0a, 0x15, 0x46, 0x55, 0x4e, 0x43, + 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, + 0x4e, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x54, 0x52, 0x49, 0x4d, 0x10, 0x01, 0x2a, 0x44, 0x0a, + 0x09, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x12, 0x56, 0x41, + 0x4c, 0x55, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, + 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x4e, 0x55, 0x4d, 0x42, 0x45, 0x52, 0x10, 0x01, 0x12, 0x0a, + 0x0a, 0x06, 0x53, 0x54, 0x52, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x12, 0x07, 0x0a, 0x03, 0x4f, 0x42, + 0x4a, 0x10, 0x03, 0x3a, 0x48, 0x0a, 0x04, 0x68, 0x74, 0x74, 0x70, 0x12, 0x1e, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4d, 0x65, + 0x74, 0x68, 0x6f, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xb9, 0xce, 0x06, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x48, + 0x74, 0x74, 0x70, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x04, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x4d, 0x0a, + 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x1e, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, + 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xc9, 0xce, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x13, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x41, 0x70, 0x69, 0x4d, 0x65, + 0x74, 0x68, 0x6f, 0x64, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x3a, 0x5b, 0x0a, 0x0c, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x12, 0x1f, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xbd, 0xce, + 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x61, 0x70, 0x69, + 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x52, 0x0b, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x3a, 0x50, 0x0a, 0x05, 0x72, 0x75, 0x6c, + 0x65, 0x73, 0x12, 0x1d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x18, 0xc6, 0xcc, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x65, 0x61, 0x73, 0x65, + 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x75, 0x6c, 0x65, 0x73, 0x52, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x42, 0x29, 0x0a, 0x0c, 0x63, + 0x6f, 0x6d, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x42, 0x10, 0x41, 0x6e, 0x6e, + 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0xa2, + 0x02, 0x04, 0x45, 0x41, 0x50, 0x49, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_httpoptions_annotations_proto_rawDescOnce sync.Once + file_httpoptions_annotations_proto_rawDescData = file_httpoptions_annotations_proto_rawDesc +) + +func file_httpoptions_annotations_proto_rawDescGZIP() []byte { + file_httpoptions_annotations_proto_rawDescOnce.Do(func() { + file_httpoptions_annotations_proto_rawDescData = protoimpl.X.CompressGZIP(file_httpoptions_annotations_proto_rawDescData) + }) + return file_httpoptions_annotations_proto_rawDescData +} + +var file_httpoptions_annotations_proto_enumTypes = make([]protoimpl.EnumInfo, 7) +var file_httpoptions_annotations_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_httpoptions_annotations_proto_goTypes = []interface{}{ + (ApiSourceType)(0), // 0: ease.api.ApiSourceType + (AuthTokenType)(0), // 1: ease.api.AuthTokenType + (SpecSourceType)(0), // 2: ease.api.SpecSourceType + (LoadBalancer)(0), // 3: ease.api.LoadBalancer + (OperatorType)(0), // 4: ease.api.OperatorType + (FunctionType)(0), // 5: ease.api.FunctionType + (ValueType)(0), // 6: ease.api.ValueType + (*ApiMethod)(nil), // 7: ease.api.ApiMethod + (*ServiceSpec)(nil), // 8: ease.api.ServiceSpec + (*ValidationRule)(nil), // 9: ease.api.ValidationRule + (*ValidationRules)(nil), // 10: ease.api.ValidationRules + (data.ServiceId)(0), // 11: data.ServiceId + (*descriptor.MethodOptions)(nil), // 12: google.protobuf.MethodOptions + (*descriptor.ServiceOptions)(nil), // 13: google.protobuf.ServiceOptions + (*descriptor.FieldOptions)(nil), // 14: google.protobuf.FieldOptions + (*HttpRule)(nil), // 15: ease.api.HttpRule +} +var file_httpoptions_annotations_proto_depIdxs = []int32{ + 0, // 0: ease.api.ApiMethod.api_source:type_name -> ease.api.ApiSourceType + 1, // 1: ease.api.ApiMethod.token_type:type_name -> ease.api.AuthTokenType + 2, // 2: ease.api.ApiMethod.spec_source_type:type_name -> ease.api.SpecSourceType + 11, // 3: ease.api.ServiceSpec.service_id:type_name -> data.ServiceId + 3, // 4: ease.api.ServiceSpec.balancer:type_name -> ease.api.LoadBalancer + 4, // 5: ease.api.ValidationRule.operator:type_name -> ease.api.OperatorType + 6, // 6: ease.api.ValidationRule.type:type_name -> ease.api.ValueType + 5, // 7: ease.api.ValidationRule.function:type_name -> ease.api.FunctionType + 9, // 8: ease.api.ValidationRules.rules:type_name -> ease.api.ValidationRule + 12, // 9: ease.api.http:extendee -> google.protobuf.MethodOptions + 12, // 10: ease.api.method:extendee -> google.protobuf.MethodOptions + 13, // 11: ease.api.service_spec:extendee -> google.protobuf.ServiceOptions + 14, // 12: ease.api.rules:extendee -> google.protobuf.FieldOptions + 15, // 13: ease.api.http:type_name -> ease.api.HttpRule + 7, // 14: ease.api.method:type_name -> ease.api.ApiMethod + 8, // 15: ease.api.service_spec:type_name -> ease.api.ServiceSpec + 10, // 16: ease.api.rules:type_name -> ease.api.ValidationRules + 17, // [17:17] is the sub-list for method output_type + 17, // [17:17] is the sub-list for method input_type + 13, // [13:17] is the sub-list for extension type_name + 9, // [9:13] is the sub-list for extension extendee + 0, // [0:9] is the sub-list for field type_name +} + +func init() { file_httpoptions_annotations_proto_init() } +func file_httpoptions_annotations_proto_init() { + if File_httpoptions_annotations_proto != nil { + return + } + file_httpoptions_http_proto_init() + if !protoimpl.UnsafeEnabled { + file_httpoptions_annotations_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ApiMethod); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_httpoptions_annotations_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ServiceSpec); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_httpoptions_annotations_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ValidationRule); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_httpoptions_annotations_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ValidationRules); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_httpoptions_annotations_proto_rawDesc, + NumEnums: 7, + NumMessages: 4, + NumExtensions: 4, + NumServices: 0, + }, + GoTypes: file_httpoptions_annotations_proto_goTypes, + DependencyIndexes: file_httpoptions_annotations_proto_depIdxs, + EnumInfos: file_httpoptions_annotations_proto_enumTypes, + MessageInfos: file_httpoptions_annotations_proto_msgTypes, + ExtensionInfos: file_httpoptions_annotations_proto_extTypes, + }.Build() + File_httpoptions_annotations_proto = out.File + file_httpoptions_annotations_proto_rawDesc = nil + file_httpoptions_annotations_proto_goTypes = nil + file_httpoptions_annotations_proto_depIdxs = nil } diff --git a/httpoptions/annotations.proto b/httpoptions/annotations.proto index 873f98d..3ef09df 100644 --- a/httpoptions/annotations.proto +++ b/httpoptions/annotations.proto @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +// See `https://github.com/googleapis/googleapis/blob/master/google/api/annotations.proto` syntax = "proto3"; package ease.api; @@ -22,6 +23,7 @@ import "data/data.proto"; import "frontend/error.proto"; option java_multiple_files = true; +// option go_package = "github.com/binchencoder/ease-gateway/httpoptions;annotations"; option java_outer_classname = "AnnotationsProto"; option java_package = "com.ease.api"; option objc_class_prefix = "EAPI"; diff --git a/httpoptions/http.pb.go b/httpoptions/http.pb.go old mode 100755 new mode 100644 index d874d90..d644dbf --- a/httpoptions/http.pb.go +++ b/httpoptions/http.pb.go @@ -1,162 +1,461 @@ +// Copyright 2019 Google LLC. +// +// 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. +// See `https://github.com/googleapis/googleapis/blob/master/google/api/http.proto` + // Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.23.0 +// protoc v3.12.3 // source: httpoptions/http.proto package ease_api import ( - fmt "fmt" proto "github.com/golang/protobuf/proto" - math "math" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" ) -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) -// 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.ProtoPackageIsVersion3 // please upgrade the proto package +// This is a compile-time assertion that a sufficiently up-to-date version +// of the legacy proto package is being used. +const _ = proto.ProtoPackageIsVersion4 +// Defines the HTTP configuration for an API service. It contains a list of +// [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method +// to one or more HTTP REST API methods. type Http struct { - Rules []*HttpRule `protobuf:"bytes,1,rep,name=rules,proto3" json:"rules,omitempty"` - FullyDecodeReservedExpansion bool `protobuf:"varint,2,opt,name=fully_decode_reserved_expansion,json=fullyDecodeReservedExpansion,proto3" json:"fully_decode_reserved_expansion,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // A list of HTTP configuration rules that apply to individual API methods. + // + // **NOTE:** All service configuration rules follow "last one wins" order. + Rules []*HttpRule `protobuf:"bytes,1,rep,name=rules,proto3" json:"rules,omitempty"` + // When set to true, URL path parameters will be fully URI-decoded except in + // cases of single segment matches in reserved expansion, where "%2F" will be + // left encoded. + // + // The default behavior is to not decode RFC 6570 reserved characters in multi + // segment matches. + FullyDecodeReservedExpansion bool `protobuf:"varint,2,opt,name=fully_decode_reserved_expansion,json=fullyDecodeReservedExpansion,proto3" json:"fully_decode_reserved_expansion,omitempty"` +} + +func (x *Http) Reset() { + *x = Http{} + if protoimpl.UnsafeEnabled { + mi := &file_httpoptions_http_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *Http) Reset() { *m = Http{} } -func (m *Http) String() string { return proto.CompactTextString(m) } -func (*Http) ProtoMessage() {} -func (*Http) Descriptor() ([]byte, []int) { - return fileDescriptor_855b53eccb99bc99, []int{0} +func (x *Http) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *Http) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Http.Unmarshal(m, b) -} -func (m *Http) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Http.Marshal(b, m, deterministic) -} -func (m *Http) XXX_Merge(src proto.Message) { - xxx_messageInfo_Http.Merge(m, src) -} -func (m *Http) XXX_Size() int { - return xxx_messageInfo_Http.Size(m) -} -func (m *Http) XXX_DiscardUnknown() { - xxx_messageInfo_Http.DiscardUnknown(m) +func (*Http) ProtoMessage() {} + +func (x *Http) ProtoReflect() protoreflect.Message { + mi := &file_httpoptions_http_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_Http proto.InternalMessageInfo +// Deprecated: Use Http.ProtoReflect.Descriptor instead. +func (*Http) Descriptor() ([]byte, []int) { + return file_httpoptions_http_proto_rawDescGZIP(), []int{0} +} -func (m *Http) GetRules() []*HttpRule { - if m != nil { - return m.Rules +func (x *Http) GetRules() []*HttpRule { + if x != nil { + return x.Rules } return nil } -func (m *Http) GetFullyDecodeReservedExpansion() bool { - if m != nil { - return m.FullyDecodeReservedExpansion +func (x *Http) GetFullyDecodeReservedExpansion() bool { + if x != nil { + return x.FullyDecodeReservedExpansion } return false } +// # gRPC Transcoding +// +// gRPC Transcoding is a feature for mapping between a gRPC method and one or +// more HTTP REST endpoints. It allows developers to build a single API service +// that supports both gRPC APIs and REST APIs. Many systems, including [Google +// APIs](https://github.com/googleapis/googleapis), +// [Cloud Endpoints](https://cloud.google.com/endpoints), [gRPC +// Gateway](https://github.com/grpc-ecosystem/grpc-gateway), +// and [Envoy](https://github.com/envoyproxy/envoy) proxy support this feature +// and use it for large scale production services. +// +// `HttpRule` defines the schema of the gRPC/REST mapping. The mapping specifies +// how different portions of the gRPC request message are mapped to the URL +// path, URL query parameters, and HTTP request body. It also controls how the +// gRPC response message is mapped to the HTTP response body. `HttpRule` is +// typically specified as an `google.api.http` annotation on the gRPC method. +// +// Each mapping specifies a URL path template and an HTTP method. The path +// template may refer to one or more fields in the gRPC request message, as long +// as each field is a non-repeated field with a primitive (non-message) type. +// The path template controls how fields of the request message are mapped to +// the URL path. +// +// Example: +// +// service Messaging { +// rpc GetMessage(GetMessageRequest) returns (Message) { +// option (google.api.http) = { +// get: "/v1/{name=messages/*}" +// }; +// } +// } +// message GetMessageRequest { +// string name = 1; // Mapped to URL path. +// } +// message Message { +// string text = 1; // The resource content. +// } +// +// This enables an HTTP REST to gRPC mapping as below: +// +// HTTP | gRPC +// -----|----- +// `GET /v1/messages/123456` | `GetMessage(name: "messages/123456")` +// +// Any fields in the request message which are not bound by the path template +// automatically become HTTP query parameters if there is no HTTP request body. +// For example: +// +// service Messaging { +// rpc GetMessage(GetMessageRequest) returns (Message) { +// option (google.api.http) = { +// get:"/v1/messages/{message_id}" +// }; +// } +// } +// message GetMessageRequest { +// message SubMessage { +// string subfield = 1; +// } +// string message_id = 1; // Mapped to URL path. +// int64 revision = 2; // Mapped to URL query parameter `revision`. +// SubMessage sub = 3; // Mapped to URL query parameter `sub.subfield`. +// } +// +// This enables a HTTP JSON to RPC mapping as below: +// +// HTTP | gRPC +// -----|----- +// `GET /v1/messages/123456?revision=2&sub.subfield=foo` | +// `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield: +// "foo"))` +// +// Note that fields which are mapped to URL query parameters must have a +// primitive type or a repeated primitive type or a non-repeated message type. +// In the case of a repeated type, the parameter can be repeated in the URL +// as `...?param=A¶m=B`. In the case of a message type, each field of the +// message is mapped to a separate parameter, such as +// `...?foo.a=A&foo.b=B&foo.c=C`. +// +// For HTTP methods that allow a request body, the `body` field +// specifies the mapping. Consider a REST update method on the +// message resource collection: +// +// service Messaging { +// rpc UpdateMessage(UpdateMessageRequest) returns (Message) { +// option (google.api.http) = { +// patch: "/v1/messages/{message_id}" +// body: "message" +// }; +// } +// } +// message UpdateMessageRequest { +// string message_id = 1; // mapped to the URL +// Message message = 2; // mapped to the body +// } +// +// The following HTTP JSON to RPC mapping is enabled, where the +// representation of the JSON in the request body is determined by +// protos JSON encoding: +// +// HTTP | gRPC +// -----|----- +// `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: +// "123456" message { text: "Hi!" })` +// +// The special name `*` can be used in the body mapping to define that +// every field not bound by the path template should be mapped to the +// request body. This enables the following alternative definition of +// the update method: +// +// service Messaging { +// rpc UpdateMessage(Message) returns (Message) { +// option (google.api.http) = { +// patch: "/v1/messages/{message_id}" +// body: "*" +// }; +// } +// } +// message Message { +// string message_id = 1; +// string text = 2; +// } +// +// +// The following HTTP JSON to RPC mapping is enabled: +// +// HTTP | gRPC +// -----|----- +// `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: +// "123456" text: "Hi!")` +// +// Note that when using `*` in the body mapping, it is not possible to +// have HTTP parameters, as all fields not bound by the path end in +// the body. This makes this option more rarely used in practice when +// defining REST APIs. The common usage of `*` is in custom methods +// which don't use the URL at all for transferring data. +// +// It is possible to define multiple HTTP methods for one RPC by using +// the `additional_bindings` option. Example: +// +// service Messaging { +// rpc GetMessage(GetMessageRequest) returns (Message) { +// option (google.api.http) = { +// get: "/v1/messages/{message_id}" +// additional_bindings { +// get: "/v1/users/{user_id}/messages/{message_id}" +// } +// }; +// } +// } +// message GetMessageRequest { +// string message_id = 1; +// string user_id = 2; +// } +// +// This enables the following two alternative HTTP JSON to RPC mappings: +// +// HTTP | gRPC +// -----|----- +// `GET /v1/messages/123456` | `GetMessage(message_id: "123456")` +// `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id: +// "123456")` +// +// ## Rules for HTTP mapping +// +// 1. Leaf request fields (recursive expansion nested messages in the request +// message) are classified into three categories: +// - Fields referred by the path template. They are passed via the URL path. +// - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They are passed via the HTTP +// request body. +// - All other fields are passed via the URL query parameters, and the +// parameter name is the field path in the request message. A repeated +// field can be represented as multiple query parameters under the same +// name. +// 2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL query parameter, all fields +// are passed via URL path and HTTP request body. +// 3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP request body, all +// fields are passed via URL path and URL query parameters. +// +// ### Path template syntax +// +// Template = "/" Segments [ Verb ] ; +// Segments = Segment { "/" Segment } ; +// Segment = "*" | "**" | LITERAL | Variable ; +// Variable = "{" FieldPath [ "=" Segments ] "}" ; +// FieldPath = IDENT { "." IDENT } ; +// Verb = ":" LITERAL ; +// +// The syntax `*` matches a single URL path segment. The syntax `**` matches +// zero or more URL path segments, which must be the last part of the URL path +// except the `Verb`. +// +// The syntax `Variable` matches part of the URL path as specified by its +// template. A variable template must not contain other variables. If a variable +// matches a single path segment, its template may be omitted, e.g. `{var}` +// is equivalent to `{var=*}`. +// +// The syntax `LITERAL` matches literal text in the URL path. If the `LITERAL` +// contains any reserved character, such characters should be percent-encoded +// before the matching. +// +// If a variable contains exactly one path segment, such as `"{var}"` or +// `"{var=*}"`, when such a variable is expanded into a URL path on the client +// side, all characters except `[-_.~0-9a-zA-Z]` are percent-encoded. The +// server side does the reverse decoding. Such variables show up in the +// [Discovery +// Document](https://developers.google.com/discovery/v1/reference/apis) as +// `{var}`. +// +// If a variable contains multiple path segments, such as `"{var=foo/*}"` +// or `"{var=**}"`, when such a variable is expanded into a URL path on the +// client side, all characters except `[-_.~/0-9a-zA-Z]` are percent-encoded. +// The server side does the reverse decoding, except "%2F" and "%2f" are left +// unchanged. Such variables show up in the +// [Discovery +// Document](https://developers.google.com/discovery/v1/reference/apis) as +// `{+var}`. +// +// ## Using gRPC API Service Configuration +// +// gRPC API Service Configuration (service config) is a configuration language +// for configuring a gRPC service to become a user-facing product. The +// service config is simply the YAML representation of the `google.api.Service` +// proto message. +// +// As an alternative to annotating your proto file, you can configure gRPC +// transcoding in your service config YAML files. You do this by specifying a +// `HttpRule` that maps the gRPC method to a REST endpoint, achieving the same +// effect as the proto annotation. This can be particularly useful if you +// have a proto that is reused in multiple services. Note that any transcoding +// specified in the service config will override any matching transcoding +// configuration in the proto. +// +// Example: +// +// http: +// rules: +// # Selects a gRPC method and applies HttpRule to it. +// - selector: example.v1.Messaging.GetMessage +// get: /v1/messages/{message_id}/{sub.subfield} +// +// ## Special notes +// +// When gRPC Transcoding is used to map a gRPC to JSON REST endpoints, the +// proto to JSON conversion must follow the [proto3 +// specification](https://developers.google.com/protocol-buffers/docs/proto3#json). +// +// While the single segment variable follows the semantics of +// [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 Simple String +// Expansion, the multi segment variable **does not** follow RFC 6570 Section +// 3.2.3 Reserved Expansion. The reason is that the Reserved Expansion +// does not expand special characters like `?` and `#`, which would lead +// to invalid URLs. As the result, gRPC Transcoding uses a custom encoding +// for multi segment variables. +// +// The path variables **must not** refer to any repeated or mapped field, +// because client libraries are not capable of handling such variable expansion. +// +// The path variables **must not** capture the leading "/" character. The reason +// is that the most common use case "{var}" does not capture the leading "/" +// character. For consistency, all path variables must share the same behavior. +// +// Repeated message fields must not be mapped to URL query parameters, because +// no client library can support such complicated mapping. +// +// If an API needs to use a JSON array for request or response body, it can map +// the request or response body to a repeated field. However, some gRPC +// Transcoding implementations may not support this feature. type HttpRule struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Selects a method to which this rule applies. + // + // Refer to [selector][google.api.DocumentationRule.selector] for syntax details. Selector string `protobuf:"bytes,1,opt,name=selector,proto3" json:"selector,omitempty"` - // Types that are valid to be assigned to Pattern: + // Determines the URL pattern is matched by this rules. This pattern can be + // used with any of the {get|put|post|delete|patch} methods. A custom method + // can be defined using the 'custom' field. + // + // Types that are assignable to Pattern: // *HttpRule_Get // *HttpRule_Put // *HttpRule_Post // *HttpRule_Delete // *HttpRule_Patch // *HttpRule_Custom - Pattern isHttpRule_Pattern `protobuf_oneof:"pattern"` - Body string `protobuf:"bytes,7,opt,name=body,proto3" json:"body,omitempty"` - ResponseBody string `protobuf:"bytes,12,opt,name=response_body,json=responseBody,proto3" json:"response_body,omitempty"` - AdditionalBindings []*HttpRule `protobuf:"bytes,11,rep,name=additional_bindings,json=additionalBindings,proto3" json:"additional_bindings,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *HttpRule) Reset() { *m = HttpRule{} } -func (m *HttpRule) String() string { return proto.CompactTextString(m) } -func (*HttpRule) ProtoMessage() {} -func (*HttpRule) Descriptor() ([]byte, []int) { - return fileDescriptor_855b53eccb99bc99, []int{1} -} - -func (m *HttpRule) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_HttpRule.Unmarshal(m, b) -} -func (m *HttpRule) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_HttpRule.Marshal(b, m, deterministic) -} -func (m *HttpRule) XXX_Merge(src proto.Message) { - xxx_messageInfo_HttpRule.Merge(m, src) -} -func (m *HttpRule) XXX_Size() int { - return xxx_messageInfo_HttpRule.Size(m) -} -func (m *HttpRule) XXX_DiscardUnknown() { - xxx_messageInfo_HttpRule.DiscardUnknown(m) -} - -var xxx_messageInfo_HttpRule proto.InternalMessageInfo - -func (m *HttpRule) GetSelector() string { - if m != nil { - return m.Selector + Pattern isHttpRule_Pattern `protobuf_oneof:"pattern"` + // The name of the request field whose value is mapped to the HTTP request + // body, or `*` for mapping all request fields not captured by the path + // pattern to the HTTP body, or omitted for not having any HTTP request body. + // + // NOTE: the referred field must be present at the top-level of the request + // message type. + Body string `protobuf:"bytes,7,opt,name=body,proto3" json:"body,omitempty"` + // Optional. The name of the response field whose value is mapped to the HTTP + // response body. When omitted, the entire response message will be used + // as the HTTP response body. + // + // NOTE: The referred field must be present at the top-level of the response + // message type. + ResponseBody string `protobuf:"bytes,12,opt,name=response_body,json=responseBody,proto3" json:"response_body,omitempty"` + // Additional HTTP bindings for the selector. Nested bindings must + // not contain an `additional_bindings` field themselves (that is, + // the nesting may only be one level deep). + AdditionalBindings []*HttpRule `protobuf:"bytes,11,rep,name=additional_bindings,json=additionalBindings,proto3" json:"additional_bindings,omitempty"` +} + +func (x *HttpRule) Reset() { + *x = HttpRule{} + if protoimpl.UnsafeEnabled { + mi := &file_httpoptions_http_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } - return "" -} - -type isHttpRule_Pattern interface { - isHttpRule_Pattern() -} - -type HttpRule_Get struct { - Get string `protobuf:"bytes,2,opt,name=get,proto3,oneof"` } -type HttpRule_Put struct { - Put string `protobuf:"bytes,3,opt,name=put,proto3,oneof"` +func (x *HttpRule) String() string { + return protoimpl.X.MessageStringOf(x) } -type HttpRule_Post struct { - Post string `protobuf:"bytes,4,opt,name=post,proto3,oneof"` -} +func (*HttpRule) ProtoMessage() {} -type HttpRule_Delete struct { - Delete string `protobuf:"bytes,5,opt,name=delete,proto3,oneof"` +func (x *HttpRule) ProtoReflect() protoreflect.Message { + mi := &file_httpoptions_http_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -type HttpRule_Patch struct { - Patch string `protobuf:"bytes,6,opt,name=patch,proto3,oneof"` +// Deprecated: Use HttpRule.ProtoReflect.Descriptor instead. +func (*HttpRule) Descriptor() ([]byte, []int) { + return file_httpoptions_http_proto_rawDescGZIP(), []int{1} } -type HttpRule_Custom struct { - Custom *CustomHttpPattern `protobuf:"bytes,8,opt,name=custom,proto3,oneof"` +func (x *HttpRule) GetSelector() string { + if x != nil { + return x.Selector + } + return "" } -func (*HttpRule_Get) isHttpRule_Pattern() {} - -func (*HttpRule_Put) isHttpRule_Pattern() {} - -func (*HttpRule_Post) isHttpRule_Pattern() {} - -func (*HttpRule_Delete) isHttpRule_Pattern() {} - -func (*HttpRule_Patch) isHttpRule_Pattern() {} - -func (*HttpRule_Custom) isHttpRule_Pattern() {} - func (m *HttpRule) GetPattern() isHttpRule_Pattern { if m != nil { return m.Pattern @@ -164,160 +463,316 @@ func (m *HttpRule) GetPattern() isHttpRule_Pattern { return nil } -func (m *HttpRule) GetGet() string { - if x, ok := m.GetPattern().(*HttpRule_Get); ok { +func (x *HttpRule) GetGet() string { + if x, ok := x.GetPattern().(*HttpRule_Get); ok { return x.Get } return "" } -func (m *HttpRule) GetPut() string { - if x, ok := m.GetPattern().(*HttpRule_Put); ok { +func (x *HttpRule) GetPut() string { + if x, ok := x.GetPattern().(*HttpRule_Put); ok { return x.Put } return "" } -func (m *HttpRule) GetPost() string { - if x, ok := m.GetPattern().(*HttpRule_Post); ok { +func (x *HttpRule) GetPost() string { + if x, ok := x.GetPattern().(*HttpRule_Post); ok { return x.Post } return "" } -func (m *HttpRule) GetDelete() string { - if x, ok := m.GetPattern().(*HttpRule_Delete); ok { +func (x *HttpRule) GetDelete() string { + if x, ok := x.GetPattern().(*HttpRule_Delete); ok { return x.Delete } return "" } -func (m *HttpRule) GetPatch() string { - if x, ok := m.GetPattern().(*HttpRule_Patch); ok { +func (x *HttpRule) GetPatch() string { + if x, ok := x.GetPattern().(*HttpRule_Patch); ok { return x.Patch } return "" } -func (m *HttpRule) GetCustom() *CustomHttpPattern { - if x, ok := m.GetPattern().(*HttpRule_Custom); ok { +func (x *HttpRule) GetCustom() *CustomHttpPattern { + if x, ok := x.GetPattern().(*HttpRule_Custom); ok { return x.Custom } return nil } -func (m *HttpRule) GetBody() string { - if m != nil { - return m.Body +func (x *HttpRule) GetBody() string { + if x != nil { + return x.Body } return "" } -func (m *HttpRule) GetResponseBody() string { - if m != nil { - return m.ResponseBody +func (x *HttpRule) GetResponseBody() string { + if x != nil { + return x.ResponseBody } return "" } -func (m *HttpRule) GetAdditionalBindings() []*HttpRule { - if m != nil { - return m.AdditionalBindings +func (x *HttpRule) GetAdditionalBindings() []*HttpRule { + if x != nil { + return x.AdditionalBindings } return nil } -// XXX_OneofWrappers is for the internal use of the proto package. -func (*HttpRule) XXX_OneofWrappers() []interface{} { - return []interface{}{ - (*HttpRule_Get)(nil), - (*HttpRule_Put)(nil), - (*HttpRule_Post)(nil), - (*HttpRule_Delete)(nil), - (*HttpRule_Patch)(nil), - (*HttpRule_Custom)(nil), - } +type isHttpRule_Pattern interface { + isHttpRule_Pattern() } -type CustomHttpPattern struct { - Kind string `protobuf:"bytes,1,opt,name=kind,proto3" json:"kind,omitempty"` - Path string `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` +type HttpRule_Get struct { + // Maps to HTTP GET. Used for listing and getting information about + // resources. + Get string `protobuf:"bytes,2,opt,name=get,proto3,oneof"` } -func (m *CustomHttpPattern) Reset() { *m = CustomHttpPattern{} } -func (m *CustomHttpPattern) String() string { return proto.CompactTextString(m) } -func (*CustomHttpPattern) ProtoMessage() {} -func (*CustomHttpPattern) Descriptor() ([]byte, []int) { - return fileDescriptor_855b53eccb99bc99, []int{2} +type HttpRule_Put struct { + // Maps to HTTP PUT. Used for replacing a resource. + Put string `protobuf:"bytes,3,opt,name=put,proto3,oneof"` } -func (m *CustomHttpPattern) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_CustomHttpPattern.Unmarshal(m, b) +type HttpRule_Post struct { + // Maps to HTTP POST. Used for creating a resource or performing an action. + Post string `protobuf:"bytes,4,opt,name=post,proto3,oneof"` } -func (m *CustomHttpPattern) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_CustomHttpPattern.Marshal(b, m, deterministic) + +type HttpRule_Delete struct { + // Maps to HTTP DELETE. Used for deleting a resource. + Delete string `protobuf:"bytes,5,opt,name=delete,proto3,oneof"` } -func (m *CustomHttpPattern) XXX_Merge(src proto.Message) { - xxx_messageInfo_CustomHttpPattern.Merge(m, src) + +type HttpRule_Patch struct { + // Maps to HTTP PATCH. Used for updating a resource. + Patch string `protobuf:"bytes,6,opt,name=patch,proto3,oneof"` } -func (m *CustomHttpPattern) XXX_Size() int { - return xxx_messageInfo_CustomHttpPattern.Size(m) + +type HttpRule_Custom struct { + // The custom pattern is used for specifying an HTTP method that is not + // included in the `pattern` field, such as HEAD, or "*" to leave the + // HTTP method unspecified for this rule. The wild-card rule is useful + // for services that provide content to Web (HTML) clients. + Custom *CustomHttpPattern `protobuf:"bytes,8,opt,name=custom,proto3,oneof"` } -func (m *CustomHttpPattern) XXX_DiscardUnknown() { - xxx_messageInfo_CustomHttpPattern.DiscardUnknown(m) + +func (*HttpRule_Get) isHttpRule_Pattern() {} + +func (*HttpRule_Put) isHttpRule_Pattern() {} + +func (*HttpRule_Post) isHttpRule_Pattern() {} + +func (*HttpRule_Delete) isHttpRule_Pattern() {} + +func (*HttpRule_Patch) isHttpRule_Pattern() {} + +func (*HttpRule_Custom) isHttpRule_Pattern() {} + +// A custom pattern is used for defining custom HTTP verb. +type CustomHttpPattern struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The name of this custom HTTP verb. + Kind string `protobuf:"bytes,1,opt,name=kind,proto3" json:"kind,omitempty"` + // The path matched by this custom verb. + Path string `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"` +} + +func (x *CustomHttpPattern) Reset() { + *x = CustomHttpPattern{} + if protoimpl.UnsafeEnabled { + mi := &file_httpoptions_http_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -var xxx_messageInfo_CustomHttpPattern proto.InternalMessageInfo +func (x *CustomHttpPattern) String() string { + return protoimpl.X.MessageStringOf(x) +} -func (m *CustomHttpPattern) GetKind() string { - if m != nil { - return m.Kind +func (*CustomHttpPattern) ProtoMessage() {} + +func (x *CustomHttpPattern) ProtoReflect() protoreflect.Message { + mi := &file_httpoptions_http_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CustomHttpPattern.ProtoReflect.Descriptor instead. +func (*CustomHttpPattern) Descriptor() ([]byte, []int) { + return file_httpoptions_http_proto_rawDescGZIP(), []int{2} +} + +func (x *CustomHttpPattern) GetKind() string { + if x != nil { + return x.Kind } return "" } -func (m *CustomHttpPattern) GetPath() string { - if m != nil { - return m.Path +func (x *CustomHttpPattern) GetPath() string { + if x != nil { + return x.Path } return "" } -func init() { - proto.RegisterType((*Http)(nil), "ease.api.Http") - proto.RegisterType((*HttpRule)(nil), "ease.api.HttpRule") - proto.RegisterType((*CustomHttpPattern)(nil), "ease.api.CustomHttpPattern") -} - -func init() { proto.RegisterFile("httpoptions/http.proto", fileDescriptor_855b53eccb99bc99) } - -var fileDescriptor_855b53eccb99bc99 = []byte{ - // 377 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x92, 0xc1, 0x8e, 0xd3, 0x30, - 0x10, 0x86, 0x49, 0x9b, 0x66, 0x93, 0x69, 0x39, 0x60, 0xd0, 0xca, 0x02, 0x24, 0xa2, 0x70, 0xc9, - 0x29, 0x48, 0x8b, 0x38, 0x71, 0x22, 0x4b, 0xa5, 0x72, 0xab, 0xf2, 0x02, 0x91, 0x1b, 0x0f, 0x6d, - 0x44, 0x6a, 0x5b, 0xf1, 0x04, 0xe8, 0xeb, 0xf0, 0x50, 0x3c, 0x0f, 0xb2, 0x93, 0xb4, 0x07, 0xb4, - 0xb7, 0xf9, 0xff, 0xf9, 0x34, 0xfe, 0x35, 0x1e, 0xb8, 0x3f, 0x11, 0x19, 0x6d, 0xa8, 0xd5, 0xca, - 0x7e, 0x70, 0x75, 0x61, 0x7a, 0x4d, 0x9a, 0xc5, 0x28, 0x2c, 0x16, 0xc2, 0xb4, 0xd9, 0x2f, 0x08, - 0x77, 0x44, 0x86, 0xe5, 0xb0, 0xea, 0x87, 0x0e, 0x2d, 0x0f, 0xd2, 0x65, 0xbe, 0x7e, 0x60, 0xc5, - 0x4c, 0x14, 0xae, 0x5d, 0x0d, 0x1d, 0x56, 0x23, 0xc0, 0xb6, 0xf0, 0xee, 0xfb, 0xd0, 0x75, 0x97, - 0x5a, 0x62, 0xa3, 0x25, 0xd6, 0x3d, 0x5a, 0xec, 0x7f, 0xa2, 0xac, 0xf1, 0xb7, 0x11, 0xca, 0xb6, - 0x5a, 0xf1, 0x45, 0x1a, 0xe4, 0x71, 0xf5, 0xd6, 0x63, 0x5f, 0x3d, 0x55, 0x4d, 0xd0, 0x76, 0x66, - 0xb2, 0xbf, 0x0b, 0x88, 0xe7, 0xd1, 0xec, 0x35, 0xc4, 0x16, 0x3b, 0x6c, 0x48, 0xf7, 0x3c, 0x48, - 0x83, 0x3c, 0xa9, 0xae, 0x9a, 0x31, 0x58, 0x1e, 0x91, 0xfc, 0xcc, 0x64, 0xf7, 0xac, 0x72, 0xc2, - 0x79, 0x66, 0x20, 0xbe, 0x9c, 0x3d, 0x33, 0x10, 0x7b, 0x05, 0xa1, 0xd1, 0x96, 0x78, 0x38, 0x99, - 0x5e, 0x31, 0x0e, 0x91, 0xc4, 0x0e, 0x09, 0xf9, 0x6a, 0xf2, 0x27, 0xcd, 0xee, 0x61, 0x65, 0x04, - 0x35, 0x27, 0x1e, 0x4d, 0x8d, 0x51, 0xb2, 0x4f, 0x10, 0x35, 0x83, 0x25, 0x7d, 0xe6, 0x71, 0x1a, - 0xe4, 0xeb, 0x87, 0x37, 0xb7, 0x55, 0x3c, 0x7a, 0xdf, 0xa5, 0xde, 0x0b, 0x22, 0xec, 0x95, 0x1b, - 0x37, 0xc2, 0x8c, 0x41, 0x78, 0xd0, 0xf2, 0xc2, 0xef, 0x7c, 0x7c, 0x5f, 0xb3, 0xf7, 0xf0, 0xbc, - 0x47, 0x6b, 0xb4, 0xb2, 0x58, 0xfb, 0xe6, 0xc6, 0x37, 0x37, 0xb3, 0x59, 0x3a, 0xe8, 0x11, 0x5e, - 0x0a, 0x29, 0x5b, 0xf7, 0x47, 0xa2, 0xab, 0x0f, 0xad, 0x92, 0xad, 0x3a, 0x5a, 0xbe, 0x7e, 0xf2, - 0x1f, 0xd8, 0x0d, 0x2f, 0x27, 0xba, 0x4c, 0xe0, 0xce, 0x8c, 0x91, 0xb2, 0xcf, 0xf0, 0xe2, 0xbf, - 0x9c, 0x2e, 0xdd, 0x8f, 0x56, 0xc9, 0x69, 0xb9, 0xbe, 0x76, 0x9e, 0x11, 0x74, 0x1a, 0x37, 0x5b, - 0xf9, 0xba, 0xcc, 0x60, 0xd3, 0xe8, 0xf3, 0xf5, 0xd1, 0x32, 0xf1, 0x43, 0xdc, 0xcd, 0xec, 0x83, - 0x3f, 0x8b, 0x70, 0xfb, 0x65, 0xff, 0xed, 0x10, 0xf9, 0x1b, 0xfa, 0xf8, 0x2f, 0x00, 0x00, 0xff, - 0xff, 0x64, 0x5b, 0xb8, 0x5e, 0x5d, 0x02, 0x00, 0x00, +var File_httpoptions_http_proto protoreflect.FileDescriptor + +var file_httpoptions_http_proto_rawDesc = []byte{ + 0x0a, 0x16, 0x68, 0x74, 0x74, 0x70, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x68, 0x74, + 0x74, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x61, + 0x70, 0x69, 0x22, 0x77, 0x0a, 0x04, 0x48, 0x74, 0x74, 0x70, 0x12, 0x28, 0x0a, 0x05, 0x72, 0x75, + 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x65, 0x61, 0x73, 0x65, + 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x48, 0x74, 0x74, 0x70, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x05, 0x72, + 0x75, 0x6c, 0x65, 0x73, 0x12, 0x45, 0x0a, 0x1f, 0x66, 0x75, 0x6c, 0x6c, 0x79, 0x5f, 0x64, 0x65, + 0x63, 0x6f, 0x64, 0x65, 0x5f, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x5f, 0x65, 0x78, + 0x70, 0x61, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1c, 0x66, + 0x75, 0x6c, 0x6c, 0x79, 0x44, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x64, 0x45, 0x78, 0x70, 0x61, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0xd6, 0x02, 0x0a, 0x08, + 0x48, 0x74, 0x74, 0x70, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x6c, 0x65, + 0x63, 0x74, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x65, 0x6c, 0x65, + 0x63, 0x74, 0x6f, 0x72, 0x12, 0x12, 0x0a, 0x03, 0x67, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x48, 0x00, 0x52, 0x03, 0x67, 0x65, 0x74, 0x12, 0x12, 0x0a, 0x03, 0x70, 0x75, 0x74, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x03, 0x70, 0x75, 0x74, 0x12, 0x14, 0x0a, 0x04, + 0x70, 0x6f, 0x73, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x70, 0x6f, + 0x73, 0x74, 0x12, 0x18, 0x0a, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x09, 0x48, 0x00, 0x52, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x16, 0x0a, 0x05, + 0x70, 0x61, 0x74, 0x63, 0x68, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x70, + 0x61, 0x74, 0x63, 0x68, 0x12, 0x35, 0x0a, 0x06, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x18, 0x08, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x48, 0x74, 0x74, 0x70, 0x50, 0x61, 0x74, 0x74, 0x65, 0x72, + 0x6e, 0x48, 0x00, 0x52, 0x06, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x12, 0x12, 0x0a, 0x04, 0x62, + 0x6f, 0x64, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x12, + 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x62, 0x6f, 0x64, 0x79, + 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x42, 0x6f, 0x64, 0x79, 0x12, 0x43, 0x0a, 0x13, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x61, 0x6c, 0x5f, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x12, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x48, 0x74, 0x74, + 0x70, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x12, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, + 0x6c, 0x42, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x42, 0x09, 0x0a, 0x07, 0x70, 0x61, 0x74, + 0x74, 0x65, 0x72, 0x6e, 0x22, 0x3b, 0x0a, 0x11, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x48, 0x74, + 0x74, 0x70, 0x50, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x12, 0x0a, + 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, + 0x68, 0x42, 0x25, 0x0a, 0x0c, 0x63, 0x6f, 0x6d, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x61, 0x70, + 0x69, 0x42, 0x09, 0x48, 0x74, 0x74, 0x70, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0xf8, 0x01, + 0x01, 0xa2, 0x02, 0x04, 0x45, 0x41, 0x50, 0x49, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_httpoptions_http_proto_rawDescOnce sync.Once + file_httpoptions_http_proto_rawDescData = file_httpoptions_http_proto_rawDesc +) + +func file_httpoptions_http_proto_rawDescGZIP() []byte { + file_httpoptions_http_proto_rawDescOnce.Do(func() { + file_httpoptions_http_proto_rawDescData = protoimpl.X.CompressGZIP(file_httpoptions_http_proto_rawDescData) + }) + return file_httpoptions_http_proto_rawDescData +} + +var file_httpoptions_http_proto_msgTypes = make([]protoimpl.MessageInfo, 3) +var file_httpoptions_http_proto_goTypes = []interface{}{ + (*Http)(nil), // 0: ease.api.Http + (*HttpRule)(nil), // 1: ease.api.HttpRule + (*CustomHttpPattern)(nil), // 2: ease.api.CustomHttpPattern +} +var file_httpoptions_http_proto_depIdxs = []int32{ + 1, // 0: ease.api.Http.rules:type_name -> ease.api.HttpRule + 2, // 1: ease.api.HttpRule.custom:type_name -> ease.api.CustomHttpPattern + 1, // 2: ease.api.HttpRule.additional_bindings:type_name -> ease.api.HttpRule + 3, // [3:3] is the sub-list for method output_type + 3, // [3:3] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name +} + +func init() { file_httpoptions_http_proto_init() } +func file_httpoptions_http_proto_init() { + if File_httpoptions_http_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_httpoptions_http_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Http); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_httpoptions_http_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*HttpRule); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_httpoptions_http_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CustomHttpPattern); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_httpoptions_http_proto_msgTypes[1].OneofWrappers = []interface{}{ + (*HttpRule_Get)(nil), + (*HttpRule_Put)(nil), + (*HttpRule_Post)(nil), + (*HttpRule_Delete)(nil), + (*HttpRule_Patch)(nil), + (*HttpRule_Custom)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_httpoptions_http_proto_rawDesc, + NumEnums: 0, + NumMessages: 3, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_httpoptions_http_proto_goTypes, + DependencyIndexes: file_httpoptions_http_proto_depIdxs, + MessageInfos: file_httpoptions_http_proto_msgTypes, + }.Build() + File_httpoptions_http_proto = out.File + file_httpoptions_http_proto_rawDesc = nil + file_httpoptions_http_proto_goTypes = nil + file_httpoptions_http_proto_depIdxs = nil } diff --git a/httpoptions/http.proto b/httpoptions/http.proto index 9c32667..b714862 100644 --- a/httpoptions/http.proto +++ b/httpoptions/http.proto @@ -11,12 +11,13 @@ // 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. -// - +// See `https://github.com/googleapis/googleapis/blob/master/google/api/http.proto` syntax = "proto3"; package ease.api; +option cc_enable_arenas = true; +// option go_package = "github.com/binchencoder/ease-gateway/httpoptions;annotations"; option java_multiple_files = true; option java_outer_classname = "HttpProto"; option java_package = "com.ease.api"; @@ -26,19 +27,19 @@ option objc_class_prefix = "EAPI"; // [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method // to one or more HTTP REST API methods. message Http { - // A list of HTTP configuration rules that apply to individual API methods. - // - // **NOTE:** All service configuration rules follow "last one wins" order. - repeated HttpRule rules = 1; - - // When set to true, URL path parameters will be fully URI-decoded except in - // cases of single segment matches in reserved expansion, where "%2F" will be - // left encoded. - // - // The default behavior is to not decode RFC 6570 reserved characters in multi - // segment matches. - bool fully_decode_reserved_expansion = 2; -} + // A list of HTTP configuration rules that apply to individual API methods. + // + // **NOTE:** All service configuration rules follow "last one wins" order. + repeated HttpRule rules = 1; + + // When set to true, URL path parameters will be fully URI-decoded except in + // cases of single segment matches in reserved expansion, where "%2F" will be + // left encoded. + // + // The default behavior is to not decode RFC 6570 reserved characters in multi + // segment matches. + bool fully_decode_reserved_expansion = 2; + } // # gRPC Transcoding // diff --git a/integrate/hook.go b/integrate/hook.go index c204713..db7fb0f 100755 --- a/integrate/hook.go +++ b/integrate/hook.go @@ -7,11 +7,11 @@ import ( "strconv" "time" - "github.com/golang/protobuf/proto" "golang.org/x/net/context" gr "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/proto" "github.com/binchencoder/ease-gateway/gateway/runtime" options "github.com/binchencoder/ease-gateway/httpoptions" diff --git a/proto/examples/BUILD.bazel b/proto/examples/BUILD.bazel index ae9069f..5816390 100644 --- a/proto/examples/BUILD.bazel +++ b/proto/examples/BUILD.bazel @@ -1,6 +1,6 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library") load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") -load("//gateway/protoc-gen-swagger:defs.bzl", "protoc_gen_swagger") +load("//gateway/protoc-gen-openapiv2:defs.bzl", "protoc_gen_openapiv2") package(default_visibility = ["//visibility:public"]) @@ -25,7 +25,8 @@ proto_library( go_proto_library( name = "examplepb_go_proto", compilers = [ - "@io_bazel_rules_go//proto:go_grpc", + "//:go_apiv2", + "//:go_grpc", "//gateway/protoc-gen-grpc-gateway:go_gen_grpc_gateway", # keep ], importpath = "github.com/binchencoder/ease-gateway/proto/examples", @@ -56,8 +57,8 @@ go_library( ], ) -protoc_gen_swagger( - name = "examplepb_protoc_gen_swagger", +protoc_gen_openapiv2( + name = "examplepb_protoc_gen_openapiv2", proto = ":examplepb_proto", single_output = False, # Outputs a single swagger.json file. ) \ No newline at end of file diff --git a/proto/examples/echo_service.pb.go b/proto/examples/echo_service.pb.go index 3e67030..a1e64fe 100755 --- a/proto/examples/echo_service.pb.go +++ b/proto/examples/echo_service.pb.go @@ -1,18 +1,14 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.22.0 -// protoc v3.9.0 +// protoc v3.8.0 // source: proto/examples/echo_service.proto -package proto +package examples import ( - context "context" _ "github.com/binchencoder/ease-gateway/httpoptions" proto "github.com/golang/protobuf/proto" - grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" @@ -260,64 +256,78 @@ var File_proto_examples_echo_service_proto protoreflect.FileDescriptor var file_proto_examples_echo_service_proto_rawDesc = []byte{ 0x0a, 0x21, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x1a, 0x1d, 0x68, - 0x74, 0x74, 0x70, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x46, 0x0a, 0x08, - 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x12, 0x1c, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x67, - 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x08, 0x70, 0x72, - 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x14, 0x0a, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x42, 0x06, 0x0a, 0x04, - 0x6d, 0x61, 0x72, 0x6b, 0x22, 0x89, 0x02, 0x0a, 0x0d, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x31, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x42, 0x21, 0xb2, 0xe4, 0x34, 0x1d, 0x0a, 0x04, 0x08, 0x05, 0x10, 0x02, 0x0a, 0x09, - 0x08, 0x06, 0x10, 0x02, 0x1a, 0x01, 0x32, 0x20, 0x01, 0x0a, 0x0a, 0x08, 0x07, 0x10, 0x02, 0x1a, - 0x02, 0x36, 0x31, 0x20, 0x01, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1f, 0x0a, 0x03, 0x6e, 0x75, 0x6d, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x42, 0x0d, 0xb2, 0xe4, 0x34, 0x09, 0x0a, 0x07, 0x08, 0x01, - 0x10, 0x01, 0x1a, 0x01, 0x30, 0x52, 0x03, 0x6e, 0x75, 0x6d, 0x12, 0x1b, 0x0a, 0x08, 0x6c, 0x69, - 0x6e, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x07, - 0x6c, 0x69, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x12, 0x14, 0x0a, 0x04, 0x6c, 0x61, 0x6e, 0x67, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x6c, 0x61, 0x6e, 0x67, 0x12, 0x2a, 0x0a, - 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, - 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, - 0x64, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x10, 0x0a, 0x02, 0x65, 0x6e, 0x18, - 0x06, 0x20, 0x01, 0x28, 0x03, 0x48, 0x01, 0x52, 0x02, 0x65, 0x6e, 0x12, 0x24, 0x0a, 0x02, 0x6e, - 0x6f, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, - 0x65, 0x73, 0x2e, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x48, 0x01, 0x52, 0x02, 0x6e, - 0x6f, 0x42, 0x06, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x42, 0x05, 0x0a, 0x03, 0x65, 0x78, 0x74, - 0x32, 0xd8, 0x03, 0x0a, 0x0b, 0x45, 0x63, 0x68, 0x6f, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x12, 0xee, 0x01, 0x0a, 0x04, 0x45, 0x63, 0x68, 0x6f, 0x12, 0x17, 0x2e, 0x65, 0x78, 0x61, 0x6d, - 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x1a, 0x17, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x53, 0x69, - 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xb3, 0x01, 0xca, 0xf3, - 0x34, 0xae, 0x01, 0x22, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, - 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x5a, 0x1d, 0x12, 0x1b, 0x2f, 0x76, - 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x2f, 0x7b, - 0x69, 0x64, 0x7d, 0x2f, 0x7b, 0x6e, 0x75, 0x6d, 0x7d, 0x5a, 0x24, 0x12, 0x22, 0x2f, 0x76, 0x31, + 0x6f, 0x74, 0x6f, 0x12, 0x1b, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, + 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, + 0x1a, 0x1d, 0x68, 0x74, 0x74, 0x70, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x61, 0x6e, + 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, + 0x46, 0x0a, 0x08, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x12, 0x1c, 0x0a, 0x08, 0x70, + 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, + 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x14, 0x0a, 0x04, 0x6e, 0x6f, 0x74, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x42, + 0x06, 0x0a, 0x04, 0x6d, 0x61, 0x72, 0x6b, 0x22, 0xaf, 0x02, 0x0a, 0x0d, 0x53, 0x69, 0x6d, 0x70, + 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x31, 0x0a, 0x02, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x21, 0xb2, 0xe4, 0x34, 0x1d, 0x0a, 0x04, 0x08, 0x05, 0x10, + 0x02, 0x0a, 0x09, 0x08, 0x06, 0x10, 0x02, 0x1a, 0x01, 0x32, 0x20, 0x01, 0x0a, 0x0a, 0x08, 0x07, + 0x10, 0x02, 0x1a, 0x02, 0x36, 0x31, 0x20, 0x01, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1f, 0x0a, 0x03, + 0x6e, 0x75, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x42, 0x0d, 0xb2, 0xe4, 0x34, 0x09, 0x0a, + 0x07, 0x08, 0x01, 0x10, 0x01, 0x1a, 0x01, 0x30, 0x52, 0x03, 0x6e, 0x75, 0x6d, 0x12, 0x1b, 0x0a, + 0x08, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x48, + 0x00, 0x52, 0x07, 0x6c, 0x69, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x12, 0x14, 0x0a, 0x04, 0x6c, 0x61, + 0x6e, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x6c, 0x61, 0x6e, 0x67, + 0x12, 0x3d, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x25, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x45, + 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, + 0x10, 0x0a, 0x02, 0x65, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x48, 0x01, 0x52, 0x02, 0x65, + 0x6e, 0x12, 0x37, 0x0a, 0x02, 0x6e, 0x6f, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, + 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x45, 0x6d, 0x62, 0x65, + 0x64, 0x64, 0x65, 0x64, 0x48, 0x01, 0x52, 0x02, 0x6e, 0x6f, 0x42, 0x06, 0x0a, 0x04, 0x63, 0x6f, + 0x64, 0x65, 0x42, 0x05, 0x0a, 0x03, 0x65, 0x78, 0x74, 0x32, 0xcc, 0x04, 0x0a, 0x0b, 0x45, 0x63, + 0x68, 0x6f, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x94, 0x02, 0x0a, 0x04, 0x45, 0x63, + 0x68, 0x6f, 0x12, 0x2a, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, + 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, + 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x2a, + 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x53, 0x69, 0x6d, + 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xb3, 0x01, 0xca, 0xf3, 0x34, + 0xae, 0x01, 0x22, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, + 0x65, 0x63, 0x68, 0x6f, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x5a, 0x1d, 0x12, 0x1b, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x2f, 0x7b, 0x69, - 0x64, 0x7d, 0x2f, 0x7b, 0x6e, 0x75, 0x6d, 0x7d, 0x2f, 0x7b, 0x6c, 0x61, 0x6e, 0x67, 0x7d, 0x5a, - 0x31, 0x12, 0x2f, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, - 0x63, 0x68, 0x6f, 0x31, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x2f, 0x7b, 0x6c, 0x69, 0x6e, 0x65, 0x5f, - 0x6e, 0x75, 0x6d, 0x7d, 0x2f, 0x7b, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x6e, 0x6f, 0x74, - 0x65, 0x7d, 0x5a, 0x1d, 0x12, 0x1b, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, - 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x32, 0x2f, 0x7b, 0x6e, 0x6f, 0x2e, 0x6e, 0x6f, 0x74, 0x65, - 0x7d, 0x12, 0x5c, 0x0a, 0x08, 0x45, 0x63, 0x68, 0x6f, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x17, 0x2e, - 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x17, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, - 0x73, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, - 0x1e, 0xca, 0xf3, 0x34, 0x1a, 0x22, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, - 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x62, 0x6f, 0x64, 0x79, 0x3a, 0x01, 0x2a, 0x12, - 0x5d, 0x0a, 0x0a, 0x45, 0x63, 0x68, 0x6f, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x17, 0x2e, - 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x17, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, - 0x73, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, - 0x1d, 0xca, 0xf3, 0x34, 0x19, 0x2a, 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, - 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x1a, 0x1b, - 0xea, 0xf3, 0x34, 0x17, 0x08, 0xb6, 0x95, 0xff, 0xff, 0x07, 0x12, 0x04, 0x67, 0x72, 0x70, 0x63, - 0x1a, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x01, 0x42, 0x38, 0x0a, 0x20, 0x63, - 0x6f, 0x6d, 0x2e, 0x62, 0x69, 0x6e, 0x63, 0x68, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, - 0x65, 0x61, 0x73, 0x65, 0x67, 0x77, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x42, - 0x0d, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x5a, 0x05, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x64, 0x7d, 0x2f, 0x7b, 0x6e, 0x75, 0x6d, 0x7d, 0x5a, 0x24, 0x12, 0x22, 0x2f, 0x76, 0x31, 0x2f, + 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x2f, 0x7b, 0x69, 0x64, + 0x7d, 0x2f, 0x7b, 0x6e, 0x75, 0x6d, 0x7d, 0x2f, 0x7b, 0x6c, 0x61, 0x6e, 0x67, 0x7d, 0x5a, 0x31, + 0x12, 0x2f, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, + 0x68, 0x6f, 0x31, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x2f, 0x7b, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x6e, + 0x75, 0x6d, 0x7d, 0x2f, 0x7b, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x6e, 0x6f, 0x74, 0x65, + 0x7d, 0x5a, 0x1d, 0x12, 0x1b, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, + 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x32, 0x2f, 0x7b, 0x6e, 0x6f, 0x2e, 0x6e, 0x6f, 0x74, 0x65, 0x7d, + 0x12, 0x82, 0x01, 0x0a, 0x08, 0x45, 0x63, 0x68, 0x6f, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x2a, 0x2e, + 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x53, 0x69, 0x6d, 0x70, + 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x2a, 0x2e, 0x67, 0x72, 0x70, 0x63, + 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, + 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x1e, 0xca, 0xf3, 0x34, 0x1a, 0x22, 0x15, 0x2f, 0x76, 0x31, + 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x62, 0x6f, + 0x64, 0x79, 0x3a, 0x01, 0x2a, 0x12, 0x83, 0x01, 0x0a, 0x0a, 0x45, 0x63, 0x68, 0x6f, 0x44, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x12, 0x2a, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, + 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, + 0x65, 0x73, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x1a, 0x2a, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x53, + 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x1d, 0xca, 0xf3, + 0x34, 0x19, 0x2a, 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, + 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x1a, 0x1b, 0xea, 0xf3, 0x34, + 0x17, 0x08, 0xb6, 0x95, 0xff, 0xff, 0x07, 0x12, 0x04, 0x67, 0x72, 0x70, 0x63, 0x1a, 0x07, 0x64, + 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x01, 0x42, 0x6e, 0x0a, 0x20, 0x63, 0x6f, 0x6d, 0x2e, + 0x62, 0x69, 0x6e, 0x63, 0x68, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x65, 0x61, 0x73, + 0x65, 0x67, 0x77, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x42, 0x0d, 0x45, 0x78, + 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x5a, 0x3b, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x69, 0x6e, 0x63, 0x68, 0x65, 0x6e, 0x63, + 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x65, 0x61, 0x73, 0x65, 0x2d, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, + 0x79, 0x2f, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, + 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -334,18 +344,18 @@ func file_proto_examples_echo_service_proto_rawDescGZIP() []byte { var file_proto_examples_echo_service_proto_msgTypes = make([]protoimpl.MessageInfo, 2) var file_proto_examples_echo_service_proto_goTypes = []interface{}{ - (*Embedded)(nil), // 0: examples.Embedded - (*SimpleMessage)(nil), // 1: examples.SimpleMessage + (*Embedded)(nil), // 0: grpc.gateway.proto.examples.Embedded + (*SimpleMessage)(nil), // 1: grpc.gateway.proto.examples.SimpleMessage } var file_proto_examples_echo_service_proto_depIdxs = []int32{ - 0, // 0: examples.SimpleMessage.status:type_name -> examples.Embedded - 0, // 1: examples.SimpleMessage.no:type_name -> examples.Embedded - 1, // 2: examples.EchoService.Echo:input_type -> examples.SimpleMessage - 1, // 3: examples.EchoService.EchoBody:input_type -> examples.SimpleMessage - 1, // 4: examples.EchoService.EchoDelete:input_type -> examples.SimpleMessage - 1, // 5: examples.EchoService.Echo:output_type -> examples.SimpleMessage - 1, // 6: examples.EchoService.EchoBody:output_type -> examples.SimpleMessage - 1, // 7: examples.EchoService.EchoDelete:output_type -> examples.SimpleMessage + 0, // 0: grpc.gateway.proto.examples.SimpleMessage.status:type_name -> grpc.gateway.proto.examples.Embedded + 0, // 1: grpc.gateway.proto.examples.SimpleMessage.no:type_name -> grpc.gateway.proto.examples.Embedded + 1, // 2: grpc.gateway.proto.examples.EchoService.Echo:input_type -> grpc.gateway.proto.examples.SimpleMessage + 1, // 3: grpc.gateway.proto.examples.EchoService.EchoBody:input_type -> grpc.gateway.proto.examples.SimpleMessage + 1, // 4: grpc.gateway.proto.examples.EchoService.EchoDelete:input_type -> grpc.gateway.proto.examples.SimpleMessage + 1, // 5: grpc.gateway.proto.examples.EchoService.Echo:output_type -> grpc.gateway.proto.examples.SimpleMessage + 1, // 6: grpc.gateway.proto.examples.EchoService.EchoBody:output_type -> grpc.gateway.proto.examples.SimpleMessage + 1, // 7: grpc.gateway.proto.examples.EchoService.EchoDelete:output_type -> grpc.gateway.proto.examples.SimpleMessage 5, // [5:8] is the sub-list for method output_type 2, // [2:5] is the sub-list for method input_type 2, // [2:2] is the sub-list for extension type_name @@ -413,155 +423,3 @@ func file_proto_examples_echo_service_proto_init() { file_proto_examples_echo_service_proto_goTypes = nil file_proto_examples_echo_service_proto_depIdxs = nil } - -// Reference imports to suppress errors if they are not otherwise used. -var _ context.Context -var _ grpc.ClientConnInterface - -// 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.SupportPackageIsVersion6 - -// EchoServiceClient is the client API for EchoService service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. -type EchoServiceClient interface { - Echo(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) - EchoBody(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) - EchoDelete(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) -} - -type echoServiceClient struct { - cc grpc.ClientConnInterface -} - -func NewEchoServiceClient(cc grpc.ClientConnInterface) EchoServiceClient { - return &echoServiceClient{cc} -} - -func (c *echoServiceClient) Echo(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) { - out := new(SimpleMessage) - err := c.cc.Invoke(ctx, "/examples.EchoService/Echo", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *echoServiceClient) EchoBody(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) { - out := new(SimpleMessage) - err := c.cc.Invoke(ctx, "/examples.EchoService/EchoBody", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *echoServiceClient) EchoDelete(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) { - out := new(SimpleMessage) - err := c.cc.Invoke(ctx, "/examples.EchoService/EchoDelete", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -// EchoServiceServer is the server API for EchoService service. -type EchoServiceServer interface { - Echo(context.Context, *SimpleMessage) (*SimpleMessage, error) - EchoBody(context.Context, *SimpleMessage) (*SimpleMessage, error) - EchoDelete(context.Context, *SimpleMessage) (*SimpleMessage, error) -} - -// UnimplementedEchoServiceServer can be embedded to have forward compatible implementations. -type UnimplementedEchoServiceServer struct { -} - -func (*UnimplementedEchoServiceServer) Echo(context.Context, *SimpleMessage) (*SimpleMessage, error) { - return nil, status.Errorf(codes.Unimplemented, "method Echo not implemented") -} -func (*UnimplementedEchoServiceServer) EchoBody(context.Context, *SimpleMessage) (*SimpleMessage, error) { - return nil, status.Errorf(codes.Unimplemented, "method EchoBody not implemented") -} -func (*UnimplementedEchoServiceServer) EchoDelete(context.Context, *SimpleMessage) (*SimpleMessage, error) { - return nil, status.Errorf(codes.Unimplemented, "method EchoDelete not implemented") -} - -func RegisterEchoServiceServer(s *grpc.Server, srv EchoServiceServer) { - s.RegisterService(&_EchoService_serviceDesc, srv) -} - -func _EchoService_Echo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(SimpleMessage) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(EchoServiceServer).Echo(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/examples.EchoService/Echo", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(EchoServiceServer).Echo(ctx, req.(*SimpleMessage)) - } - return interceptor(ctx, in, info, handler) -} - -func _EchoService_EchoBody_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(SimpleMessage) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(EchoServiceServer).EchoBody(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/examples.EchoService/EchoBody", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(EchoServiceServer).EchoBody(ctx, req.(*SimpleMessage)) - } - return interceptor(ctx, in, info, handler) -} - -func _EchoService_EchoDelete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(SimpleMessage) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(EchoServiceServer).EchoDelete(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/examples.EchoService/EchoDelete", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(EchoServiceServer).EchoDelete(ctx, req.(*SimpleMessage)) - } - return interceptor(ctx, in, info, handler) -} - -var _EchoService_serviceDesc = grpc.ServiceDesc{ - ServiceName: "examples.EchoService", - HandlerType: (*EchoServiceServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "Echo", - Handler: _EchoService_Echo_Handler, - }, - { - MethodName: "EchoBody", - Handler: _EchoService_EchoBody_Handler, - }, - { - MethodName: "EchoDelete", - Handler: _EchoService_EchoDelete_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "proto/examples/echo_service.proto", -} diff --git a/proto/examples/echo_service.pb.gw.go b/proto/examples/echo_service.pb.gw.go index 349464c..f6d0b6a 100755 --- a/proto/examples/echo_service.pb.gw.go +++ b/proto/examples/echo_service.pb.gw.go @@ -2,11 +2,11 @@ // source: proto/examples/echo_service.proto /* -Package proto is a reverse proxy. +Package examples is a reverse proxy. It translates gRPC into RESTful JSON APIs. */ -package proto +package examples import ( "context" @@ -25,13 +25,13 @@ import ( "github.com/binchencoder/skylb-api/client" "github.com/binchencoder/skylb-api/client/option" skypb "github.com/binchencoder/skylb-api/proto" - "github.com/golang/protobuf/proto" - "github.com/grpc-ecosystem/grpc-gateway/utilities" + "github.com/grpc-ecosystem/grpc-gateway/v2/utilities" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/grpclog" "google.golang.org/grpc/naming" "google.golang.org/grpc/status" + "google.golang.org/protobuf/proto" ) // Suppress "imported and not used" errors @@ -61,7 +61,7 @@ var proto_examples_echo_service_error = lgr.ToGrpcError(codes.InvalidArgument, & // Validation methods start -func Validate__examples_SimpleMessage(v *SimpleMessage) error { +func Validate__grpc_gateway_proto_examples_SimpleMessage(v *SimpleMessage) error { if v == nil { return nil } @@ -134,7 +134,6 @@ func request_EchoService_Echo_0(ctx context.Context, marshaler runtime.Marshaler } protoReq.Id, err = runtime.String(val) - if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } @@ -150,7 +149,7 @@ func request_EchoService_Echo_0(ctx context.Context, marshaler runtime.Marshaler // Validate // SimpleMessage - if err := Validate__examples_SimpleMessage(&protoReq); err != nil { + if err := Validate__grpc_gateway_proto_examples_SimpleMessage(&protoReq); err != nil { runtime.RequestHandled(ctx, spec, "EchoService", "Echo", nil, &metadata, err) return nil, metadata, err } @@ -183,7 +182,6 @@ func local_request_EchoService_Echo_0(ctx context.Context, marshaler runtime.Mar } protoReq.Id, err = runtime.String(val) - if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } @@ -223,7 +221,6 @@ func request_EchoService_Echo_1(ctx context.Context, marshaler runtime.Marshaler } protoReq.Id, err = runtime.String(val) - if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } @@ -235,7 +232,6 @@ func request_EchoService_Echo_1(ctx context.Context, marshaler runtime.Marshaler } protoReq.Num, err = runtime.Int64(val) - if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "num", err) } @@ -251,7 +247,7 @@ func request_EchoService_Echo_1(ctx context.Context, marshaler runtime.Marshaler // Validate // SimpleMessage - if err := Validate__examples_SimpleMessage(&protoReq); err != nil { + if err := Validate__grpc_gateway_proto_examples_SimpleMessage(&protoReq); err != nil { runtime.RequestHandled(ctx, spec, "EchoService", "Echo", nil, &metadata, err) return nil, metadata, err } @@ -284,7 +280,6 @@ func local_request_EchoService_Echo_1(ctx context.Context, marshaler runtime.Mar } protoReq.Id, err = runtime.String(val) - if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } @@ -295,7 +290,6 @@ func local_request_EchoService_Echo_1(ctx context.Context, marshaler runtime.Mar } protoReq.Num, err = runtime.Int64(val) - if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "num", err) } @@ -335,7 +329,6 @@ func request_EchoService_Echo_2(ctx context.Context, marshaler runtime.Marshaler } protoReq.Id, err = runtime.String(val) - if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } @@ -347,7 +340,6 @@ func request_EchoService_Echo_2(ctx context.Context, marshaler runtime.Marshaler } protoReq.Num, err = runtime.Int64(val) - if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "num", err) } @@ -364,7 +356,6 @@ func request_EchoService_Echo_2(ctx context.Context, marshaler runtime.Marshaler return nil, metadata, status.Errorf(codes.InvalidArgument, "expect type: *SimpleMessage_Lang, but: %t\n", protoReq.Code) } protoReq.Code.(*SimpleMessage_Lang).Lang, err = runtime.String(val) - if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "lang", err) } @@ -380,7 +371,7 @@ func request_EchoService_Echo_2(ctx context.Context, marshaler runtime.Marshaler // Validate // SimpleMessage - if err := Validate__examples_SimpleMessage(&protoReq); err != nil { + if err := Validate__grpc_gateway_proto_examples_SimpleMessage(&protoReq); err != nil { runtime.RequestHandled(ctx, spec, "EchoService", "Echo", nil, &metadata, err) return nil, metadata, err } @@ -413,7 +404,6 @@ func local_request_EchoService_Echo_2(ctx context.Context, marshaler runtime.Mar } protoReq.Id, err = runtime.String(val) - if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } @@ -424,7 +414,6 @@ func local_request_EchoService_Echo_2(ctx context.Context, marshaler runtime.Mar } protoReq.Num, err = runtime.Int64(val) - if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "num", err) } @@ -440,7 +429,6 @@ func local_request_EchoService_Echo_2(ctx context.Context, marshaler runtime.Mar return nil, metadata, status.Errorf(codes.InvalidArgument, "expect type: *SimpleMessage_Lang, but: %t\n", protoReq.Code) } protoReq.Code.(*SimpleMessage_Lang).Lang, err = runtime.String(val) - if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "lang", err) } @@ -480,7 +468,6 @@ func request_EchoService_Echo_3(ctx context.Context, marshaler runtime.Marshaler } protoReq.Id, err = runtime.String(val) - if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } @@ -497,7 +484,6 @@ func request_EchoService_Echo_3(ctx context.Context, marshaler runtime.Marshaler return nil, metadata, status.Errorf(codes.InvalidArgument, "expect type: *SimpleMessage_LineNum, but: %t\n", protoReq.Code) } protoReq.Code.(*SimpleMessage_LineNum).LineNum, err = runtime.Int64(val) - if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "line_num", err) } @@ -509,7 +495,6 @@ func request_EchoService_Echo_3(ctx context.Context, marshaler runtime.Marshaler } err = runtime.PopulateFieldFromPath(&protoReq, "status.note", val) - if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "status.note", err) } @@ -525,7 +510,7 @@ func request_EchoService_Echo_3(ctx context.Context, marshaler runtime.Marshaler // Validate // SimpleMessage - if err := Validate__examples_SimpleMessage(&protoReq); err != nil { + if err := Validate__grpc_gateway_proto_examples_SimpleMessage(&protoReq); err != nil { runtime.RequestHandled(ctx, spec, "EchoService", "Echo", nil, &metadata, err) return nil, metadata, err } @@ -558,7 +543,6 @@ func local_request_EchoService_Echo_3(ctx context.Context, marshaler runtime.Mar } protoReq.Id, err = runtime.String(val) - if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) } @@ -574,7 +558,6 @@ func local_request_EchoService_Echo_3(ctx context.Context, marshaler runtime.Mar return nil, metadata, status.Errorf(codes.InvalidArgument, "expect type: *SimpleMessage_LineNum, but: %t\n", protoReq.Code) } protoReq.Code.(*SimpleMessage_LineNum).LineNum, err = runtime.Int64(val) - if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "line_num", err) } @@ -585,7 +568,6 @@ func local_request_EchoService_Echo_3(ctx context.Context, marshaler runtime.Mar } err = runtime.PopulateFieldFromPath(&protoReq, "status.note", val) - if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "status.note", err) } @@ -625,7 +607,6 @@ func request_EchoService_Echo_4(ctx context.Context, marshaler runtime.Marshaler } err = runtime.PopulateFieldFromPath(&protoReq, "no.note", val) - if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "no.note", err) } @@ -641,7 +622,7 @@ func request_EchoService_Echo_4(ctx context.Context, marshaler runtime.Marshaler // Validate // SimpleMessage - if err := Validate__examples_SimpleMessage(&protoReq); err != nil { + if err := Validate__grpc_gateway_proto_examples_SimpleMessage(&protoReq); err != nil { runtime.RequestHandled(ctx, spec, "EchoService", "Echo", nil, &metadata, err) return nil, metadata, err } @@ -674,7 +655,6 @@ func local_request_EchoService_Echo_4(ctx context.Context, marshaler runtime.Mar } err = runtime.PopulateFieldFromPath(&protoReq, "no.note", val) - if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "no.note", err) } @@ -709,7 +689,7 @@ func request_EchoService_EchoBody_0(ctx context.Context, marshaler runtime.Marsh // Validate // SimpleMessage - if err := Validate__examples_SimpleMessage(&protoReq); err != nil { + if err := Validate__grpc_gateway_proto_examples_SimpleMessage(&protoReq); err != nil { runtime.RequestHandled(ctx, spec, "EchoService", "EchoBody", nil, &metadata, err) return nil, metadata, err } @@ -762,7 +742,7 @@ func request_EchoService_EchoDelete_0(ctx context.Context, marshaler runtime.Mar // Validate // SimpleMessage - if err := Validate__examples_SimpleMessage(&protoReq); err != nil { + if err := Validate__grpc_gateway_proto_examples_SimpleMessage(&protoReq); err != nil { runtime.RequestHandled(ctx, spec, "EchoService", "EchoDelete", nil, &metadata, err) return nil, metadata, err } @@ -804,7 +784,7 @@ func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.proto.examples.EchoService/Echo") if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -824,7 +804,7 @@ func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.proto.examples.EchoService/Echo") if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -844,7 +824,7 @@ func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.proto.examples.EchoService/Echo") if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -864,7 +844,7 @@ func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.proto.examples.EchoService/Echo") if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -884,7 +864,7 @@ func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.proto.examples.EchoService/Echo") if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -904,7 +884,7 @@ func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.proto.examples.EchoService/EchoBody") if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -924,7 +904,7 @@ func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.proto.examples.EchoService/EchoDelete") if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -1010,12 +990,13 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) if client == nil { - runtime.DefaultOtherErrorHandler(w, req, "service disabled", http.StatusInternalServerError) + err := status.Error(codes.Internal, "service disabled") + runtime.HTTPError(inctx, mux, outboundMarshaler, w, req, err) return } - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) if err != nil { grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) @@ -1024,7 +1005,7 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux } ctx, cancel := context.WithCancel(req.Context()) defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.proto.examples.EchoService/Echo") if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -1046,12 +1027,13 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) if client == nil { - runtime.DefaultOtherErrorHandler(w, req, "service disabled", http.StatusInternalServerError) + err := status.Error(codes.Internal, "service disabled") + runtime.HTTPError(inctx, mux, outboundMarshaler, w, req, err) return } - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) if err != nil { grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) @@ -1060,7 +1042,7 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux } ctx, cancel := context.WithCancel(req.Context()) defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.proto.examples.EchoService/Echo") if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -1082,12 +1064,13 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) if client == nil { - runtime.DefaultOtherErrorHandler(w, req, "service disabled", http.StatusInternalServerError) + err := status.Error(codes.Internal, "service disabled") + runtime.HTTPError(inctx, mux, outboundMarshaler, w, req, err) return } - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) if err != nil { grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) @@ -1096,7 +1079,7 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux } ctx, cancel := context.WithCancel(req.Context()) defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.proto.examples.EchoService/Echo") if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -1118,12 +1101,13 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) if client == nil { - runtime.DefaultOtherErrorHandler(w, req, "service disabled", http.StatusInternalServerError) + err := status.Error(codes.Internal, "service disabled") + runtime.HTTPError(inctx, mux, outboundMarshaler, w, req, err) return } - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) if err != nil { grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) @@ -1132,7 +1116,7 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux } ctx, cancel := context.WithCancel(req.Context()) defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.proto.examples.EchoService/Echo") if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -1154,12 +1138,13 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) if client == nil { - runtime.DefaultOtherErrorHandler(w, req, "service disabled", http.StatusInternalServerError) + err := status.Error(codes.Internal, "service disabled") + runtime.HTTPError(inctx, mux, outboundMarshaler, w, req, err) return } - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) if err != nil { grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) @@ -1168,7 +1153,7 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux } ctx, cancel := context.WithCancel(req.Context()) defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.proto.examples.EchoService/Echo") if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -1190,12 +1175,13 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) if client == nil { - runtime.DefaultOtherErrorHandler(w, req, "service disabled", http.StatusInternalServerError) + err := status.Error(codes.Internal, "service disabled") + runtime.HTTPError(inctx, mux, outboundMarshaler, w, req, err) return } - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "EchoBody", w, req) if err != nil { grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) @@ -1204,7 +1190,7 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux } ctx, cancel := context.WithCancel(req.Context()) defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.proto.examples.EchoService/EchoBody") if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -1226,12 +1212,13 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) if client == nil { - runtime.DefaultOtherErrorHandler(w, req, "service disabled", http.StatusInternalServerError) + err := status.Error(codes.Internal, "service disabled") + runtime.HTTPError(inctx, mux, outboundMarshaler, w, req, err) return } - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "EchoDelete", w, req) if err != nil { grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) @@ -1240,7 +1227,7 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux } ctx, cancel := context.WithCancel(req.Context()) defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.proto.examples.EchoService/EchoDelete") if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -1304,19 +1291,19 @@ func DisableEchoService_Service() { } var ( - pattern_EchoService_Echo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"v1", "example", "echo", "id"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_EchoService_Echo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"v1", "example", "echo", "id"}, "")) - pattern_EchoService_Echo_1 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 1, 0, 4, 1, 5, 4}, []string{"v1", "example", "echo", "id", "num"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_EchoService_Echo_1 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 1, 0, 4, 1, 5, 4}, []string{"v1", "example", "echo", "id", "num"}, "")) - pattern_EchoService_Echo_2 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5}, []string{"v1", "example", "echo", "id", "num", "lang"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_EchoService_Echo_2 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5}, []string{"v1", "example", "echo", "id", "num", "lang"}, "")) - pattern_EchoService_Echo_3 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5}, []string{"v1", "example", "echo1", "id", "line_num", "status.note"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_EchoService_Echo_3 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5}, []string{"v1", "example", "echo1", "id", "line_num", "status.note"}, "")) - pattern_EchoService_Echo_4 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"v1", "example", "echo2", "no.note"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_EchoService_Echo_4 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"v1", "example", "echo2", "no.note"}, "")) - pattern_EchoService_EchoBody_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "example", "echo_body"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_EchoService_EchoBody_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "example", "echo_body"}, "")) - pattern_EchoService_EchoDelete_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "example", "echo_delete"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_EchoService_EchoDelete_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "example", "echo_delete"}, "")) ) var ( diff --git a/proto/examples/echo_service.proto b/proto/examples/echo_service.proto index 96b28b6..c0eb95e 100644 --- a/proto/examples/echo_service.proto +++ b/proto/examples/echo_service.proto @@ -1,15 +1,12 @@ syntax = "proto3"; -option go_package = "proto"; + +option go_package = "github.com/binchencoder/ease-gateway/gateway/proto/examples"; + +package grpc.gateway.proto.examples; option java_package = "com.binchencoder.easegw.examples"; option java_outer_classname = "ExamplesProto"; -// Echo Service -// -// Echo Service API consists of a single service which returns -// a message. -package examples; - // import "google/api/annotations.proto"; import "httpoptions/annotations.proto"; @@ -52,7 +49,7 @@ message SimpleMessage { rules: { type: NUMBER, operator: GT, - value: "0", + value: "0", } } ] diff --git a/proto/examples/echo_service.swagger.json b/proto/examples/echo_service.swagger.json index 4df8d71..8031bf2 100755 --- a/proto/examples/echo_service.swagger.json +++ b/proto/examples/echo_service.swagger.json @@ -1,8 +1,7 @@ { "swagger": "2.0", "info": { - "title": "Echo Service", - "description": "Echo Service API consists of a single service which returns\na message.", + "title": "proto/examples/echo_service.proto", "version": "version not set" }, "consumes": [ @@ -23,12 +22,6 @@ "schema": { "$ref": "#/definitions/examplesSimpleMessage" } - }, - "default": { - "description": "An unexpected error response", - "schema": { - "$ref": "#/definitions/gatewayruntimeError" - } } }, "parameters": [ @@ -56,12 +49,6 @@ "schema": { "$ref": "#/definitions/examplesSimpleMessage" } - }, - "default": { - "description": "An unexpected error response", - "schema": { - "$ref": "#/definitions/gatewayruntimeError" - } } }, "parameters": [ @@ -80,7 +67,7 @@ "format": "int64" }, { - "name": "line_num", + "name": "lineNum", "in": "query", "required": false, "type": "string", @@ -142,12 +129,6 @@ "schema": { "$ref": "#/definitions/examplesSimpleMessage" } - }, - "default": { - "description": "An unexpected error response", - "schema": { - "$ref": "#/definitions/gatewayruntimeError" - } } }, "parameters": [ @@ -172,7 +153,7 @@ "type": "string" }, { - "name": "line_num", + "name": "lineNum", "in": "query", "required": false, "type": "string", @@ -217,7 +198,7 @@ ] } }, - "/v1/example/echo1/{id}/{line_num}/{status.note}": { + "/v1/example/echo1/{id}/{lineNum}/{status.note}": { "get": { "summary": "Echo method receives a simple message and returns it.", "description": "The message posted as the id parameter will also be\nreturned.", @@ -228,12 +209,6 @@ "schema": { "$ref": "#/definitions/examplesSimpleMessage" } - }, - "default": { - "description": "An unexpected error response", - "schema": { - "$ref": "#/definitions/gatewayruntimeError" - } } }, "parameters": [ @@ -245,7 +220,7 @@ "type": "string" }, { - "name": "line_num", + "name": "lineNum", "in": "path", "required": true, "type": "string", @@ -308,12 +283,6 @@ "schema": { "$ref": "#/definitions/examplesSimpleMessage" } - }, - "default": { - "description": "An unexpected error response", - "schema": { - "$ref": "#/definitions/gatewayruntimeError" - } } }, "parameters": [ @@ -338,7 +307,7 @@ "format": "int64" }, { - "name": "line_num", + "name": "lineNum", "in": "query", "required": false, "type": "string", @@ -387,12 +356,6 @@ "schema": { "$ref": "#/definitions/examplesSimpleMessage" } - }, - "default": { - "description": "An unexpected error response", - "schema": { - "$ref": "#/definitions/gatewayruntimeError" - } } }, "parameters": [ @@ -420,12 +383,6 @@ "schema": { "$ref": "#/definitions/examplesSimpleMessage" } - }, - "default": { - "description": "An unexpected error response", - "schema": { - "$ref": "#/definitions/gatewayruntimeError" - } } }, "parameters": [ @@ -444,7 +401,7 @@ "format": "int64" }, { - "name": "line_num", + "name": "lineNum", "in": "query", "required": false, "type": "string", @@ -546,7 +503,7 @@ } ] }, - "line_num": { + "lineNum": { "type": "string", "format": "int64" }, @@ -565,113 +522,6 @@ } }, "description": "SimpleMessage represents a simple message sent to the Echo service." - }, - "frontendError": { - "type": "object", - "properties": { - "code": { - "$ref": "#/definitions/frontendErrorCode", - "description": "The general error code." - }, - "params": { - "type": "array", - "items": { - "type": "string" - }, - "description": "The general parameters with which to render a localized string." - }, - "debug": { - "type": "string", - "description": "The debug information. Only populated in DEV, TEST, and QA environment.\nIn PROD environment it will be stripped off before returning to the\nclient." - }, - "details": { - "type": "array", - "items": { - "$ref": "#/definitions/frontendErrorMessage" - }, - "description": "The detailed error messages." - } - }, - "description": "message GetMyMemosResponse {\n frontend.Error error = 1;\n\n int32 current_page = 2;\n int32 page_total = 3;\n string continue_token = 4;\n\n repeated MemoMsg memos = 5;\n }", - "title": "The error wrapper message. All frontend messages should contain exactly\none field with this message as the first field. Example:" - }, - "frontendErrorCode": { - "type": "string", - "enum": [ - "NONE", - "SERVICE_DOWN", - "SERVICE_INTERNAL_ERROR", - "SERVICE_INTERNAL_ACCIDENTAL_ERROR", - "SERVICE_BAD_PARAM_ERROR", - "SERVICE_UNREACHABLE_CODE", - "UNDEFINED", - "BADPARAM_ERROR", - "RESOURCE_NOT_FOUND", - "BAD_REQUEST", - "AUTHEN_ERROR", - "SERVER_ERROR", - "NORIGHT_ERROR", - "NODATA_ERROR", - "USER_ERROR", - "INVALID_SIGNATURE", - "IGOAL_DUPLICATE_TAG", - "IGOAL_NO_ONLINE_TMPL_MANAGE_PERMISSION", - "IGOAL_IMPORT_TEMPLATE_FILE_SIZE_EXCEEDED", - "IGOAL_VERSION_CONFLICT_ERROR", - "IGOAL_DOC_UPLOAD_FILE_NUMBER_EXCEEDED" - ], - "default": "NONE", - "description": "/### Enum for all error codes.\n/### Localization Guide for error codes. Error code which requires Localization\n/### need to provide a //@Trans chinese comment on the above line.\n\n - SERVICE_DOWN: /### 100000 - 120000 Common error\n@Trans 当前服务正在维护,请稍后再试.\n - SERVICE_INTERNAL_ERROR: @Trans 当前服务内部错误,请稍后再试.\n - SERVICE_INTERNAL_ACCIDENTAL_ERROR: @Trans 找不到意中的“它”,请稍后重试!\n - SERVICE_BAD_PARAM_ERROR: @Trans 程序参数错误.\n - SERVICE_UNREACHABLE_CODE: @Trans 程序编码错误.\n - UNDEFINED: @Trans Undefined error.\n - BADPARAM_ERROR: @Trans 参数不合法\n - RESOURCE_NOT_FOUND: @Trans 无法找到\n - BAD_REQUEST: @Trans 无效请求\n - AUTHEN_ERROR: /### 500500-500999: Common error codes.\n@Trans 用户认证失败,需重新登录\n - SERVER_ERROR: @Trans 服务器端错误\n - NORIGHT_ERROR: @Trans 权限不足\n - NODATA_ERROR: @Trans 数据不存在或已删除\n - USER_ERROR: @Trans 用户不存在或已停用\n - INVALID_SIGNATURE: @Trans 无效验签\n - IGOAL_DUPLICATE_TAG: @Trans 主线分类名称重复!\n - IGOAL_NO_ONLINE_TMPL_MANAGE_PERMISSION: @Trans 您无权限进行此操作!\n - IGOAL_IMPORT_TEMPLATE_FILE_SIZE_EXCEEDED: @Trans 模板文件大小超限!\n - IGOAL_VERSION_CONFLICT_ERROR: @Trans 系统开小差了,请稍后尝试!\n - IGOAL_DOC_UPLOAD_FILE_NUMBER_EXCEEDED: @Trans 上传文件数量超过上限!" - }, - "frontendErrorMessage": { - "type": "object", - "properties": { - "code": { - "$ref": "#/definitions/frontendErrorCode", - "description": "The error code." - }, - "params": { - "type": "array", - "items": { - "type": "string" - }, - "description": "The parameters used to render a localized string." - } - }, - "description": "An error message including its error code and the parameters to render\na localized string." - }, - "gatewayruntimeError": { - "type": "object", - "properties": { - "error": { - "$ref": "#/definitions/frontendError" - }, - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "$ref": "#/definitions/protobufAny" - } - } - } - }, - "protobufAny": { - "type": "object", - "properties": { - "type_url": { - "type": "string" - }, - "value": { - "type": "string", - "format": "byte" - } - } } } } diff --git a/proto/examples/echo_service_grpc.pb.go b/proto/examples/echo_service_grpc.pb.go new file mode 100755 index 0000000..be3e2a5 --- /dev/null +++ b/proto/examples/echo_service_grpc.pb.go @@ -0,0 +1,158 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. + +package examples + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// 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.SupportPackageIsVersion6 + +// EchoServiceClient is the client API for EchoService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type EchoServiceClient interface { + Echo(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) + EchoBody(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) + EchoDelete(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) +} + +type echoServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewEchoServiceClient(cc grpc.ClientConnInterface) EchoServiceClient { + return &echoServiceClient{cc} +} + +func (c *echoServiceClient) Echo(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) { + out := new(SimpleMessage) + err := c.cc.Invoke(ctx, "/grpc.gateway.proto.examples.EchoService/Echo", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *echoServiceClient) EchoBody(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) { + out := new(SimpleMessage) + err := c.cc.Invoke(ctx, "/grpc.gateway.proto.examples.EchoService/EchoBody", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *echoServiceClient) EchoDelete(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) { + out := new(SimpleMessage) + err := c.cc.Invoke(ctx, "/grpc.gateway.proto.examples.EchoService/EchoDelete", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// EchoServiceServer is the server API for EchoService service. +type EchoServiceServer interface { + Echo(context.Context, *SimpleMessage) (*SimpleMessage, error) + EchoBody(context.Context, *SimpleMessage) (*SimpleMessage, error) + EchoDelete(context.Context, *SimpleMessage) (*SimpleMessage, error) +} + +// UnimplementedEchoServiceServer can be embedded to have forward compatible implementations. +type UnimplementedEchoServiceServer struct { +} + +func (*UnimplementedEchoServiceServer) Echo(context.Context, *SimpleMessage) (*SimpleMessage, error) { + return nil, status.Errorf(codes.Unimplemented, "method Echo not implemented") +} +func (*UnimplementedEchoServiceServer) EchoBody(context.Context, *SimpleMessage) (*SimpleMessage, error) { + return nil, status.Errorf(codes.Unimplemented, "method EchoBody not implemented") +} +func (*UnimplementedEchoServiceServer) EchoDelete(context.Context, *SimpleMessage) (*SimpleMessage, error) { + return nil, status.Errorf(codes.Unimplemented, "method EchoDelete not implemented") +} + +func RegisterEchoServiceServer(s *grpc.Server, srv EchoServiceServer) { + s.RegisterService(&_EchoService_serviceDesc, srv) +} + +func _EchoService_Echo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SimpleMessage) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(EchoServiceServer).Echo(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/grpc.gateway.proto.examples.EchoService/Echo", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(EchoServiceServer).Echo(ctx, req.(*SimpleMessage)) + } + return interceptor(ctx, in, info, handler) +} + +func _EchoService_EchoBody_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SimpleMessage) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(EchoServiceServer).EchoBody(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/grpc.gateway.proto.examples.EchoService/EchoBody", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(EchoServiceServer).EchoBody(ctx, req.(*SimpleMessage)) + } + return interceptor(ctx, in, info, handler) +} + +func _EchoService_EchoDelete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SimpleMessage) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(EchoServiceServer).EchoDelete(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/grpc.gateway.proto.examples.EchoService/EchoDelete", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(EchoServiceServer).EchoDelete(ctx, req.(*SimpleMessage)) + } + return interceptor(ctx, in, info, handler) +} + +var _EchoService_serviceDesc = grpc.ServiceDesc{ + ServiceName: "grpc.gateway.proto.examples.EchoService", + HandlerType: (*EchoServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Echo", + Handler: _EchoService_Echo_Handler, + }, + { + MethodName: "EchoBody", + Handler: _EchoService_EchoBody_Handler, + }, + { + MethodName: "EchoDelete", + Handler: _EchoService_EchoDelete_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "proto/examples/echo_service.proto", +} diff --git a/repositories.bzl b/repositories.bzl index 5ba76ca..42d2e23 100644 --- a/repositories.bzl +++ b/repositories.bzl @@ -20,11 +20,20 @@ def go_repositories(): version = "v0.0.5", ) + # go_repository( + # name = "com_github_grpc_ecosystem_grpc_gateway", + # importpath = "github.com/grpc-ecosystem/grpc-gateway", + # sum = "h1:8ERzHx8aj1Sc47mu9n/AksaKCSWrMchFtkdrS4BIj5o=", + # version = "v1.14.6", + # ) go_repository( name = "com_github_grpc_ecosystem_grpc_gateway", importpath = "github.com/grpc-ecosystem/grpc-gateway", - sum = "h1:8ERzHx8aj1Sc47mu9n/AksaKCSWrMchFtkdrS4BIj5o=", - version = "v1.14.6", + urls = [ + "https://codeload.github.com/grpc-ecosystem/grpc-gateway/tar.gz/5c1639cccb7d6abc747643ed07321b0052b809d5", + ], + strip_prefix = "grpc-gateway-5c1639cccb7d6abc747643ed07321b0052b809d5", + type = "tar.gz", ) go_repository( name = "com_github_grpc_ecosystem_grpc_opentracing", @@ -71,8 +80,8 @@ def go_repositories(): go_repository( name = "com_github_golang_protobuf", importpath = "github.com/golang/protobuf", - sum = "h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=", - version = "v1.3.3", + sum = "h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=", + version = "v1.4.2", ) go_repository( name = "com_github_google_uuid", @@ -80,6 +89,12 @@ def go_repositories(): sum = "h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=", version = "v1.1.1", ) + go_repository( + name = "com_github_google_go_cmp", + importpath = "github.com/google/go-cmp", + sum = "h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=", + version = "v0.5.0", + ) go_repository( name = "com_github_klauspost_cpuid", importpath = "github.com/klauspost/cpuid", @@ -207,6 +222,24 @@ def go_repositories(): sum = "h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk=", version = "v1.27.1", ) + go_repository( + name = "org_golang_google_grpc_cmd_protoc_gen_go_grpc", + importpath = "google.golang.org/grpc/cmd/protoc-gen-go-grpc", + sum = "h1:KNluVV5ay+orsSPJ6XTpwJQ8qBhrBkOTmtBFGeDlBcY=", + version = "v0.0.0-20200527211525-6c9e30c09db2", + ) + go_repository( + name = "org_golang_google_protobuf", + importpath = "google.golang.org/protobuf", + sum = "h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=", + version = "v1.25.0", + ) + go_repository( + name = "org_golang_x_xerrors", + importpath = "golang.org/x/xerrors", + sum = "h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=", + version = "v0.0.0-20191204190536-9bdfabe68543", + ) go_repository( name = "org_golang_x_oauth2", importpath = "golang.org/x/oauth2", From ae113b3427d5f121ddf188e0cba8a515b4439e1b Mon Sep 17 00:00:00 2001 From: binchen Date: Wed, 28 Oct 2020 17:09:29 +0800 Subject: [PATCH 24/56] Add Issues.md --- Issues.md | 71 +++++++++++++++++++++++++++++++++++++ WORKSPACE | 4 +-- gateway/runtime/BUILD.bazel | 14 ++++---- integrate/BUILD.bazel | 2 +- repositories.bzl | 6 ++++ 5 files changed, 87 insertions(+), 10 deletions(-) create mode 100644 Issues.md diff --git a/Issues.md b/Issues.md new file mode 100644 index 0000000..249004e --- /dev/null +++ b/Issues.md @@ -0,0 +1,71 @@ +# Issues + +## 依赖版本问题 + +1. org_golang_google_grpc + ```go + go_repository( + name = "org_golang_google_grpc", + importpath = "google.golang.org/grpc", + sum = "h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk=", + version = "v1.27.1", + ) + ``` + + ```go + go_repository( + name = "org_golang_google_grpc", + importpath = "google.golang.org/grpc", + sum = "h1:DGeFlSan2f+WEtCERJ4J9GJWk15TxUi8QGagfI87Xyc=", + version = "v1.33.1", + ) + ``` + + org_golang_google_grpc 最新版本已经升级到v1.33.1,编译会出现如下error: + + ```verilog + chenbin@chenbin-ThinkPad:~/.../github-workspace/ease-gateway$ bazel build gateway/... + ERROR: /home/chenbin/.cache/bazel/_bazel_chenbin/95d98bab223e52f58e53a4599e22df3c/external/com_github_binchencoder_skylb_api/balancer/BUILD:5:1: no such package '@org_golang_google_grpc//naming': BUILD file not found in directory 'naming' of external repository @org_golang_google_grpc. Add a BUILD file to a directory to mark it as a package. and referenced by '@com_github_binchencoder_skylb_api//balancer:go_default_library' + ERROR: Analysis of target '//gateway/runtime:go_default_test' failed; build aborted: no such package '@org_golang_google_grpc//naming': BUILD file not found in directory 'naming' of external repository @org_golang_google_grpc. Add a BUILD file to a directory to mark it as a package. + INFO: Elapsed time: 3.781s + INFO: 0 processes. + FAILED: Build did NOT complete successfully (43 packages loaded, 588 targets configured) + ``` + +2. org_golang_google_grpc_cmd_protoc_gen_go_grpc + + ```go + go_repository( + name = "org_golang_google_grpc_cmd_protoc_gen_go_grpc", + importpath = "google.golang.org/grpc/cmd/protoc-gen-go-grpc", + sum = "h1:KNluVV5ay+orsSPJ6XTpwJQ8qBhrBkOTmtBFGeDlBcY=", + version = "v0.0.0-20200527211525-6c9e30c09db2", + ) + ``` + + ```go + go_repository( + name = "org_golang_google_grpc_cmd_protoc_gen_go_grpc", + importpath = "google.golang.org/grpc/cmd/protoc-gen-go-grpc", + sum = "h1:lQ+dE99pFsb8osbJB3oRfE5eW4Hx6a/lZQr8Jh+eoT4=", + version = "v1.0.0", + ) + ``` + + github.com/grpc-ecosystem/grpc-gateway 使用 org_golang_google_grpc_cmd_protoc_gen_go_grpc的版本是v1.0.0,ease-gateway 升级会出现如下error: + + ```verilog + chenbin@chenbin-ThinkPad:~/.../github-workspace/ease-gateway$ bazel build gateway/... + INFO: Analyzed 32 targets (103 packages loaded, 1391 targets configured). + INFO: Found 32 targets... + ERROR: /home/chenbin/.cache/bazel/_bazel_chenbin/95d98bab223e52f58e53a4599e22df3c/external/com_github_grpc_ecosystem_grpc_gateway/runtime/internal/examplepb/BUILD.bazel:39:1: GoCompilePkg external/com_github_grpc_ecosystem_grpc_gateway/runtime/internal/examplepb/go_default_library.a failed (Exit 1) builder failed: error executing command bazel-out/host/bin/external/go_sdk/builder compilepkg -sdk external/go_sdk -installsuffix linux_amd64 -src ... (remaining 67 argument(s) skipped) + + Use --sandbox_debug to see verbose messages from the sandbox + /home/chenbin/.cache/bazel/_bazel_chenbin/95d98bab223e52f58e53a4599e22df3c/sandbox/linux-sandbox/845/execroot/com_github_binchencoder_ease_gateway/bazel-out/k8-fastbuild/bin/external/com_github_grpc_ecosystem_grpc_gateway/runtime/internal/examplepb/examplepb_go_proto_/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/internal/examplepb/non_standard_names_grpc.pb.go:14:11: undefined: grpc.SupportPackageIsVersion7 + compilepkg: error running subcommand external/go_sdk/pkg/tool/linux_amd64/compile: exit status 2 + INFO: Elapsed time: 11.320s, Critical Path: 1.12s + INFO: 5 processes: 5 linux-sandbox. + FAILED: Build did NOT complete successfully + ``` + + \ No newline at end of file diff --git a/WORKSPACE b/WORKSPACE index 9b82e53..da0019c 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -5,9 +5,9 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") # ----------从github下载扩展 io_bazel_rules_go ---------- http_archive( name = "io_bazel_rules_go", - sha256 = "a8d6b1b354d371a646d2f7927319974e0f9e52f73a2452d2b3877118169eb6bb", + sha256 = "d1ffd055969c8f8d431e2d439813e42326961d0942bdf734d2c95dc30c369566", urls = [ - "https://github.com/bazelbuild/rules_go/releases/download/v0.23.3/rules_go-v0.23.3.tar.gz", + "https://github.com/bazelbuild/rules_go/releases/download/v0.24.5/rules_go-v0.24.5.tar.gz", ], ) diff --git a/gateway/runtime/BUILD.bazel b/gateway/runtime/BUILD.bazel index ed32a61..30ab37b 100644 --- a/gateway/runtime/BUILD.bazel +++ b/gateway/runtime/BUILD.bazel @@ -19,8 +19,8 @@ go_library( "@com_github_binchencoder_skylb_api//proto:go_default_library", "@com_github_golang_protobuf//ptypes:go_default_library_gen", "@com_github_grpc_ecosystem_grpc_gateway//utilities:go_default_library", - "@com_github_grpc_ecosystem_grpc_gateway//internal/httprule:go_default_library", - "@com_github_pborman_uuid//:go_default_library", + "@com_github_grpc_ecosystem_grpc_gateway//internal/httprule:go_default_library", + "@com_github_pborman_uuid//:go_default_library", "@com_github_golang_protobuf//jsonpb:go_default_library_gen", "@go_googleapis//google/api:httpbody_go_proto", "@io_bazel_rules_go//proto/wkt:duration_go_proto", @@ -35,7 +35,7 @@ go_library( "@org_golang_google_protobuf//proto:go_default_library", "@org_golang_google_protobuf//reflect/protoreflect:go_default_library", "@org_golang_google_protobuf//reflect/protoregistry:go_default_library", - "@org_golang_google_grpc//:go_default_library", + "@org_golang_google_grpc//:go_default_library", "@org_golang_x_net//context:go_default_library", ], ) @@ -59,12 +59,12 @@ go_test( deps = [ "//examples/proto:go_default_library", "//gateway/internal:go_default_library", - "//gateway/runtime/internal/examplepb:go_default_library", + "//gateway/runtime/internal/examplepb:go_default_library", "//httpoptions:go_default_library", "@com_github_binchencoder_letsgo//hashring:go_default_library", "@com_github_binchencoder_skylb_api//proto:go_default_library", "@com_github_grpc_ecosystem_grpc_gateway//utilities:go_default_library", - "@com_github_grpc_ecosystem_grpc_gateway//runtime/internal/examplepb:go_default_library", + "@com_github_grpc_ecosystem_grpc_gateway//runtime/internal/examplepb:go_default_library", "@com_github_golang_protobuf//ptypes:go_default_library_gen", "@com_github_golang_protobuf//proto:go_default_library", "@com_github_google_go_cmp//cmp:go_default_library", @@ -84,7 +84,7 @@ go_test( "@org_golang_google_protobuf//encoding/protojson:go_default_library", "@org_golang_google_protobuf//proto:go_default_library", "@org_golang_google_protobuf//testing/protocmp:go_default_library", - "@org_golang_google_grpc//:go_default_library", - "@org_golang_x_net//context:go_default_library", + "@org_golang_google_grpc//:go_default_library", + "@org_golang_x_net//context:go_default_library", ], ) diff --git a/integrate/BUILD.bazel b/integrate/BUILD.bazel index 93b83c5..477ee7c 100755 --- a/integrate/BUILD.bazel +++ b/integrate/BUILD.bazel @@ -13,9 +13,9 @@ go_library( "//httpoptions:go_default_library", "//gateway/runtime:go_default_library", "//integrate/metrics:go_default_library", + "//util:go_default_library", "@com_github_binchencoder_gateway_proto//data:go_default_library", "@com_github_binchencoder_gateway_proto//frontend:go_default_library", - "//util:go_default_library", "@com_github_binchencoder_letsgo//grpc:go_default_library", "@com_github_binchencoder_letsgo//trace:go_default_library", "@com_github_golang_protobuf//proto:go_default_library", diff --git a/repositories.bzl b/repositories.bzl index 42d2e23..a73ce5e 100644 --- a/repositories.bzl +++ b/repositories.bzl @@ -216,6 +216,12 @@ def go_repositories(): version = "v3.0.0-20200615113413-eeeca48fe776", ) + go_repository( + name = "org_golang_google_genproto", + importpath = "google.golang.org/genproto", + sum = "h1:d4k3uIU763E31Rk4UZPA47oOoBymMsDImV3U4mGhX9E=", + version = "v0.0.0-20201026171402-d4b8fe4fd877", + ) go_repository( name = "org_golang_google_grpc", importpath = "google.golang.org/grpc", From fe6c67c5bd6b166b7a847595dbf138bf14171adb Mon Sep 17 00:00:00 2001 From: binchen Date: Thu, 29 Oct 2020 16:14:02 +0800 Subject: [PATCH 25/56] Update based on github.com/grpc-ecosystem/grpc-gateway master branch. grpc-gateway updated on 2020/10/28 --- WORKSPACE | 75 +- gateway/internal/codegenerator/BUILD.bazel | 28 - gateway/internal/codegenerator/doc.go | 4 - gateway/internal/codegenerator/parse_req.go | 23 - .../internal/codegenerator/parse_req_test.go | 72 - gateway/internal/descriptor/BUILD.bazel | 12 +- .../descriptor/apiconfig/apiconfig.pb.go | 171 ++ .../descriptor/openapi_configuration.go | 59 + .../descriptor/openapi_configuration_test.go | 115 + .../descriptor/openapiconfig/BUILD.bazel | 26 + .../openapiconfig/openapiconfig.pb.go | 689 +++++ .../openapiconfig/openapiconfig.proto | 51 + gateway/internal/descriptor/registry.go | 265 +- gateway/internal/descriptor/registry_test.go | 293 +- gateway/internal/descriptor/services.go | 36 +- gateway/internal/descriptor/services_test.go | 94 +- gateway/internal/descriptor/types.go | 61 +- gateway/internal/generator/generator.go | 7 +- gateway/protoc-gen-grpc-gateway/BUILD.bazel | 17 +- .../internal/gengateway/BUILD.bazel | 7 +- .../internal/gengateway/generator.go | 87 +- .../internal/gengateway/generator_test.go | 187 +- .../internal/gengateway/template.go | 1 + .../internal/gengateway/template_test.go | 3 +- gateway/protoc-gen-grpc-gateway/main.go | 159 +- gateway/protoc-gen-grpc-gateway/main_test.go | 32 + gateway/protoc-gen-openapiv2/BUILD.bazel | 6 +- gateway/protoc-gen-openapiv2/defs.bzl | 11 +- .../internal/genopenapi/BUILD.bazel | 22 +- .../internal/genopenapi/generator.go | 22 +- .../internal/genopenapi/template.go | 143 +- .../internal/genopenapi/template_test.go | 1462 +++++++-- gateway/protoc-gen-openapiv2/main.go | 21 +- .../protoc-gen-openapiv2/options/BUILD.bazel | 1 - .../options/annotations.pb.go | 242 ++ .../options/openapiv2.pb.go | 2615 +++++++++++++++++ .../options/openapiv2.proto | 6 +- gateway/runtime/BUILD.bazel | 12 +- gateway/runtime/context.go | 63 +- gateway/runtime/errors.go | 22 + gateway/runtime/fieldmask.go | 68 +- gateway/runtime/mux.go | 25 +- gateway/runtime/mux_test.go | 17 +- integrate/BUILD.bazel | 2 +- repositories.bzl | 101 +- 45 files changed, 6307 insertions(+), 1128 deletions(-) delete mode 100644 gateway/internal/codegenerator/BUILD.bazel delete mode 100644 gateway/internal/codegenerator/doc.go delete mode 100644 gateway/internal/codegenerator/parse_req.go delete mode 100644 gateway/internal/codegenerator/parse_req_test.go create mode 100644 gateway/internal/descriptor/apiconfig/apiconfig.pb.go create mode 100644 gateway/internal/descriptor/openapi_configuration.go create mode 100644 gateway/internal/descriptor/openapi_configuration_test.go create mode 100644 gateway/internal/descriptor/openapiconfig/BUILD.bazel create mode 100644 gateway/internal/descriptor/openapiconfig/openapiconfig.pb.go create mode 100644 gateway/internal/descriptor/openapiconfig/openapiconfig.proto create mode 100644 gateway/protoc-gen-grpc-gateway/main_test.go create mode 100644 gateway/protoc-gen-openapiv2/options/annotations.pb.go create mode 100644 gateway/protoc-gen-openapiv2/options/openapiv2.pb.go diff --git a/WORKSPACE b/WORKSPACE index da0019c..8bf12d5 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -2,11 +2,40 @@ workspace(name = "com_github_binchencoder_ease_gateway") load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") -# ----------从github下载扩展 io_bazel_rules_go ---------- +http_archive( + name = "bazel_skylib", + sha256 = "1c531376ac7e5a180e0237938a2536de0c54d93f5c278634818e0efc952dd56c", + urls = [ + "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.0.3/bazel-skylib-1.0.3.tar.gz", + "https://github.com/bazelbuild/bazel-skylib/releases/download/1.0.3/bazel-skylib-1.0.3.tar.gz", + ], +) + +load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace") + +bazel_skylib_workspace() + +http_archive( + name = "rules_proto", + sha256 = "602e7161d9195e50246177e7c55b2f39950a9cf7366f74ed5f22fd45750cd208", + strip_prefix = "rules_proto-97d8af4dc474595af3900dd85cb3a29ad28cc313", + urls = [ + "https://mirror.bazel.build/github.com/bazelbuild/rules_proto/archive/97d8af4dc474595af3900dd85cb3a29ad28cc313.tar.gz", + "https://github.com/bazelbuild/rules_proto/archive/97d8af4dc474595af3900dd85cb3a29ad28cc313.tar.gz", + ], +) + +load("@rules_proto//proto:repositories.bzl", "rules_proto_dependencies", "rules_proto_toolchains") + +rules_proto_dependencies() + +rules_proto_toolchains() + http_archive( name = "io_bazel_rules_go", sha256 = "d1ffd055969c8f8d431e2d439813e42326961d0942bdf734d2c95dc30c369566", urls = [ + "https://storage.googleapis.com/bazel-mirror/github.com/bazelbuild/rules_go/releases/download/v0.24.5/rules_go-v0.24.5.tar.gz", "https://github.com/bazelbuild/rules_go/releases/download/v0.24.5/rules_go-v0.24.5.tar.gz", ], ) @@ -15,28 +44,26 @@ http_archive( # 一般来说都会使用gazelle工具来自动生成 BUILD 文件, 而不是手写. http_archive( name = "bazel_gazelle", - sha256 = "cdb02a887a7187ea4d5a27452311a75ed8637379a1287d8eeb952138ea485f7d", + sha256 = "b85f48fa105c4403326e9525ad2b2cc437babaa6e15a3fc0b1dbab0ab064bc7c", urls = [ - "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.21.1/bazel-gazelle-v0.21.1.tar.gz", + "https://storage.googleapis.com/bazel-mirror/github.com/bazelbuild/bazel-gazelle/releases/download/v0.22.2/bazel-gazelle-v0.22.2.tar.gz", + "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.22.2/bazel-gazelle-v0.22.2.tar.gz", ], ) - # 从下载的扩展里载入 go_rules_dependencies go_register_toolchains 函数 load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies") - # 注册一堆常用依赖 如github.com/google/protobuf golang.org/x/net go_rules_dependencies() - # 下载golang工具链 go_register_toolchains() load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies", "go_repository") - # 加载gazelle依赖 gazelle_dependencies() # Use gazelle to declare Go dependencies in Bazel. # gazelle:repository_macro repositories.bzl%go_repositories + load("//:repositories.bzl", "go_repositories") go_repositories() @@ -64,43 +91,15 @@ protobuf_deps() # ---------- com_github_bazelbuild_buildtools ---------- http_archive( name = "com_github_bazelbuild_buildtools", - sha256 = "f11fc80da0681a6d64632a850346ed2d4e5cbb0908306d9a2a2915f707048a10", - strip_prefix = "buildtools-3.3.0", - urls = ["https://github.com/bazelbuild/buildtools/archive/3.3.0.tar.gz"], + sha256 = "a02ba93b96a8151b5d8d3466580f6c1f7e77212c4eb181cba53eb2cae7752a23", + strip_prefix = "buildtools-3.5.0", + urls = ["https://github.com/bazelbuild/buildtools/archive/3.5.0.tar.gz"], ) load("@com_github_bazelbuild_buildtools//buildifier:deps.bzl", "buildifier_dependencies") buildifier_dependencies() -go_repository( - name = "org_golang_x_net", - importpath = "golang.org/x/net", - sum = "h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4=", - version = "v0.0.0-20200625001655-4c5254603344", -) - -go_repository( - name = "org_golang_x_sys", - importpath = "golang.org/x/sys", - sum = "h1:Ih9Yo4hSPImZOpfGuA4bR/ORKTAbhZo2AbWNRCnevdo=", - version = "v0.0.0-20200625212154-ddb9806d33ae", -) - -go_repository( - name = "org_golang_x_text", - importpath = "golang.org/x/text", - sum = "h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=", - version = "v0.3.3", -) - -go_repository( - name = "org_golang_x_tools", - importpath = "golang.org/x/tools", - sum = "h1:/e4fNMHdLn7SQSxTrRZTma2xjQW6ELdxcnpqMhpo9X4=", - version = "v0.0.0-20200702044944-0cc1aa72b347", -) - # ---------- local repositories # local_repository( # name = "com_github_binchencoder_gateway_proto", diff --git a/gateway/internal/codegenerator/BUILD.bazel b/gateway/internal/codegenerator/BUILD.bazel deleted file mode 100644 index fd9ba63..0000000 --- a/gateway/internal/codegenerator/BUILD.bazel +++ /dev/null @@ -1,28 +0,0 @@ -load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") - -package(default_visibility = ["//visibility:public"]) - -go_library( - name = "go_default_library", - srcs = [ - "doc.go", - "parse_req.go", - ], - importpath = "github.com/binchencoder/ease-gateway/gateway/internal/codegenerator", - deps = [ - "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", - "@org_golang_google_protobuf//proto:go_default_library", - ], -) - -go_test( - name = "go_default_test", - srcs = ["parse_req_test.go"], - embed = [":go_default_library"], - deps = [ - "@com_github_google_go_cmp//cmp:go_default_library", - "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", - "@org_golang_google_protobuf//proto:go_default_library", - "@org_golang_google_protobuf//testing/protocmp:go_default_library", - ], -) diff --git a/gateway/internal/codegenerator/doc.go b/gateway/internal/codegenerator/doc.go deleted file mode 100644 index 3645317..0000000 --- a/gateway/internal/codegenerator/doc.go +++ /dev/null @@ -1,4 +0,0 @@ -/* -Package codegenerator contains reusable functions used by the code generators. -*/ -package codegenerator diff --git a/gateway/internal/codegenerator/parse_req.go b/gateway/internal/codegenerator/parse_req.go deleted file mode 100644 index dd489f0..0000000 --- a/gateway/internal/codegenerator/parse_req.go +++ /dev/null @@ -1,23 +0,0 @@ -package codegenerator - -import ( - "fmt" - "io" - "io/ioutil" - - pluginpb "github.com/golang/protobuf/protoc-gen-go/plugin" - "google.golang.org/protobuf/proto" -) - -// ParseRequest parses a code generator request from a proto Message. -func ParseRequest(r io.Reader) (*pluginpb.CodeGeneratorRequest, error) { - input, err := ioutil.ReadAll(r) - if err != nil { - return nil, fmt.Errorf("failed to read code generator request: %v", err) - } - req := new(pluginpb.CodeGeneratorRequest) - if err = proto.Unmarshal(input, req); err != nil { - return nil, fmt.Errorf("failed to unmarshal code generator request: %v", err) - } - return req, nil -} diff --git a/gateway/internal/codegenerator/parse_req_test.go b/gateway/internal/codegenerator/parse_req_test.go deleted file mode 100644 index c4926eb..0000000 --- a/gateway/internal/codegenerator/parse_req_test.go +++ /dev/null @@ -1,72 +0,0 @@ -package codegenerator_test - -import ( - "bytes" - "fmt" - "io" - "reflect" - "strings" - "testing" - - pluginpb "github.com/golang/protobuf/protoc-gen-go/plugin" - "github.com/google/go-cmp/cmp" - // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/codegenerator" - "github.com/binchencoder/ease-gateway/gateway/internal/codegenerator" - "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/testing/protocmp" -) - -var parseReqTests = []struct { - name string - in io.Reader - out *pluginpb.CodeGeneratorRequest - err error -}{ - { - "Empty input should produce empty output", - mustGetReader(&pluginpb.CodeGeneratorRequest{}), - &pluginpb.CodeGeneratorRequest{}, - nil, - }, - { - "Invalid reader should produce error", - &invalidReader{}, - nil, - fmt.Errorf("failed to read code generator request: invalid reader"), - }, - { - "Invalid proto message should produce error", - strings.NewReader("{}"), - nil, - fmt.Errorf("failed to unmarshal code generator request: unexpected EOF"), - }, -} - -func TestParseRequest(t *testing.T) { - for _, tt := range parseReqTests { - t.Run(tt.name, func(t *testing.T) { - out, err := codegenerator.ParseRequest(tt.in) - if !reflect.DeepEqual(err, tt.err) { - t.Errorf("got %v, want %v", err, tt.err) - } - if diff := cmp.Diff(out, tt.out, protocmp.Transform()); diff != "" { - t.Errorf(diff) - } - }) - } -} - -func mustGetReader(pb proto.Message) io.Reader { - b, err := proto.Marshal(pb) - if err != nil { - panic(err) - } - return bytes.NewBuffer(b) -} - -type invalidReader struct { -} - -func (*invalidReader) Read(p []byte) (int, error) { - return 0, fmt.Errorf("invalid reader") -} diff --git a/gateway/internal/descriptor/BUILD.bazel b/gateway/internal/descriptor/BUILD.bazel index 2b846ca..2b766e2 100644 --- a/gateway/internal/descriptor/BUILD.bazel +++ b/gateway/internal/descriptor/BUILD.bazel @@ -6,6 +6,7 @@ go_library( name = "go_default_library", srcs = [ "grpc_api_configuration.go", + "openapi_configuration.go", "registry.go", "services.go", "types.go", @@ -14,15 +15,20 @@ go_library( deps = [ "//gateway/internal/casing:go_default_library", "//gateway/internal/descriptor/apiconfig:go_default_library", + "//gateway/internal/descriptor/openapiconfig:go_default_library", + "//gateway/protoc-gen-openapiv2/options:go_default_library", "//httpoptions:go_default_library", "@com_github_binchencoder_gateway_proto//data:go_default_library", "@com_github_ghodss_yaml//:go_default_library", "@com_github_golang_glog//:go_default_library", "@com_github_grpc_ecosystem_grpc_gateway//internal/httprule:go_default_library", + "@org_golang_google_protobuf//compiler/protogen:go_default_library", "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", "@io_bazel_rules_go//proto/wkt:descriptor_go_proto", "@org_golang_google_protobuf//encoding/protojson:go_default_library", "@org_golang_google_protobuf//proto:go_default_library", + "@org_golang_google_protobuf//types/descriptorpb:go_default_library", + "@org_golang_google_protobuf//types/pluginpb:go_default_library", ], ) @@ -38,9 +44,11 @@ go_test( embed = [":go_default_library"], deps = [ "@com_github_grpc_ecosystem_grpc_gateway//internal/httprule:go_default_library", - "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", - "@io_bazel_rules_go//proto/wkt:descriptor_go_proto", + "//gateway/protoc-gen-openapiv2/options:go_default_library", + "@org_golang_google_protobuf//compiler/protogen:go_default_library", "@org_golang_google_protobuf//encoding/prototext:go_default_library", "@org_golang_google_protobuf//proto:go_default_library", + "@org_golang_google_protobuf//types/descriptorpb:go_default_library", + "@org_golang_google_protobuf//types/pluginpb:go_default_library", ], ) diff --git a/gateway/internal/descriptor/apiconfig/apiconfig.pb.go b/gateway/internal/descriptor/apiconfig/apiconfig.pb.go new file mode 100644 index 0000000..1254efb --- /dev/null +++ b/gateway/internal/descriptor/apiconfig/apiconfig.pb.go @@ -0,0 +1,171 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.23.0 +// protoc v3.12.3 +// source: gateway/internal/descriptor/apiconfig/apiconfig.proto + +package apiconfig + +import ( + proto "github.com/golang/protobuf/proto" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + httpoptions "httpoptions" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// This is a compile-time assertion that a sufficiently up-to-date version +// of the legacy proto package is being used. +const _ = proto.ProtoPackageIsVersion4 + +// GrpcAPIService represents a stripped down version of google.api.Service . +// Compare to https://github.com/googleapis/googleapis/blob/master/google/api/service.proto +// The original imports 23 other protobuf files we are not interested in. If a significant +// subset (>50%) of these start being reproduced in this file we should swap to using the +// full generated version instead. +// +// For the purposes of the gateway generator we only consider a small subset of all +// available features google supports in their service descriptions. Thanks to backwards +// compatibility guarantees by protobuf it is safe for us to remove the other fields. +type GrpcAPIService struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Http Rule. + Http *httpoptions.Http `protobuf:"bytes,1,opt,name=http,proto3" json:"http,omitempty"` +} + +func (x *GrpcAPIService) Reset() { + *x = GrpcAPIService{} + if protoimpl.UnsafeEnabled { + mi := &file_gateway_internal_descriptor_apiconfig_apiconfig_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GrpcAPIService) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GrpcAPIService) ProtoMessage() {} + +func (x *GrpcAPIService) ProtoReflect() protoreflect.Message { + mi := &file_gateway_internal_descriptor_apiconfig_apiconfig_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GrpcAPIService.ProtoReflect.Descriptor instead. +func (*GrpcAPIService) Descriptor() ([]byte, []int) { + return file_gateway_internal_descriptor_apiconfig_apiconfig_proto_rawDescGZIP(), []int{0} +} + +func (x *GrpcAPIService) GetHttp() *httpoptions.Http { + if x != nil { + return x.Http + } + return nil +} + +var File_gateway_internal_descriptor_apiconfig_apiconfig_proto protoreflect.FileDescriptor + +var file_gateway_internal_descriptor_apiconfig_apiconfig_proto_rawDesc = []byte{ + 0x0a, 0x35, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, + 0x61, 0x6c, 0x2f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2f, 0x61, 0x70, + 0x69, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2f, 0x61, 0x70, 0x69, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x2a, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, + 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x64, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x63, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x1a, 0x16, 0x68, 0x74, 0x74, 0x70, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x2f, 0x68, 0x74, 0x74, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x34, 0x0a, 0x0e, 0x47, + 0x72, 0x70, 0x63, 0x41, 0x50, 0x49, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x22, 0x0a, + 0x04, 0x68, 0x74, 0x74, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x65, 0x61, + 0x73, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x48, 0x74, 0x74, 0x70, 0x52, 0x04, 0x68, 0x74, 0x74, + 0x70, 0x42, 0x4b, 0x5a, 0x49, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x62, 0x69, 0x6e, 0x63, 0x68, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x65, 0x61, 0x73, + 0x65, 0x2d, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2f, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, + 0x79, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x6f, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_gateway_internal_descriptor_apiconfig_apiconfig_proto_rawDescOnce sync.Once + file_gateway_internal_descriptor_apiconfig_apiconfig_proto_rawDescData = file_gateway_internal_descriptor_apiconfig_apiconfig_proto_rawDesc +) + +func file_gateway_internal_descriptor_apiconfig_apiconfig_proto_rawDescGZIP() []byte { + file_gateway_internal_descriptor_apiconfig_apiconfig_proto_rawDescOnce.Do(func() { + file_gateway_internal_descriptor_apiconfig_apiconfig_proto_rawDescData = protoimpl.X.CompressGZIP(file_gateway_internal_descriptor_apiconfig_apiconfig_proto_rawDescData) + }) + return file_gateway_internal_descriptor_apiconfig_apiconfig_proto_rawDescData +} + +var file_gateway_internal_descriptor_apiconfig_apiconfig_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_gateway_internal_descriptor_apiconfig_apiconfig_proto_goTypes = []interface{}{ + (*GrpcAPIService)(nil), // 0: grpc.gateway.internal.descriptor.apiconfig.GrpcAPIService + (*httpoptions.Http)(nil), // 1: ease.api.Http +} +var file_gateway_internal_descriptor_apiconfig_apiconfig_proto_depIdxs = []int32{ + 1, // 0: grpc.gateway.internal.descriptor.apiconfig.GrpcAPIService.http:type_name -> ease.api.Http + 1, // [1:1] is the sub-list for method output_type + 1, // [1:1] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name +} + +func init() { file_gateway_internal_descriptor_apiconfig_apiconfig_proto_init() } +func file_gateway_internal_descriptor_apiconfig_apiconfig_proto_init() { + if File_gateway_internal_descriptor_apiconfig_apiconfig_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_gateway_internal_descriptor_apiconfig_apiconfig_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GrpcAPIService); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_gateway_internal_descriptor_apiconfig_apiconfig_proto_rawDesc, + NumEnums: 0, + NumMessages: 1, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_gateway_internal_descriptor_apiconfig_apiconfig_proto_goTypes, + DependencyIndexes: file_gateway_internal_descriptor_apiconfig_apiconfig_proto_depIdxs, + MessageInfos: file_gateway_internal_descriptor_apiconfig_apiconfig_proto_msgTypes, + }.Build() + File_gateway_internal_descriptor_apiconfig_apiconfig_proto = out.File + file_gateway_internal_descriptor_apiconfig_apiconfig_proto_rawDesc = nil + file_gateway_internal_descriptor_apiconfig_apiconfig_proto_goTypes = nil + file_gateway_internal_descriptor_apiconfig_apiconfig_proto_depIdxs = nil +} diff --git a/gateway/internal/descriptor/openapi_configuration.go b/gateway/internal/descriptor/openapi_configuration.go new file mode 100644 index 0000000..5010128 --- /dev/null +++ b/gateway/internal/descriptor/openapi_configuration.go @@ -0,0 +1,59 @@ +package descriptor + +import ( + "fmt" + "io/ioutil" + + "github.com/ghodss/yaml" + // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor/openapiconfig" + "github.com/binchencoder/ease-gateway/gateway/internal/descriptor/openapiconfig" + "google.golang.org/protobuf/encoding/protojson" +) + +func loadOpenAPIConfigFromYAML(yamlFileContents []byte, yamlSourceLogName string) (*openapiconfig.OpenAPIConfig, error) { + jsonContents, err := yaml.YAMLToJSON(yamlFileContents) + if err != nil { + return nil, fmt.Errorf("failed to convert OpenAPI Configuration from YAML in '%v' to JSON: %v", yamlSourceLogName, err) + } + + // Reject unknown fields because OpenAPIConfig is only used here + unmarshaler := protojson.UnmarshalOptions{ + DiscardUnknown: false, + } + + openapiConfiguration := openapiconfig.OpenAPIConfig{} + if err := unmarshaler.Unmarshal(jsonContents, &openapiConfiguration); err != nil { + return nil, fmt.Errorf("failed to parse gRPC API Configuration from YAML in '%v': %v", yamlSourceLogName, err) + } + + return &openapiConfiguration, nil +} + +func registerOpenAPIOptions(registry *Registry, openAPIConfig *openapiconfig.OpenAPIConfig, yamlSourceLogName string) error { + if openAPIConfig.OpenapiOptions == nil { + // Nothing to do + return nil + } + + if err := registry.RegisterOpenAPIOptions(openAPIConfig.OpenapiOptions); err != nil { + return fmt.Errorf("failed to register option in %s: %s", yamlSourceLogName, err) + } + return nil +} + +// LoadOpenAPIConfigFromYAML loads an OpenAPI Configuration from the given YAML file +// and registers the OpenAPI options the given registry. +// This must be done after loading the proto file. +func (r *Registry) LoadOpenAPIConfigFromYAML(yamlFile string) error { + yamlFileContents, err := ioutil.ReadFile(yamlFile) + if err != nil { + return fmt.Errorf("failed to read gRPC API Configuration description from '%v': %v", yamlFile, err) + } + + config, err := loadOpenAPIConfigFromYAML(yamlFileContents, yamlFile) + if err != nil { + return err + } + + return registerOpenAPIOptions(r, config, yamlFile) +} diff --git a/gateway/internal/descriptor/openapi_configuration_test.go b/gateway/internal/descriptor/openapi_configuration_test.go new file mode 100644 index 0000000..6755b19 --- /dev/null +++ b/gateway/internal/descriptor/openapi_configuration_test.go @@ -0,0 +1,115 @@ +package descriptor + +import ( + "strings" + "testing" + + // "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options" + "github.com/binchencoder/ease-gateway/gateway/protoc-gen-openapiv2/options" +) + +func TestLoadOpenAPIConfigFromYAMLRejectInvalidYAML(t *testing.T) { + config, err := loadOpenAPIConfigFromYAML([]byte(` +openapiOptions: +file: +- file: test.proto + - option: + schemes: + - HTTP + - HTTPS + - WSS + securityDefinitions: + security: + ApiKeyAuth: + type: TYPE_API_KEY + in: IN_HEADER + name: "X-API-Key" +`), "invalidyaml") + if err == nil { + t.Fatal(err) + } + + if !strings.Contains(err.Error(), "line 4") { + t.Errorf("Expected yaml error to be detected in line 4. Got other error: %v", err) + } + + if config != nil { + t.Fatal("Config returned") + } +} + +func TestLoadOpenAPIConfigFromYAML(t *testing.T) { + config, err := loadOpenAPIConfigFromYAML([]byte(` +openapiOptions: + file: + - file: test.proto + option: + schemes: + - HTTP + - HTTPS + - WSS + securityDefinitions: + security: + ApiKeyAuth: + type: TYPE_API_KEY + in: IN_HEADER + name: "X-API-Key" +`), "openapi_options") + if err != nil { + t.Fatal(err) + } + + if config.OpenapiOptions == nil { + t.Fatal("OpenAPIOptions is empty") + } + + opts := config.OpenapiOptions + if numFileOpts := len(opts.File); numFileOpts != 1 { + t.Fatalf("expected 1 file option but got %d", numFileOpts) + } + + fileOpt := opts.File[0] + + if fileOpt.File != "test.proto" { + t.Fatalf("file option has unexpected binding %s", fileOpt.File) + } + + swaggerOpt := fileOpt.Option + + if swaggerOpt == nil { + t.Fatal("expected option to be set") + } + + if numSchemes := len(swaggerOpt.Schemes); numSchemes != 3 { + t.Fatalf("expected 3 schemes but got %d", numSchemes) + } + if swaggerOpt.Schemes[0] != options.Scheme_HTTP { + t.Fatalf("expected first scheme to be HTTP but got %s", swaggerOpt.Schemes[0]) + } + if swaggerOpt.Schemes[1] != options.Scheme_HTTPS { + t.Fatalf("expected second scheme to be HTTPS but got %s", swaggerOpt.Schemes[1]) + } + if swaggerOpt.Schemes[2] != options.Scheme_WSS { + t.Fatalf("expected third scheme to be WSS but got %s", swaggerOpt.Schemes[2]) + } + + if swaggerOpt.SecurityDefinitions == nil { + t.Fatal("expected securityDefinitions to be set") + } + if numSecOpts := len(swaggerOpt.SecurityDefinitions.Security); numSecOpts != 1 { + t.Fatalf("expected 1 security option but got %d", numSecOpts) + } + secOpt, ok := swaggerOpt.SecurityDefinitions.Security["ApiKeyAuth"] + if !ok { + t.Fatal("no SecurityScheme for key \"ApiKeyAuth\"") + } + if secOpt.Type != options.SecurityScheme_TYPE_API_KEY { + t.Fatalf("expected scheme type to be TYPE_API_KEY but got %s", secOpt.Type) + } + if secOpt.In != options.SecurityScheme_IN_HEADER { + t.Fatalf("expected scheme in to be IN_HEADER but got %s", secOpt.In) + } + if secOpt.Name != "X-API-Key" { + t.Fatalf("expected name to be X-API-Key but got %s", secOpt.Name) + } +} diff --git a/gateway/internal/descriptor/openapiconfig/BUILD.bazel b/gateway/internal/descriptor/openapiconfig/BUILD.bazel new file mode 100644 index 0000000..de3dbf7 --- /dev/null +++ b/gateway/internal/descriptor/openapiconfig/BUILD.bazel @@ -0,0 +1,26 @@ +load("@rules_proto//proto:defs.bzl", "proto_library") +load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") + +proto_library( + name = "openapiconfig_proto", + srcs = ["openapiconfig.proto"], + visibility = ["//:__subpackages__"], + deps = ["//gateway/protoc-gen-openapiv2/options:options_proto"], +) + +go_proto_library( + name = "openapiconfig_go_proto", + compilers = ["//:go_apiv2"], + importpath = "github.com/binchencoder/ease-gateway/gateway/internal/descriptor/openapiconfig", + proto = ":openapiconfig_proto", + visibility = ["//:__subpackages__"], + deps = ["//gateway/protoc-gen-openapiv2/options:go_default_library"], +) + +go_library( + name = "go_default_library", + embed = [":openapiconfig_go_proto"], + importpath = "github.com/binchencoder/ease-gateway/gateway/internal/descriptor/openapiconfig", + visibility = ["//:__subpackages__"], +) diff --git a/gateway/internal/descriptor/openapiconfig/openapiconfig.pb.go b/gateway/internal/descriptor/openapiconfig/openapiconfig.pb.go new file mode 100644 index 0000000..25e9f65 --- /dev/null +++ b/gateway/internal/descriptor/openapiconfig/openapiconfig.pb.go @@ -0,0 +1,689 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.23.0 +// protoc v3.12.3 +// source: gateway/internal/descriptor/openapiconfig/openapiconfig.proto + +package openapiconfig + +import ( + options "github.com/binchencoder/ease-gateway/gateway/protoc-gen-openapiv2/options" + proto "github.com/golang/protobuf/proto" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// This is a compile-time assertion that a sufficiently up-to-date version +// of the legacy proto package is being used. +const _ = proto.ProtoPackageIsVersion4 + +// OpenAPIFileOption represents OpenAPI options on a file +type OpenAPIFileOption struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + File string `protobuf:"bytes,1,opt,name=file,proto3" json:"file,omitempty"` + Option *options.Swagger `protobuf:"bytes,2,opt,name=option,proto3" json:"option,omitempty"` +} + +func (x *OpenAPIFileOption) Reset() { + *x = OpenAPIFileOption{} + if protoimpl.UnsafeEnabled { + mi := &file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *OpenAPIFileOption) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*OpenAPIFileOption) ProtoMessage() {} + +func (x *OpenAPIFileOption) ProtoReflect() protoreflect.Message { + mi := &file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use OpenAPIFileOption.ProtoReflect.Descriptor instead. +func (*OpenAPIFileOption) Descriptor() ([]byte, []int) { + return file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_rawDescGZIP(), []int{0} +} + +func (x *OpenAPIFileOption) GetFile() string { + if x != nil { + return x.File + } + return "" +} + +func (x *OpenAPIFileOption) GetOption() *options.Swagger { + if x != nil { + return x.Option + } + return nil +} + +// OpenAPIMethodOption represents OpenAPI options on a method +type OpenAPIMethodOption struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Method string `protobuf:"bytes,1,opt,name=method,proto3" json:"method,omitempty"` + Option *options.Operation `protobuf:"bytes,2,opt,name=option,proto3" json:"option,omitempty"` +} + +func (x *OpenAPIMethodOption) Reset() { + *x = OpenAPIMethodOption{} + if protoimpl.UnsafeEnabled { + mi := &file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *OpenAPIMethodOption) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*OpenAPIMethodOption) ProtoMessage() {} + +func (x *OpenAPIMethodOption) ProtoReflect() protoreflect.Message { + mi := &file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use OpenAPIMethodOption.ProtoReflect.Descriptor instead. +func (*OpenAPIMethodOption) Descriptor() ([]byte, []int) { + return file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_rawDescGZIP(), []int{1} +} + +func (x *OpenAPIMethodOption) GetMethod() string { + if x != nil { + return x.Method + } + return "" +} + +func (x *OpenAPIMethodOption) GetOption() *options.Operation { + if x != nil { + return x.Option + } + return nil +} + +// OpenAPIMessageOption represents OpenAPI options on a message +type OpenAPIMessageOption struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` + Option *options.Schema `protobuf:"bytes,2,opt,name=option,proto3" json:"option,omitempty"` +} + +func (x *OpenAPIMessageOption) Reset() { + *x = OpenAPIMessageOption{} + if protoimpl.UnsafeEnabled { + mi := &file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *OpenAPIMessageOption) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*OpenAPIMessageOption) ProtoMessage() {} + +func (x *OpenAPIMessageOption) ProtoReflect() protoreflect.Message { + mi := &file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use OpenAPIMessageOption.ProtoReflect.Descriptor instead. +func (*OpenAPIMessageOption) Descriptor() ([]byte, []int) { + return file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_rawDescGZIP(), []int{2} +} + +func (x *OpenAPIMessageOption) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +func (x *OpenAPIMessageOption) GetOption() *options.Schema { + if x != nil { + return x.Option + } + return nil +} + +// OpenAPIServiceOption represents OpenAPI options on a service +type OpenAPIServiceOption struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Service string `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"` // ex: Service + Option *options.Tag `protobuf:"bytes,2,opt,name=option,proto3" json:"option,omitempty"` +} + +func (x *OpenAPIServiceOption) Reset() { + *x = OpenAPIServiceOption{} + if protoimpl.UnsafeEnabled { + mi := &file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *OpenAPIServiceOption) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*OpenAPIServiceOption) ProtoMessage() {} + +func (x *OpenAPIServiceOption) ProtoReflect() protoreflect.Message { + mi := &file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use OpenAPIServiceOption.ProtoReflect.Descriptor instead. +func (*OpenAPIServiceOption) Descriptor() ([]byte, []int) { + return file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_rawDescGZIP(), []int{3} +} + +func (x *OpenAPIServiceOption) GetService() string { + if x != nil { + return x.Service + } + return "" +} + +func (x *OpenAPIServiceOption) GetOption() *options.Tag { + if x != nil { + return x.Option + } + return nil +} + +// OpenAPIFieldOption represents OpenAPI options on a field +type OpenAPIFieldOption struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Field string `protobuf:"bytes,1,opt,name=field,proto3" json:"field,omitempty"` + Option *options.JSONSchema `protobuf:"bytes,2,opt,name=option,proto3" json:"option,omitempty"` +} + +func (x *OpenAPIFieldOption) Reset() { + *x = OpenAPIFieldOption{} + if protoimpl.UnsafeEnabled { + mi := &file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *OpenAPIFieldOption) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*OpenAPIFieldOption) ProtoMessage() {} + +func (x *OpenAPIFieldOption) ProtoReflect() protoreflect.Message { + mi := &file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use OpenAPIFieldOption.ProtoReflect.Descriptor instead. +func (*OpenAPIFieldOption) Descriptor() ([]byte, []int) { + return file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_rawDescGZIP(), []int{4} +} + +func (x *OpenAPIFieldOption) GetField() string { + if x != nil { + return x.Field + } + return "" +} + +func (x *OpenAPIFieldOption) GetOption() *options.JSONSchema { + if x != nil { + return x.Option + } + return nil +} + +// OpenAPIOptions represents OpenAPI protobuf options +type OpenAPIOptions struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + File []*OpenAPIFileOption `protobuf:"bytes,1,rep,name=file,proto3" json:"file,omitempty"` + Method []*OpenAPIMethodOption `protobuf:"bytes,2,rep,name=method,proto3" json:"method,omitempty"` + Message []*OpenAPIMessageOption `protobuf:"bytes,3,rep,name=message,proto3" json:"message,omitempty"` + Service []*OpenAPIServiceOption `protobuf:"bytes,4,rep,name=service,proto3" json:"service,omitempty"` + Field []*OpenAPIFieldOption `protobuf:"bytes,5,rep,name=field,proto3" json:"field,omitempty"` +} + +func (x *OpenAPIOptions) Reset() { + *x = OpenAPIOptions{} + if protoimpl.UnsafeEnabled { + mi := &file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *OpenAPIOptions) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*OpenAPIOptions) ProtoMessage() {} + +func (x *OpenAPIOptions) ProtoReflect() protoreflect.Message { + mi := &file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use OpenAPIOptions.ProtoReflect.Descriptor instead. +func (*OpenAPIOptions) Descriptor() ([]byte, []int) { + return file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_rawDescGZIP(), []int{5} +} + +func (x *OpenAPIOptions) GetFile() []*OpenAPIFileOption { + if x != nil { + return x.File + } + return nil +} + +func (x *OpenAPIOptions) GetMethod() []*OpenAPIMethodOption { + if x != nil { + return x.Method + } + return nil +} + +func (x *OpenAPIOptions) GetMessage() []*OpenAPIMessageOption { + if x != nil { + return x.Message + } + return nil +} + +func (x *OpenAPIOptions) GetService() []*OpenAPIServiceOption { + if x != nil { + return x.Service + } + return nil +} + +func (x *OpenAPIOptions) GetField() []*OpenAPIFieldOption { + if x != nil { + return x.Field + } + return nil +} + +// OpenAPIConfig represents a set of OpenAPI options +type OpenAPIConfig struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + OpenapiOptions *OpenAPIOptions `protobuf:"bytes,1,opt,name=openapi_options,json=openapiOptions,proto3" json:"openapi_options,omitempty"` +} + +func (x *OpenAPIConfig) Reset() { + *x = OpenAPIConfig{} + if protoimpl.UnsafeEnabled { + mi := &file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *OpenAPIConfig) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*OpenAPIConfig) ProtoMessage() {} + +func (x *OpenAPIConfig) ProtoReflect() protoreflect.Message { + mi := &file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use OpenAPIConfig.ProtoReflect.Descriptor instead. +func (*OpenAPIConfig) Descriptor() ([]byte, []int) { + return file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_rawDescGZIP(), []int{6} +} + +func (x *OpenAPIConfig) GetOpenapiOptions() *OpenAPIOptions { + if x != nil { + return x.OpenapiOptions + } + return nil +} + +var File_gateway_internal_descriptor_openapiconfig_openapiconfig_proto protoreflect.FileDescriptor + +var file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_rawDesc = []byte{ + 0x0a, 0x3d, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, + 0x61, 0x6c, 0x2f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2f, 0x6f, 0x70, + 0x65, 0x6e, 0x61, 0x70, 0x69, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2f, 0x6f, 0x70, 0x65, 0x6e, + 0x61, 0x70, 0x69, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, + 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, + 0x72, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, + 0x34, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, + 0x67, 0x65, 0x6e, 0x2d, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2f, 0x6f, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x73, 0x0a, 0x11, 0x4f, 0x70, 0x65, 0x6e, 0x41, 0x50, 0x49, + 0x46, 0x69, 0x6c, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x69, + 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x4a, + 0x0a, 0x06, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, + 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, + 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x77, 0x61, 0x67, 0x67, + 0x65, 0x72, 0x52, 0x06, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x7b, 0x0a, 0x13, 0x4f, 0x70, + 0x65, 0x6e, 0x41, 0x50, 0x49, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x4c, 0x0a, 0x06, 0x6f, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x67, 0x72, 0x70, 0x63, + 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, + 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x06, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x7b, 0x0a, 0x14, 0x4f, 0x70, 0x65, 0x6e, 0x41, + 0x50, 0x49, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x49, 0x0a, 0x06, 0x6f, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x67, 0x72, 0x70, 0x63, + 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, + 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x06, 0x6f, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x78, 0x0a, 0x14, 0x4f, 0x70, 0x65, 0x6e, 0x41, 0x50, 0x49, 0x53, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x46, 0x0a, 0x06, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, + 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, + 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x2e, 0x54, 0x61, 0x67, 0x52, 0x06, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x79, + 0x0a, 0x12, 0x4f, 0x70, 0x65, 0x6e, 0x41, 0x50, 0x49, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4f, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x4d, 0x0a, 0x06, 0x6f, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x67, 0x72, 0x70, + 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, + 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4a, 0x53, 0x4f, 0x4e, 0x53, 0x63, 0x68, 0x65, 0x6d, + 0x61, 0x52, 0x06, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xde, 0x03, 0x0a, 0x0e, 0x4f, 0x70, + 0x65, 0x6e, 0x41, 0x50, 0x49, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x55, 0x0a, 0x04, + 0x66, 0x69, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x41, 0x2e, 0x67, 0x72, 0x70, + 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, + 0x61, 0x6c, 0x2e, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x61, 0x70, 0x69, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x4f, 0x70, 0x65, 0x6e, + 0x41, 0x50, 0x49, 0x46, 0x69, 0x6c, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x04, 0x66, + 0x69, 0x6c, 0x65, 0x12, 0x5b, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x02, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x43, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, + 0x61, 0x79, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x64, 0x65, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x63, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x41, 0x50, 0x49, 0x4d, 0x65, 0x74, 0x68, + 0x6f, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, + 0x12, 0x5e, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x44, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, + 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x63, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x41, 0x50, 0x49, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x12, 0x5e, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x04, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x44, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, + 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x63, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x41, 0x50, 0x49, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x12, 0x58, 0x0a, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x42, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x69, + 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x6f, 0x72, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x41, 0x50, 0x49, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4f, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x22, 0x78, 0x0a, 0x0d, 0x4f, 0x70, + 0x65, 0x6e, 0x41, 0x50, 0x49, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x67, 0x0a, 0x0f, 0x6f, + 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, + 0x77, 0x61, 0x79, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x64, 0x65, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x63, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x41, 0x50, 0x49, 0x4f, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x0e, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x4f, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x50, 0x5a, 0x4e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x62, 0x69, 0x6e, 0x63, 0x68, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, + 0x65, 0x61, 0x73, 0x65, 0x2d, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2f, 0x67, 0x61, 0x74, + 0x65, 0x77, 0x61, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x64, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_rawDescOnce sync.Once + file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_rawDescData = file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_rawDesc +) + +func file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_rawDescGZIP() []byte { + file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_rawDescOnce.Do(func() { + file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_rawDescData = protoimpl.X.CompressGZIP(file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_rawDescData) + }) + return file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_rawDescData +} + +var file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_msgTypes = make([]protoimpl.MessageInfo, 7) +var file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_goTypes = []interface{}{ + (*OpenAPIFileOption)(nil), // 0: grpc.gateway.internal.descriptor.openapiconfig.OpenAPIFileOption + (*OpenAPIMethodOption)(nil), // 1: grpc.gateway.internal.descriptor.openapiconfig.OpenAPIMethodOption + (*OpenAPIMessageOption)(nil), // 2: grpc.gateway.internal.descriptor.openapiconfig.OpenAPIMessageOption + (*OpenAPIServiceOption)(nil), // 3: grpc.gateway.internal.descriptor.openapiconfig.OpenAPIServiceOption + (*OpenAPIFieldOption)(nil), // 4: grpc.gateway.internal.descriptor.openapiconfig.OpenAPIFieldOption + (*OpenAPIOptions)(nil), // 5: grpc.gateway.internal.descriptor.openapiconfig.OpenAPIOptions + (*OpenAPIConfig)(nil), // 6: grpc.gateway.internal.descriptor.openapiconfig.OpenAPIConfig + (*options.Swagger)(nil), // 7: grpc.gateway.protoc_gen_openapiv2.options.Swagger + (*options.Operation)(nil), // 8: grpc.gateway.protoc_gen_openapiv2.options.Operation + (*options.Schema)(nil), // 9: grpc.gateway.protoc_gen_openapiv2.options.Schema + (*options.Tag)(nil), // 10: grpc.gateway.protoc_gen_openapiv2.options.Tag + (*options.JSONSchema)(nil), // 11: grpc.gateway.protoc_gen_openapiv2.options.JSONSchema +} +var file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_depIdxs = []int32{ + 7, // 0: grpc.gateway.internal.descriptor.openapiconfig.OpenAPIFileOption.option:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Swagger + 8, // 1: grpc.gateway.internal.descriptor.openapiconfig.OpenAPIMethodOption.option:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Operation + 9, // 2: grpc.gateway.internal.descriptor.openapiconfig.OpenAPIMessageOption.option:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Schema + 10, // 3: grpc.gateway.internal.descriptor.openapiconfig.OpenAPIServiceOption.option:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Tag + 11, // 4: grpc.gateway.internal.descriptor.openapiconfig.OpenAPIFieldOption.option:type_name -> grpc.gateway.protoc_gen_openapiv2.options.JSONSchema + 0, // 5: grpc.gateway.internal.descriptor.openapiconfig.OpenAPIOptions.file:type_name -> grpc.gateway.internal.descriptor.openapiconfig.OpenAPIFileOption + 1, // 6: grpc.gateway.internal.descriptor.openapiconfig.OpenAPIOptions.method:type_name -> grpc.gateway.internal.descriptor.openapiconfig.OpenAPIMethodOption + 2, // 7: grpc.gateway.internal.descriptor.openapiconfig.OpenAPIOptions.message:type_name -> grpc.gateway.internal.descriptor.openapiconfig.OpenAPIMessageOption + 3, // 8: grpc.gateway.internal.descriptor.openapiconfig.OpenAPIOptions.service:type_name -> grpc.gateway.internal.descriptor.openapiconfig.OpenAPIServiceOption + 4, // 9: grpc.gateway.internal.descriptor.openapiconfig.OpenAPIOptions.field:type_name -> grpc.gateway.internal.descriptor.openapiconfig.OpenAPIFieldOption + 5, // 10: grpc.gateway.internal.descriptor.openapiconfig.OpenAPIConfig.openapi_options:type_name -> grpc.gateway.internal.descriptor.openapiconfig.OpenAPIOptions + 11, // [11:11] is the sub-list for method output_type + 11, // [11:11] is the sub-list for method input_type + 11, // [11:11] is the sub-list for extension type_name + 11, // [11:11] is the sub-list for extension extendee + 0, // [0:11] is the sub-list for field type_name +} + +func init() { file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_init() } +func file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_init() { + if File_gateway_internal_descriptor_openapiconfig_openapiconfig_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*OpenAPIFileOption); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*OpenAPIMethodOption); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*OpenAPIMessageOption); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*OpenAPIServiceOption); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*OpenAPIFieldOption); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*OpenAPIOptions); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*OpenAPIConfig); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_rawDesc, + NumEnums: 0, + NumMessages: 7, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_goTypes, + DependencyIndexes: file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_depIdxs, + MessageInfos: file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_msgTypes, + }.Build() + File_gateway_internal_descriptor_openapiconfig_openapiconfig_proto = out.File + file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_rawDesc = nil + file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_goTypes = nil + file_gateway_internal_descriptor_openapiconfig_openapiconfig_proto_depIdxs = nil +} diff --git a/gateway/internal/descriptor/openapiconfig/openapiconfig.proto b/gateway/internal/descriptor/openapiconfig/openapiconfig.proto new file mode 100644 index 0000000..3c194f2 --- /dev/null +++ b/gateway/internal/descriptor/openapiconfig/openapiconfig.proto @@ -0,0 +1,51 @@ +syntax = "proto3"; + +package grpc.gateway.internal.descriptor.openapiconfig; + +option go_package = "github.com/binchencoder/ease-gateway/gateway/internal/descriptor/openapiconfig"; + +import "gateway/protoc-gen-openapiv2/options/openapiv2.proto"; + +// OpenAPIFileOption represents OpenAPI options on a file +message OpenAPIFileOption { + string file = 1; + grpc.gateway.protoc_gen_openapiv2.options.Swagger option = 2; +} + +// OpenAPIMethodOption represents OpenAPI options on a method +message OpenAPIMethodOption { + string method = 1; + grpc.gateway.protoc_gen_openapiv2.options.Operation option = 2; +} + +// OpenAPIMessageOption represents OpenAPI options on a message +message OpenAPIMessageOption { + string message = 1; + grpc.gateway.protoc_gen_openapiv2.options.Schema option = 2; +} + +// OpenAPIServiceOption represents OpenAPI options on a service +message OpenAPIServiceOption { + string service = 1; // ex: Service + grpc.gateway.protoc_gen_openapiv2.options.Tag option = 2; +} + +// OpenAPIFieldOption represents OpenAPI options on a field +message OpenAPIFieldOption { + string field = 1; + grpc.gateway.protoc_gen_openapiv2.options.JSONSchema option = 2; +} + +// OpenAPIOptions represents OpenAPI protobuf options +message OpenAPIOptions { + repeated OpenAPIFileOption file = 1; + repeated OpenAPIMethodOption method = 2; + repeated OpenAPIMessageOption message = 3; + repeated OpenAPIServiceOption service = 4; + repeated OpenAPIFieldOption field = 5; +} + +// OpenAPIConfig represents a set of OpenAPI options +message OpenAPIConfig { + OpenAPIOptions openapi_options = 1; +} diff --git a/gateway/internal/descriptor/registry.go b/gateway/internal/descriptor/registry.go index 7d318c7..0978e17 100644 --- a/gateway/internal/descriptor/registry.go +++ b/gateway/internal/descriptor/registry.go @@ -2,16 +2,18 @@ package descriptor import ( "fmt" - "path" - "path/filepath" "strings" "github.com/golang/glog" - descriptorpb "github.com/golang/protobuf/protoc-gen-go/descriptor" - pluginpb "github.com/golang/protobuf/protoc-gen-go/plugin" - + // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor/openapiconfig" + "github.com/binchencoder/ease-gateway/gateway/internal/descriptor/openapiconfig" + // "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options" + "github.com/binchencoder/ease-gateway/gateway/protoc-gen-openapiv2/options" // "google.golang.org/genproto/googleapis/api/annotations" annotations "github.com/binchencoder/ease-gateway/httpoptions" + "google.golang.org/protobuf/compiler/protogen" + "google.golang.org/protobuf/types/descriptorpb" + "google.golang.org/protobuf/types/pluginpb" ) // Registry is a registry of information extracted from pluginpb.CodeGeneratorRequest. @@ -28,9 +30,6 @@ type Registry struct { // prefix is a prefix to be inserted to golang package paths generated from proto package names. prefix string - // importPath is used as the package if no input files declare go_package. If it contains slashes, everything up to the rightmost slash is ignored. - importPath string - // pkgMap is a user-specified mapping from file path to proto package. pkgMap map[string]string @@ -86,6 +85,32 @@ type Registry struct { simpleOperationIDs bool standalone bool + // warnOnUnboundMethods causes the registry to emit warning logs if an RPC method + // has no HttpRule annotation. + warnOnUnboundMethods bool + + // fileOptions is a mapping of file name to additional OpenAPI file options + fileOptions map[string]*options.Swagger + + // methodOptions is a mapping of fully-qualified method name to additional OpenAPI method options + methodOptions map[string]*options.Operation + + // messageOptions is a mapping of fully-qualified message name to additional OpenAPI message options + messageOptions map[string]*options.Schema + + //serviceOptions is a mapping of fully-qualified service name to additional OpenAPI service options + serviceOptions map[string]*options.Tag + + // fieldOptions is a mapping of the fully-qualified name of the parent message concat + // field name and a period to additional OpenAPI field options + fieldOptions map[string]*options.JSONSchema + + // generateUnboundMethods causes the registry to generate proxy methods even for + // RPC methods that have no HttpRule annotation. + generateUnboundMethods bool + + // omitPackageDoc, if false, causes a package comment to be included in the generated code. + omitPackageDoc bool } type repeatedFieldSeparator struct { @@ -111,44 +136,52 @@ func NewRegistry() *Registry { name: "csv", sep: ',', }, + fileOptions: make(map[string]*options.Swagger), + methodOptions: make(map[string]*options.Operation), + messageOptions: make(map[string]*options.Schema), + serviceOptions: make(map[string]*options.Tag), + fieldOptions: make(map[string]*options.JSONSchema), } } // Load loads definitions of services, methods, messages, enumerations and fields from "req". func (r *Registry) Load(req *pluginpb.CodeGeneratorRequest) error { - for _, file := range req.GetProtoFile() { - r.loadFile(file) + gen, err := protogen.Options{}.New(req) + if err != nil { + return err } + return r.load(gen) +} - var targetPkg string - for _, name := range req.FileToGenerate { - target := r.files[name] - if target == nil { - return fmt.Errorf("no such file: %s", name) - } - name := r.packageIdentityName(target.FileDescriptorProto) - if targetPkg == "" { - targetPkg = name - } else { - if targetPkg != name { - return fmt.Errorf("inconsistent package names: %s %s", targetPkg, name) - } - } +func (r *Registry) LoadFromPlugin(gen *protogen.Plugin) error { + return r.load(gen) +} - if err := r.loadServices(target); err != nil { +func (r *Registry) load(gen *protogen.Plugin) error { + for filePath, f := range gen.FilesByPath { + r.loadFile(filePath, f) + } + + for filePath, f := range gen.FilesByPath { + if !f.Generate { + continue + } + file := r.files[filePath] + if err := r.loadServices(file); err != nil { return err } } + return nil } // loadFile loads messages, enumerations and fields from "file". // It does not loads services and methods in "file". You need to call // loadServices after loadFiles is called for all files to load services and methods. -func (r *Registry) loadFile(file *descriptorpb.FileDescriptorProto) { +func (r *Registry) loadFile(filePath string, file *protogen.File) { pkg := GoPackage{ - Path: r.goPackagePath(file), - Name: r.defaultGoPackageName(file), + Path: string(file.GoImportPath), + Name: string(file.GoPackageName), } if r.standalone { pkg.Alias = "ext" + strings.Title(pkg.Name) @@ -164,13 +197,14 @@ func (r *Registry) loadFile(file *descriptorpb.FileDescriptorProto) { } } f := &File{ - FileDescriptorProto: file, - GoPkg: pkg, + FileDescriptorProto: file.Proto, + GoPkg: pkg, + GeneratedFilenamePrefix: file.GeneratedFilenamePrefix, } - r.files[file.GetName()] = f - r.registerMsg(f, nil, file.GetMessageType()) - r.registerEnum(f, nil, file.GetEnumType()) + r.files[filePath] = f + r.registerMsg(f, nil, file.Proto.MessageType) + r.registerEnum(f, nil, file.Proto.EnumType) } func (r *Registry) registerMsg(file *File, outerPath []string, msgs []*descriptorpb.DescriptorProto) { @@ -333,13 +367,6 @@ func (r *Registry) SetStandalone(standalone bool) { r.standalone = standalone } -// SetImportPath registers the importPath which is used as the package if no -// input files declare go_package. If it contains slashes, everything up to the -// rightmost slash is ignored. -func (r *Registry) SetImportPath(importPath string) { - r.importPath = importPath -} - // ReserveGoPackageAlias reserves the unique alias of go package. // If succeeded, the alias will be never used for other packages in generated go files. // If failed, the alias is already taken by another package, so you need to use another @@ -355,27 +382,6 @@ func (r *Registry) ReserveGoPackageAlias(alias, pkgpath string) error { return nil } -// goPackagePath returns the go package path which go files generated from "f" should have. -// It respects the mapping registered by AddPkgMap if exists. Or use go_package as import path -// if it includes a slash, Otherwide, it generates a path from the file name of "f". -func (r *Registry) goPackagePath(f *descriptorpb.FileDescriptorProto) string { - name := f.GetName() - if pkg, ok := r.pkgMap[name]; ok { - return path.Join(r.prefix, pkg) - } - - gopkg := f.Options.GetGoPackage() - idx := strings.LastIndex(gopkg, "/") - if idx >= 0 { - if sc := strings.LastIndex(gopkg, ";"); sc > 0 { - gopkg = gopkg[:sc+1-1] - } - return gopkg - } - - return path.Join(r.prefix, path.Dir(name)) -} - // GetAllFQMNs returns a list of all FQMNs func (r *Registry) GetAllFQMNs() []string { var keys []string @@ -539,53 +545,118 @@ func (r *Registry) GetSimpleOperationIDs() bool { return r.simpleOperationIDs } -// sanitizePackageName replaces unallowed character in package name -// with allowed character. -func sanitizePackageName(pkgName string) string { - pkgName = strings.Replace(pkgName, ".", "_", -1) - pkgName = strings.Replace(pkgName, "-", "_", -1) - return pkgName +// SetWarnOnUnboundMethods sets warnOnUnboundMethods +func (r *Registry) SetWarnOnUnboundMethods(warn bool) { + r.warnOnUnboundMethods = warn +} + +// SetGenerateUnboundMethods sets generateUnboundMethods +func (r *Registry) SetGenerateUnboundMethods(generate bool) { + r.generateUnboundMethods = generate +} + +// SetOmitPackageDoc controls whether the generated code contains a package comment (if set to false, it will contain one) +func (r *Registry) SetOmitPackageDoc(omit bool) { + r.omitPackageDoc = omit } -// defaultGoPackageName returns the default go package name to be used for go files generated from "f". -// You might need to use an unique alias for the package when you import it. Use ReserveGoPackageAlias to get a unique alias. -func (r *Registry) defaultGoPackageName(f *descriptorpb.FileDescriptorProto) string { - name := r.packageIdentityName(f) - return sanitizePackageName(name) +// GetOmitPackageDoc returns whether a package comment will be omitted from the generated code +func (r *Registry) GetOmitPackageDoc() bool { + return r.omitPackageDoc } -// packageIdentityName returns the identity of packages. -// protoc-gen-grpc-gateway rejects CodeGenerationRequests which contains more than one packages -// as protoc-gen-go does. -func (r *Registry) packageIdentityName(f *descriptorpb.FileDescriptorProto) string { - if f.Options != nil && f.Options.GoPackage != nil { - gopkg := f.Options.GetGoPackage() - idx := strings.LastIndex(gopkg, "/") - if idx < 0 { - gopkg = gopkg[idx+1:] +// RegisterOpenAPIOptions registers OpenAPI options +func (r *Registry) RegisterOpenAPIOptions(opts *openapiconfig.OpenAPIOptions) error { + if opts == nil { + return nil + } + + for _, opt := range opts.File { + if _, ok := r.files[opt.File]; !ok { + return fmt.Errorf("no file %s found", opt.File) + } + r.fileOptions[opt.File] = opt.Option + } + + // build map of all registered methods + methods := make(map[string]struct{}) + services := make(map[string]struct{}) + for _, f := range r.files { + for _, s := range f.Services { + services[s.FQSN()] = struct{}{} + for _, m := range s.Methods { + methods[m.FQMN()] = struct{}{} + } } + } - gopkg = gopkg[idx+1:] - // package name is overrided with the string after the - // ';' character - sc := strings.IndexByte(gopkg, ';') - if sc < 0 { - return sanitizePackageName(gopkg) + for _, opt := range opts.Method { + qualifiedMethod := "." + opt.Method + if _, ok := methods[qualifiedMethod]; !ok { + return fmt.Errorf("no method %s found", opt.Method) + } + r.methodOptions[qualifiedMethod] = opt.Option + } + for _, opt := range opts.Message { + qualifiedMessage := "." + opt.Message + if _, ok := r.msgs[qualifiedMessage]; !ok { + return fmt.Errorf("no message %s found", opt.Message) } - return sanitizePackageName(gopkg[sc+1:]) + r.messageOptions[qualifiedMessage] = opt.Option } - if p := r.importPath; len(p) != 0 { - if i := strings.LastIndex(p, "/"); i >= 0 { - p = p[i+1:] + + for _, opt := range opts.Service { + qualifiedService := "." + opt.Service + if _, ok := services[qualifiedService]; !ok { + return fmt.Errorf("no service %s found", opt.Service) } - return p + r.serviceOptions[qualifiedService] = opt.Option } - if f.Package == nil { - base := filepath.Base(f.GetName()) - ext := filepath.Ext(base) - return strings.TrimSuffix(base, ext) + // build map of all registered fields + fields := make(map[string]struct{}) + for _, m := range r.msgs { + for _, f := range m.Fields { + fields[f.FQFN()] = struct{}{} + } + } + for _, opt := range opts.Field { + qualifiedField := "." + opt.Field + if _, ok := fields[qualifiedField]; !ok { + return fmt.Errorf("no field %s found", opt.Field) + } + r.fieldOptions[qualifiedField] = opt.Option } - return f.GetPackage() + return nil +} + +// GetOpenAPIFileOption returns a registered OpenAPI option for a file +func (r *Registry) GetOpenAPIFileOption(file string) (*options.Swagger, bool) { + opt, ok := r.fileOptions[file] + return opt, ok +} + +// GetOpenAPIMethodOption returns a registered OpenAPI option for a method +func (r *Registry) GetOpenAPIMethodOption(qualifiedMethod string) (*options.Operation, bool) { + opt, ok := r.methodOptions[qualifiedMethod] + return opt, ok +} + +// GetOpenAPIMessageOption returns a registered OpenAPI option for a message +func (r *Registry) GetOpenAPIMessageOption(qualifiedMessage string) (*options.Schema, bool) { + opt, ok := r.messageOptions[qualifiedMessage] + return opt, ok +} + +// GetOpenAPIServiceOption returns a registered OpenAPI option for a service +func (r *Registry) GetOpenAPIServiceOption(qualifiedService string) (*options.Tag, bool) { + opt, ok := r.serviceOptions[qualifiedService] + return opt, ok +} + +// GetOpenAPIFieldOption returns a registered OpenAPI option for a field +func (r *Registry) GetOpenAPIFieldOption(qualifiedField string) (*options.JSONSchema, bool) { + opt, ok := r.fieldOptions[qualifiedField] + return opt, ok } diff --git a/gateway/internal/descriptor/registry_test.go b/gateway/internal/descriptor/registry_test.go index 59f0579..39cdb92 100644 --- a/gateway/internal/descriptor/registry_test.go +++ b/gateway/internal/descriptor/registry_test.go @@ -3,26 +3,42 @@ package descriptor import ( "testing" - descriptorpb "github.com/golang/protobuf/protoc-gen-go/descriptor" - pluginpb "github.com/golang/protobuf/protoc-gen-go/plugin" + // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor/openapiconfig" + "github.com/binchencoder/ease-gateway/gateway/internal/descriptor/openapiconfig" + "google.golang.org/protobuf/compiler/protogen" "google.golang.org/protobuf/encoding/prototext" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/descriptorpb" + "google.golang.org/protobuf/types/pluginpb" ) -func loadFile(t *testing.T, reg *Registry, src string) *descriptorpb.FileDescriptorProto { - var file descriptorpb.FileDescriptorProto - if err := prototext.Unmarshal([]byte(src), &file); err != nil { - t.Fatalf("proto.UnmarshalText(%s, &file) failed with %v; want success", src, err) +func newGeneratorFromSources(req *pluginpb.CodeGeneratorRequest, sources ...string) (*protogen.Plugin, error) { + for _, src := range sources { + var fd descriptorpb.FileDescriptorProto + if err := prototext.Unmarshal([]byte(src), &fd); err != nil { + return nil, err + } + req.FileToGenerate = append(req.FileToGenerate, fd.GetName()) + req.ProtoFile = append(req.ProtoFile, &fd) } - reg.loadFile(&file) - return &file + return protogen.Options{}.New(req) } -func load(t *testing.T, reg *Registry, src string) error { - var req pluginpb.CodeGeneratorRequest - if err := prototext.Unmarshal([]byte(src), &req); err != nil { - t.Fatalf("proto.UnmarshalText(%s, &file) failed with %v; want success", src, err) +func loadFileWithCodeGeneratorRequest(t *testing.T, reg *Registry, req *pluginpb.CodeGeneratorRequest, sources ...string) []*descriptorpb.FileDescriptorProto { + plugin, err := newGeneratorFromSources(req, sources...) + if err != nil { + t.Fatalf("failed to create a generator: %v", err) } - return reg.Load(&req) + err = reg.LoadFromPlugin(plugin) + if err != nil { + t.Fatalf("failed to Registry.LoadFromPlugin(): %v", err) + } + return plugin.Request.ProtoFile +} + +func loadFile(t *testing.T, reg *Registry, src string) *descriptorpb.FileDescriptorProto { + fds := loadFileWithCodeGeneratorRequest(t, reg, &pluginpb.CodeGeneratorRequest{}, src) + return fds[0] } func TestLoadFile(t *testing.T) { @@ -136,8 +152,9 @@ func TestLoadFileWithoutPackage(t *testing.T) { func TestLoadFileWithMapping(t *testing.T) { reg := NewRegistry() - reg.AddPkgMap("path/to/example.proto", "example.com/proj/example/proto") - loadFile(t, reg, ` + loadFileWithCodeGeneratorRequest(t, reg, &pluginpb.CodeGeneratorRequest{ + Parameter: proto.String("Mpath/to/example.proto=example.com/proj/example/proto"), + }, ` name: 'path/to/example.proto' package: 'example' `) @@ -204,13 +221,12 @@ func TestLoadFileWithPackageNameCollision(t *testing.T) { func TestLoadFileWithIdenticalGoPkg(t *testing.T) { reg := NewRegistry() - reg.AddPkgMap("path/to/another.proto", "example.com/example") - reg.AddPkgMap("path/to/example.proto", "example.com/example") - loadFile(t, reg, ` + loadFileWithCodeGeneratorRequest(t, reg, &pluginpb.CodeGeneratorRequest{ + Parameter: proto.String("Mpath/to/another.proto=example.com/example,Mpath/to/example.proto=example.com/example"), + }, ` name: 'path/to/another.proto' package: 'example' - `) - loadFile(t, reg, ` + `, ` name: 'path/to/example.proto' package: 'example' `) @@ -236,25 +252,9 @@ func TestLoadFileWithIdenticalGoPkg(t *testing.T) { } } -func TestLoadFileWithPrefix(t *testing.T) { - reg := NewRegistry() - reg.SetPrefix("third_party") - loadFile(t, reg, ` - name: 'path/to/example.proto' - package: 'example' - `) - - file := reg.files["path/to/example.proto"] - if file == nil { - t.Errorf("reg.files[%q] = nil; want non-nil", "example.proto") - return - } - wantPkg := GoPackage{Path: "third_party/path/to", Name: "example"} - if got, want := file.GoPkg, wantPkg; got != want { - t.Errorf("file.GoPkg = %#v; want %#v", got, want) - } -} - +// TestLookupMsgWithoutPackage tests a case when there is no "package" directive. +// In Go, it is required to have a generated package so we rely on +// google.golang.org/protobuf/compiler/protogen to provide it. func TestLookupMsgWithoutPackage(t *testing.T) { reg := NewRegistry() fd := loadFile(t, reg, ` @@ -520,8 +520,11 @@ func TestLoadWithInconsistentTargetPackage(t *testing.T) { consistent: true, }, } { - reg := NewRegistry() - err := load(t, reg, spec.req) + var req pluginpb.CodeGeneratorRequest + if err := prototext.Unmarshal([]byte(spec.req), &req); err != nil { + t.Fatalf("proto.UnmarshalText(%s, &file) failed with %v; want success", spec.req, err) + } + _, err := newGeneratorFromSources(&req) if got, want := err == nil, spec.consistent; got != want { if want { t.Errorf("reg.Load(%s) failed with %v; want success", spec.req, err) @@ -532,7 +535,7 @@ func TestLoadWithInconsistentTargetPackage(t *testing.T) { } } -func TestLoadOverridedPackageName(t *testing.T) { +func TestLoadOverriddenPackageName(t *testing.T) { reg := NewRegistry() loadFile(t, reg, ` name: 'example.proto' @@ -569,43 +572,6 @@ func TestLoadWithStandalone(t *testing.T) { } } -func TestLoadSetInputPath(t *testing.T) { - reg := NewRegistry() - reg.SetImportPath("foo/examplepb") - loadFile(t, reg, ` - name: 'example.proto' - package: 'example' - `) - file := reg.files["example.proto"] - if file == nil { - t.Errorf("reg.files[%q] = nil; want non-nil", "example.proto") - return - } - wantPkg := GoPackage{Path: ".", Name: "examplepb"} - if got, want := file.GoPkg, wantPkg; got != want { - t.Errorf("file.GoPkg = %#v; want %#v", got, want) - } -} - -func TestLoadGoPackageInputPath(t *testing.T) { - reg := NewRegistry() - reg.SetImportPath("examplepb") - loadFile(t, reg, ` - name: 'example.proto' - package: 'example' - options < go_package: 'example.com/xyz;pb' > - `) - file := reg.files["example.proto"] - if file == nil { - t.Errorf("reg.files[%q] = nil; want non-nil", "example.proto") - return - } - wantPkg := GoPackage{Path: "example.com/xyz", Name: "pb"} - if got, want := file.GoPkg, wantPkg; got != want { - t.Errorf("file.GoPkg = %#v; want %#v", got, want) - } -} - func TestUnboundExternalHTTPRules(t *testing.T) { reg := NewRegistry() methodName := ".example.ExampleService.Echo" @@ -635,6 +601,175 @@ func TestUnboundExternalHTTPRules(t *testing.T) { assertStringSlice(t, "unbound external HTTP rules", reg.UnboundExternalHTTPRules(), []string{}) } +func TestRegisterOpenAPIOptions(t *testing.T) { + codeReqText := `file_to_generate: 'a.proto' + proto_file < + name: 'a.proto' + package: 'example.foo' + options < go_package: 'foo' > + message_type < + name: 'ExampleMessage' + field < + name: 'str' + label: LABEL_OPTIONAL + type: TYPE_STRING + number: 1 + > + > + service < + name: "AService" + method < + name: "Meth" + input_type: "ExampleMessage" + output_type: "ExampleMessage" + options < + [google.api.http] < post: "/v1/a" body: "*" > + > + > + > + > + ` + var codeReq pluginpb.CodeGeneratorRequest + if err := prototext.Unmarshal([]byte(codeReqText), &codeReq); err != nil { + t.Fatalf("proto.UnmarshalText(%s, &file) failed with %v; want success", codeReqText, err) + } + + for _, tcase := range []struct { + options *openapiconfig.OpenAPIOptions + shouldErr bool + desc string + }{ + { + desc: "handle nil options", + }, + { + desc: "successfully add options if referenced entity exists", + options: &openapiconfig.OpenAPIOptions{ + File: []*openapiconfig.OpenAPIFileOption{ + { + File: "a.proto", + }, + }, + Method: []*openapiconfig.OpenAPIMethodOption{ + { + Method: "example.foo.AService.Meth", + }, + }, + Message: []*openapiconfig.OpenAPIMessageOption{ + { + Message: "example.foo.ExampleMessage", + }, + }, + Service: []*openapiconfig.OpenAPIServiceOption{ + { + Service: "example.foo.AService", + }, + }, + Field: []*openapiconfig.OpenAPIFieldOption{ + { + Field: "example.foo.ExampleMessage.str", + }, + }, + }, + }, + { + desc: "reject fully qualified names with leading \".\"", + options: &openapiconfig.OpenAPIOptions{ + File: []*openapiconfig.OpenAPIFileOption{ + { + File: "a.proto", + }, + }, + Method: []*openapiconfig.OpenAPIMethodOption{ + { + Method: ".example.foo.AService.Meth", + }, + }, + Message: []*openapiconfig.OpenAPIMessageOption{ + { + Message: ".example.foo.ExampleMessage", + }, + }, + Service: []*openapiconfig.OpenAPIServiceOption{ + { + Service: ".example.foo.AService", + }, + }, + Field: []*openapiconfig.OpenAPIFieldOption{ + { + Field: ".example.foo.ExampleMessage.str", + }, + }, + }, + shouldErr: true, + }, + { + desc: "error if file does not exist", + options: &openapiconfig.OpenAPIOptions{ + File: []*openapiconfig.OpenAPIFileOption{ + { + File: "b.proto", + }, + }, + }, + shouldErr: true, + }, + { + desc: "error if method does not exist", + options: &openapiconfig.OpenAPIOptions{ + Method: []*openapiconfig.OpenAPIMethodOption{ + { + Method: "example.foo.AService.Meth2", + }, + }, + }, + shouldErr: true, + }, + { + desc: "error if message does not exist", + options: &openapiconfig.OpenAPIOptions{ + Message: []*openapiconfig.OpenAPIMessageOption{ + { + Message: "example.foo.NonexistentMessage", + }, + }, + }, + shouldErr: true, + }, + { + desc: "error if service does not exist", + options: &openapiconfig.OpenAPIOptions{ + Service: []*openapiconfig.OpenAPIServiceOption{ + { + Service: "example.foo.AService1", + }, + }, + }, + shouldErr: true, + }, + { + desc: "error if field does not exist", + options: &openapiconfig.OpenAPIOptions{ + Field: []*openapiconfig.OpenAPIFieldOption{ + { + Field: "example.foo.ExampleMessage.str1", + }, + }, + }, + shouldErr: true, + }, + } { + t.Run(tcase.desc, func(t *testing.T) { + reg := NewRegistry() + loadFileWithCodeGeneratorRequest(t, reg, &codeReq) + err := reg.RegisterOpenAPIOptions(tcase.options) + if (err != nil) != tcase.shouldErr { + t.Fatalf("got unexpected error: %s", err) + } + }) + } +} + func assertStringSlice(t *testing.T, message string, got, want []string) { if len(got) != len(want) { t.Errorf("%s = %#v len(%d); want %#v len(%d)", message, got, len(got), want, len(want)) diff --git a/gateway/internal/descriptor/services.go b/gateway/internal/descriptor/services.go index 24efff4..8e5187c 100644 --- a/gateway/internal/descriptor/services.go +++ b/gateway/internal/descriptor/services.go @@ -6,11 +6,11 @@ import ( "strings" "github.com/golang/glog" - descriptorpb "github.com/golang/protobuf/protoc-gen-go/descriptor" "github.com/grpc-ecosystem/grpc-gateway/v2/internal/httprule" // options "google.golang.org/genproto/googleapis/api/annotations" options "github.com/binchencoder/ease-gateway/httpoptions" "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/descriptorpb" ) var ( @@ -62,7 +62,20 @@ func (r *Registry) loadServices(file *File) error { optsList = append(optsList, opts) } if len(optsList) == 0 { - glog.Warningf("No HttpRule found for method: %s.%s", svc.GetName(), md.GetName()) + if r.generateUnboundMethods { + defaultOpts, err := defaultAPIOptions(svc, md) + if err != nil { + glog.Errorf("Failed to generate default HttpRule from %s.%s: %v", svc.GetName(), md.GetName(), err) + return err + } + optsList = append(optsList, defaultOpts) + } else { + logFn := glog.V(1).Infof + if r.warnOnUnboundMethods { + logFn = glog.Warningf + } + logFn("No HttpRule found for method: %s.%s", svc.GetName(), md.GetName()) + } } meth, err := r.newMethod(svc, md, optsList, mopts) if err != nil { @@ -279,6 +292,25 @@ func extractAPIOptions(meth *descriptorpb.MethodDescriptorProto) (*options.HttpR return opts, mopts, nil } +func defaultAPIOptions(svc *Service, md *descriptorpb.MethodDescriptorProto) (*options.HttpRule, error) { + // FQSN prefixes the service's full name with a '.', e.g.: '.example.ExampleService' + fqsn := strings.TrimPrefix(svc.FQSN(), ".") + + // This generates an HttpRule that matches the gRPC mapping to HTTP/2 described in + // https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#requests + // i.e.: + // * method is POST + // * path is "//" + // * body should contain the serialized request message + rule := &options.HttpRule{ + Pattern: &options.HttpRule_Post{ + Post: fmt.Sprintf("/%s/%s", fqsn, md.GetName()), + }, + Body: "*", + } + return rule, nil +} + func (r *Registry) newParam(meth *Method, path string) (Parameter, error) { msg := meth.RequestType fields, err := r.resolveFieldPath(msg, path, true) diff --git a/gateway/internal/descriptor/services_test.go b/gateway/internal/descriptor/services_test.go index c665c5d..6214fcc 100644 --- a/gateway/internal/descriptor/services_test.go +++ b/gateway/internal/descriptor/services_test.go @@ -4,10 +4,11 @@ import ( "reflect" "testing" - descriptorpb "github.com/golang/protobuf/protoc-gen-go/descriptor" "github.com/grpc-ecosystem/grpc-gateway/v2/internal/httprule" + "google.golang.org/protobuf/compiler/protogen" "google.golang.org/protobuf/encoding/prototext" "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/descriptorpb" ) func compilePath(t *testing.T, path string) httprule.Template { @@ -19,9 +20,14 @@ func compilePath(t *testing.T, path string) httprule.Template { } func testExtractServices(t *testing.T, input []*descriptorpb.FileDescriptorProto, target string, wantSvcs []*Service) { - reg := NewRegistry() + testExtractServicesWithRegistry(t, NewRegistry(), input, target, wantSvcs) +} + +func testExtractServicesWithRegistry(t *testing.T, reg *Registry, input []*descriptorpb.FileDescriptorProto, target string, wantSvcs []*Service) { for _, file := range input { - reg.loadFile(file) + reg.loadFile(file.GetName(), &protogen.File{ + Proto: file, + }) } err := reg.loadServices(reg.files[target]) if err != nil { @@ -282,6 +288,74 @@ func TestExtractServicesWithoutAnnotation(t *testing.T) { testExtractServices(t, []*descriptorpb.FileDescriptorProto{&fd}, "path/to/example.proto", file.Services) } +func TestExtractServicesGenerateUnboundMethods(t *testing.T) { + src := ` + name: "path/to/example.proto", + package: "example" + message_type < + name: "StringMessage" + field < + name: "string" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_STRING + > + > + service < + name: "ExampleService" + method < + name: "Echo" + input_type: "StringMessage" + output_type: "StringMessage" + > + > + ` + var fd descriptorpb.FileDescriptorProto + if err := prototext.Unmarshal([]byte(src), &fd); err != nil { + t.Fatalf("prototext.Unmarshal (%s, &fd) failed with %v; want success", src, err) + } + msg := &Message{ + DescriptorProto: fd.MessageType[0], + Fields: []*Field{ + { + FieldDescriptorProto: fd.MessageType[0].Field[0], + }, + }, + } + file := &File{ + FileDescriptorProto: &fd, + GoPkg: GoPackage{ + Path: "path/to/example.pb", + Name: "example_pb", + }, + Messages: []*Message{msg}, + Services: []*Service{ + { + ServiceDescriptorProto: fd.Service[0], + Methods: []*Method{ + { + MethodDescriptorProto: fd.Service[0].Method[0], + RequestType: msg, + ResponseType: msg, + Bindings: []*Binding{ + { + PathTmpl: compilePath(t, "/example.ExampleService/Echo"), + HTTPMethod: "POST", + Body: &Body{FieldPath: nil}, + }, + }, + }, + }, + }, + }, + } + + crossLinkFixture(file) + reg := NewRegistry() + reg.SetGenerateUnboundMethods(true) + testExtractServicesWithRegistry(t, reg, []*descriptorpb.FileDescriptorProto{&fd}, "path/to/example.proto", file.Services) +} + func TestExtractServicesCrossPackage(t *testing.T) { srcs := []string{ ` @@ -328,7 +402,7 @@ func TestExtractServicesCrossPackage(t *testing.T) { for _, src := range srcs { var fd descriptorpb.FileDescriptorProto if err := prototext.Unmarshal([]byte(src), &fd); err != nil { - t.Fatalf("proto.UnmarshalText(%s, &fd) failed with %v; want success", src, err) + t.Fatalf("prototext.Unmarshal(%s, &fd) failed with %v; want success", src, err) } fds = append(fds, &fd) } @@ -973,7 +1047,9 @@ func TestExtractServicesWithError(t *testing.T) { if err := prototext.Unmarshal([]byte(src), &fd); err != nil { t.Fatalf("proto.UnmarshalText(%s, &fd) failed with %v; want success", src, err) } - reg.loadFile(&fd) + reg.loadFile(spec.target, &protogen.File{ + Proto: &fd, + }) } err := reg.loadServices(reg.files[spec.target]) if err == nil { @@ -1153,7 +1229,9 @@ func TestResolveFieldPath(t *testing.T) { t.Fatalf("proto.Unmarshal(%s) failed with %v; want success", spec.src, err) } reg := NewRegistry() - reg.loadFile(&file) + reg.loadFile(file.GetName(), &protogen.File{ + Proto: &file, + }) f, err := reg.LookupFile(file.GetName()) if err != nil { t.Fatalf("reg.LookupFile(%q) failed with %v; want success; on file=%s", file.GetName(), err, spec.src) @@ -1255,7 +1333,9 @@ func TestExtractServicesWithDeleteBody(t *testing.T) { if err := prototext.Unmarshal([]byte(src), &fd); err != nil { t.Fatalf("proto.UnmarshalText(%s, &fd) failed with %v; want success", src, err) } - reg.loadFile(&fd) + reg.loadFile(fd.GetName(), &protogen.File{ + Proto: &fd, + }) } err := reg.loadServices(reg.files[spec.target]) if spec.expectErr && err == nil { diff --git a/gateway/internal/descriptor/types.go b/gateway/internal/descriptor/types.go index 12dae9e..ef2c0d7 100644 --- a/gateway/internal/descriptor/types.go +++ b/gateway/internal/descriptor/types.go @@ -4,10 +4,12 @@ import ( "fmt" "strings" "unicode" - descriptorpb "github.com/golang/protobuf/protoc-gen-go/descriptor" + // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/casing" "github.com/binchencoder/ease-gateway/gateway/internal/casing" "github.com/grpc-ecosystem/grpc-gateway/v2/internal/httprule" + "google.golang.org/protobuf/types/descriptorpb" + "google.golang.org/protobuf/types/pluginpb" options "github.com/binchencoder/ease-gateway/httpoptions" "github.com/binchencoder/gateway-proto/data" @@ -19,13 +21,13 @@ func IsWellKnownType(typeName string) bool { return ok } -// GoPackage represents a golang package +// GoPackage represents a golang package. type GoPackage struct { // Path is the package path to the package. Path string // Name is the package name of the package Name string - // Alias is an alias of the package unique within the current invokation of grpc-gateway generator. + // Alias is an alias of the package unique within the current invocation of grpc-gateway generator. Alias string } @@ -42,11 +44,24 @@ func (p GoPackage) String() string { return fmt.Sprintf("%s %q", p.Alias, p.Path) } +// ResponseFile wraps pluginpb.CodeGeneratorResponse_File. +type ResponseFile struct { + *pluginpb.CodeGeneratorResponse_File + // GoPkg is the Go package of the generated file. + GoPkg GoPackage +} + // File wraps descriptorpb.FileDescriptorProto for richer features. type File struct { *descriptorpb.FileDescriptorProto - // GoPkg is the go package of the go file generated from this file.. + // GoPkg is the go package of the go file generated from this file. GoPkg GoPackage + // GeneratedFilenamePrefix is used to construct filenames for generated + // files associated with this source file. + // + // For example, the source file "dir/foo.proto" might have a filename prefix + // of "dir/foo". Appending ".pb.go" produces an output file of "dir/foo.pb.go". + GeneratedFilenamePrefix string // Messages is the list of messages defined in this file. Messages []*Message // Enums is the list of enums defined in this file. @@ -69,20 +84,20 @@ func (f *File) proto2() bool { return f.Syntax == nil || f.GetSyntax() == "proto2" } -// Message describes a protocol buffer message types +// Message describes a protocol buffer message types. type Message struct { - // File is the file where the message is defined + *descriptorpb.DescriptorProto + // File is the file where the message is defined. File *File // Outers is a list of outer messages if this message is a nested type. Outers []string - *descriptorpb.DescriptorProto + // Fields is a list of message fields. Fields []*Field - // Index is proto path index of this message in File. Index int - + // ForcePrefixedName when set to true, prefixes a type with a package prefix. ForcePrefixedName bool - + // Checked fields, with key constructed with message's package, and field type, // And value as the HasRule result. // To avoid deadloop in HasRule(). Example problem messages: @@ -191,16 +206,16 @@ func (m *Message) GoType(currentPackage string) string { return fmt.Sprintf("%s.%s", m.File.Pkg(), name) } -// Enum describes a protocol buffer enum types +// Enum describes a protocol buffer enum types. type Enum struct { + *descriptorpb.EnumDescriptorProto // File is the file where the enum is defined File *File // Outers is a list of outer messages if this enum is a nested type. Outers []string - *descriptorpb.EnumDescriptorProto - + // Index is a enum index value. Index int - + // ForcePrefixedName when set to true, prefixes a type with a package prefix. ForcePrefixedName bool } @@ -232,9 +247,9 @@ func (e *Enum) GoType(currentPackage string) string { // Service wraps descriptorpb.ServiceDescriptorProto for richer features. type Service struct { + *descriptorpb.ServiceDescriptorProto // File is the file where this service is defined. File *File - *descriptorpb.ServiceDescriptorProto // service ID uniquely identifies this service in context of org. ServiceId *data.ServiceId @@ -250,7 +265,7 @@ type Service struct { // Methods is the list of methods defined in this service. Methods []*Method - + // ForcePrefixedName when set to true, prefixes a type with a package prefix. ForcePrefixedName bool } @@ -283,10 +298,9 @@ func (s *Service) ClientConstructorName() string { // Method wraps descriptorpb.MethodDescriptorProto for richer features. type Method struct { + *descriptorpb.MethodDescriptorProto // Service is the service which this method belongs to. Service *Service - *descriptorpb.MethodDescriptorProto - // RequestType is the message type of requests to this method. RequestType *Message // ResponseType is the message type of responses from this method. @@ -305,7 +319,7 @@ type Method struct { // FQMN returns a fully qualified rpc method name of this method. func (m *Method) FQMN() string { - components := []string{} + var components []string components = append(components, m.Service.FQSN()) components = append(components, m.GetName()) return strings.Join(components, ".") @@ -344,17 +358,22 @@ func (b *Binding) ExplicitParams() []string { // Field wraps descriptorpb.FieldDescriptorProto for richer features. type Field struct { + *descriptorpb.FieldDescriptorProto // Message is the message type which this field belongs to. Message *Message // FieldMessage is the message type of the field. FieldMessage *Message - *descriptorpb.FieldDescriptorProto - + // ForcePrefixedName when set to true, prefixes a type with a package prefix. ForcePrefixedName bool Rules []*Rule } +// FQFN returns a fully qualified field name of this field. +func (f *Field) FQFN() string { + return strings.Join([]string{f.Message.FQMN(), f.GetName()}, ".") +} + // IsOneOf return true if this field is oneof field. func (f *Field) IsOneOf() bool { return f.OneofIndex != nil diff --git a/gateway/internal/generator/generator.go b/gateway/internal/generator/generator.go index 8ec129a..ee5f503 100644 --- a/gateway/internal/generator/generator.go +++ b/gateway/internal/generator/generator.go @@ -2,13 +2,12 @@ package generator import ( - pluginpb "github.com/golang/protobuf/protoc-gen-go/plugin" - // descriptorpb "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor" - descriptorpb "github.com/binchencoder/ease-gateway/gateway/internal/descriptor" + // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor" + "github.com/binchencoder/ease-gateway/gateway/internal/descriptor" ) // Generator is an abstraction of code generators. type Generator interface { // Generate generates output files from input .proto files. - Generate(targets []*descriptorpb.File) ([]*pluginpb.CodeGeneratorResponse_File, error) + Generate(targets []*descriptor.File) ([]*descriptor.ResponseFile, error) } diff --git a/gateway/protoc-gen-grpc-gateway/BUILD.bazel b/gateway/protoc-gen-grpc-gateway/BUILD.bazel index 48a3ca8..edbd060 100644 --- a/gateway/protoc-gen-grpc-gateway/BUILD.bazel +++ b/gateway/protoc-gen-grpc-gateway/BUILD.bazel @@ -1,4 +1,4 @@ -load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library") +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test") load("@io_bazel_rules_go//proto:compiler.bzl", "go_proto_compiler") package(default_visibility = ["//visibility:private"]) @@ -11,9 +11,7 @@ go_library( "//gateway/internal/descriptor:go_default_library", "//gateway/protoc-gen-grpc-gateway/internal/gengateway:go_default_library", "@com_github_golang_glog//:go_default_library", - "@com_github_grpc_ecosystem_grpc_gateway//internal/codegenerator:go_default_library", - "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", - "@org_golang_google_protobuf//proto:go_default_library", + "@org_golang_google_protobuf//compiler/protogen:go_default_library", ], ) @@ -40,8 +38,15 @@ go_proto_compiler( "@org_golang_google_grpc//:go_default_library", "@org_golang_google_grpc//codes:go_default_library", "@org_golang_google_grpc//grpclog:go_default_library", + "@org_golang_google_grpc//metadata:go_default_library", "@org_golang_google_grpc//status:go_default_library", - "@org_golang_x_net//context:go_default_library", - "@org_golang_google_protobuf//proto:go_default_library", + "@org_golang_google_protobuf//proto:go_default_library", ], ) + +go_test( + name = "go_default_test", + srcs = ["main_test.go"], + embed = [":go_default_library"], + deps = ["//gateway/internal/descriptor:go_default_library"], +) diff --git a/gateway/protoc-gen-grpc-gateway/internal/gengateway/BUILD.bazel b/gateway/protoc-gen-grpc-gateway/internal/gengateway/BUILD.bazel index a3b18ba..665a4bb 100644 --- a/gateway/protoc-gen-grpc-gateway/internal/gengateway/BUILD.bazel +++ b/gateway/protoc-gen-grpc-gateway/internal/gengateway/BUILD.bazel @@ -13,13 +13,12 @@ go_library( deps = [ "//httpoptions:go_default_library", "//gateway/internal/casing:go_default_library", - "//gateway/runtime:go_default_library", "//gateway/internal/descriptor:go_default_library", "//gateway/internal/generator:go_default_library", "@com_github_grpc_ecosystem_grpc_gateway//utilities:go_default_library", "@com_github_golang_glog//:go_default_library", - "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", "@org_golang_google_protobuf//proto:go_default_library", + "@org_golang_google_protobuf//types/pluginpb:go_default_library", ], ) @@ -32,9 +31,9 @@ go_test( ], embed = [":go_default_library"], deps = [ - "//gateway/internal/descriptor:go_default_library", + "//gateway/internal/descriptor:go_default_library", "@com_github_grpc_ecosystem_grpc_gateway//internal/httprule:go_default_library", - "@io_bazel_rules_go//proto/wkt:descriptor_go_proto", "@org_golang_google_protobuf//proto:go_default_library", + "@org_golang_google_protobuf//types/descriptorpb:go_default_library", ], ) diff --git a/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator.go b/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator.go index 82684ac..a35a322 100644 --- a/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator.go +++ b/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator.go @@ -3,48 +3,32 @@ package gengateway import ( "errors" "fmt" - "go/format" - "path" - "path/filepath" - "strings" - "github.com/golang/glog" - pluginpb "github.com/golang/protobuf/protoc-gen-go/plugin" - // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor" "github.com/binchencoder/ease-gateway/gateway/internal/descriptor" - // gen "github.com/grpc-ecosystem/grpc-gateway/v2/internal/generator" gen "github.com/binchencoder/ease-gateway/gateway/internal/generator" + "go/format" "google.golang.org/protobuf/proto" - - options "github.com/binchencoder/ease-gateway/httpoptions" + "google.golang.org/protobuf/types/pluginpb" + "path" ) var ( errNoTargetService = errors.New("no target service defined in the file") ) -type pathType int - -const ( - pathTypeImport pathType = iota - pathTypeSourceRelative -) - type generator struct { reg *descriptor.Registry baseImports []descriptor.GoPackage useRequestContext bool registerFuncSuffix string - pathType pathType - modulePath string allowPatchFeature bool standalone bool } // New returns a new generator which generates grpc gateway files. -func New(reg *descriptor.Registry, useRequestContext bool, registerFuncSuffix, pathTypeString, modulePathString string, +func New(reg *descriptor.Registry, useRequestContext bool, registerFuncSuffix string, allowPatchFeature, standalone bool) gen.Generator { var imports []descriptor.GoPackage for pkgpath, alias := range map[string]string{ @@ -92,32 +76,21 @@ func New(reg *descriptor.Registry, useRequestContext bool, registerFuncSuffix, p imports = append(imports, pkg) } - var pathType pathType - switch pathTypeString { - case "", "import": - // paths=import is default - case "source_relative": - pathType = pathTypeSourceRelative - default: - glog.Fatalf(`Unknown path type %q: want "import" or "source_relative".`, pathTypeString) - } - return &generator{ reg: reg, baseImports: imports, useRequestContext: useRequestContext, registerFuncSuffix: registerFuncSuffix, - pathType: pathType, - modulePath: modulePathString, allowPatchFeature: allowPatchFeature, standalone: standalone, } } -func (g *generator) Generate(targets []*descriptor.File) ([]*pluginpb.CodeGeneratorResponse_File, error) { - var files []*pluginpb.CodeGeneratorResponse_File +func (g *generator) Generate(targets []*descriptor.File) ([]*descriptor.ResponseFile, error) { + var files []*descriptor.ResponseFile for _, file := range targets { glog.V(1).Infof("Processing %s", file.GetName()) + code, err := g.generate(file) if err == errNoTargetService { glog.V(1).Infof("%s: %v", file.GetName(), err) @@ -131,44 +104,17 @@ func (g *generator) Generate(targets []*descriptor.File) ([]*pluginpb.CodeGenera glog.Errorf("%v: %s", err, code) return nil, err } - name, err := g.getFilePath(file) - if err != nil { - glog.Errorf("%v: %s", err, code) - return nil, err - } - ext := filepath.Ext(name) - base := strings.TrimSuffix(name, ext) - output := fmt.Sprintf("%s.pb.gw.go", base) - files = append(files, &pluginpb.CodeGeneratorResponse_File{ - Name: proto.String(output), - Content: proto.String(string(formatted)), + files = append(files, &descriptor.ResponseFile{ + GoPkg: file.GoPkg, + CodeGeneratorResponse_File: &pluginpb.CodeGeneratorResponse_File{ + Name: proto.String(file.GeneratedFilenamePrefix + ".pb.gw.go"), + Content: proto.String(string(formatted)), + }, }) - glog.V(1).Infof("Will emit %s", output) } return files, nil } -func (g *generator) getFilePath(file *descriptor.File) (string, error) { - name := file.GetName() - switch { - case g.modulePath != "" && g.pathType != pathTypeImport: - return "", errors.New("cannot use module= with paths=") - - case g.modulePath != "": - trimPath, pkgPath := g.modulePath+"/", file.GoPkg.Path+"/" - if !strings.HasPrefix(pkgPath, trimPath) { - return "", fmt.Errorf("%v: file go path does not match module prefix: %v", file.GoPkg.Path, trimPath) - } - return filepath.Join(strings.TrimPrefix(pkgPath, trimPath), filepath.Base(name)), nil - - case g.pathType == pathTypeImport && file.GoPkg.Path != "": - return fmt.Sprintf("%s/%s", file.GoPkg.Path, filepath.Base(name)), nil - - default: - return name, nil - } -} - func (g *generator) generate(file *descriptor.File) (string, error) { pkgSeen := make(map[string]bool) var imports []descriptor.GoPackage @@ -189,10 +135,6 @@ func (g *generator) generate(file *descriptor.File) (string, error) { if m.RequestType.HasRule() { g.populateImportForValidation(m.RequestType, file, &pkgSeen, &imports) } - if m.Options == nil || !proto.HasExtension(m.Options, options.E_Http) || - pkg == file.GoPkg || pkgSeen[pkg.Path] { - continue - } if len(m.Bindings) == 0 || pkg == file.GoPkg || pkgSeen[pkg.Path] { continue @@ -208,6 +150,9 @@ func (g *generator) generate(file *descriptor.File) (string, error) { RegisterFuncSuffix: g.registerFuncSuffix, AllowPatchFeature: g.allowPatchFeature, } + if g.reg != nil { + params.OmitPackageDoc = g.reg.GetOmitPackageDoc() + } return applyTemplate(params, g.reg) } diff --git a/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator_test.go b/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator_test.go index 32fdc80..9e30d4c 100644 --- a/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator_test.go +++ b/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator_test.go @@ -1,27 +1,15 @@ package gengateway import ( - "errors" - "path/filepath" - "strings" "testing" - descriptorpb "github.com/golang/protobuf/protoc-gen-go/descriptor" // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor" "github.com/binchencoder/ease-gateway/gateway/internal/descriptor" "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/descriptorpb" ) -func newExampleFileDescriptor() *descriptor.File { - return newExampleFileDescriptorWithGoPkg( - &descriptor.GoPackage{ - Path: "example.com/path/to/example/example.pb", - Name: "example_pb", - }, - ) -} - -func newExampleFileDescriptorWithGoPkg(gp *descriptor.GoPackage) *descriptor.File { +func newExampleFileDescriptorWithGoPkg(gp *descriptor.GoPackage, filenamePrefix string) *descriptor.File { msgdesc := &descriptorpb.DescriptorProto{ Name: proto.String("ExampleMessage"), } @@ -59,8 +47,9 @@ func newExampleFileDescriptorWithGoPkg(gp *descriptor.GoPackage) *descriptor.Fil MessageType: []*descriptorpb.DescriptorProto{msgdesc}, Service: []*descriptorpb.ServiceDescriptorProto{svc}, }, - GoPkg: *gp, - Messages: []*descriptor.Message{msg}, + GoPkg: *gp, + GeneratedFilenamePrefix: filenamePrefix, + Messages: []*descriptor.Message{msg}, Services: []*descriptor.Service{ { ServiceDescriptorProto: svc, @@ -87,159 +76,23 @@ func newExampleFileDescriptorWithGoPkg(gp *descriptor.GoPackage) *descriptor.Fil } } -func TestGenerateServiceWithoutBindings(t *testing.T) { - file := newExampleFileDescriptor() - g := &generator{} - got, err := g.generate(crossLinkFixture(file)) +func TestGenerator_Generate(t *testing.T) { + g := new(generator) + result, err := g.Generate([]*descriptor.File{ + crossLinkFixture(newExampleFileDescriptorWithGoPkg(&descriptor.GoPackage{ + Path: "example.com/path/to/example", + Name: "example_pb", + }, "path/to/example")), + }) if err != nil { - t.Errorf("generate(%#v) failed with %v; want success", file, err) - return + t.Fatalf("failed to generate stubs: %v", err) } - if notwanted := `"github.com/golang/protobuf/ptypes/empty"`; strings.Contains(got, notwanted) { - t.Errorf("generate(%#v) = %s; does not want to contain %s", file, got, notwanted) - } -} - -func TestGenerateOutputPath(t *testing.T) { - cases := []struct { - file *descriptor.File - pathType pathType - modulePath string - expected string - expectedError error - }{ - { - file: newExampleFileDescriptorWithGoPkg( - &descriptor.GoPackage{ - Path: "example.com/path/to/example", - Name: "example_pb", - }, - ), - expected: "example.com/path/to/example", - }, - { - file: newExampleFileDescriptorWithGoPkg( - &descriptor.GoPackage{ - Path: "example", - Name: "example_pb", - }, - ), - expected: "example", - }, - { - file: newExampleFileDescriptorWithGoPkg( - &descriptor.GoPackage{ - Path: "example.com/path/to/example", - Name: "example_pb", - }, - ), - pathType: pathTypeSourceRelative, - expected: ".", - }, - { - file: newExampleFileDescriptorWithGoPkg( - &descriptor.GoPackage{ - Path: "example", - Name: "example_pb", - }, - ), - pathType: pathTypeSourceRelative, - expected: ".", - }, - { - file: newExampleFileDescriptorWithGoPkg( - &descriptor.GoPackage{ - Path: "example.com/path/root", - Name: "example_pb", - }, - ), - modulePath: "example.com/path/root", - expected: ".", - }, - { - file: newExampleFileDescriptorWithGoPkg( - &descriptor.GoPackage{ - Path: "example.com/path/to/example", - Name: "example_pb", - }, - ), - modulePath: "example.com/path/to", - expected: "example", - }, - { - file: newExampleFileDescriptorWithGoPkg( - &descriptor.GoPackage{ - Path: "example.com/path/to/example/with/many/nested/paths", - Name: "example_pb", - }, - ), - modulePath: "example.com/path/to", - expected: "example/with/many/nested/paths", - }, - - // Error cases - { - file: newExampleFileDescriptorWithGoPkg( - &descriptor.GoPackage{ - Path: "example.com/path/root", - Name: "example_pb", - }, - ), - modulePath: "example.com/path/root", - pathType: pathTypeSourceRelative, // Not allowed - expectedError: errors.New("cannot use module= with paths="), - }, - { - file: newExampleFileDescriptorWithGoPkg( - &descriptor.GoPackage{ - Path: "example.com/path/rootextra", - Name: "example_pb", - }, - ), - modulePath: "example.com/path/root", - expectedError: errors.New("example.com/path/rootextra: file go path does not match module prefix: example.com/path/root/"), - }, + if len(result) != 1 { + t.Fatalf("expected to generate one file, got: %d", len(result)) } - - for _, c := range cases { - g := &generator{ - pathType: c.pathType, - modulePath: c.modulePath, - } - - file := c.file - gots, err := g.Generate([]*descriptor.File{crossLinkFixture(file)}) - - // If we expect an error response, check it matches what we want - if c.expectedError != nil { - if err == nil || err.Error() != c.expectedError.Error() { - t.Errorf("Generate(%#v) failed with %v; wants error of: %v", file, err, c.expectedError) - } - return - } - - // Handle case where we don't expect an error - if err != nil { - t.Errorf("Generate(%#v) failed with %v; wants success", file, err) - return - } - - if len(gots) != 1 { - t.Errorf("Generate(%#v) failed; expects on result got %d", file, len(gots)) - return - } - - got := gots[0] - if got.Name == nil { - t.Errorf("Generate(%#v) failed; expects non-nil Name(%v)", file, got.Name) - return - } - - gotPath := filepath.Dir(*got.Name) - expectedPath := c.expected - if gotPath != expectedPath { - t.Errorf("Generate(%#v) failed; got path: %s expected path: %s", file, gotPath, expectedPath) - return - } + expectedName := "path/to/example.pb.gw.go" + gotName := result[0].GetName() + if gotName != expectedName { + t.Fatalf("invalid name %q, expected %q", gotName, expectedName) } } diff --git a/gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go b/gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go index f70c8c5..aa6af49 100644 --- a/gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go +++ b/gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go @@ -22,6 +22,7 @@ type param struct { UseRequestContext bool RegisterFuncSuffix string AllowPatchFeature bool + OmitPackageDoc bool } type binding struct { diff --git a/gateway/protoc-gen-grpc-gateway/internal/gengateway/template_test.go b/gateway/protoc-gen-grpc-gateway/internal/gengateway/template_test.go index e6fffb0..28db071 100644 --- a/gateway/protoc-gen-grpc-gateway/internal/gengateway/template_test.go +++ b/gateway/protoc-gen-grpc-gateway/internal/gengateway/template_test.go @@ -4,12 +4,11 @@ import ( "strings" "testing" - descriptorpb "github.com/golang/protobuf/protoc-gen-go/descriptor" // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor" "github.com/binchencoder/ease-gateway/gateway/internal/descriptor" - // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/httprule" "github.com/grpc-ecosystem/grpc-gateway/v2/internal/httprule" "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/descriptorpb" ) func crossLinkFixture(f *descriptor.File) *descriptor.File { diff --git a/gateway/protoc-gen-grpc-gateway/main.go b/gateway/protoc-gen-grpc-gateway/main.go index 2a2ce12..f79141b 100644 --- a/gateway/protoc-gen-grpc-gateway/main.go +++ b/gateway/protoc-gen-grpc-gateway/main.go @@ -15,31 +15,26 @@ import ( "strings" "github.com/golang/glog" - pluginpb "github.com/golang/protobuf/protoc-gen-go/plugin" - "github.com/grpc-ecosystem/grpc-gateway/v2/internal/codegenerator" - // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor" "github.com/binchencoder/ease-gateway/gateway/internal/descriptor" - // "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway/internal/gengateway" "github.com/binchencoder/ease-gateway/gateway/protoc-gen-grpc-gateway/internal/gengateway" - "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/compiler/protogen" ) var ( - importPrefix = flag.String("import_prefix", "", "prefix to be added to go package paths for imported proto files") - importPath = flag.String("import_path", "", "used as the package if no input files declare go_package. If it contains slashes, everything up to the rightmost slash is ignored.") registerFuncSuffix = flag.String("register_func_suffix", "Handler", "used to construct names of generated Register* methods.") useRequestContext = flag.Bool("request_context", true, "determine whether to use http.Request's context or not") allowDeleteBody = flag.Bool("allow_delete_body", false, "unless set, HTTP DELETE methods may not have a body") grpcAPIConfiguration = flag.String("grpc_api_configuration", "", "path to gRPC API Configuration in YAML format") - pathType = flag.String("paths", "", "specifies how the paths of generated files are structured") - modulePath = flag.String("module", "", "specifies a module prefix that will be stripped from the go package to determine the output directory") allowRepeatedFieldsInBody = flag.Bool("allow_repeated_fields_in_body", false, "allows to use repeated field in `body` and `response_body` field of `google.api.http` annotation option") repeatedPathParamSeparator = flag.String("repeated_path_param_separator", "csv", "configures how repeated fields should be split. Allowed values are `csv`, `pipes`, `ssv` and `tsv`.") allowPatchFeature = flag.Bool("allow_patch_feature", true, "determines whether to use PATCH feature involving update masks (using google.protobuf.FieldMask).") + omitPackageDoc = flag.Bool("omit_package_doc", false, "if true, no package comment will be included in the generated code") standalone = flag.Bool("standalone", false, "generates a standalone gateway package, which imports the target service package") versionFlag = flag.Bool("version", false, "print the current version") + warnOnUnboundMethods = flag.Bool("warn_on_unbound_methods", false, "emit a warning message if an RPC method has no HttpRule annotation") + generateUnboundMethods = flag.Bool("generate_unbound_methods", false, "generate proxy methods even for RPC methods that have no HttpRule annotation") ) // Variables set by goreleaser at build time @@ -58,96 +53,94 @@ func main() { os.Exit(0) } - reg := descriptor.NewRegistry() - descriptor.Reg = reg + protogen.Options{ + ParamFunc: flag.CommandLine.Set, + }.Run(func(gen *protogen.Plugin) error { + reg := descriptor.NewRegistry() + descriptor.Reg = reg - glog.V(1).Info("Parsing code generator request") - req, err := codegenerator.ParseRequest(os.Stdin) - if err != nil { - glog.Fatal(err) - } - glog.V(1).Info("Parsed code generator request") - if req.Parameter != nil { - for _, p := range strings.Split(req.GetParameter(), ",") { - spec := strings.SplitN(p, "=", 2) - if len(spec) == 1 { - if err := flag.CommandLine.Set(spec[0], ""); err != nil { - glog.Fatalf("Cannot set flag %s", p) - } - continue - } - name, value := spec[0], spec[1] - if strings.HasPrefix(name, "M") { - reg.AddPkgMap(name[1:], value) - continue - } - if err := flag.CommandLine.Set(name, value); err != nil { - glog.Fatalf("Cannot set flag %s", p) - } + err := applyFlags(reg) + if err != nil { + return err } - } - g := gengateway.New(reg, *useRequestContext, *registerFuncSuffix, *pathType, *modulePath, *allowPatchFeature, *standalone) + generator := gengateway.New(reg, *useRequestContext, *registerFuncSuffix, *allowPatchFeature, *standalone) - if *grpcAPIConfiguration != "" { - if err := reg.LoadGrpcAPIServiceFromYAML(*grpcAPIConfiguration); err != nil { - emitError(err) - return + glog.V(1).Infof("Parsing code generator request") + + if err := reg.LoadFromPlugin(gen); err != nil { + return err } - } - reg.SetStandalone(*standalone) - reg.SetPrefix(*importPrefix) - reg.SetImportPath(*importPath) - reg.SetAllowDeleteBody(*allowDeleteBody) - reg.SetAllowRepeatedFieldsInBody(*allowRepeatedFieldsInBody) - if err := reg.SetRepeatedPathParamSeparator(*repeatedPathParamSeparator); err != nil { - emitError(err) - return - } - if err := reg.Load(req); err != nil { - emitError(err) - return - } + unboundHTTPRules := reg.UnboundExternalHTTPRules() + if len(unboundHTTPRules) != 0 { + return fmt.Errorf("HTTP rules without a matching selector: %s", strings.Join(unboundHTTPRules, ", ")) + } - unboundHTTPRules := reg.UnboundExternalHTTPRules() - if len(unboundHTTPRules) != 0 { - emitError(fmt.Errorf("HTTP rules without a matching selector: %s", strings.Join(unboundHTTPRules, ", "))) - return - } + var targets []*descriptor.File + for _, target := range gen.Request.FileToGenerate { + f, err := reg.LookupFile(target) + if err != nil { + return err + } + targets = append(targets, f) + } - var targets []*descriptor.File - for _, target := range req.FileToGenerate { - f, err := reg.LookupFile(target) - if err != nil { - glog.Fatal(err) + files, err := generator.Generate(targets) + for _, f := range files { + glog.V(1).Infof("NewGeneratedFile %q in %s", f.GetName(), f.GoPkg) + genFile := gen.NewGeneratedFile(f.GetName(), protogen.GoImportPath(f.GoPkg.Path)) + if _, err := genFile.Write([]byte(f.GetContent())); err != nil { + return err + } } - targets = append(targets, f) - } - out, err := g.Generate(targets) - glog.V(1).Info("Processed code generator request") - if err != nil { - emitError(err) + glog.V(1).Info("Processed code generator request") + + return err + }) +} + +func parseFlags(reg *descriptor.Registry, parameter string) { + if parameter == "" { return } - emitFiles(out) -} -func emitFiles(out []*pluginpb.CodeGeneratorResponse_File) { - emitResp(&pluginpb.CodeGeneratorResponse{File: out}) -} + for _, p := range strings.Split(parameter, ",") { + spec := strings.SplitN(p, "=", 2) + if len(spec) == 1 { + if err := flag.CommandLine.Set(spec[0], ""); err != nil { + glog.Fatalf("Cannot set flag %s", p) + } + continue + } + + name, value := spec[0], spec[1] -func emitError(err error) { - emitResp(&pluginpb.CodeGeneratorResponse{Error: proto.String(err.Error())}) + if strings.HasPrefix(name, "M") { + reg.AddPkgMap(name[1:], value) + continue + } + if err := flag.CommandLine.Set(name, value); err != nil { + glog.Fatalf("Cannot set flag %s", p) + } + } } -func emitResp(resp *pluginpb.CodeGeneratorResponse) { - buf, err := proto.Marshal(resp) - if err != nil { - glog.Fatal(err) +func applyFlags(reg *descriptor.Registry) error { + if *grpcAPIConfiguration != "" { + if err := reg.LoadGrpcAPIServiceFromYAML(*grpcAPIConfiguration); err != nil { + return err + } } - if _, err := os.Stdout.Write(buf); err != nil { - glog.Fatal(err) + if *warnOnUnboundMethods && *generateUnboundMethods { + glog.Warningf("Option warn_on_unbound_methods has no effect when generate_unbound_methods is used.") } + reg.SetStandalone(*standalone) + reg.SetAllowDeleteBody(*allowDeleteBody) + reg.SetAllowRepeatedFieldsInBody(*allowRepeatedFieldsInBody) + reg.SetOmitPackageDoc(*omitPackageDoc) + reg.SetWarnOnUnboundMethods(*warnOnUnboundMethods) + reg.SetGenerateUnboundMethods(*generateUnboundMethods) + return reg.SetRepeatedPathParamSeparator(*repeatedPathParamSeparator) } diff --git a/gateway/protoc-gen-grpc-gateway/main_test.go b/gateway/protoc-gen-grpc-gateway/main_test.go new file mode 100644 index 0000000..7708b12 --- /dev/null +++ b/gateway/protoc-gen-grpc-gateway/main_test.go @@ -0,0 +1,32 @@ +package main + +import ( + "testing" + + // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor" + "github.com/binchencoder/ease-gateway/gateway/internal/descriptor" +) + +func TestParseFlagsEmptyNoPanic(t *testing.T) { + reg := descriptor.NewRegistry() + parseFlags(reg, "") +} + +func TestParseFlags(t *testing.T) { + reg := descriptor.NewRegistry() + parseFlags(reg, "allow_repeated_fields_in_body=true") + if *allowRepeatedFieldsInBody != true { + t.Errorf("flag allow_repeated_fields_in_body was not set correctly, wanted true got %v", *allowRepeatedFieldsInBody) + } +} + +func TestParseFlagsMultiple(t *testing.T) { + reg := descriptor.NewRegistry() + parseFlags(reg, "allow_repeated_fields_in_body=true,repeated_path_param_separator=csv") + if *allowRepeatedFieldsInBody != true { + t.Errorf("flag allow_repeated_fields_in_body was not set correctly, wanted 'true' got '%v'", *allowRepeatedFieldsInBody) + } + if *repeatedPathParamSeparator != "csv" { + t.Errorf("flag importPrefix was not set correctly, wanted 'csv' got '%v'", *repeatedPathParamSeparator) + } +} diff --git a/gateway/protoc-gen-openapiv2/BUILD.bazel b/gateway/protoc-gen-openapiv2/BUILD.bazel index d9afac7..5daacad 100644 --- a/gateway/protoc-gen-openapiv2/BUILD.bazel +++ b/gateway/protoc-gen-openapiv2/BUILD.bazel @@ -1,18 +1,18 @@ load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test") -package(default_visibility = ["//visibility:public"]) +package(default_visibility = ["//visibility:private"]) go_library( name = "go_default_library", srcs = ["main.go"], importpath = "github.com/binchencoder/ease-gateway/gateway/protoc-gen-openapiv2", deps = [ + "@com_github_grpc_ecosystem_grpc_gateway//internal/codegenerator:go_default_library", "//gateway/internal/descriptor:go_default_library", "//gateway/protoc-gen-openapiv2/internal/genopenapi:go_default_library", "@com_github_golang_glog//:go_default_library", - "@com_github_grpc_ecosystem_grpc_gateway//internal/codegenerator:go_default_library", - "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", "@org_golang_google_protobuf//proto:go_default_library", + "@org_golang_google_protobuf//types/pluginpb:go_default_library", ], ) diff --git a/gateway/protoc-gen-openapiv2/defs.bzl b/gateway/protoc-gen-openapiv2/defs.bzl index 71822d5..146bc1e 100644 --- a/gateway/protoc-gen-openapiv2/defs.bzl +++ b/gateway/protoc-gen-openapiv2/defs.bzl @@ -53,7 +53,8 @@ def _run_proto_gen_openapi( protoc_gen_openapiv2, grpc_api_configuration, single_output, - json_names_for_fields): + json_names_for_fields, + fqn_for_openapi_name): args = actions.args() args.add("--plugin", "protoc-gen-openapiv2=%s" % protoc_gen_openapiv2.path) @@ -69,6 +70,9 @@ def _run_proto_gen_openapi( if not json_names_for_fields: args.add("--openapiv2_opt", "json_names_for_fields=false") + if fqn_for_openapi_name: + args.add("--openapi_opt", "fqn_for_openapi_name=true") + proto_file_infos = _direct_source_infos(proto_info) # TODO(yannic): Use |proto_info.transitive_descriptor_sets| when @@ -153,6 +157,7 @@ def _proto_gen_openapi_impl(ctx): grpc_api_configuration = ctx.file.grpc_api_configuration, single_output = ctx.attr.single_output, json_names_for_fields = ctx.attr.json_names_for_fields, + fqn_for_openapi_name = ctx.attr.fqn_for_openapi_name, ), ), ), @@ -176,6 +181,10 @@ protoc_gen_openapiv2 = rule( default = True, mandatory = False, ), + "fqn_for_openapi_name": attr.bool( + default = False, + mandatory = False, + ), "_protoc": attr.label( default = "@com_google_protobuf//:protoc", executable = True, diff --git a/gateway/protoc-gen-openapiv2/internal/genopenapi/BUILD.bazel b/gateway/protoc-gen-openapiv2/internal/genopenapi/BUILD.bazel index eb346c7..67c49ae 100644 --- a/gateway/protoc-gen-openapiv2/internal/genopenapi/BUILD.bazel +++ b/gateway/protoc-gen-openapiv2/internal/genopenapi/BUILD.bazel @@ -14,7 +14,6 @@ go_library( ], importpath = "github.com/binchencoder/ease-gateway/gateway/protoc-gen-openapiv2/internal/genopenapi", deps = [ - "//gateway/internal:go_default_library", "//gateway/internal/casing:go_default_library", "//gateway/internal/descriptor:go_default_library", "//gateway/internal/generator:go_default_library", @@ -24,11 +23,11 @@ go_library( "@com_github_golang_protobuf//descriptor:go_default_library_gen", "@go_googleapis//google/rpc:status_go_proto", "@io_bazel_rules_go//proto/wkt:any_go_proto", - "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", - "@io_bazel_rules_go//proto/wkt:descriptor_go_proto", "@io_bazel_rules_go//proto/wkt:struct_go_proto", "@org_golang_google_protobuf//encoding/protojson:go_default_library", "@org_golang_google_protobuf//proto:go_default_library", + "@org_golang_google_protobuf//types/descriptorpb:go_default_library", + "@org_golang_google_protobuf//types/pluginpb:go_default_library", ], ) @@ -39,14 +38,19 @@ go_test( embed = [":go_default_library"], deps = [ "//gateway/internal/descriptor:go_default_library", - "//gateway/protoc-gen-openapiv2/options:go_default_library", - "//gateway/runtime:go_default_library", + "//gateway/internal/descriptor/openapiconfig:go_default_library", "@com_github_grpc_ecosystem_grpc_gateway//internal/httprule:go_default_library", + "//gateway/protoc-gen-openapiv2/options:go_default_library", + "//gateway/runtime:go_default_library", "@com_github_google_go_cmp//cmp:go_default_library", - "@io_bazel_rules_go//proto/wkt:any_go_proto", - "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", - "@io_bazel_rules_go//proto/wkt:descriptor_go_proto", - "@io_bazel_rules_go//proto/wkt:struct_go_proto", + "@io_bazel_rules_go//proto/wkt:field_mask_go_proto", "@org_golang_google_protobuf//proto:go_default_library", + "@org_golang_google_protobuf//reflect/protodesc:go_default_library", + "@org_golang_google_protobuf//types/descriptorpb:go_default_library", + "@org_golang_google_protobuf//types/known/durationpb:go_default_library", + "@org_golang_google_protobuf//types/known/structpb:go_default_library", + "@org_golang_google_protobuf//types/known/timestamppb:go_default_library", + "@org_golang_google_protobuf//types/known/wrapperspb:go_default_library", + "@org_golang_google_protobuf//types/pluginpb:go_default_library", ], ) diff --git a/gateway/protoc-gen-openapiv2/internal/genopenapi/generator.go b/gateway/protoc-gen-openapiv2/internal/genopenapi/generator.go index 16a25ca..f3b7a7b 100644 --- a/gateway/protoc-gen-openapiv2/internal/genopenapi/generator.go +++ b/gateway/protoc-gen-openapiv2/internal/genopenapi/generator.go @@ -10,10 +10,8 @@ import ( "strings" "github.com/golang/glog" - descriptorpb "github.com/golang/protobuf/protoc-gen-go/descriptor" - pluginpb "github.com/golang/protobuf/protoc-gen-go/plugin" anypb "github.com/golang/protobuf/ptypes/any" - //"github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor" + // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor" "github.com/binchencoder/ease-gateway/gateway/internal/descriptor" // gen "github.com/grpc-ecosystem/grpc-gateway/v2/internal/generator" gen "github.com/binchencoder/ease-gateway/gateway/internal/generator" @@ -21,11 +19,11 @@ import ( openapi_options "github.com/binchencoder/ease-gateway/gateway/protoc-gen-openapiv2/options" statuspb "google.golang.org/genproto/googleapis/rpc/status" "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/descriptorpb" + "google.golang.org/protobuf/types/pluginpb" //lint:ignore SA1019 known issue, will be replaced when possible legacydescriptor "github.com/golang/protobuf/descriptor" - - ) var ( @@ -143,7 +141,7 @@ func extensionMarshalJSON(so interface{}, extensions []extension) ([]byte, error } // encodeOpenAPI converts OpenAPI file obj to pluginpb.CodeGeneratorResponse_File -func encodeOpenAPI(file *wrapper) (*pluginpb.CodeGeneratorResponse_File, error) { +func encodeOpenAPI(file *wrapper) (*descriptor.ResponseFile, error) { var formatted bytes.Buffer enc := json.NewEncoder(&formatted) enc.SetIndent("", " ") @@ -154,14 +152,16 @@ func encodeOpenAPI(file *wrapper) (*pluginpb.CodeGeneratorResponse_File, error) ext := filepath.Ext(name) base := strings.TrimSuffix(name, ext) output := fmt.Sprintf("%s.swagger.json", base) - return &pluginpb.CodeGeneratorResponse_File{ - Name: proto.String(output), - Content: proto.String(formatted.String()), + return &descriptor.ResponseFile{ + CodeGeneratorResponse_File: &pluginpb.CodeGeneratorResponse_File{ + Name: proto.String(output), + Content: proto.String(formatted.String()), + }, }, nil } -func (g *generator) Generate(targets []*descriptor.File) ([]*pluginpb.CodeGeneratorResponse_File, error) { - var files []*pluginpb.CodeGeneratorResponse_File +func (g *generator) Generate(targets []*descriptor.File) ([]*descriptor.ResponseFile, error) { + var files []*descriptor.ResponseFile if g.reg.IsAllowMerge() { var mergedTarget *descriptor.File // try to find proto leader diff --git a/gateway/protoc-gen-openapiv2/internal/genopenapi/template.go b/gateway/protoc-gen-openapiv2/internal/genopenapi/template.go index f2b6f84..4defa99 100644 --- a/gateway/protoc-gen-openapiv2/internal/genopenapi/template.go +++ b/gateway/protoc-gen-openapiv2/internal/genopenapi/template.go @@ -15,23 +15,31 @@ import ( "text/template" "github.com/golang/glog" - descriptorpb "github.com/golang/protobuf/protoc-gen-go/descriptor" structpb "github.com/golang/protobuf/ptypes/struct" // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/casing" "github.com/binchencoder/ease-gateway/gateway/internal/casing" // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor" "github.com/binchencoder/ease-gateway/gateway/internal/descriptor" - - options "github.com/binchencoder/ease-gateway/httpoptions" - // openapi_options "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options" openapi_options "github.com/binchencoder/ease-gateway/gateway/protoc-gen-openapiv2/options" "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/descriptorpb" + + options "github.com/binchencoder/ease-gateway/httpoptions" ) +// wktSchemas are the schemas of well-known-types. +// The schemas must match with the behavior of the JSON unmarshaler in +// https://github.com/protocolbuffers/protobuf-go/blob/v1.25.0/encoding/protojson/well_known_types.go var wktSchemas = map[string]schemaCore{ + ".google.protobuf.FieldMask": { + Type: "array", + Items: (*openapiItemsObject)(&schemaCore{ + Type: "string", + }), + }, ".google.protobuf.Timestamp": { Type: "string", Format: "date-time", @@ -115,9 +123,9 @@ func getEnumDefault(enum *descriptor.Enum) string { } // messageToQueryParameters converts a message to a list of OpenAPI query parameters. -func messageToQueryParameters(message *descriptor.Message, reg *descriptor.Registry, pathParams []descriptor.Parameter) (params []openapiParameterObject, err error) { +func messageToQueryParameters(message *descriptor.Message, reg *descriptor.Registry, pathParams []descriptor.Parameter, body *descriptor.Body) (params []openapiParameterObject, err error) { for _, field := range message.Fields { - p, err := queryParams(message, field, "", reg, pathParams) + p, err := queryParams(message, field, "", reg, pathParams, body) if err != nil { return nil, err } @@ -127,8 +135,8 @@ func messageToQueryParameters(message *descriptor.Message, reg *descriptor.Regis } // queryParams converts a field to a list of OpenAPI query parameters recursively through the use of nestedQueryParams. -func queryParams(message *descriptor.Message, field *descriptor.Field, prefix string, reg *descriptor.Registry, pathParams []descriptor.Parameter) (params []openapiParameterObject, err error) { - return nestedQueryParams(message, field, prefix, reg, pathParams, map[string]bool{}) +func queryParams(message *descriptor.Message, field *descriptor.Field, prefix string, reg *descriptor.Registry, pathParams []descriptor.Parameter, body *descriptor.Body) (params []openapiParameterObject, err error) { + return nestedQueryParams(message, field, prefix, reg, pathParams, body, map[string]bool{}) } // nestedQueryParams converts a field to a list of OpenAPI query parameters recursively. @@ -137,13 +145,24 @@ func queryParams(message *descriptor.Message, field *descriptor.Field, prefix st // touched map[string]bool // If a cycle is discovered, an error is returned, as cyclical data structures aren't allowed // in query parameters. -func nestedQueryParams(message *descriptor.Message, field *descriptor.Field, prefix string, reg *descriptor.Registry, pathParams []descriptor.Parameter, touchedIn map[string]bool) (params []openapiParameterObject, err error) { +func nestedQueryParams(message *descriptor.Message, field *descriptor.Field, prefix string, reg *descriptor.Registry, pathParams []descriptor.Parameter, body *descriptor.Body, touchedIn map[string]bool) (params []openapiParameterObject, err error) { // make sure the parameter is not already listed as a path parameter for _, pathParam := range pathParams { if pathParam.Target == field { return nil, nil } } + // make sure the parameter is not already listed as a body parameter + if body != nil { + if body.FieldPath == nil { + return nil, nil + } + for _, fieldPath := range body.FieldPath { + if fieldPath.Target == field { + return nil, nil + } + } + } schema := schemaOfField(field, reg, nil) fieldType := field.GetTypeName() if message.File != nil { @@ -236,7 +255,7 @@ func nestedQueryParams(message *descriptor.Message, field *descriptor.Field, pre // Check for cyclical message reference: isCycle := touchedIn[*msg.Name] if isCycle { - return nil, fmt.Errorf("Recursive types are not allowed for query parameters, cycle found on %q", fieldType) + return nil, fmt.Errorf("recursive types are not allowed for query parameters, cycle found on %q", fieldType) } // Construct a new map with the message name so a cycle further down the recursive path can be detected. @@ -255,7 +274,7 @@ func nestedQueryParams(message *descriptor.Message, field *descriptor.Field, pre } else { fieldName = field.GetName() } - p, err := nestedQueryParams(msg, nestedField, prefix+fieldName+".", reg, pathParams, touchedOut) + p, err := nestedQueryParams(msg, nestedField, prefix+fieldName+".", reg, pathParams, body, touchedOut) if err != nil { return nil, err } @@ -349,7 +368,7 @@ func renderMessagesAsDefinition(messages messageMap, d openapiDefinitionsObject, if err := updateOpenAPIDataFromComments(reg, &schema, msg, msgComments, false); err != nil { panic(err) } - opts, err := extractSchemaOptionFromMessageDescriptor(msg.DescriptorProto) + opts, err := getMessageOpenAPIOption(reg, msg) if err != nil { panic(err) } @@ -492,7 +511,7 @@ func schemaOfField(f *descriptor.Field, reg *descriptor.Registry, refs refMap) o } } - if j, err := extractJSONSchemaFromFieldDescriptor(fd); err == nil { + if j, err := getFieldOpenAPIOption(reg, f); err == nil { updateswaggerObjectFromJSONSchema(&ret, j, reg, f) } @@ -526,9 +545,10 @@ func primitiveSchema(t descriptorpb.FieldDescriptorProto_Type) (ftype, format st // Ditto. return "integer", "int64", true case descriptorpb.FieldDescriptorProto_TYPE_BOOL: - return "boolean", "boolean", true + // NOTE: in OpenAPI specification, format should be empty on boolean type + return "boolean", "", true case descriptorpb.FieldDescriptorProto_TYPE_STRING: - // NOTE: in OpenAPI specifition, format should be empty on string type + // NOTE: in OpenAPI specification, format should be empty on string type return "string", "", true case descriptorpb.FieldDescriptorProto_TYPE_BYTES: return "string", "byte", true @@ -904,9 +924,15 @@ func renderServices(services []*descriptor.Service, paths openapiPathsObject, re Required: true, Schema: &schema, }) + // add the parameters to the query string + queryParams, err := messageToQueryParameters(meth.RequestType, reg, b.PathParams, b.Body) + if err != nil { + return err + } + parameters = append(parameters, queryParams...) } else if b.HTTPMethod == "GET" || b.HTTPMethod == "DELETE" { // add the parameters to the query string - queryParams, err := messageToQueryParameters(meth.RequestType, reg, b.PathParams) + queryParams, err := messageToQueryParameters(meth.RequestType, reg, b.PathParams, b.Body) if err != nil { return err } @@ -971,13 +997,13 @@ func renderServices(services []*descriptor.Service, paths openapiPathsObject, re }, }, } - streamErrDef, hasStreamError := fullyQualifiedNameToOpenAPIName(".grpc.gateway.runtime.StreamError", reg) - if hasStreamError { + statusDef, hasStatus := fullyQualifiedNameToOpenAPIName(".google.rpc.Status", reg) + if hasStatus { props = append(props, keyVal{ Key: "error", Value: openapiSchemaObject{ schemaCore: schemaCore{ - Ref: fmt.Sprintf("#/definitions/%s", streamErrDef)}, + Ref: fmt.Sprintf("#/definitions/%s", statusDef)}, }, }) } @@ -1001,11 +1027,11 @@ func renderServices(services []*descriptor.Service, paths openapiPathsObject, re }, } if !reg.GetDisableDefaultErrors() { - errDef, hasErrDef := fullyQualifiedNameToOpenAPIName(".grpc.gateway.runtime.Error", reg) + errDef, hasErrDef := fullyQualifiedNameToOpenAPIName(".google.rpc.Status", reg) if hasErrDef { // https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#responses-object operationObject.Responses["default"] = openapiResponseObject{ - Description: "An unexpected error response", + Description: "An unexpected error response.", Schema: openapiSchemaObject{ schemaCore: schemaCore{ Ref: fmt.Sprintf("#/definitions/%s", errDef), @@ -1035,7 +1061,7 @@ func renderServices(services []*descriptor.Service, paths openapiPathsObject, re panic(err) } - opts, err := extractOperationOptionFromMethodDescriptor(meth.MethodDescriptorProto) + opts, err := getMethodOpenAPIOption(reg, meth) if opts != nil { if err != nil { panic(err) @@ -1172,7 +1198,7 @@ func applyTemplate(p param) (*openapiSwaggerObject, error) { if !p.reg.GetDisableDefaultErrors() { // Add the error type to the message map - runtimeError, swgRef, err := lookupMsgAndOpenAPIName(".grpc.gateway.runtime", "Error", p.reg) + runtimeError, swgRef, err := lookupMsgAndOpenAPIName("google.rpc", "Status", p.reg) if err == nil { messages[swgRef] = runtimeError } else { @@ -1195,7 +1221,7 @@ func applyTemplate(p param) (*openapiSwaggerObject, error) { } // There may be additional options in the OpenAPI option in the proto. - spb, err := extractOpenAPIOptionFromFileDescriptor(p.FileDescriptorProto) + spb, err := getFileOpenAPIOption(p.reg, p.File) if err != nil { panic(err) } @@ -1784,6 +1810,66 @@ func extractJSONSchemaFromFieldDescriptor(fd *descriptorpb.FieldDescriptorProto) return opts, nil } +func getMethodOpenAPIOption(reg *descriptor.Registry, meth *descriptor.Method) (*openapi_options.Operation, error) { + opts, err := extractOperationOptionFromMethodDescriptor(meth.MethodDescriptorProto) + if err != nil { + return nil, err + } + if opts != nil { + return opts, nil + } + opts, ok := reg.GetOpenAPIMethodOption(meth.FQMN()) + if !ok { + return nil, nil + } + return opts, nil +} + +func getMessageOpenAPIOption(reg *descriptor.Registry, msg *descriptor.Message) (*openapi_options.Schema, error) { + opts, err := extractSchemaOptionFromMessageDescriptor(msg.DescriptorProto) + if err != nil { + return nil, err + } + if opts != nil { + return opts, nil + } + opts, ok := reg.GetOpenAPIMessageOption(msg.FQMN()) + if !ok { + return nil, nil + } + return opts, nil +} + +func getFileOpenAPIOption(reg *descriptor.Registry, file *descriptor.File) (*openapi_options.Swagger, error) { + opts, err := extractOpenAPIOptionFromFileDescriptor(file.FileDescriptorProto) + if err != nil { + return nil, err + } + if opts != nil { + return opts, nil + } + opts, ok := reg.GetOpenAPIFileOption(*file.Name) + if !ok { + return nil, nil + } + return opts, nil +} + +func getFieldOpenAPIOption(reg *descriptor.Registry, fd *descriptor.Field) (*openapi_options.JSONSchema, error) { + opts, err := extractJSONSchemaFromFieldDescriptor(fd.FieldDescriptorProto) + if err != nil { + return nil, err + } + if opts != nil { + return opts, nil + } + opts, ok := reg.GetOpenAPIFieldOption(fd.FQFN()) + if !ok { + return nil, nil + } + return opts, nil +} + func protoJSONSchemaToOpenAPISchemaCore(j *openapi_options.JSONSchema, reg *descriptor.Registry, refs refMap) schemaCore { ret := schemaCore{} @@ -1843,8 +1929,8 @@ func openapiSchemaFromProtoSchema(s *openapi_options.Schema, reg *descriptor.Reg ret.schemaCore = protoJSONSchemaToOpenAPISchemaCore(s.GetJsonSchema(), reg, refs) updateswaggerObjectFromJSONSchema(&ret, s.GetJsonSchema(), reg, data) - if s != nil && s.Example != nil { - ret.Example = json.RawMessage(s.Example.Value) + if s != nil && s.Example != "" { + ret.Example = json.RawMessage(s.Example) } return ret @@ -1889,13 +1975,14 @@ func protoJSONSchemaTypeToFormat(in []openapi_options.JSONSchema_JSONSchemaSimpl case openapi_options.JSONSchema_ARRAY: return "array", "" case openapi_options.JSONSchema_BOOLEAN: - return "boolean", "boolean" + // NOTE: in OpenAPI specification, format should be empty on boolean type + return "boolean", "" case openapi_options.JSONSchema_INTEGER: return "integer", "int32" case openapi_options.JSONSchema_NUMBER: return "number", "double" case openapi_options.JSONSchema_STRING: - // NOTE: in OpenAPI specifition, format should be empty on string type + // NOTE: in OpenAPI specification, format should be empty on string type return "string", "" default: // Maybe panic? diff --git a/gateway/protoc-gen-openapiv2/internal/genopenapi/template_test.go b/gateway/protoc-gen-openapiv2/internal/genopenapi/template_test.go index 78a3ef7..2b55842 100644 --- a/gateway/protoc-gen-openapiv2/internal/genopenapi/template_test.go +++ b/gateway/protoc-gen-openapiv2/internal/genopenapi/template_test.go @@ -8,20 +8,25 @@ import ( "strings" "testing" - descriptorpb "github.com/golang/protobuf/protoc-gen-go/descriptor" - pluginpb "github.com/golang/protobuf/protoc-gen-go/plugin" - anypb "github.com/golang/protobuf/ptypes/any" - structpb "github.com/golang/protobuf/ptypes/struct" "github.com/google/go-cmp/cmp" // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor" "github.com/binchencoder/ease-gateway/gateway/internal/descriptor" + // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor/openapiconfig" + "github.com/binchencoder/ease-gateway/gateway/internal/descriptor/openapiconfig" "github.com/grpc-ecosystem/grpc-gateway/v2/internal/httprule" - // openapi_options "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options" openapi_options "github.com/binchencoder/ease-gateway/gateway/protoc-gen-openapiv2/options" // "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" "github.com/binchencoder/ease-gateway/gateway/runtime" + "google.golang.org/genproto/protobuf/field_mask" "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/reflect/protodesc" + "google.golang.org/protobuf/types/descriptorpb" + "google.golang.org/protobuf/types/known/durationpb" + "google.golang.org/protobuf/types/known/structpb" + "google.golang.org/protobuf/types/known/timestamppb" + "google.golang.org/protobuf/types/known/wrapperspb" + "google.golang.org/protobuf/types/pluginpb" ) var marshaler = &runtime.JSONPb{} @@ -221,7 +226,7 @@ func TestMessageToQueryParametersWithEnumAsInt(t *testing.T) { if err != nil { t.Fatalf("failed to lookup message: %s", err) } - params, err := messageToQueryParameters(message, reg, []descriptor.Parameter{}) + params, err := messageToQueryParameters(message, reg, []descriptor.Parameter{}, nil) if err != nil { t.Fatalf("failed to convert message to query parameters: %s", err) } @@ -401,7 +406,7 @@ func TestMessageToQueryParameters(t *testing.T) { if err != nil { t.Fatalf("failed to lookup message: %s", err) } - params, err := messageToQueryParameters(message, reg, []descriptor.Parameter{}) + params, err := messageToQueryParameters(message, reg, []descriptor.Parameter{}, nil) if err != nil { t.Fatalf("failed to convert message to query parameters: %s", err) } @@ -521,7 +526,7 @@ func TestMessageToQueryParametersNoRecursive(t *testing.T) { t.Fatalf("failed to lookup message: %s", err) } - _, err = messageToQueryParameters(message, reg, []descriptor.Parameter{}) + _, err = messageToQueryParameters(message, reg, []descriptor.Parameter{}, nil) if err != nil { t.Fatalf("No recursion error should be thrown: %s", err) } @@ -639,7 +644,7 @@ func TestMessageToQueryParametersRecursive(t *testing.T) { if err != nil { t.Fatalf("failed to lookup message: %s", err) } - _, err = messageToQueryParameters(message, reg, []descriptor.Parameter{}) + _, err = messageToQueryParameters(message, reg, []descriptor.Parameter{}, nil) if err == nil { t.Fatalf("It should not be allowed to have recursive query parameters") } @@ -746,7 +751,128 @@ func TestMessageToQueryParametersWithJsonName(t *testing.T) { if err != nil { t.Fatalf("failed to lookup message: %s", err) } - params, err := messageToQueryParameters(message, reg, []descriptor.Parameter{}) + params, err := messageToQueryParameters(message, reg, []descriptor.Parameter{}, nil) + if err != nil { + t.Fatalf("failed to convert message to query parameters: %s", err) + } + if !reflect.DeepEqual(params, test.Params) { + t.Errorf("expected %v, got %v", test.Params, params) + } + } +} + +func TestMessageToQueryParametersWellKnownTypes(t *testing.T) { + type test struct { + MsgDescs []*descriptorpb.DescriptorProto + WellKnownMsgDescs []*descriptorpb.DescriptorProto + Message string + Params []openapiParameterObject + } + + tests := []test{ + { + MsgDescs: []*descriptorpb.DescriptorProto{ + { + Name: proto.String("ExampleMessage"), + Field: []*descriptorpb.FieldDescriptorProto{ + { + Name: proto.String("a_field_mask"), + Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + TypeName: proto.String(".google.protobuf.FieldMask"), + Number: proto.Int32(1), + }, + { + Name: proto.String("a_timestamp"), + Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + TypeName: proto.String(".google.protobuf.Timestamp"), + Number: proto.Int32(2), + }, + }, + }, + }, + WellKnownMsgDescs: []*descriptorpb.DescriptorProto{ + { + Name: proto.String("FieldMask"), + Field: []*descriptorpb.FieldDescriptorProto{ + { + Name: proto.String("paths"), + Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), + Label: descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(), + Number: proto.Int32(1), + }, + }, + }, + { + Name: proto.String("Timestamp"), + Field: []*descriptorpb.FieldDescriptorProto{ + { + Name: proto.String("seconds"), + Type: descriptorpb.FieldDescriptorProto_TYPE_INT64.Enum(), + Number: proto.Int32(1), + }, + { + Name: proto.String("nanos"), + Type: descriptorpb.FieldDescriptorProto_TYPE_INT32.Enum(), + Number: proto.Int32(2), + }, + }, + }, + }, + Message: "ExampleMessage", + Params: []openapiParameterObject{ + { + Name: "a_field_mask", + In: "query", + Required: false, + Type: "array", + Items: &openapiItemsObject{ + Type: "string", + }, + CollectionFormat: "multi", + }, + { + Name: "a_timestamp", + In: "query", + Required: false, + Type: "string", + Format: "date-time", + }, + }, + }, + } + + for _, test := range tests { + reg := descriptor.NewRegistry() + reg.SetEnumsAsInts(true) + err := reg.Load(&pluginpb.CodeGeneratorRequest{ + ProtoFile: []*descriptorpb.FileDescriptorProto{ + { + SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, + Name: proto.String("google/well_known.proto"), + Package: proto.String("google.protobuf"), + Dependency: []string{}, + MessageType: test.WellKnownMsgDescs, + Service: []*descriptorpb.ServiceDescriptorProto{}, + }, + { + SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, + Name: proto.String("acme/example.proto"), + Package: proto.String("example"), + Dependency: []string{"google/well_known.proto"}, + MessageType: test.MsgDescs, + Service: []*descriptorpb.ServiceDescriptorProto{}, + }, + }, + }) + if err != nil { + t.Fatalf("failed to load CodeGeneratorRequest: %v", err) + } + + message, err := reg.LookupMsg("", ".example."+test.Message) + if err != nil { + t.Fatalf("failed to lookup message: %s", err) + } + params, err := messageToQueryParameters(message, reg, []descriptor.Parameter{}, nil) if err != nil { t.Fatalf("failed to convert message to query parameters: %s", err) } @@ -777,7 +903,6 @@ func TestApplyTemplateSimple(t *testing.T) { SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, Name: proto.String("example.proto"), Package: proto.String("example"), - Dependency: []string{"a.example/b/c.proto", "a.example/d/e.proto"}, MessageType: []*descriptorpb.DescriptorProto{msgdesc}, Service: []*descriptorpb.ServiceDescriptorProto{svc}, }, @@ -878,7 +1003,6 @@ func TestApplyTemplateMultiService(t *testing.T) { SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, Name: proto.String("example.proto"), Package: proto.String("example"), - Dependency: []string{"a.example/b/c.proto", "a.example/d/e.proto"}, MessageType: []*descriptorpb.DescriptorProto{msgdesc}, Service: []*descriptorpb.ServiceDescriptorProto{svc}, }, @@ -966,160 +1090,191 @@ func TestApplyTemplateMultiService(t *testing.T) { } func TestApplyTemplateOverrideOperationID(t *testing.T) { - msgdesc := &descriptorpb.DescriptorProto{ - Name: proto.String("ExampleMessage"), - } - meth := &descriptorpb.MethodDescriptorProto{ - Name: proto.String("Example"), - InputType: proto.String("ExampleMessage"), - OutputType: proto.String("ExampleMessage"), - Options: &descriptorpb.MethodOptions{}, - } - openapiOperation := openapi_options.Operation{ - OperationId: "MyExample", - } - proto.SetExtension(proto.Message(meth.Options), openapi_options.E_Openapiv2Operation, &openapiOperation) - svc := &descriptorpb.ServiceDescriptorProto{ - Name: proto.String("ExampleService"), - Method: []*descriptorpb.MethodDescriptorProto{meth}, - } - msg := &descriptor.Message{ - DescriptorProto: msgdesc, - } - file := descriptor.File{ - FileDescriptorProto: &descriptorpb.FileDescriptorProto{ - SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, - Name: proto.String("example.proto"), - Package: proto.String("example"), - Dependency: []string{"a.example/b/c.proto", "a.example/d/e.proto"}, - MessageType: []*descriptorpb.DescriptorProto{msgdesc}, - Service: []*descriptorpb.ServiceDescriptorProto{svc}, - }, - GoPkg: descriptor.GoPackage{ - Path: "example.com/path/to/example/example.pb", - Name: "example_pb", - }, - Messages: []*descriptor.Message{msg}, - Services: []*descriptor.Service{ - { - ServiceDescriptorProto: svc, - Methods: []*descriptor.Method{ - { - MethodDescriptorProto: meth, - RequestType: msg, - ResponseType: msg, - Bindings: []*descriptor.Binding{ - { - HTTPMethod: "GET", - Body: &descriptor.Body{FieldPath: nil}, - PathTmpl: httprule.Template{ - Version: 1, - OpCodes: []int{0, 0}, - Template: "/v1/echo", // TODO(achew22): Figure out what this should really be + newFile := func() *descriptor.File { + msgdesc := &descriptorpb.DescriptorProto{ + Name: proto.String("ExampleMessage"), + } + meth := &descriptorpb.MethodDescriptorProto{ + Name: proto.String("Example"), + InputType: proto.String("ExampleMessage"), + OutputType: proto.String("ExampleMessage"), + Options: &descriptorpb.MethodOptions{}, + } + svc := &descriptorpb.ServiceDescriptorProto{ + Name: proto.String("ExampleService"), + Method: []*descriptorpb.MethodDescriptorProto{meth}, + } + msg := &descriptor.Message{ + DescriptorProto: msgdesc, + } + return &descriptor.File{ + FileDescriptorProto: &descriptorpb.FileDescriptorProto{ + SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, + Name: proto.String("example.proto"), + Package: proto.String("example"), + MessageType: []*descriptorpb.DescriptorProto{msgdesc}, + Service: []*descriptorpb.ServiceDescriptorProto{svc}, + }, + GoPkg: descriptor.GoPackage{ + Path: "example.com/path/to/example/example.pb", + Name: "example_pb", + }, + Messages: []*descriptor.Message{msg}, + Services: []*descriptor.Service{ + { + ServiceDescriptorProto: svc, + Methods: []*descriptor.Method{ + { + MethodDescriptorProto: meth, + RequestType: msg, + ResponseType: msg, + Bindings: []*descriptor.Binding{ + { + HTTPMethod: "GET", + Body: &descriptor.Body{FieldPath: nil}, + PathTmpl: httprule.Template{ + Version: 1, + OpCodes: []int{0, 0}, + Template: "/v1/echo", // TODO(achew22): Figure out what this should really be + }, }, }, }, }, }, }, - }, + } } - reg := descriptor.NewRegistry() - if err := AddErrorDefs(reg); err != nil { - t.Errorf("AddErrorDefs(%#v) failed with %v; want success", reg, err) - return - } - fileCL := crossLinkFixture(&file) - err := reg.Load(reqFromFile(fileCL)) - if err != nil { - t.Errorf("reg.Load(%#v) failed with %v; want success", file, err) - return - } - result, err := applyTemplate(param{File: fileCL, reg: reg}) - if err != nil { - t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err) - return - } - if want, is := "MyExample", result.Paths["/v1/echo"].Get.OperationID; !reflect.DeepEqual(is, want) { - t.Errorf("applyTemplate(%#v).Paths[0].Get.OperationID = %s want to be %s", file, is, want) + verifyTemplateFromReq := func(t *testing.T, reg *descriptor.Registry, file *descriptor.File, opts *openapiconfig.OpenAPIOptions) { + if err := AddErrorDefs(reg); err != nil { + t.Errorf("AddErrorDefs(%#v) failed with %v; want success", reg, err) + return + } + fileCL := crossLinkFixture(file) + err := reg.Load(reqFromFile(fileCL)) + if err != nil { + t.Errorf("reg.Load(%#v) failed with %v; want success", *file, err) + return + } + if opts != nil { + if err := reg.RegisterOpenAPIOptions(opts); err != nil { + t.Fatalf("failed to register OpenAPI options: %s", err) + } + } + result, err := applyTemplate(param{File: fileCL, reg: reg}) + if err != nil { + t.Errorf("applyTemplate(%#v) failed with %v; want success", *file, err) + return + } + if want, is := "MyExample", result.Paths["/v1/echo"].Get.OperationID; !reflect.DeepEqual(is, want) { + t.Errorf("applyTemplate(%#v).Paths[0].Get.OperationID = %s want to be %s", *file, is, want) + } + + // If there was a failure, print out the input and the json result for debugging. + if t.Failed() { + t.Errorf("had: %s", *file) + t.Errorf("got: %s", fmt.Sprint(result)) + } } - // If there was a failure, print out the input and the json result for debugging. - if t.Failed() { - t.Errorf("had: %s", file) - t.Errorf("got: %s", fmt.Sprint(result)) + openapiOperation := openapi_options.Operation{ + OperationId: "MyExample", } + + t.Run("verify override via method option", func(t *testing.T) { + file := newFile() + proto.SetExtension(proto.Message(file.Services[0].Methods[0].MethodDescriptorProto.Options), + openapi_options.E_Openapiv2Operation, &openapiOperation) + + reg := descriptor.NewRegistry() + verifyTemplateFromReq(t, reg, file, nil) + }) + + t.Run("verify override options annotations", func(t *testing.T) { + file := newFile() + reg := descriptor.NewRegistry() + opts := &openapiconfig.OpenAPIOptions{ + Method: []*openapiconfig.OpenAPIMethodOption{ + { + Method: "example.ExampleService.Example", + Option: &openapiOperation, + }, + }, + } + verifyTemplateFromReq(t, reg, file, opts) + }) } func TestApplyTemplateExtensions(t *testing.T) { - msgdesc := &descriptorpb.DescriptorProto{ - Name: proto.String("ExampleMessage"), - } - meth := &descriptorpb.MethodDescriptorProto{ - Name: proto.String("Example"), - InputType: proto.String("ExampleMessage"), - OutputType: proto.String("ExampleMessage"), - Options: &descriptorpb.MethodOptions{}, - } - svc := &descriptorpb.ServiceDescriptorProto{ - Name: proto.String("ExampleService"), - Method: []*descriptorpb.MethodDescriptorProto{meth}, - } - msg := &descriptor.Message{ - DescriptorProto: msgdesc, + newFile := func() *descriptor.File { + msgdesc := &descriptorpb.DescriptorProto{ + Name: proto.String("ExampleMessage"), + } + meth := &descriptorpb.MethodDescriptorProto{ + Name: proto.String("Example"), + InputType: proto.String("ExampleMessage"), + OutputType: proto.String("ExampleMessage"), + Options: &descriptorpb.MethodOptions{}, + } + svc := &descriptorpb.ServiceDescriptorProto{ + Name: proto.String("ExampleService"), + Method: []*descriptorpb.MethodDescriptorProto{meth}, + } + msg := &descriptor.Message{ + DescriptorProto: msgdesc, + } + return &descriptor.File{ + FileDescriptorProto: &descriptorpb.FileDescriptorProto{ + SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, + Name: proto.String("example.proto"), + Package: proto.String("example"), + MessageType: []*descriptorpb.DescriptorProto{msgdesc}, + Service: []*descriptorpb.ServiceDescriptorProto{svc}, + Options: &descriptorpb.FileOptions{}, + }, + GoPkg: descriptor.GoPackage{ + Path: "example.com/path/to/example/example.pb", + Name: "example_pb", + }, + Messages: []*descriptor.Message{msg}, + Services: []*descriptor.Service{ + { + ServiceDescriptorProto: svc, + Methods: []*descriptor.Method{ + { + MethodDescriptorProto: meth, + RequestType: msg, + ResponseType: msg, + Bindings: []*descriptor.Binding{ + { + HTTPMethod: "GET", + Body: &descriptor.Body{FieldPath: nil}, + PathTmpl: httprule.Template{ + Version: 1, + OpCodes: []int{0, 0}, + Template: "/v1/echo", // TODO(achew22): Figure out what this should really be + }, + }, + }, + }, + }, + }, + }, + } } - file := descriptor.File{ - FileDescriptorProto: &descriptorpb.FileDescriptorProto{ - SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, - Name: proto.String("example.proto"), - Package: proto.String("example"), - Dependency: []string{"a.example/b/c.proto", "a.example/d/e.proto"}, - MessageType: []*descriptorpb.DescriptorProto{msgdesc}, - Service: []*descriptorpb.ServiceDescriptorProto{svc}, - Options: &descriptorpb.FileOptions{}, + swagger := openapi_options.Swagger{ + Info: &openapi_options.Info{ + Title: "test", + Extensions: map[string]*structpb.Value{ + "x-info-extension": {Kind: &structpb.Value_StringValue{StringValue: "bar"}}, + }, }, - GoPkg: descriptor.GoPackage{ - Path: "example.com/path/to/example/example.pb", - Name: "example_pb", - }, - Messages: []*descriptor.Message{msg}, - Services: []*descriptor.Service{ - { - ServiceDescriptorProto: svc, - Methods: []*descriptor.Method{ - { - MethodDescriptorProto: meth, - RequestType: msg, - ResponseType: msg, - Bindings: []*descriptor.Binding{ - { - HTTPMethod: "GET", - Body: &descriptor.Body{FieldPath: nil}, - PathTmpl: httprule.Template{ - Version: 1, - OpCodes: []int{0, 0}, - Template: "/v1/echo", // TODO(achew22): Figure out what this should really be - }, - }, - }, - }, - }, - }, - }, - } - swagger := openapi_options.Swagger{ - Info: &openapi_options.Info{ - Title: "test", - Extensions: map[string]*structpb.Value{ - "x-info-extension": {Kind: &structpb.Value_StringValue{StringValue: "bar"}}, - }, - }, - Extensions: map[string]*structpb.Value{ - "x-foo": {Kind: &structpb.Value_StringValue{StringValue: "bar"}}, - "x-bar": {Kind: &structpb.Value_ListValue{ListValue: &structpb.ListValue{ - Values: []*structpb.Value{{Kind: &structpb.Value_StringValue{StringValue: "baz"}}}, - }}}, + Extensions: map[string]*structpb.Value{ + "x-foo": {Kind: &structpb.Value_StringValue{StringValue: "bar"}}, + "x-bar": {Kind: &structpb.Value_ListValue{ListValue: &structpb.ListValue{ + Values: []*structpb.Value{{Kind: &structpb.Value_StringValue{StringValue: "baz"}}}, + }}}, }, SecurityDefinitions: &openapi_options.SecurityDefinitions{ Security: map[string]*openapi_options.SecurityScheme{ @@ -1131,7 +1286,6 @@ func TestApplyTemplateExtensions(t *testing.T) { }, }, } - proto.SetExtension(proto.Message(file.FileDescriptorProto.Options), openapi_options.E_Openapiv2Swagger, &swagger) openapiOperation := openapi_options.Operation{ Responses: map[string]*openapi_options.Response{ "200": { @@ -1144,90 +1298,122 @@ func TestApplyTemplateExtensions(t *testing.T) { "x-op-foo": {Kind: &structpb.Value_StringValue{StringValue: "baz"}}, }, } - proto.SetExtension(proto.Message(meth.Options), openapi_options.E_Openapiv2Operation, &openapiOperation) - reg := descriptor.NewRegistry() - if err := AddErrorDefs(reg); err != nil { - t.Errorf("AddErrorDefs(%#v) failed with %v; want success", reg, err) - return - } - fileCL := crossLinkFixture(&file) - err := reg.Load(reqFromFile(fileCL)) - if err != nil { - t.Errorf("reg.Load(%#v) failed with %v; want success", file, err) - return - } - result, err := applyTemplate(param{File: fileCL, reg: reg}) - if err != nil { - t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err) - return - } - if want, is, name := "2.0", result.Swagger, "Swagger"; !reflect.DeepEqual(is, want) { - t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want) - } - if got, want := len(result.extensions), 2; got != want { - t.Fatalf("len(applyTemplate(%#v).Extensions) = %d want to be %d", file, got, want) - } - if got, want := result.extensions[0].key, "x-bar"; got != want { - t.Errorf("applyTemplate(%#v).Extensions[0].key = %s want to be %s", file, got, want) - } - if got, want := result.extensions[1].key, "x-foo"; got != want { - t.Errorf("applyTemplate(%#v).Extensions[1].key = %s want to be %s", file, got, want) - } - { - var got []string - err = marshaler.Unmarshal(result.extensions[0].value, &got) + verifyTemplateExtensions := func(t *testing.T, reg *descriptor.Registry, file *descriptor.File, + opts *openapiconfig.OpenAPIOptions) { + if err := AddErrorDefs(reg); err != nil { + t.Errorf("AddErrorDefs(%#v) failed with %v; want success", reg, err) + return + } + fileCL := crossLinkFixture(file) + err := reg.Load(reqFromFile(fileCL)) if err != nil { - t.Fatalf("marshaler.Unmarshal failed: %v", err) + t.Errorf("reg.Load(%#v) failed with %v; want success", file, err) + return } - want := []string{"baz"} - if diff := cmp.Diff(got, want); diff != "" { - t.Errorf(diff) + if opts != nil { + if err := reg.RegisterOpenAPIOptions(opts); err != nil { + t.Fatalf("failed to register OpenAPI annotations: %s", err) + } } - } - { - var got string - err = marshaler.Unmarshal(result.extensions[1].value, &got) + result, err := applyTemplate(param{File: fileCL, reg: reg}) if err != nil { - t.Fatalf("marshaler.Unmarshal failed: %v", err) + t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err) + return } - want := "bar" - if diff := cmp.Diff(got, want); diff != "" { - t.Errorf(diff) + if want, is, name := "2.0", result.Swagger, "Swagger"; !reflect.DeepEqual(is, want) { + t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want) + } + if got, want := len(result.extensions), 2; got != want { + t.Fatalf("len(applyTemplate(%#v).Extensions) = %d want to be %d", file, got, want) + } + if got, want := result.extensions[0].key, "x-bar"; got != want { + t.Errorf("applyTemplate(%#v).Extensions[0].key = %s want to be %s", file, got, want) + } + if got, want := result.extensions[1].key, "x-foo"; got != want { + t.Errorf("applyTemplate(%#v).Extensions[1].key = %s want to be %s", file, got, want) + } + { + var got []string + err = marshaler.Unmarshal(result.extensions[0].value, &got) + if err != nil { + t.Fatalf("marshaler.Unmarshal failed: %v", err) + } + want := []string{"baz"} + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf(diff) + } + } + { + var got string + err = marshaler.Unmarshal(result.extensions[1].value, &got) + if err != nil { + t.Fatalf("marshaler.Unmarshal failed: %v", err) + } + want := "bar" + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf(diff) + } } - } - var scheme openapiSecuritySchemeObject - for _, v := range result.SecurityDefinitions { - scheme = v - } - if want, is, name := []extension{ - {key: "x-security-baz", value: json.RawMessage("true")}, - }, scheme.extensions, "SecurityScheme.Extensions"; !reflect.DeepEqual(is, want) { - t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want) - } + var scheme openapiSecuritySchemeObject + for _, v := range result.SecurityDefinitions { + scheme = v + } + if want, is, name := []extension{ + {key: "x-security-baz", value: json.RawMessage("true")}, + }, scheme.extensions, "SecurityScheme.Extensions"; !reflect.DeepEqual(is, want) { + t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want) + } - if want, is, name := []extension{ - {key: "x-info-extension", value: json.RawMessage("\"bar\"")}, - }, result.Info.extensions, "Info.Extensions"; !reflect.DeepEqual(is, want) { - t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want) - } + if want, is, name := []extension{ + {key: "x-info-extension", value: json.RawMessage("\"bar\"")}, + }, result.Info.extensions, "Info.Extensions"; !reflect.DeepEqual(is, want) { + t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want) + } - var operation *openapiOperationObject - var response openapiResponseObject - for _, v := range result.Paths { - operation = v.Get - response = v.Get.Responses["200"] - } - if want, is, name := []extension{ - {key: "x-op-foo", value: json.RawMessage("\"baz\"")}, - }, operation.extensions, "operation.Extensions"; !reflect.DeepEqual(is, want) { - t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want) - } - if want, is, name := []extension{ - {key: "x-resp-id", value: json.RawMessage("\"resp1000\"")}, - }, response.extensions, "response.Extensions"; !reflect.DeepEqual(is, want) { - t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want) + var operation *openapiOperationObject + var response openapiResponseObject + for _, v := range result.Paths { + operation = v.Get + response = v.Get.Responses["200"] + } + if want, is, name := []extension{ + {key: "x-op-foo", value: json.RawMessage("\"baz\"")}, + }, operation.extensions, "operation.Extensions"; !reflect.DeepEqual(is, want) { + t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want) + } + if want, is, name := []extension{ + {key: "x-resp-id", value: json.RawMessage("\"resp1000\"")}, + }, response.extensions, "response.Extensions"; !reflect.DeepEqual(is, want) { + t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want) + } } + t.Run("verify template options set via proto options", func(t *testing.T) { + file := newFile() + proto.SetExtension(proto.Message(file.FileDescriptorProto.Options), openapi_options.E_Openapiv2Swagger, &swagger) + proto.SetExtension(proto.Message(file.Services[0].Methods[0].Options), openapi_options.E_Openapiv2Operation, &openapiOperation) + reg := descriptor.NewRegistry() + verifyTemplateExtensions(t, reg, file, nil) + }) + t.Run("verify template options set via annotations", func(t *testing.T) { + file := newFile() + opts := &openapiconfig.OpenAPIOptions{ + File: []*openapiconfig.OpenAPIFileOption{ + { + File: "example.proto", + Option: &swagger, + }, + }, + Method: []*openapiconfig.OpenAPIMethodOption{ + { + Method: "example.ExampleService.Example", + Option: &openapiOperation, + }, + }, + } + reg := descriptor.NewRegistry() + verifyTemplateExtensions(t, reg, file, opts) + }) } func TestApplyTemplateRequestWithoutClientStreaming(t *testing.T) { @@ -1697,6 +1883,184 @@ func TestApplyTemplateRequestWithUnusedReferences(t *testing.T) { } } +func TestApplyTemplateRequestWithBodyQueryParameters(t *testing.T) { + bookDesc := &descriptorpb.DescriptorProto{ + Name: proto.String("Book"), + Field: []*descriptorpb.FieldDescriptorProto{ + { + Name: proto.String("name"), + Label: descriptorpb.FieldDescriptorProto_LABEL_REQUIRED.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), + Number: proto.Int32(1), + }, + { + Name: proto.String("id"), + Label: descriptorpb.FieldDescriptorProto_LABEL_REQUIRED.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), + Number: proto.Int32(2), + }, + }, + } + createDesc := &descriptorpb.DescriptorProto{ + Name: proto.String("CreateBookRequest"), + Field: []*descriptorpb.FieldDescriptorProto{ + { + Name: proto.String("parent"), + Label: descriptorpb.FieldDescriptorProto_LABEL_REQUIRED.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), + Number: proto.Int32(1), + }, + { + Name: proto.String("book"), + Label: descriptorpb.FieldDescriptorProto_LABEL_REQUIRED.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), + Number: proto.Int32(2), + }, + { + Name: proto.String("book_id"), + Label: descriptorpb.FieldDescriptorProto_LABEL_REQUIRED.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), + Number: proto.Int32(3), + }, + }, + } + meth := &descriptorpb.MethodDescriptorProto{ + Name: proto.String("CreateBook"), + InputType: proto.String("CreateBookRequest"), + OutputType: proto.String("Book"), + } + svc := &descriptorpb.ServiceDescriptorProto{ + Name: proto.String("BookService"), + Method: []*descriptorpb.MethodDescriptorProto{meth}, + } + + bookMsg := &descriptor.Message{ + DescriptorProto: bookDesc, + } + createMsg := &descriptor.Message{ + DescriptorProto: createDesc, + } + + parentField := &descriptor.Field{ + Message: createMsg, + FieldDescriptorProto: createMsg.GetField()[0], + } + bookField := &descriptor.Field{ + Message: createMsg, + FieldMessage: bookMsg, + FieldDescriptorProto: createMsg.GetField()[1], + } + bookIDField := &descriptor.Field{ + Message: createMsg, + FieldDescriptorProto: createMsg.GetField()[2], + } + + createMsg.Fields = []*descriptor.Field{parentField, bookField, bookIDField} + + file := descriptor.File{ + FileDescriptorProto: &descriptorpb.FileDescriptorProto{ + SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, + Name: proto.String("book.proto"), + MessageType: []*descriptorpb.DescriptorProto{bookDesc, createDesc}, + Service: []*descriptorpb.ServiceDescriptorProto{svc}, + }, + GoPkg: descriptor.GoPackage{ + Path: "example.com/path/to/book.pb", + Name: "book_pb", + }, + Messages: []*descriptor.Message{bookMsg, createMsg}, + Services: []*descriptor.Service{ + { + ServiceDescriptorProto: svc, + Methods: []*descriptor.Method{ + { + MethodDescriptorProto: meth, + RequestType: createMsg, + ResponseType: bookMsg, + Bindings: []*descriptor.Binding{ + { + HTTPMethod: "POST", + PathTmpl: httprule.Template{ + Version: 1, + OpCodes: []int{0, 0}, + Template: "/v1/{parent=publishers/*}/books", + }, + PathParams: []descriptor.Parameter{ + { + FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{ + { + Name: "parent", + Target: parentField, + }, + }), + Target: parentField, + }, + }, + Body: &descriptor.Body{ + FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{ + { + Name: "book", + Target: bookField, + }, + }), + }, + }, + }, + }, + }, + }, + }, + } + reg := descriptor.NewRegistry() + if err := AddErrorDefs(reg); err != nil { + t.Errorf("AddErrorDefs(%#v) failed with %v; want success", reg, err) + return + } + err := reg.Load(&pluginpb.CodeGeneratorRequest{ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto}}) + if err != nil { + t.Errorf("Registry.Load() failed with %v; want success", err) + return + } + result, err := applyTemplate(param{File: crossLinkFixture(&file), reg: reg}) + if err != nil { + t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err) + return + } + + if _, ok := result.Paths["/v1/{parent=publishers/*}/books"].Post.Responses["200"]; !ok { + t.Errorf("applyTemplate(%#v).%s = expected 200 response to be defined", file, `result.Paths["/v1/{parent=publishers/*}/books"].Post.Responses["200"]`) + } else { + if want, got, name := 3, len(result.Paths["/v1/{parent=publishers/*}/books"].Post.Parameters), `len(result.Paths["/v1/{parent=publishers/*}/books"].Post.Parameters)`; !reflect.DeepEqual(got, want) { + t.Errorf("applyTemplate(%#v).%s = %d want to be %d", file, name, got, want) + } + + type param struct { + Name string + In string + Required bool + } + + p0 := result.Paths["/v1/{parent=publishers/*}/books"].Post.Parameters[0] + if want, got, name := (param{"parent", "path", true}), (param{p0.Name, p0.In, p0.Required}), `result.Paths["/v1/{parent=publishers/*}/books"].Post.Parameters[0]`; !reflect.DeepEqual(got, want) { + t.Errorf("applyTemplate(%#v).%s = %v want to be %v", file, name, got, want) + } + p1 := result.Paths["/v1/{parent=publishers/*}/books"].Post.Parameters[1] + if want, got, name := (param{"body", "body", true}), (param{p1.Name, p1.In, p1.Required}), `result.Paths["/v1/{parent=publishers/*}/books"].Post.Parameters[1]`; !reflect.DeepEqual(got, want) { + t.Errorf("applyTemplate(%#v).%s = %v want to be %v", file, name, got, want) + } + p2 := result.Paths["/v1/{parent=publishers/*}/books"].Post.Parameters[2] + if want, got, name := (param{"book_id", "query", false}), (param{p2.Name, p2.In, p2.Required}), `result.Paths["/v1/{parent=publishers/*}/books"].Post.Parameters[1]`; !reflect.DeepEqual(got, want) { + t.Errorf("applyTemplate(%#v).%s = %v want to be %v", file, name, got, want) + } + } + + // If there was a failure, print out the input and the json result for debugging. + if t.Failed() { + t.Errorf("had: %s", file) + t.Errorf("got: %s", fmt.Sprint(result)) + } +} + func generateFieldsForJSONReservedName() []*descriptor.Field { fields := make([]*descriptor.Field, 0) fieldName := string("json_name") @@ -1942,11 +2306,20 @@ func TestFQMNtoOpenAPIName(t *testing.T) { func TestSchemaOfField(t *testing.T) { type test struct { - field *descriptor.Field - refs refMap - expected schemaCore + field *descriptor.Field + refs refMap + expected openapiSchemaObject + openAPIOptions *openapiconfig.OpenAPIOptions } + jsonSchema := &openapi_options.JSONSchema{ + Title: "field title", + Description: "field description", + } + + var fieldOptions = new(descriptorpb.FieldOptions) + proto.SetExtension(fieldOptions, openapi_options.E_Openapiv2Field, jsonSchema) + tests := []test{ { field: &descriptor.Field{ @@ -1956,8 +2329,10 @@ func TestSchemaOfField(t *testing.T) { }, }, refs: make(refMap), - expected: schemaCore{ - Type: "string", + expected: openapiSchemaObject{ + schemaCore: schemaCore{ + Type: "string", + }, }, }, { @@ -1969,9 +2344,60 @@ func TestSchemaOfField(t *testing.T) { }, }, refs: make(refMap), - expected: schemaCore{ - Type: "array", - Items: &openapiItemsObject{ + expected: openapiSchemaObject{ + schemaCore: schemaCore{ + Type: "array", + Items: &openapiItemsObject{ + Type: "string", + }, + }, + }, + }, + { + field: &descriptor.Field{ + FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ + Name: proto.String("wrapped_field"), + TypeName: proto.String(".google.protobuf.FieldMask"), + Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + }, + }, + refs: make(refMap), + expected: openapiSchemaObject{ + schemaCore: schemaCore{ + Type: "array", + Items: &openapiItemsObject{ + Type: "string", + }, + }, + }, + }, + { + field: &descriptor.Field{ + FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ + Name: proto.String("wrapped_field"), + TypeName: proto.String(".google.protobuf.Timestamp"), + Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + }, + }, + refs: make(refMap), + expected: openapiSchemaObject{ + schemaCore: schemaCore{ + Type: "string", + Format: "date-time", + }, + }, + }, + { + field: &descriptor.Field{ + FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ + Name: proto.String("wrapped_field"), + TypeName: proto.String(".google.protobuf.Duration"), + Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + }, + }, + refs: make(refMap), + expected: openapiSchemaObject{ + schemaCore: schemaCore{ Type: "string", }, }, @@ -1985,8 +2411,10 @@ func TestSchemaOfField(t *testing.T) { }, }, refs: make(refMap), - expected: schemaCore{ - Type: "string", + expected: openapiSchemaObject{ + schemaCore: schemaCore{ + Type: "string", + }, }, }, { @@ -1999,10 +2427,12 @@ func TestSchemaOfField(t *testing.T) { }, }, refs: make(refMap), - expected: schemaCore{ - Type: "array", - Items: &openapiItemsObject{ - Type: "string", + expected: openapiSchemaObject{ + schemaCore: schemaCore{ + Type: "array", + Items: &openapiItemsObject{ + Type: "string", + }, }, }, }, @@ -2015,9 +2445,11 @@ func TestSchemaOfField(t *testing.T) { }, }, refs: make(refMap), - expected: schemaCore{ - Type: "string", - Format: "byte", + expected: openapiSchemaObject{ + schemaCore: schemaCore{ + Type: "string", + Format: "byte", + }, }, }, { @@ -2029,9 +2461,11 @@ func TestSchemaOfField(t *testing.T) { }, }, refs: make(refMap), - expected: schemaCore{ - Type: "integer", - Format: "int32", + expected: openapiSchemaObject{ + schemaCore: schemaCore{ + Type: "integer", + Format: "int32", + }, }, }, { @@ -2043,9 +2477,11 @@ func TestSchemaOfField(t *testing.T) { }, }, refs: make(refMap), - expected: schemaCore{ - Type: "integer", - Format: "int64", + expected: openapiSchemaObject{ + schemaCore: schemaCore{ + Type: "integer", + Format: "int64", + }, }, }, { @@ -2057,9 +2493,11 @@ func TestSchemaOfField(t *testing.T) { }, }, refs: make(refMap), - expected: schemaCore{ - Type: "string", - Format: "int64", + expected: openapiSchemaObject{ + schemaCore: schemaCore{ + Type: "string", + Format: "int64", + }, }, }, { @@ -2071,9 +2509,11 @@ func TestSchemaOfField(t *testing.T) { }, }, refs: make(refMap), - expected: schemaCore{ - Type: "string", - Format: "uint64", + expected: openapiSchemaObject{ + schemaCore: schemaCore{ + Type: "string", + Format: "uint64", + }, }, }, { @@ -2085,9 +2525,11 @@ func TestSchemaOfField(t *testing.T) { }, }, refs: make(refMap), - expected: schemaCore{ - Type: "number", - Format: "float", + expected: openapiSchemaObject{ + schemaCore: schemaCore{ + Type: "number", + Format: "float", + }, }, }, { @@ -2099,9 +2541,11 @@ func TestSchemaOfField(t *testing.T) { }, }, refs: make(refMap), - expected: schemaCore{ - Type: "number", - Format: "double", + expected: openapiSchemaObject{ + schemaCore: schemaCore{ + Type: "number", + Format: "double", + }, }, }, { @@ -2113,8 +2557,10 @@ func TestSchemaOfField(t *testing.T) { }, }, refs: make(refMap), - expected: schemaCore{ - Type: "boolean", + expected: openapiSchemaObject{ + schemaCore: schemaCore{ + Type: "boolean", + }, }, }, { @@ -2126,8 +2572,10 @@ func TestSchemaOfField(t *testing.T) { }, }, refs: make(refMap), - expected: schemaCore{ - Type: "object", + expected: openapiSchemaObject{ + schemaCore: schemaCore{ + Type: "object", + }, }, }, { @@ -2139,8 +2587,10 @@ func TestSchemaOfField(t *testing.T) { }, }, refs: make(refMap), - expected: schemaCore{ - Type: "object", + expected: openapiSchemaObject{ + schemaCore: schemaCore{ + Type: "object", + }, }, }, { @@ -2152,11 +2602,13 @@ func TestSchemaOfField(t *testing.T) { }, }, refs: make(refMap), - expected: schemaCore{ - Type: "array", - Items: (*openapiItemsObject)(&schemaCore{ - Type: "object", - }), + expected: openapiSchemaObject{ + schemaCore: schemaCore{ + Type: "array", + Items: (*openapiItemsObject)(&schemaCore{ + Type: "object", + }), + }, }, }, { @@ -2164,12 +2616,14 @@ func TestSchemaOfField(t *testing.T) { FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ Name: proto.String("wrapped_field"), TypeName: proto.String(".google.protobuf.NullValue"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_ENUM.Enum(), }, }, refs: make(refMap), - expected: schemaCore{ - Type: "string", + expected: openapiSchemaObject{ + schemaCore: schemaCore{ + Type: "string", + }, }, }, { @@ -2181,47 +2635,311 @@ func TestSchemaOfField(t *testing.T) { }, }, refs: refMap{".example.Message": struct{}{}}, - expected: schemaCore{ - Ref: "#/definitions/exampleMessage", + expected: openapiSchemaObject{ + schemaCore: schemaCore{ + Ref: "#/definitions/exampleMessage", + }, }, }, - } - - reg := descriptor.NewRegistry() - reg.Load(&pluginpb.CodeGeneratorRequest{ - ProtoFile: []*descriptorpb.FileDescriptorProto{ - { - SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, - Name: proto.String("example.proto"), - Package: proto.String("example"), - Dependency: []string{}, - MessageType: []*descriptorpb.DescriptorProto{ + { + field: &descriptor.Field{ + FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ + Name: proto.String("map_field"), + Label: descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + TypeName: proto.String(".example.Message.MapFieldEntry"), + Options: fieldOptions, + }, + }, + refs: make(refMap), + expected: openapiSchemaObject{ + schemaCore: schemaCore{ + Type: "object", + }, + AdditionalProperties: &openapiSchemaObject{ + schemaCore: schemaCore{Type: "string"}, + }, + Title: "field title", + Description: "field description", + }, + }, + { + field: &descriptor.Field{ + FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ + Name: proto.String("array_field"), + Label: descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), + Options: fieldOptions, + }, + }, + refs: make(refMap), + expected: openapiSchemaObject{ + schemaCore: schemaCore{ + Type: "array", + Items: (*openapiItemsObject)(&schemaCore{Type: "string"}), + }, + Title: "field title", + Description: "field description", + }, + }, + { + field: &descriptor.Field{ + FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ + Name: proto.String("primitive_field"), + Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_INT32.Enum(), + Options: fieldOptions, + }, + }, + refs: make(refMap), + expected: openapiSchemaObject{ + schemaCore: schemaCore{ + Type: "integer", + Format: "int32", + }, + Title: "field title", + Description: "field description", + }, + }, + { + field: &descriptor.Field{ + FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ + Name: proto.String("message_field"), + Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + TypeName: proto.String(".example.Empty"), + Options: fieldOptions, + }, + }, + refs: refMap{".example.Empty": struct{}{}}, + expected: openapiSchemaObject{ + schemaCore: schemaCore{ + Ref: "#/definitions/exampleEmpty", + }, + Title: "field title", + Description: "field description", + }, + }, + { + field: &descriptor.Field{ + FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ + Name: proto.String("map_field"), // should be called map_field_option but it's not valid map field name + Label: descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + TypeName: proto.String(".example.Message.MapFieldEntry"), + }, + }, + openAPIOptions: &openapiconfig.OpenAPIOptions{ + Field: []*openapiconfig.OpenAPIFieldOption{ { - Name: proto.String("Message"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("value"), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - }, - }, + Field: "example.Message.map_field", + Option: jsonSchema, + }, + }, + }, + refs: make(refMap), + expected: openapiSchemaObject{ + schemaCore: schemaCore{ + Type: "object", + }, + AdditionalProperties: &openapiSchemaObject{ + schemaCore: schemaCore{Type: "string"}, + }, + Title: "field title", + Description: "field description", + }, + }, + { + field: &descriptor.Field{ + FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ + Name: proto.String("array_field_option"), + Label: descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), + }, + }, + openAPIOptions: &openapiconfig.OpenAPIOptions{ + Field: []*openapiconfig.OpenAPIFieldOption{ + { + Field: "example.Message.array_field_option", + Option: jsonSchema, }, }, - EnumType: []*descriptorpb.EnumDescriptorProto{ + }, + refs: make(refMap), + expected: openapiSchemaObject{ + schemaCore: schemaCore{ + Type: "array", + Items: (*openapiItemsObject)(&schemaCore{Type: "string"}), + }, + Title: "field title", + Description: "field description", + }, + }, + { + field: &descriptor.Field{ + FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ + Name: proto.String("primitive_field_option"), + Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_INT32.Enum(), + }, + }, + openAPIOptions: &openapiconfig.OpenAPIOptions{ + Field: []*openapiconfig.OpenAPIFieldOption{ { - Name: proto.String("Message"), + Field: "example.Message.primitive_field_option", + Option: jsonSchema, }, }, - Service: []*descriptorpb.ServiceDescriptorProto{}, + }, + refs: make(refMap), + expected: openapiSchemaObject{ + schemaCore: schemaCore{ + Type: "integer", + Format: "int32", + }, + Title: "field title", + Description: "field description", }, }, - }) - + { + field: &descriptor.Field{ + FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ + Name: proto.String("message_field_option"), + Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + TypeName: proto.String(".example.Empty"), + }, + }, + openAPIOptions: &openapiconfig.OpenAPIOptions{ + Field: []*openapiconfig.OpenAPIFieldOption{ + { + Field: "example.Message.message_field_option", + Option: jsonSchema, + }, + }, + }, + refs: refMap{".example.Empty": struct{}{}}, + expected: openapiSchemaObject{ + schemaCore: schemaCore{ + Ref: "#/definitions/exampleEmpty", + }, + Title: "field title", + Description: "field description", + }, + }, + } for _, test := range tests { + reg := descriptor.NewRegistry() + req := &pluginpb.CodeGeneratorRequest{ + ProtoFile: []*descriptorpb.FileDescriptorProto{ + { + Name: proto.String("third_party/google.proto"), + Package: proto.String("google.protobuf"), + MessageType: []*descriptorpb.DescriptorProto{ + protodesc.ToDescriptorProto((&structpb.Struct{}).ProtoReflect().Descriptor()), + protodesc.ToDescriptorProto((&structpb.Value{}).ProtoReflect().Descriptor()), + protodesc.ToDescriptorProto((&structpb.ListValue{}).ProtoReflect().Descriptor()), + protodesc.ToDescriptorProto((&field_mask.FieldMask{}).ProtoReflect().Descriptor()), + protodesc.ToDescriptorProto((×tamppb.Timestamp{}).ProtoReflect().Descriptor()), + protodesc.ToDescriptorProto((&durationpb.Duration{}).ProtoReflect().Descriptor()), + protodesc.ToDescriptorProto((&wrapperspb.StringValue{}).ProtoReflect().Descriptor()), + protodesc.ToDescriptorProto((&wrapperspb.BytesValue{}).ProtoReflect().Descriptor()), + protodesc.ToDescriptorProto((&wrapperspb.Int32Value{}).ProtoReflect().Descriptor()), + protodesc.ToDescriptorProto((&wrapperspb.UInt32Value{}).ProtoReflect().Descriptor()), + protodesc.ToDescriptorProto((&wrapperspb.Int64Value{}).ProtoReflect().Descriptor()), + protodesc.ToDescriptorProto((&wrapperspb.UInt64Value{}).ProtoReflect().Descriptor()), + protodesc.ToDescriptorProto((&wrapperspb.FloatValue{}).ProtoReflect().Descriptor()), + protodesc.ToDescriptorProto((&wrapperspb.DoubleValue{}).ProtoReflect().Descriptor()), + protodesc.ToDescriptorProto((&wrapperspb.BoolValue{}).ProtoReflect().Descriptor()), + }, + EnumType: []*descriptorpb.EnumDescriptorProto{ + protodesc.ToEnumDescriptorProto(structpb.NullValue(0).Descriptor()), + }, + }, + { + SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, + Name: proto.String("example.proto"), + Package: proto.String("example"), + Dependency: []string{"third_party/google.proto"}, + MessageType: []*descriptorpb.DescriptorProto{ + { + Name: proto.String("Message"), + Field: []*descriptorpb.FieldDescriptorProto{ + { + Name: proto.String("value"), + Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), + Number: proto.Int32(1), + }, + func() *descriptorpb.FieldDescriptorProto { + fd := test.field.FieldDescriptorProto + fd.Number = proto.Int32(2) + return fd + }(), + }, + NestedType: []*descriptorpb.DescriptorProto{ + { + Name: proto.String("MapFieldEntry"), + Options: &descriptorpb.MessageOptions{MapEntry: proto.Bool(true)}, + Field: []*descriptorpb.FieldDescriptorProto{ + { + Name: proto.String("key"), + Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), + Number: proto.Int32(1), + }, + { + Name: proto.String("value"), + Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), + Number: proto.Int32(2), + }, + }, + }, + }, + }, + { + Name: proto.String("Empty"), + }, + }, + EnumType: []*descriptorpb.EnumDescriptorProto{ + { + Name: proto.String("MessageType"), + Value: []*descriptorpb.EnumValueDescriptorProto{ + { + Name: proto.String("MESSAGE_TYPE_1"), + Number: proto.Int32(0), + }, + }, + }, + }, + Service: []*descriptorpb.ServiceDescriptorProto{}, + }, + }, + } + err := reg.Load(req) + if err != nil { + t.Errorf("failed to reg.Load(req): %v", err) + } + + // set field's parent message pointer to message so field can resolve its FQFN + test.field.Message = &descriptor.Message{ + DescriptorProto: req.ProtoFile[1].MessageType[0], + File: &descriptor.File{ + FileDescriptorProto: req.ProtoFile[1], + }, + } + + if test.openAPIOptions != nil { + if err := reg.RegisterOpenAPIOptions(test.openAPIOptions); err != nil { + t.Fatalf("failed to register OpenAPI options: %s", err) + } + } + refs := make(refMap) actual := schemaOfField(test.field, reg, refs) - expectedSchemaObject := openapiSchemaObject{schemaCore: test.expected} + expectedSchemaObject := test.expected if e, a := expectedSchemaObject, actual; !reflect.DeepEqual(a, e) { - t.Errorf("Expected schemaOfField(%v) = %v, actual: %v", test.field, e, a) + t.Errorf("Expected schemaOfField(%v) = \n%#+v, actual: \n%#+v", test.field, e, a) } if !reflect.DeepEqual(refs, test.refs) { t.Errorf("Expected schemaOfField(%v) to add refs %v, not %v", test.field, test.refs, refs) @@ -2232,10 +2950,11 @@ func TestSchemaOfField(t *testing.T) { func TestRenderMessagesAsDefinition(t *testing.T) { tests := []struct { - descr string - msgDescs []*descriptorpb.DescriptorProto - schema map[string]openapi_options.Schema // per-message schema to add - defs openapiDefinitionsObject + descr string + msgDescs []*descriptorpb.DescriptorProto + schema map[string]openapi_options.Schema // per-message schema to add + defs openapiDefinitionsObject + openAPIOptions *openapiconfig.OpenAPIOptions }{ { descr: "no OpenAPI options", @@ -2254,10 +2973,7 @@ func TestRenderMessagesAsDefinition(t *testing.T) { }, schema: map[string]openapi_options.Schema{ "Message": { - Example: &anypb.Any{ - TypeUrl: "this_isnt_used", - Value: []byte(`{"foo":"bar"}`), - }, + Example: `{"foo":"bar"}`, }, }, defs: map[string]openapiSchemaObject{ @@ -2274,9 +2990,7 @@ func TestRenderMessagesAsDefinition(t *testing.T) { }, schema: map[string]openapi_options.Schema{ "Message": { - Example: &anypb.Any{ - Value: []byte(`XXXX anything goes XXXX`), - }, + Example: `XXXX anything goes XXXX`, }, }, defs: map[string]openapiSchemaObject{ @@ -2364,6 +3078,64 @@ func TestRenderMessagesAsDefinition(t *testing.T) { }, }, }, + { + descr: "JSONSchema options from registry", + msgDescs: []*descriptorpb.DescriptorProto{ + {Name: proto.String("Message")}, + }, + openAPIOptions: &openapiconfig.OpenAPIOptions{ + Message: []*openapiconfig.OpenAPIMessageOption{ + { + Message: "example.Message", + Option: &openapi_options.Schema{ + JsonSchema: &openapi_options.JSONSchema{ + Title: "title", + Description: "desc", + MultipleOf: 100, + Maximum: 101, + ExclusiveMaximum: true, + Minimum: 1, + ExclusiveMinimum: true, + MaxLength: 10, + MinLength: 3, + Pattern: "[a-z]+", + MaxItems: 20, + MinItems: 2, + UniqueItems: true, + MaxProperties: 33, + MinProperties: 22, + Required: []string{"req"}, + ReadOnly: true, + }, + }, + }, + }, + }, + defs: map[string]openapiSchemaObject{ + "Message": { + schemaCore: schemaCore{ + Type: "object", + }, + Title: "title", + Description: "desc", + MultipleOf: 100, + Maximum: 101, + ExclusiveMaximum: true, + Minimum: 1, + ExclusiveMinimum: true, + MaxLength: 10, + MinLength: 3, + Pattern: "[a-z]+", + MaxItems: 20, + MinItems: 2, + UniqueItems: true, + MaxProperties: 33, + MinProperties: 22, + Required: []string{"req"}, + ReadOnly: true, + }, + }, + }, } for _, test := range tests { @@ -2406,6 +3178,12 @@ func TestRenderMessagesAsDefinition(t *testing.T) { } } + if test.openAPIOptions != nil { + if err := reg.RegisterOpenAPIOptions(test.openAPIOptions); err != nil { + t.Fatalf("failed to register OpenAPI options: %s", err) + } + } + refs := make(refMap) actual := make(openapiDefinitionsObject) renderMessagesAsDefinition(msgMap, actual, reg, refs) @@ -2586,11 +3364,12 @@ func TestUpdateOpenAPIDataFromComments(t *testing.T) { func TestMessageOptionsWithGoTemplate(t *testing.T) { tests := []struct { - descr string - msgDescs []*descriptorpb.DescriptorProto - schema map[string]openapi_options.Schema // per-message schema to add - defs openapiDefinitionsObject - useGoTemplate bool + descr string + msgDescs []*descriptorpb.DescriptorProto + schema map[string]openapi_options.Schema // per-message schema to add + defs openapiDefinitionsObject + openAPIOptions *openapiconfig.OpenAPIOptions + useGoTemplate bool }{ { descr: "external docs option", @@ -2652,6 +3431,41 @@ func TestMessageOptionsWithGoTemplate(t *testing.T) { }, useGoTemplate: false, }, + { + descr: "registered OpenAPIOption", + msgDescs: []*descriptorpb.DescriptorProto{ + {Name: proto.String("Message")}, + }, + openAPIOptions: &openapiconfig.OpenAPIOptions{ + Message: []*openapiconfig.OpenAPIMessageOption{ + { + Message: "example.Message", + Option: &openapi_options.Schema{ + JsonSchema: &openapi_options.JSONSchema{ + Title: "{{.Name}}", + Description: "Description {{with \"which means nothing\"}}{{printf \"%q\" .}}{{end}}", + }, + ExternalDocs: &openapi_options.ExternalDocumentation{ + Description: "Description {{with \"which means nothing\"}}{{printf \"%q\" .}}{{end}}", + }, + }, + }, + }, + }, + defs: map[string]openapiSchemaObject{ + "Message": { + schemaCore: schemaCore{ + Type: "object", + }, + Title: "Message", + Description: `Description "which means nothing"`, + ExternalDocs: &openapiExternalDocumentationObject{ + Description: `Description "which means nothing"`, + }, + }, + }, + useGoTemplate: true, + }, } for _, test := range tests { @@ -2695,6 +3509,12 @@ func TestMessageOptionsWithGoTemplate(t *testing.T) { } } + if test.openAPIOptions != nil { + if err := reg.RegisterOpenAPIOptions(test.openAPIOptions); err != nil { + t.Fatalf("failed to register OpenAPI options: %s", err) + } + } + refs := make(refMap) actual := make(openapiDefinitionsObject) renderMessagesAsDefinition(msgMap, actual, reg, refs) @@ -2730,7 +3550,7 @@ func TestTemplateWithoutErrorDefinition(t *testing.T) { SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, Name: proto.String("example.proto"), Package: proto.String("example"), - MessageType: []*descriptorpb.DescriptorProto{msgdesc, msgdesc}, + MessageType: []*descriptorpb.DescriptorProto{msgdesc}, Service: []*descriptorpb.ServiceDescriptorProto{svc}, }, GoPkg: descriptor.GoPackage{ @@ -2765,7 +3585,11 @@ func TestTemplateWithoutErrorDefinition(t *testing.T) { }, } reg := descriptor.NewRegistry() - reg.Load(&pluginpb.CodeGeneratorRequest{ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto}}) + err := reg.Load(&pluginpb.CodeGeneratorRequest{ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto}}) + if err != nil { + t.Errorf("failed to reg.Load(): %v", err) + return + } result, err := applyTemplate(param{File: crossLinkFixture(&file), reg: reg}) if err != nil { t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err) diff --git a/gateway/protoc-gen-openapiv2/main.go b/gateway/protoc-gen-openapiv2/main.go index c3f497a..e180b06 100644 --- a/gateway/protoc-gen-openapiv2/main.go +++ b/gateway/protoc-gen-openapiv2/main.go @@ -7,13 +7,14 @@ import ( "strings" "github.com/golang/glog" - pluginpb "github.com/golang/protobuf/protoc-gen-go/plugin" "github.com/grpc-ecosystem/grpc-gateway/v2/internal/codegenerator" + // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor" "github.com/binchencoder/ease-gateway/gateway/internal/descriptor" // genopenapi "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/internal/genopenapi" genopenapi "github.com/binchencoder/ease-gateway/gateway/protoc-gen-openapiv2/internal/genopenapi" "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/pluginpb" ) var ( @@ -33,6 +34,8 @@ var ( disableDefaultErrors = flag.Bool("disable_default_errors", false, "if set, disables generation of default errors. This is useful if you have defined custom error handling") enumsAsInts = flag.Bool("enums_as_ints", false, "whether to render enum values as integers, as opposed to string values") simpleOperationIDs = flag.Bool("simple_operation_ids", false, "whether to remove the service prefix in the operationID generation. Can introduce duplicate operationIDs, use with caution.") + openAPIConfiguration = flag.String("openapi_configuration", "", "path to OpenAPI Configuration in YAML format") + generateUnboundMethods = flag.Bool("generate_unbound_methods", false, "generate swagger metadata even for RPC methods that have no HttpRule annotation") ) // Variables set by goreleaser at build time @@ -88,6 +91,7 @@ func main() { reg.SetEnumsAsInts(*enumsAsInts) reg.SetDisableDefaultErrors(*disableDefaultErrors) reg.SetSimpleOperationIDs(*simpleOperationIDs) + reg.SetGenerateUnboundMethods(*generateUnboundMethods) if err := reg.SetRepeatedPathParamSeparator(*repeatedPathParamSeparator); err != nil { emitError(err) return @@ -115,6 +119,13 @@ func main() { return } + if *openAPIConfiguration != "" { + if err := reg.LoadOpenAPIConfigFromYAML(*openAPIConfiguration); err != nil { + emitError(err) + return + } + } + var targets []*descriptor.File for _, target := range req.FileToGenerate { f, err := reg.LookupFile(target) @@ -133,8 +144,12 @@ func main() { emitFiles(out) } -func emitFiles(out []*pluginpb.CodeGeneratorResponse_File) { - emitResp(&pluginpb.CodeGeneratorResponse{File: out}) +func emitFiles(out []*descriptor.ResponseFile) { + files := make([]*pluginpb.CodeGeneratorResponse_File, len(out)) + for idx, item := range out { + files[idx] = item.CodeGeneratorResponse_File + } + emitResp(&pluginpb.CodeGeneratorResponse{File: files}) } func emitError(err error) { diff --git a/gateway/protoc-gen-openapiv2/options/BUILD.bazel b/gateway/protoc-gen-openapiv2/options/BUILD.bazel index 4d22229..21e9273 100644 --- a/gateway/protoc-gen-openapiv2/options/BUILD.bazel +++ b/gateway/protoc-gen-openapiv2/options/BUILD.bazel @@ -25,7 +25,6 @@ proto_library( "openapiv2.proto", ], deps = [ - "@com_google_protobuf//:any_proto", "@com_google_protobuf//:descriptor_proto", "@com_google_protobuf//:struct_proto", ], diff --git a/gateway/protoc-gen-openapiv2/options/annotations.pb.go b/gateway/protoc-gen-openapiv2/options/annotations.pb.go new file mode 100644 index 0000000..b8af0e1 --- /dev/null +++ b/gateway/protoc-gen-openapiv2/options/annotations.pb.go @@ -0,0 +1,242 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.23.0 +// protoc v3.12.3 +// source: gateway/protoc-gen-openapiv2/options/annotations.proto + +package options + +import ( + proto "github.com/golang/protobuf/proto" + descriptor "github.com/golang/protobuf/protoc-gen-go/descriptor" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// This is a compile-time assertion that a sufficiently up-to-date version +// of the legacy proto package is being used. +const _ = proto.ProtoPackageIsVersion4 + +var file_gateway_protoc_gen_openapiv2_options_annotations_proto_extTypes = []protoimpl.ExtensionInfo{ + { + ExtendedType: (*descriptor.FileOptions)(nil), + ExtensionType: (*Swagger)(nil), + Field: 1042, + Name: "grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger", + Tag: "bytes,1042,opt,name=openapiv2_swagger", + Filename: "gateway/protoc-gen-openapiv2/options/annotations.proto", + }, + { + ExtendedType: (*descriptor.MethodOptions)(nil), + ExtensionType: (*Operation)(nil), + Field: 1042, + Name: "grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation", + Tag: "bytes,1042,opt,name=openapiv2_operation", + Filename: "gateway/protoc-gen-openapiv2/options/annotations.proto", + }, + { + ExtendedType: (*descriptor.MessageOptions)(nil), + ExtensionType: (*Schema)(nil), + Field: 1042, + Name: "grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema", + Tag: "bytes,1042,opt,name=openapiv2_schema", + Filename: "gateway/protoc-gen-openapiv2/options/annotations.proto", + }, + { + ExtendedType: (*descriptor.ServiceOptions)(nil), + ExtensionType: (*Tag)(nil), + Field: 1042, + Name: "grpc.gateway.protoc_gen_openapiv2.options.openapiv2_tag", + Tag: "bytes,1042,opt,name=openapiv2_tag", + Filename: "gateway/protoc-gen-openapiv2/options/annotations.proto", + }, + { + ExtendedType: (*descriptor.FieldOptions)(nil), + ExtensionType: (*JSONSchema)(nil), + Field: 1042, + Name: "grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field", + Tag: "bytes,1042,opt,name=openapiv2_field", + Filename: "gateway/protoc-gen-openapiv2/options/annotations.proto", + }, +} + +// Extension fields to descriptor.FileOptions. +var ( + // ID assigned by protobuf-global-extension-registry@google.com for grpc-gateway project. + // + // All IDs are the same, as assigned. It is okay that they are the same, as they extend + // different descriptor messages. + // + // optional grpc.gateway.protoc_gen_openapiv2.options.Swagger openapiv2_swagger = 1042; + E_Openapiv2Swagger = &file_gateway_protoc_gen_openapiv2_options_annotations_proto_extTypes[0] +) + +// Extension fields to descriptor.MethodOptions. +var ( + // ID assigned by protobuf-global-extension-registry@google.com for grpc-gateway project. + // + // All IDs are the same, as assigned. It is okay that they are the same, as they extend + // different descriptor messages. + // + // optional grpc.gateway.protoc_gen_openapiv2.options.Operation openapiv2_operation = 1042; + E_Openapiv2Operation = &file_gateway_protoc_gen_openapiv2_options_annotations_proto_extTypes[1] +) + +// Extension fields to descriptor.MessageOptions. +var ( + // ID assigned by protobuf-global-extension-registry@google.com for grpc-gateway project. + // + // All IDs are the same, as assigned. It is okay that they are the same, as they extend + // different descriptor messages. + // + // optional grpc.gateway.protoc_gen_openapiv2.options.Schema openapiv2_schema = 1042; + E_Openapiv2Schema = &file_gateway_protoc_gen_openapiv2_options_annotations_proto_extTypes[2] +) + +// Extension fields to descriptor.ServiceOptions. +var ( + // ID assigned by protobuf-global-extension-registry@google.com for grpc-gateway project. + // + // All IDs are the same, as assigned. It is okay that they are the same, as they extend + // different descriptor messages. + // + // optional grpc.gateway.protoc_gen_openapiv2.options.Tag openapiv2_tag = 1042; + E_Openapiv2Tag = &file_gateway_protoc_gen_openapiv2_options_annotations_proto_extTypes[3] +) + +// Extension fields to descriptor.FieldOptions. +var ( + // ID assigned by protobuf-global-extension-registry@google.com for grpc-gateway project. + // + // All IDs are the same, as assigned. It is okay that they are the same, as they extend + // different descriptor messages. + // + // optional grpc.gateway.protoc_gen_openapiv2.options.JSONSchema openapiv2_field = 1042; + E_Openapiv2Field = &file_gateway_protoc_gen_openapiv2_options_annotations_proto_extTypes[4] +) + +var File_gateway_protoc_gen_openapiv2_options_annotations_proto protoreflect.FileDescriptor + +var file_gateway_protoc_gen_openapiv2_options_annotations_proto_rawDesc = []byte{ + 0x0a, 0x36, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, + 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2f, 0x6f, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x29, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, + 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, + 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x1a, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x34, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2f, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, + 0x69, 0x76, 0x32, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x6f, 0x70, 0x65, 0x6e, + 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x3a, 0x7e, 0x0a, 0x11, 0x6f, + 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x5f, 0x73, 0x77, 0x61, 0x67, 0x67, 0x65, 0x72, + 0x12, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x92, + 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, + 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, + 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x2e, 0x53, 0x77, 0x61, 0x67, 0x67, 0x65, 0x72, 0x52, 0x10, 0x6f, 0x70, 0x65, 0x6e, 0x61, + 0x70, 0x69, 0x76, 0x32, 0x53, 0x77, 0x61, 0x67, 0x67, 0x65, 0x72, 0x3a, 0x86, 0x01, 0x0a, 0x13, + 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x5f, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x4f, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x18, 0x92, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x67, 0x72, 0x70, + 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, + 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x12, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x4f, 0x70, 0x65, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x7e, 0x0a, 0x10, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, + 0x32, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x1f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x92, 0x08, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x31, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, + 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x63, 0x68, + 0x65, 0x6d, 0x61, 0x52, 0x0f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x53, 0x63, + 0x68, 0x65, 0x6d, 0x61, 0x3a, 0x75, 0x0a, 0x0d, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, + 0x32, 0x5f, 0x74, 0x61, 0x67, 0x12, 0x1f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4f, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x92, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, + 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, + 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x54, 0x61, 0x67, 0x52, 0x0c, 0x6f, + 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x54, 0x61, 0x67, 0x3a, 0x7e, 0x0a, 0x0f, 0x6f, + 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x1d, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x92, 0x08, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, + 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, + 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x2e, 0x4a, 0x53, 0x4f, 0x4e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x0e, 0x6f, 0x70, 0x65, + 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x42, 0x4b, 0x5a, 0x49, 0x67, + 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x69, 0x6e, 0x63, 0x68, 0x65, + 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x65, 0x61, 0x73, 0x65, 0x2d, 0x67, 0x61, 0x74, 0x65, + 0x77, 0x61, 0x79, 0x2f, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2f, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, + 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var file_gateway_protoc_gen_openapiv2_options_annotations_proto_goTypes = []interface{}{ + (*descriptor.FileOptions)(nil), // 0: google.protobuf.FileOptions + (*descriptor.MethodOptions)(nil), // 1: google.protobuf.MethodOptions + (*descriptor.MessageOptions)(nil), // 2: google.protobuf.MessageOptions + (*descriptor.ServiceOptions)(nil), // 3: google.protobuf.ServiceOptions + (*descriptor.FieldOptions)(nil), // 4: google.protobuf.FieldOptions + (*Swagger)(nil), // 5: grpc.gateway.protoc_gen_openapiv2.options.Swagger + (*Operation)(nil), // 6: grpc.gateway.protoc_gen_openapiv2.options.Operation + (*Schema)(nil), // 7: grpc.gateway.protoc_gen_openapiv2.options.Schema + (*Tag)(nil), // 8: grpc.gateway.protoc_gen_openapiv2.options.Tag + (*JSONSchema)(nil), // 9: grpc.gateway.protoc_gen_openapiv2.options.JSONSchema +} +var file_gateway_protoc_gen_openapiv2_options_annotations_proto_depIdxs = []int32{ + 0, // 0: grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger:extendee -> google.protobuf.FileOptions + 1, // 1: grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation:extendee -> google.protobuf.MethodOptions + 2, // 2: grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema:extendee -> google.protobuf.MessageOptions + 3, // 3: grpc.gateway.protoc_gen_openapiv2.options.openapiv2_tag:extendee -> google.protobuf.ServiceOptions + 4, // 4: grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field:extendee -> google.protobuf.FieldOptions + 5, // 5: grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Swagger + 6, // 6: grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Operation + 7, // 7: grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Schema + 8, // 8: grpc.gateway.protoc_gen_openapiv2.options.openapiv2_tag:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Tag + 9, // 9: grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field:type_name -> grpc.gateway.protoc_gen_openapiv2.options.JSONSchema + 10, // [10:10] is the sub-list for method output_type + 10, // [10:10] is the sub-list for method input_type + 5, // [5:10] is the sub-list for extension type_name + 0, // [0:5] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_gateway_protoc_gen_openapiv2_options_annotations_proto_init() } +func file_gateway_protoc_gen_openapiv2_options_annotations_proto_init() { + if File_gateway_protoc_gen_openapiv2_options_annotations_proto != nil { + return + } + file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_init() + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_gateway_protoc_gen_openapiv2_options_annotations_proto_rawDesc, + NumEnums: 0, + NumMessages: 0, + NumExtensions: 5, + NumServices: 0, + }, + GoTypes: file_gateway_protoc_gen_openapiv2_options_annotations_proto_goTypes, + DependencyIndexes: file_gateway_protoc_gen_openapiv2_options_annotations_proto_depIdxs, + ExtensionInfos: file_gateway_protoc_gen_openapiv2_options_annotations_proto_extTypes, + }.Build() + File_gateway_protoc_gen_openapiv2_options_annotations_proto = out.File + file_gateway_protoc_gen_openapiv2_options_annotations_proto_rawDesc = nil + file_gateway_protoc_gen_openapiv2_options_annotations_proto_goTypes = nil + file_gateway_protoc_gen_openapiv2_options_annotations_proto_depIdxs = nil +} diff --git a/gateway/protoc-gen-openapiv2/options/openapiv2.pb.go b/gateway/protoc-gen-openapiv2/options/openapiv2.pb.go new file mode 100644 index 0000000..b8e1322 --- /dev/null +++ b/gateway/protoc-gen-openapiv2/options/openapiv2.pb.go @@ -0,0 +1,2615 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.23.0 +// protoc v3.12.3 +// source: gateway/protoc-gen-openapiv2/options/openapiv2.proto + +package options + +import ( + proto "github.com/golang/protobuf/proto" + _struct "github.com/golang/protobuf/ptypes/struct" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// This is a compile-time assertion that a sufficiently up-to-date version +// of the legacy proto package is being used. +const _ = proto.ProtoPackageIsVersion4 + +// Scheme describes the schemes supported by the OpenAPI Swagger +// and Operation objects. +type Scheme int32 + +const ( + Scheme_UNKNOWN Scheme = 0 + Scheme_HTTP Scheme = 1 + Scheme_HTTPS Scheme = 2 + Scheme_WS Scheme = 3 + Scheme_WSS Scheme = 4 +) + +// Enum value maps for Scheme. +var ( + Scheme_name = map[int32]string{ + 0: "UNKNOWN", + 1: "HTTP", + 2: "HTTPS", + 3: "WS", + 4: "WSS", + } + Scheme_value = map[string]int32{ + "UNKNOWN": 0, + "HTTP": 1, + "HTTPS": 2, + "WS": 3, + "WSS": 4, + } +) + +func (x Scheme) Enum() *Scheme { + p := new(Scheme) + *p = x + return p +} + +func (x Scheme) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (Scheme) Descriptor() protoreflect.EnumDescriptor { + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_enumTypes[0].Descriptor() +} + +func (Scheme) Type() protoreflect.EnumType { + return &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_enumTypes[0] +} + +func (x Scheme) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use Scheme.Descriptor instead. +func (Scheme) EnumDescriptor() ([]byte, []int) { + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{0} +} + +type JSONSchema_JSONSchemaSimpleTypes int32 + +const ( + JSONSchema_UNKNOWN JSONSchema_JSONSchemaSimpleTypes = 0 + JSONSchema_ARRAY JSONSchema_JSONSchemaSimpleTypes = 1 + JSONSchema_BOOLEAN JSONSchema_JSONSchemaSimpleTypes = 2 + JSONSchema_INTEGER JSONSchema_JSONSchemaSimpleTypes = 3 + JSONSchema_NULL JSONSchema_JSONSchemaSimpleTypes = 4 + JSONSchema_NUMBER JSONSchema_JSONSchemaSimpleTypes = 5 + JSONSchema_OBJECT JSONSchema_JSONSchemaSimpleTypes = 6 + JSONSchema_STRING JSONSchema_JSONSchemaSimpleTypes = 7 +) + +// Enum value maps for JSONSchema_JSONSchemaSimpleTypes. +var ( + JSONSchema_JSONSchemaSimpleTypes_name = map[int32]string{ + 0: "UNKNOWN", + 1: "ARRAY", + 2: "BOOLEAN", + 3: "INTEGER", + 4: "NULL", + 5: "NUMBER", + 6: "OBJECT", + 7: "STRING", + } + JSONSchema_JSONSchemaSimpleTypes_value = map[string]int32{ + "UNKNOWN": 0, + "ARRAY": 1, + "BOOLEAN": 2, + "INTEGER": 3, + "NULL": 4, + "NUMBER": 5, + "OBJECT": 6, + "STRING": 7, + } +) + +func (x JSONSchema_JSONSchemaSimpleTypes) Enum() *JSONSchema_JSONSchemaSimpleTypes { + p := new(JSONSchema_JSONSchemaSimpleTypes) + *p = x + return p +} + +func (x JSONSchema_JSONSchemaSimpleTypes) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (JSONSchema_JSONSchemaSimpleTypes) Descriptor() protoreflect.EnumDescriptor { + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_enumTypes[1].Descriptor() +} + +func (JSONSchema_JSONSchemaSimpleTypes) Type() protoreflect.EnumType { + return &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_enumTypes[1] +} + +func (x JSONSchema_JSONSchemaSimpleTypes) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use JSONSchema_JSONSchemaSimpleTypes.Descriptor instead. +func (JSONSchema_JSONSchemaSimpleTypes) EnumDescriptor() ([]byte, []int) { + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{8, 0} +} + +// The type of the security scheme. Valid values are "basic", +// "apiKey" or "oauth2". +type SecurityScheme_Type int32 + +const ( + SecurityScheme_TYPE_INVALID SecurityScheme_Type = 0 + SecurityScheme_TYPE_BASIC SecurityScheme_Type = 1 + SecurityScheme_TYPE_API_KEY SecurityScheme_Type = 2 + SecurityScheme_TYPE_OAUTH2 SecurityScheme_Type = 3 +) + +// Enum value maps for SecurityScheme_Type. +var ( + SecurityScheme_Type_name = map[int32]string{ + 0: "TYPE_INVALID", + 1: "TYPE_BASIC", + 2: "TYPE_API_KEY", + 3: "TYPE_OAUTH2", + } + SecurityScheme_Type_value = map[string]int32{ + "TYPE_INVALID": 0, + "TYPE_BASIC": 1, + "TYPE_API_KEY": 2, + "TYPE_OAUTH2": 3, + } +) + +func (x SecurityScheme_Type) Enum() *SecurityScheme_Type { + p := new(SecurityScheme_Type) + *p = x + return p +} + +func (x SecurityScheme_Type) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (SecurityScheme_Type) Descriptor() protoreflect.EnumDescriptor { + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_enumTypes[2].Descriptor() +} + +func (SecurityScheme_Type) Type() protoreflect.EnumType { + return &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_enumTypes[2] +} + +func (x SecurityScheme_Type) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use SecurityScheme_Type.Descriptor instead. +func (SecurityScheme_Type) EnumDescriptor() ([]byte, []int) { + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{11, 0} +} + +// The location of the API key. Valid values are "query" or "header". +type SecurityScheme_In int32 + +const ( + SecurityScheme_IN_INVALID SecurityScheme_In = 0 + SecurityScheme_IN_QUERY SecurityScheme_In = 1 + SecurityScheme_IN_HEADER SecurityScheme_In = 2 +) + +// Enum value maps for SecurityScheme_In. +var ( + SecurityScheme_In_name = map[int32]string{ + 0: "IN_INVALID", + 1: "IN_QUERY", + 2: "IN_HEADER", + } + SecurityScheme_In_value = map[string]int32{ + "IN_INVALID": 0, + "IN_QUERY": 1, + "IN_HEADER": 2, + } +) + +func (x SecurityScheme_In) Enum() *SecurityScheme_In { + p := new(SecurityScheme_In) + *p = x + return p +} + +func (x SecurityScheme_In) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (SecurityScheme_In) Descriptor() protoreflect.EnumDescriptor { + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_enumTypes[3].Descriptor() +} + +func (SecurityScheme_In) Type() protoreflect.EnumType { + return &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_enumTypes[3] +} + +func (x SecurityScheme_In) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use SecurityScheme_In.Descriptor instead. +func (SecurityScheme_In) EnumDescriptor() ([]byte, []int) { + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{11, 1} +} + +// The flow used by the OAuth2 security scheme. Valid values are +// "implicit", "password", "application" or "accessCode". +type SecurityScheme_Flow int32 + +const ( + SecurityScheme_FLOW_INVALID SecurityScheme_Flow = 0 + SecurityScheme_FLOW_IMPLICIT SecurityScheme_Flow = 1 + SecurityScheme_FLOW_PASSWORD SecurityScheme_Flow = 2 + SecurityScheme_FLOW_APPLICATION SecurityScheme_Flow = 3 + SecurityScheme_FLOW_ACCESS_CODE SecurityScheme_Flow = 4 +) + +// Enum value maps for SecurityScheme_Flow. +var ( + SecurityScheme_Flow_name = map[int32]string{ + 0: "FLOW_INVALID", + 1: "FLOW_IMPLICIT", + 2: "FLOW_PASSWORD", + 3: "FLOW_APPLICATION", + 4: "FLOW_ACCESS_CODE", + } + SecurityScheme_Flow_value = map[string]int32{ + "FLOW_INVALID": 0, + "FLOW_IMPLICIT": 1, + "FLOW_PASSWORD": 2, + "FLOW_APPLICATION": 3, + "FLOW_ACCESS_CODE": 4, + } +) + +func (x SecurityScheme_Flow) Enum() *SecurityScheme_Flow { + p := new(SecurityScheme_Flow) + *p = x + return p +} + +func (x SecurityScheme_Flow) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (SecurityScheme_Flow) Descriptor() protoreflect.EnumDescriptor { + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_enumTypes[4].Descriptor() +} + +func (SecurityScheme_Flow) Type() protoreflect.EnumType { + return &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_enumTypes[4] +} + +func (x SecurityScheme_Flow) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use SecurityScheme_Flow.Descriptor instead. +func (SecurityScheme_Flow) EnumDescriptor() ([]byte, []int) { + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{11, 2} +} + +// `Swagger` is a representation of OpenAPI v2 specification's Swagger object. +// +// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#swaggerObject +// +// Example: +// +// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { +// info: { +// title: "Echo API"; +// version: "1.0"; +// description: "; +// contact: { +// name: "gRPC-Gateway project"; +// url: "https://github.com/grpc-ecosystem/grpc-gateway"; +// email: "none@example.com"; +// }; +// license: { +// name: "BSD 3-Clause License"; +// url: "https://github.com/grpc-ecosystem/grpc-gateway/blob/master/LICENSE.txt"; +// }; +// }; +// schemes: HTTPS; +// consumes: "application/json"; +// produces: "application/json"; +// }; +// +type Swagger struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Specifies the OpenAPI Specification version being used. It can be + // used by the OpenAPI UI and other clients to interpret the API listing. The + // value MUST be "2.0". + Swagger string `protobuf:"bytes,1,opt,name=swagger,proto3" json:"swagger,omitempty"` + // Provides metadata about the API. The metadata can be used by the + // clients if needed. + Info *Info `protobuf:"bytes,2,opt,name=info,proto3" json:"info,omitempty"` + // The host (name or ip) serving the API. This MUST be the host only and does + // not include the scheme nor sub-paths. It MAY include a port. If the host is + // not included, the host serving the documentation is to be used (including + // the port). The host does not support path templating. + Host string `protobuf:"bytes,3,opt,name=host,proto3" json:"host,omitempty"` + // The base path on which the API is served, which is relative to the host. If + // it is not included, the API is served directly under the host. The value + // MUST start with a leading slash (/). The basePath does not support path + // templating. + // Note that using `base_path` does not change the endpoint paths that are + // generated in the resulting OpenAPI file. If you wish to use `base_path` + // with relatively generated OpenAPI paths, the `base_path` prefix must be + // manually removed from your `google.api.http` paths and your code changed to + // serve the API from the `base_path`. + BasePath string `protobuf:"bytes,4,opt,name=base_path,json=basePath,proto3" json:"base_path,omitempty"` + // The transfer protocol of the API. Values MUST be from the list: "http", + // "https", "ws", "wss". If the schemes is not included, the default scheme to + // be used is the one used to access the OpenAPI definition itself. + Schemes []Scheme `protobuf:"varint,5,rep,packed,name=schemes,proto3,enum=grpc.gateway.protoc_gen_openapiv2.options.Scheme" json:"schemes,omitempty"` + // A list of MIME types the APIs can consume. This is global to all APIs but + // can be overridden on specific API calls. Value MUST be as described under + // Mime Types. + Consumes []string `protobuf:"bytes,6,rep,name=consumes,proto3" json:"consumes,omitempty"` + // A list of MIME types the APIs can produce. This is global to all APIs but + // can be overridden on specific API calls. Value MUST be as described under + // Mime Types. + Produces []string `protobuf:"bytes,7,rep,name=produces,proto3" json:"produces,omitempty"` + // An object to hold responses that can be used across operations. This + // property does not define global responses for all operations. + Responses map[string]*Response `protobuf:"bytes,10,rep,name=responses,proto3" json:"responses,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + // Security scheme definitions that can be used across the specification. + SecurityDefinitions *SecurityDefinitions `protobuf:"bytes,11,opt,name=security_definitions,json=securityDefinitions,proto3" json:"security_definitions,omitempty"` + // A declaration of which security schemes are applied for the API as a whole. + // The list of values describes alternative security schemes that can be used + // (that is, there is a logical OR between the security requirements). + // Individual operations can override this definition. + Security []*SecurityRequirement `protobuf:"bytes,12,rep,name=security,proto3" json:"security,omitempty"` + // Additional external documentation. + ExternalDocs *ExternalDocumentation `protobuf:"bytes,14,opt,name=external_docs,json=externalDocs,proto3" json:"external_docs,omitempty"` + Extensions map[string]*_struct.Value `protobuf:"bytes,15,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *Swagger) Reset() { + *x = Swagger{} + if protoimpl.UnsafeEnabled { + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Swagger) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Swagger) ProtoMessage() {} + +func (x *Swagger) ProtoReflect() protoreflect.Message { + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Swagger.ProtoReflect.Descriptor instead. +func (*Swagger) Descriptor() ([]byte, []int) { + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{0} +} + +func (x *Swagger) GetSwagger() string { + if x != nil { + return x.Swagger + } + return "" +} + +func (x *Swagger) GetInfo() *Info { + if x != nil { + return x.Info + } + return nil +} + +func (x *Swagger) GetHost() string { + if x != nil { + return x.Host + } + return "" +} + +func (x *Swagger) GetBasePath() string { + if x != nil { + return x.BasePath + } + return "" +} + +func (x *Swagger) GetSchemes() []Scheme { + if x != nil { + return x.Schemes + } + return nil +} + +func (x *Swagger) GetConsumes() []string { + if x != nil { + return x.Consumes + } + return nil +} + +func (x *Swagger) GetProduces() []string { + if x != nil { + return x.Produces + } + return nil +} + +func (x *Swagger) GetResponses() map[string]*Response { + if x != nil { + return x.Responses + } + return nil +} + +func (x *Swagger) GetSecurityDefinitions() *SecurityDefinitions { + if x != nil { + return x.SecurityDefinitions + } + return nil +} + +func (x *Swagger) GetSecurity() []*SecurityRequirement { + if x != nil { + return x.Security + } + return nil +} + +func (x *Swagger) GetExternalDocs() *ExternalDocumentation { + if x != nil { + return x.ExternalDocs + } + return nil +} + +func (x *Swagger) GetExtensions() map[string]*_struct.Value { + if x != nil { + return x.Extensions + } + return nil +} + +// `Operation` is a representation of OpenAPI v2 specification's Operation object. +// +// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#operationObject +// +// Example: +// +// service EchoService { +// rpc Echo(SimpleMessage) returns (SimpleMessage) { +// option (google.api.http) = { +// get: "/v1/example/echo/{id}" +// }; +// +// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { +// summary: "Get a message."; +// operation_id: "getMessage"; +// tags: "echo"; +// responses: { +// key: "200" +// value: { +// description: "OK"; +// } +// } +// }; +// } +// } +type Operation struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // A list of tags for API documentation control. Tags can be used for logical + // grouping of operations by resources or any other qualifier. + Tags []string `protobuf:"bytes,1,rep,name=tags,proto3" json:"tags,omitempty"` + // A short summary of what the operation does. For maximum readability in the + // swagger-ui, this field SHOULD be less than 120 characters. + Summary string `protobuf:"bytes,2,opt,name=summary,proto3" json:"summary,omitempty"` + // A verbose explanation of the operation behavior. GFM syntax can be used for + // rich text representation. + Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"` + // Additional external documentation for this operation. + ExternalDocs *ExternalDocumentation `protobuf:"bytes,4,opt,name=external_docs,json=externalDocs,proto3" json:"external_docs,omitempty"` + // Unique string used to identify the operation. The id MUST be unique among + // all operations described in the API. Tools and libraries MAY use the + // operationId to uniquely identify an operation, therefore, it is recommended + // to follow common programming naming conventions. + OperationId string `protobuf:"bytes,5,opt,name=operation_id,json=operationId,proto3" json:"operation_id,omitempty"` + // A list of MIME types the operation can consume. This overrides the consumes + // definition at the OpenAPI Object. An empty value MAY be used to clear the + // global definition. Value MUST be as described under Mime Types. + Consumes []string `protobuf:"bytes,6,rep,name=consumes,proto3" json:"consumes,omitempty"` + // A list of MIME types the operation can produce. This overrides the produces + // definition at the OpenAPI Object. An empty value MAY be used to clear the + // global definition. Value MUST be as described under Mime Types. + Produces []string `protobuf:"bytes,7,rep,name=produces,proto3" json:"produces,omitempty"` + // The list of possible responses as they are returned from executing this + // operation. + Responses map[string]*Response `protobuf:"bytes,9,rep,name=responses,proto3" json:"responses,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + // The transfer protocol for the operation. Values MUST be from the list: + // "http", "https", "ws", "wss". The value overrides the OpenAPI Object + // schemes definition. + Schemes []Scheme `protobuf:"varint,10,rep,packed,name=schemes,proto3,enum=grpc.gateway.protoc_gen_openapiv2.options.Scheme" json:"schemes,omitempty"` + // Declares this operation to be deprecated. Usage of the declared operation + // should be refrained. Default value is false. + Deprecated bool `protobuf:"varint,11,opt,name=deprecated,proto3" json:"deprecated,omitempty"` + // A declaration of which security schemes are applied for this operation. The + // list of values describes alternative security schemes that can be used + // (that is, there is a logical OR between the security requirements). This + // definition overrides any declared top-level security. To remove a top-level + // security declaration, an empty array can be used. + Security []*SecurityRequirement `protobuf:"bytes,12,rep,name=security,proto3" json:"security,omitempty"` + Extensions map[string]*_struct.Value `protobuf:"bytes,13,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *Operation) Reset() { + *x = Operation{} + if protoimpl.UnsafeEnabled { + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Operation) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Operation) ProtoMessage() {} + +func (x *Operation) ProtoReflect() protoreflect.Message { + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Operation.ProtoReflect.Descriptor instead. +func (*Operation) Descriptor() ([]byte, []int) { + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{1} +} + +func (x *Operation) GetTags() []string { + if x != nil { + return x.Tags + } + return nil +} + +func (x *Operation) GetSummary() string { + if x != nil { + return x.Summary + } + return "" +} + +func (x *Operation) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *Operation) GetExternalDocs() *ExternalDocumentation { + if x != nil { + return x.ExternalDocs + } + return nil +} + +func (x *Operation) GetOperationId() string { + if x != nil { + return x.OperationId + } + return "" +} + +func (x *Operation) GetConsumes() []string { + if x != nil { + return x.Consumes + } + return nil +} + +func (x *Operation) GetProduces() []string { + if x != nil { + return x.Produces + } + return nil +} + +func (x *Operation) GetResponses() map[string]*Response { + if x != nil { + return x.Responses + } + return nil +} + +func (x *Operation) GetSchemes() []Scheme { + if x != nil { + return x.Schemes + } + return nil +} + +func (x *Operation) GetDeprecated() bool { + if x != nil { + return x.Deprecated + } + return false +} + +func (x *Operation) GetSecurity() []*SecurityRequirement { + if x != nil { + return x.Security + } + return nil +} + +func (x *Operation) GetExtensions() map[string]*_struct.Value { + if x != nil { + return x.Extensions + } + return nil +} + +// `Response` is a representation of OpenAPI v2 specification's Response object. +// +// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#responseObject +// +type Response struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // `Description` is a short description of the response. + // GFM syntax can be used for rich text representation. + Description string `protobuf:"bytes,1,opt,name=description,proto3" json:"description,omitempty"` + // `Schema` optionally defines the structure of the response. + // If `Schema` is not provided, it means there is no content to the response. + Schema *Schema `protobuf:"bytes,2,opt,name=schema,proto3" json:"schema,omitempty"` + // `Examples` gives per-mimetype response examples. + // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#example-object + Examples map[string]string `protobuf:"bytes,4,rep,name=examples,proto3" json:"examples,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Extensions map[string]*_struct.Value `protobuf:"bytes,5,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *Response) Reset() { + *x = Response{} + if protoimpl.UnsafeEnabled { + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Response) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Response) ProtoMessage() {} + +func (x *Response) ProtoReflect() protoreflect.Message { + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Response.ProtoReflect.Descriptor instead. +func (*Response) Descriptor() ([]byte, []int) { + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{2} +} + +func (x *Response) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *Response) GetSchema() *Schema { + if x != nil { + return x.Schema + } + return nil +} + +func (x *Response) GetExamples() map[string]string { + if x != nil { + return x.Examples + } + return nil +} + +func (x *Response) GetExtensions() map[string]*_struct.Value { + if x != nil { + return x.Extensions + } + return nil +} + +// `Info` is a representation of OpenAPI v2 specification's Info object. +// +// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#infoObject +// +// Example: +// +// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { +// info: { +// title: "Echo API"; +// version: "1.0"; +// description: "; +// contact: { +// name: "gRPC-Gateway project"; +// url: "https://github.com/grpc-ecosystem/grpc-gateway"; +// email: "none@example.com"; +// }; +// license: { +// name: "BSD 3-Clause License"; +// url: "https://github.com/grpc-ecosystem/grpc-gateway/blob/master/LICENSE.txt"; +// }; +// }; +// ... +// }; +// +type Info struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The title of the application. + Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` + // A short description of the application. GFM syntax can be used for rich + // text representation. + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` + // The Terms of Service for the API. + TermsOfService string `protobuf:"bytes,3,opt,name=terms_of_service,json=termsOfService,proto3" json:"terms_of_service,omitempty"` + // The contact information for the exposed API. + Contact *Contact `protobuf:"bytes,4,opt,name=contact,proto3" json:"contact,omitempty"` + // The license information for the exposed API. + License *License `protobuf:"bytes,5,opt,name=license,proto3" json:"license,omitempty"` + // Provides the version of the application API (not to be confused + // with the specification version). + Version string `protobuf:"bytes,6,opt,name=version,proto3" json:"version,omitempty"` + Extensions map[string]*_struct.Value `protobuf:"bytes,7,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *Info) Reset() { + *x = Info{} + if protoimpl.UnsafeEnabled { + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Info) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Info) ProtoMessage() {} + +func (x *Info) ProtoReflect() protoreflect.Message { + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Info.ProtoReflect.Descriptor instead. +func (*Info) Descriptor() ([]byte, []int) { + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{3} +} + +func (x *Info) GetTitle() string { + if x != nil { + return x.Title + } + return "" +} + +func (x *Info) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *Info) GetTermsOfService() string { + if x != nil { + return x.TermsOfService + } + return "" +} + +func (x *Info) GetContact() *Contact { + if x != nil { + return x.Contact + } + return nil +} + +func (x *Info) GetLicense() *License { + if x != nil { + return x.License + } + return nil +} + +func (x *Info) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + +func (x *Info) GetExtensions() map[string]*_struct.Value { + if x != nil { + return x.Extensions + } + return nil +} + +// `Contact` is a representation of OpenAPI v2 specification's Contact object. +// +// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#contactObject +// +// Example: +// +// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { +// info: { +// ... +// contact: { +// name: "gRPC-Gateway project"; +// url: "https://github.com/grpc-ecosystem/grpc-gateway"; +// email: "none@example.com"; +// }; +// ... +// }; +// ... +// }; +// +type Contact struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The identifying name of the contact person/organization. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // The URL pointing to the contact information. MUST be in the format of a + // URL. + Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"` + // The email address of the contact person/organization. MUST be in the format + // of an email address. + Email string `protobuf:"bytes,3,opt,name=email,proto3" json:"email,omitempty"` +} + +func (x *Contact) Reset() { + *x = Contact{} + if protoimpl.UnsafeEnabled { + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Contact) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Contact) ProtoMessage() {} + +func (x *Contact) ProtoReflect() protoreflect.Message { + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Contact.ProtoReflect.Descriptor instead. +func (*Contact) Descriptor() ([]byte, []int) { + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{4} +} + +func (x *Contact) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *Contact) GetUrl() string { + if x != nil { + return x.Url + } + return "" +} + +func (x *Contact) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + +// `License` is a representation of OpenAPI v2 specification's License object. +// +// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#licenseObject +// +// Example: +// +// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { +// info: { +// ... +// license: { +// name: "BSD 3-Clause License"; +// url: "https://github.com/grpc-ecosystem/grpc-gateway/blob/master/LICENSE.txt"; +// }; +// ... +// }; +// ... +// }; +// +type License struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The license name used for the API. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // A URL to the license used for the API. MUST be in the format of a URL. + Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"` +} + +func (x *License) Reset() { + *x = License{} + if protoimpl.UnsafeEnabled { + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *License) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*License) ProtoMessage() {} + +func (x *License) ProtoReflect() protoreflect.Message { + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use License.ProtoReflect.Descriptor instead. +func (*License) Descriptor() ([]byte, []int) { + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{5} +} + +func (x *License) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *License) GetUrl() string { + if x != nil { + return x.Url + } + return "" +} + +// `ExternalDocumentation` is a representation of OpenAPI v2 specification's +// ExternalDocumentation object. +// +// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#externalDocumentationObject +// +// Example: +// +// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { +// ... +// external_docs: { +// description: "More about gRPC-Gateway"; +// url: "https://github.com/grpc-ecosystem/grpc-gateway"; +// } +// ... +// }; +// +type ExternalDocumentation struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // A short description of the target documentation. GFM syntax can be used for + // rich text representation. + Description string `protobuf:"bytes,1,opt,name=description,proto3" json:"description,omitempty"` + // The URL for the target documentation. Value MUST be in the format + // of a URL. + Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"` +} + +func (x *ExternalDocumentation) Reset() { + *x = ExternalDocumentation{} + if protoimpl.UnsafeEnabled { + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ExternalDocumentation) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExternalDocumentation) ProtoMessage() {} + +func (x *ExternalDocumentation) ProtoReflect() protoreflect.Message { + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExternalDocumentation.ProtoReflect.Descriptor instead. +func (*ExternalDocumentation) Descriptor() ([]byte, []int) { + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{6} +} + +func (x *ExternalDocumentation) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *ExternalDocumentation) GetUrl() string { + if x != nil { + return x.Url + } + return "" +} + +// `Schema` is a representation of OpenAPI v2 specification's Schema object. +// +// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#schemaObject +// +type Schema struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + JsonSchema *JSONSchema `protobuf:"bytes,1,opt,name=json_schema,json=jsonSchema,proto3" json:"json_schema,omitempty"` + // Adds support for polymorphism. The discriminator is the schema property + // name that is used to differentiate between other schema that inherit this + // schema. The property name used MUST be defined at this schema and it MUST + // be in the required property list. When used, the value MUST be the name of + // this schema or any schema that inherits it. + Discriminator string `protobuf:"bytes,2,opt,name=discriminator,proto3" json:"discriminator,omitempty"` + // Relevant only for Schema "properties" definitions. Declares the property as + // "read only". This means that it MAY be sent as part of a response but MUST + // NOT be sent as part of the request. Properties marked as readOnly being + // true SHOULD NOT be in the required list of the defined schema. Default + // value is false. + ReadOnly bool `protobuf:"varint,3,opt,name=read_only,json=readOnly,proto3" json:"read_only,omitempty"` + // Additional external documentation for this schema. + ExternalDocs *ExternalDocumentation `protobuf:"bytes,5,opt,name=external_docs,json=externalDocs,proto3" json:"external_docs,omitempty"` + // A free-form property to include an example of an instance for this schema in JSON. + // This is copied verbatim to the output. + Example string `protobuf:"bytes,6,opt,name=example,proto3" json:"example,omitempty"` +} + +func (x *Schema) Reset() { + *x = Schema{} + if protoimpl.UnsafeEnabled { + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Schema) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Schema) ProtoMessage() {} + +func (x *Schema) ProtoReflect() protoreflect.Message { + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Schema.ProtoReflect.Descriptor instead. +func (*Schema) Descriptor() ([]byte, []int) { + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{7} +} + +func (x *Schema) GetJsonSchema() *JSONSchema { + if x != nil { + return x.JsonSchema + } + return nil +} + +func (x *Schema) GetDiscriminator() string { + if x != nil { + return x.Discriminator + } + return "" +} + +func (x *Schema) GetReadOnly() bool { + if x != nil { + return x.ReadOnly + } + return false +} + +func (x *Schema) GetExternalDocs() *ExternalDocumentation { + if x != nil { + return x.ExternalDocs + } + return nil +} + +func (x *Schema) GetExample() string { + if x != nil { + return x.Example + } + return "" +} + +// `JSONSchema` represents properties from JSON Schema taken, and as used, in +// the OpenAPI v2 spec. +// +// This includes changes made by OpenAPI v2. +// +// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#schemaObject +// +// See also: https://cswr.github.io/JsonSchema/spec/basic_types/, +// https://github.com/json-schema-org/json-schema-spec/blob/master/schema.json +// +// Example: +// +// message SimpleMessage { +// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema) = { +// json_schema: { +// title: "SimpleMessage" +// description: "A simple message." +// required: ["id"] +// } +// }; +// +// // Id represents the message identifier. +// string id = 1; [ +// (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { +// {description: "The unique identifier of the simple message." +// }]; +// } +// +type JSONSchema struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Ref is used to define an external reference to include in the message. + // This could be a fully qualified proto message reference, and that type must + // be imported into the protofile. If no message is identified, the Ref will + // be used verbatim in the output. + // For example: + // `ref: ".google.protobuf.Timestamp"`. + Ref string `protobuf:"bytes,3,opt,name=ref,proto3" json:"ref,omitempty"` + // The title of the schema. + Title string `protobuf:"bytes,5,opt,name=title,proto3" json:"title,omitempty"` + // A short description of the schema. + Description string `protobuf:"bytes,6,opt,name=description,proto3" json:"description,omitempty"` + Default string `protobuf:"bytes,7,opt,name=default,proto3" json:"default,omitempty"` + ReadOnly bool `protobuf:"varint,8,opt,name=read_only,json=readOnly,proto3" json:"read_only,omitempty"` + MultipleOf float64 `protobuf:"fixed64,10,opt,name=multiple_of,json=multipleOf,proto3" json:"multiple_of,omitempty"` + // Maximum represents an inclusive upper limit for a numeric instance. The + // value of MUST be a number, + Maximum float64 `protobuf:"fixed64,11,opt,name=maximum,proto3" json:"maximum,omitempty"` + ExclusiveMaximum bool `protobuf:"varint,12,opt,name=exclusive_maximum,json=exclusiveMaximum,proto3" json:"exclusive_maximum,omitempty"` + // minimum represents an inclusive lower limit for a numeric instance. The + // value of MUST be a number, + Minimum float64 `protobuf:"fixed64,13,opt,name=minimum,proto3" json:"minimum,omitempty"` + ExclusiveMinimum bool `protobuf:"varint,14,opt,name=exclusive_minimum,json=exclusiveMinimum,proto3" json:"exclusive_minimum,omitempty"` + MaxLength uint64 `protobuf:"varint,15,opt,name=max_length,json=maxLength,proto3" json:"max_length,omitempty"` + MinLength uint64 `protobuf:"varint,16,opt,name=min_length,json=minLength,proto3" json:"min_length,omitempty"` + Pattern string `protobuf:"bytes,17,opt,name=pattern,proto3" json:"pattern,omitempty"` + MaxItems uint64 `protobuf:"varint,20,opt,name=max_items,json=maxItems,proto3" json:"max_items,omitempty"` + MinItems uint64 `protobuf:"varint,21,opt,name=min_items,json=minItems,proto3" json:"min_items,omitempty"` + UniqueItems bool `protobuf:"varint,22,opt,name=unique_items,json=uniqueItems,proto3" json:"unique_items,omitempty"` + MaxProperties uint64 `protobuf:"varint,24,opt,name=max_properties,json=maxProperties,proto3" json:"max_properties,omitempty"` + MinProperties uint64 `protobuf:"varint,25,opt,name=min_properties,json=minProperties,proto3" json:"min_properties,omitempty"` + Required []string `protobuf:"bytes,26,rep,name=required,proto3" json:"required,omitempty"` + // Items in 'array' must be unique. + Array []string `protobuf:"bytes,34,rep,name=array,proto3" json:"array,omitempty"` + Type []JSONSchema_JSONSchemaSimpleTypes `protobuf:"varint,35,rep,packed,name=type,proto3,enum=grpc.gateway.protoc_gen_openapiv2.options.JSONSchema_JSONSchemaSimpleTypes" json:"type,omitempty"` +} + +func (x *JSONSchema) Reset() { + *x = JSONSchema{} + if protoimpl.UnsafeEnabled { + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *JSONSchema) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*JSONSchema) ProtoMessage() {} + +func (x *JSONSchema) ProtoReflect() protoreflect.Message { + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use JSONSchema.ProtoReflect.Descriptor instead. +func (*JSONSchema) Descriptor() ([]byte, []int) { + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{8} +} + +func (x *JSONSchema) GetRef() string { + if x != nil { + return x.Ref + } + return "" +} + +func (x *JSONSchema) GetTitle() string { + if x != nil { + return x.Title + } + return "" +} + +func (x *JSONSchema) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *JSONSchema) GetDefault() string { + if x != nil { + return x.Default + } + return "" +} + +func (x *JSONSchema) GetReadOnly() bool { + if x != nil { + return x.ReadOnly + } + return false +} + +func (x *JSONSchema) GetMultipleOf() float64 { + if x != nil { + return x.MultipleOf + } + return 0 +} + +func (x *JSONSchema) GetMaximum() float64 { + if x != nil { + return x.Maximum + } + return 0 +} + +func (x *JSONSchema) GetExclusiveMaximum() bool { + if x != nil { + return x.ExclusiveMaximum + } + return false +} + +func (x *JSONSchema) GetMinimum() float64 { + if x != nil { + return x.Minimum + } + return 0 +} + +func (x *JSONSchema) GetExclusiveMinimum() bool { + if x != nil { + return x.ExclusiveMinimum + } + return false +} + +func (x *JSONSchema) GetMaxLength() uint64 { + if x != nil { + return x.MaxLength + } + return 0 +} + +func (x *JSONSchema) GetMinLength() uint64 { + if x != nil { + return x.MinLength + } + return 0 +} + +func (x *JSONSchema) GetPattern() string { + if x != nil { + return x.Pattern + } + return "" +} + +func (x *JSONSchema) GetMaxItems() uint64 { + if x != nil { + return x.MaxItems + } + return 0 +} + +func (x *JSONSchema) GetMinItems() uint64 { + if x != nil { + return x.MinItems + } + return 0 +} + +func (x *JSONSchema) GetUniqueItems() bool { + if x != nil { + return x.UniqueItems + } + return false +} + +func (x *JSONSchema) GetMaxProperties() uint64 { + if x != nil { + return x.MaxProperties + } + return 0 +} + +func (x *JSONSchema) GetMinProperties() uint64 { + if x != nil { + return x.MinProperties + } + return 0 +} + +func (x *JSONSchema) GetRequired() []string { + if x != nil { + return x.Required + } + return nil +} + +func (x *JSONSchema) GetArray() []string { + if x != nil { + return x.Array + } + return nil +} + +func (x *JSONSchema) GetType() []JSONSchema_JSONSchemaSimpleTypes { + if x != nil { + return x.Type + } + return nil +} + +// `Tag` is a representation of OpenAPI v2 specification's Tag object. +// +// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#tagObject +// +type Tag struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // A short description for the tag. GFM syntax can be used for rich text + // representation. + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` + // Additional external documentation for this tag. + ExternalDocs *ExternalDocumentation `protobuf:"bytes,3,opt,name=external_docs,json=externalDocs,proto3" json:"external_docs,omitempty"` +} + +func (x *Tag) Reset() { + *x = Tag{} + if protoimpl.UnsafeEnabled { + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Tag) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Tag) ProtoMessage() {} + +func (x *Tag) ProtoReflect() protoreflect.Message { + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Tag.ProtoReflect.Descriptor instead. +func (*Tag) Descriptor() ([]byte, []int) { + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{9} +} + +func (x *Tag) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *Tag) GetExternalDocs() *ExternalDocumentation { + if x != nil { + return x.ExternalDocs + } + return nil +} + +// `SecurityDefinitions` is a representation of OpenAPI v2 specification's +// Security Definitions object. +// +// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#securityDefinitionsObject +// +// A declaration of the security schemes available to be used in the +// specification. This does not enforce the security schemes on the operations +// and only serves to provide the relevant details for each scheme. +type SecurityDefinitions struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // A single security scheme definition, mapping a "name" to the scheme it + // defines. + Security map[string]*SecurityScheme `protobuf:"bytes,1,rep,name=security,proto3" json:"security,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *SecurityDefinitions) Reset() { + *x = SecurityDefinitions{} + if protoimpl.UnsafeEnabled { + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SecurityDefinitions) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SecurityDefinitions) ProtoMessage() {} + +func (x *SecurityDefinitions) ProtoReflect() protoreflect.Message { + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SecurityDefinitions.ProtoReflect.Descriptor instead. +func (*SecurityDefinitions) Descriptor() ([]byte, []int) { + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{10} +} + +func (x *SecurityDefinitions) GetSecurity() map[string]*SecurityScheme { + if x != nil { + return x.Security + } + return nil +} + +// `SecurityScheme` is a representation of OpenAPI v2 specification's +// Security Scheme object. +// +// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#securitySchemeObject +// +// Allows the definition of a security scheme that can be used by the +// operations. Supported schemes are basic authentication, an API key (either as +// a header or as a query parameter) and OAuth2's common flows (implicit, +// password, application and access code). +type SecurityScheme struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The type of the security scheme. Valid values are "basic", + // "apiKey" or "oauth2". + Type SecurityScheme_Type `protobuf:"varint,1,opt,name=type,proto3,enum=grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme_Type" json:"type,omitempty"` + // A short description for security scheme. + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` + // The name of the header or query parameter to be used. + // Valid for apiKey. + Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` + // The location of the API key. Valid values are "query" or + // "header". + // Valid for apiKey. + In SecurityScheme_In `protobuf:"varint,4,opt,name=in,proto3,enum=grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme_In" json:"in,omitempty"` + // The flow used by the OAuth2 security scheme. Valid values are + // "implicit", "password", "application" or "accessCode". + // Valid for oauth2. + Flow SecurityScheme_Flow `protobuf:"varint,5,opt,name=flow,proto3,enum=grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme_Flow" json:"flow,omitempty"` + // The authorization URL to be used for this flow. This SHOULD be in + // the form of a URL. + // Valid for oauth2/implicit and oauth2/accessCode. + AuthorizationUrl string `protobuf:"bytes,6,opt,name=authorization_url,json=authorizationUrl,proto3" json:"authorization_url,omitempty"` + // The token URL to be used for this flow. This SHOULD be in the + // form of a URL. + // Valid for oauth2/password, oauth2/application and oauth2/accessCode. + TokenUrl string `protobuf:"bytes,7,opt,name=token_url,json=tokenUrl,proto3" json:"token_url,omitempty"` + // The available scopes for the OAuth2 security scheme. + // Valid for oauth2. + Scopes *Scopes `protobuf:"bytes,8,opt,name=scopes,proto3" json:"scopes,omitempty"` + Extensions map[string]*_struct.Value `protobuf:"bytes,9,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *SecurityScheme) Reset() { + *x = SecurityScheme{} + if protoimpl.UnsafeEnabled { + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SecurityScheme) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SecurityScheme) ProtoMessage() {} + +func (x *SecurityScheme) ProtoReflect() protoreflect.Message { + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SecurityScheme.ProtoReflect.Descriptor instead. +func (*SecurityScheme) Descriptor() ([]byte, []int) { + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{11} +} + +func (x *SecurityScheme) GetType() SecurityScheme_Type { + if x != nil { + return x.Type + } + return SecurityScheme_TYPE_INVALID +} + +func (x *SecurityScheme) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *SecurityScheme) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *SecurityScheme) GetIn() SecurityScheme_In { + if x != nil { + return x.In + } + return SecurityScheme_IN_INVALID +} + +func (x *SecurityScheme) GetFlow() SecurityScheme_Flow { + if x != nil { + return x.Flow + } + return SecurityScheme_FLOW_INVALID +} + +func (x *SecurityScheme) GetAuthorizationUrl() string { + if x != nil { + return x.AuthorizationUrl + } + return "" +} + +func (x *SecurityScheme) GetTokenUrl() string { + if x != nil { + return x.TokenUrl + } + return "" +} + +func (x *SecurityScheme) GetScopes() *Scopes { + if x != nil { + return x.Scopes + } + return nil +} + +func (x *SecurityScheme) GetExtensions() map[string]*_struct.Value { + if x != nil { + return x.Extensions + } + return nil +} + +// `SecurityRequirement` is a representation of OpenAPI v2 specification's +// Security Requirement object. +// +// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#securityRequirementObject +// +// Lists the required security schemes to execute this operation. The object can +// have multiple security schemes declared in it which are all required (that +// is, there is a logical AND between the schemes). +// +// The name used for each property MUST correspond to a security scheme +// declared in the Security Definitions. +type SecurityRequirement struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Each name must correspond to a security scheme which is declared in + // the Security Definitions. If the security scheme is of type "oauth2", + // then the value is a list of scope names required for the execution. + // For other security scheme types, the array MUST be empty. + SecurityRequirement map[string]*SecurityRequirement_SecurityRequirementValue `protobuf:"bytes,1,rep,name=security_requirement,json=securityRequirement,proto3" json:"security_requirement,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *SecurityRequirement) Reset() { + *x = SecurityRequirement{} + if protoimpl.UnsafeEnabled { + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SecurityRequirement) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SecurityRequirement) ProtoMessage() {} + +func (x *SecurityRequirement) ProtoReflect() protoreflect.Message { + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SecurityRequirement.ProtoReflect.Descriptor instead. +func (*SecurityRequirement) Descriptor() ([]byte, []int) { + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{12} +} + +func (x *SecurityRequirement) GetSecurityRequirement() map[string]*SecurityRequirement_SecurityRequirementValue { + if x != nil { + return x.SecurityRequirement + } + return nil +} + +// `Scopes` is a representation of OpenAPI v2 specification's Scopes object. +// +// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#scopesObject +// +// Lists the available scopes for an OAuth2 security scheme. +type Scopes struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Maps between a name of a scope to a short description of it (as the value + // of the property). + Scope map[string]string `protobuf:"bytes,1,rep,name=scope,proto3" json:"scope,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *Scopes) Reset() { + *x = Scopes{} + if protoimpl.UnsafeEnabled { + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Scopes) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Scopes) ProtoMessage() {} + +func (x *Scopes) ProtoReflect() protoreflect.Message { + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Scopes.ProtoReflect.Descriptor instead. +func (*Scopes) Descriptor() ([]byte, []int) { + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{13} +} + +func (x *Scopes) GetScope() map[string]string { + if x != nil { + return x.Scope + } + return nil +} + +// If the security scheme is of type "oauth2", then the value is a list of +// scope names required for the execution. For other security scheme types, +// the array MUST be empty. +type SecurityRequirement_SecurityRequirementValue struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Scope []string `protobuf:"bytes,1,rep,name=scope,proto3" json:"scope,omitempty"` +} + +func (x *SecurityRequirement_SecurityRequirementValue) Reset() { + *x = SecurityRequirement_SecurityRequirementValue{} + if protoimpl.UnsafeEnabled { + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SecurityRequirement_SecurityRequirementValue) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SecurityRequirement_SecurityRequirementValue) ProtoMessage() {} + +func (x *SecurityRequirement_SecurityRequirementValue) ProtoReflect() protoreflect.Message { + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[23] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SecurityRequirement_SecurityRequirementValue.ProtoReflect.Descriptor instead. +func (*SecurityRequirement_SecurityRequirementValue) Descriptor() ([]byte, []int) { + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{12, 0} +} + +func (x *SecurityRequirement_SecurityRequirementValue) GetScope() []string { + if x != nil { + return x.Scope + } + return nil +} + +var File_gateway_protoc_gen_openapiv2_options_openapiv2_proto protoreflect.FileDescriptor + +var file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDesc = []byte{ + 0x0a, 0x34, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, + 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2f, 0x6f, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x29, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, + 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, + 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2f, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, + 0xf5, 0x07, 0x0a, 0x07, 0x53, 0x77, 0x61, 0x67, 0x67, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x73, + 0x77, 0x61, 0x67, 0x67, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x77, + 0x61, 0x67, 0x67, 0x65, 0x72, 0x12, 0x43, 0x0a, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, + 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, + 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, + 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x6f, + 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x12, 0x1b, + 0x0a, 0x09, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x62, 0x61, 0x73, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x4b, 0x0a, 0x07, 0x73, + 0x63, 0x68, 0x65, 0x6d, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x31, 0x2e, 0x67, + 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, + 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x52, + 0x07, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x6f, 0x6e, 0x73, + 0x75, 0x6d, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6f, 0x6e, 0x73, + 0x75, 0x6d, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x73, + 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x73, + 0x12, 0x5f, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x18, 0x0a, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x41, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, + 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, + 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, + 0x53, 0x77, 0x61, 0x67, 0x67, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x73, 0x12, 0x71, 0x0a, 0x14, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x64, 0x65, + 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x3e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, + 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x65, 0x63, 0x75, + 0x72, 0x69, 0x74, 0x79, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, + 0x13, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x5a, 0x0a, 0x08, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, + 0x18, 0x0c, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, + 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, + 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x69, + 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x08, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, + 0x12, 0x65, 0x0a, 0x0d, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x64, 0x6f, 0x63, + 0x73, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, + 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, + 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x44, 0x6f, 0x63, 0x75, + 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x65, 0x78, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x44, 0x6f, 0x63, 0x73, 0x12, 0x62, 0x0a, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, + 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0f, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x42, 0x2e, 0x67, 0x72, + 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, + 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x77, 0x61, 0x67, 0x67, 0x65, 0x72, 0x2e, + 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, + 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x71, 0x0a, 0x0e, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, + 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, + 0x49, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, + 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, + 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x55, + 0x0a, 0x0f, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, + 0x6b, 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x3a, 0x02, 0x38, 0x01, 0x4a, 0x04, 0x08, 0x08, 0x10, 0x09, 0x4a, 0x04, 0x08, 0x09, 0x10, + 0x0a, 0x4a, 0x04, 0x08, 0x0d, 0x10, 0x0e, 0x22, 0xff, 0x06, 0x0a, 0x09, 0x4f, 0x70, 0x65, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x6d, + 0x6d, 0x61, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x6d, 0x6d, + 0x61, 0x72, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x65, 0x0a, 0x0d, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, + 0x6c, 0x5f, 0x64, 0x6f, 0x63, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x67, + 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, + 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, + 0x6c, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, + 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x44, 0x6f, 0x63, 0x73, 0x12, 0x21, 0x0a, 0x0c, + 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, + 0x1a, 0x0a, 0x08, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x08, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x70, + 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x70, + 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x73, 0x12, 0x61, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x43, 0x2e, 0x67, 0x72, 0x70, + 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, + 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, + 0x09, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x12, 0x4b, 0x0a, 0x07, 0x73, 0x63, + 0x68, 0x65, 0x6d, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x31, 0x2e, 0x67, 0x72, + 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, + 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x52, 0x07, + 0x73, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x65, 0x70, 0x72, 0x65, + 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x64, 0x65, 0x70, + 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x5a, 0x0a, 0x08, 0x73, 0x65, 0x63, 0x75, 0x72, + 0x69, 0x74, 0x79, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3e, 0x2e, 0x67, 0x72, 0x70, 0x63, + 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, + 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, + 0x71, 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x08, 0x73, 0x65, 0x63, 0x75, 0x72, + 0x69, 0x74, 0x79, 0x12, 0x64, 0x0a, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, + 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x44, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, + 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, + 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x45, 0x78, + 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x65, + 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x71, 0x0a, 0x0e, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, + 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x49, 0x0a, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x67, + 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, + 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x55, 0x0a, 0x0f, + 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, + 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, + 0x79, 0x12, 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, + 0x02, 0x38, 0x01, 0x4a, 0x04, 0x08, 0x08, 0x10, 0x09, 0x22, 0xd5, 0x03, 0x0a, 0x08, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x49, 0x0a, 0x06, 0x73, 0x63, 0x68, 0x65, + 0x6d, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, + 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, + 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x06, 0x73, 0x63, 0x68, + 0x65, 0x6d, 0x61, 0x12, 0x5d, 0x0a, 0x08, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x18, + 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x41, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, + 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, + 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x45, 0x78, 0x61, 0x6d, 0x70, + 0x6c, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, + 0x65, 0x73, 0x12, 0x63, 0x0a, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, + 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x43, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, + 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, + 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x45, 0x78, 0x74, 0x65, + 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x65, 0x78, 0x74, + 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x3b, 0x0a, 0x0d, 0x45, 0x78, 0x61, 0x6d, 0x70, + 0x6c, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x55, 0x0a, 0x0f, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, + 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x4a, 0x04, 0x08, 0x03, 0x10, + 0x04, 0x22, 0xd6, 0x03, 0x0a, 0x04, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, + 0x74, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, + 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x28, 0x0a, 0x10, 0x74, 0x65, 0x72, 0x6d, 0x73, 0x5f, 0x6f, 0x66, 0x5f, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x74, 0x65, + 0x72, 0x6d, 0x73, 0x4f, 0x66, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x4c, 0x0a, 0x07, + 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, + 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, + 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, + 0x74, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x12, 0x4c, 0x0a, 0x07, 0x6c, 0x69, + 0x63, 0x65, 0x6e, 0x73, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x67, 0x72, + 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, + 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x52, + 0x07, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x12, 0x5f, 0x0a, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, + 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, + 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, + 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x2e, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, + 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x1a, 0x55, 0x0a, 0x0f, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, + 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x45, 0x0a, 0x07, 0x43, 0x6f, + 0x6e, 0x74, 0x61, 0x63, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x65, + 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, + 0x6c, 0x22, 0x2f, 0x0a, 0x07, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, + 0x72, 0x6c, 0x22, 0x4b, 0x0a, 0x15, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x44, 0x6f, + 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x64, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x10, 0x0a, + 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x22, + 0xaa, 0x02, 0x0a, 0x06, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x56, 0x0a, 0x0b, 0x6a, 0x73, + 0x6f, 0x6e, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x35, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, + 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4a, 0x53, 0x4f, 0x4e, + 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x0a, 0x6a, 0x73, 0x6f, 0x6e, 0x53, 0x63, 0x68, 0x65, + 0x6d, 0x61, 0x12, 0x24, 0x0a, 0x0d, 0x64, 0x69, 0x73, 0x63, 0x72, 0x69, 0x6d, 0x69, 0x6e, 0x61, + 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x64, 0x69, 0x73, 0x63, 0x72, + 0x69, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x65, 0x61, 0x64, + 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x61, + 0x64, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x65, 0x0a, 0x0d, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, + 0x6c, 0x5f, 0x64, 0x6f, 0x63, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x67, + 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, + 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, + 0x6c, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, + 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x44, 0x6f, 0x63, 0x73, 0x12, 0x18, 0x0a, 0x07, + 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x65, + 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x22, 0x9f, 0x07, 0x0a, + 0x0a, 0x4a, 0x53, 0x4f, 0x4e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x10, 0x0a, 0x03, 0x72, + 0x65, 0x66, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x72, 0x65, 0x66, 0x12, 0x14, 0x0a, + 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, + 0x74, 0x6c, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x12, + 0x1b, 0x0a, 0x09, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x61, 0x64, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x1f, 0x0a, 0x0b, + 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x5f, 0x6f, 0x66, 0x18, 0x0a, 0x20, 0x01, 0x28, + 0x01, 0x52, 0x0a, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x4f, 0x66, 0x12, 0x18, 0x0a, + 0x07, 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x01, 0x52, 0x07, + 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x12, 0x2b, 0x0a, 0x11, 0x65, 0x78, 0x63, 0x6c, 0x75, + 0x73, 0x69, 0x76, 0x65, 0x5f, 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x18, 0x0c, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x10, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x76, 0x65, 0x4d, 0x61, 0x78, + 0x69, 0x6d, 0x75, 0x6d, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x18, + 0x0d, 0x20, 0x01, 0x28, 0x01, 0x52, 0x07, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x12, 0x2b, + 0x0a, 0x11, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x76, 0x65, 0x5f, 0x6d, 0x69, 0x6e, 0x69, + 0x6d, 0x75, 0x6d, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x65, 0x78, 0x63, 0x6c, 0x75, + 0x73, 0x69, 0x76, 0x65, 0x4d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, + 0x61, 0x78, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x09, 0x6d, 0x61, 0x78, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x69, + 0x6e, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x10, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, + 0x6d, 0x69, 0x6e, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x74, + 0x74, 0x65, 0x72, 0x6e, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x74, 0x74, + 0x65, 0x72, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x61, 0x78, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x73, + 0x18, 0x14, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x49, 0x74, 0x65, 0x6d, 0x73, + 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x69, 0x6e, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x15, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x08, 0x6d, 0x69, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x21, 0x0a, + 0x0c, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x16, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x0b, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x73, + 0x12, 0x25, 0x0a, 0x0e, 0x6d, 0x61, 0x78, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, + 0x65, 0x73, 0x18, 0x18, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x6d, 0x61, 0x78, 0x50, 0x72, 0x6f, + 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x6d, 0x69, 0x6e, 0x5f, 0x70, + 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x19, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x0d, 0x6d, 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x12, 0x1a, + 0x0a, 0x08, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x18, 0x1a, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x08, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x72, + 0x72, 0x61, 0x79, 0x18, 0x22, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x61, 0x72, 0x72, 0x61, 0x79, + 0x12, 0x5f, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x23, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x4b, + 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, + 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4a, 0x53, 0x4f, 0x4e, 0x53, + 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x4a, 0x53, 0x4f, 0x4e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, + 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x52, 0x04, 0x74, 0x79, 0x70, + 0x65, 0x22, 0x77, 0x0a, 0x15, 0x4a, 0x53, 0x4f, 0x4e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x53, + 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, + 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x52, 0x52, 0x41, 0x59, + 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x42, 0x4f, 0x4f, 0x4c, 0x45, 0x41, 0x4e, 0x10, 0x02, 0x12, + 0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x10, 0x03, 0x12, 0x08, 0x0a, 0x04, + 0x4e, 0x55, 0x4c, 0x4c, 0x10, 0x04, 0x12, 0x0a, 0x0a, 0x06, 0x4e, 0x55, 0x4d, 0x42, 0x45, 0x52, + 0x10, 0x05, 0x12, 0x0a, 0x0a, 0x06, 0x4f, 0x42, 0x4a, 0x45, 0x43, 0x54, 0x10, 0x06, 0x12, 0x0a, + 0x0a, 0x06, 0x53, 0x54, 0x52, 0x49, 0x4e, 0x47, 0x10, 0x07, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, + 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x4a, 0x04, 0x08, 0x09, + 0x10, 0x0a, 0x4a, 0x04, 0x08, 0x12, 0x10, 0x13, 0x4a, 0x04, 0x08, 0x13, 0x10, 0x14, 0x4a, 0x04, + 0x08, 0x17, 0x10, 0x18, 0x4a, 0x04, 0x08, 0x1b, 0x10, 0x1c, 0x4a, 0x04, 0x08, 0x1c, 0x10, 0x1d, + 0x4a, 0x04, 0x08, 0x1d, 0x10, 0x1e, 0x4a, 0x04, 0x08, 0x1e, 0x10, 0x22, 0x4a, 0x04, 0x08, 0x24, + 0x10, 0x2a, 0x4a, 0x04, 0x08, 0x2a, 0x10, 0x2b, 0x4a, 0x04, 0x08, 0x2b, 0x10, 0x2e, 0x22, 0x94, + 0x01, 0x0a, 0x03, 0x54, 0x61, 0x67, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x65, 0x0a, 0x0d, 0x65, 0x78, 0x74, 0x65, + 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x64, 0x6f, 0x63, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x40, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, + 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x45, 0x78, 0x74, 0x65, + 0x72, 0x6e, 0x61, 0x6c, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x0c, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x44, 0x6f, 0x63, 0x73, 0x4a, + 0x04, 0x08, 0x01, 0x10, 0x02, 0x22, 0xf7, 0x01, 0x0a, 0x13, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, + 0x74, 0x79, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x68, 0x0a, + 0x08, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x4c, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, + 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x65, 0x63, 0x75, + 0x72, 0x69, 0x74, 0x79, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, + 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x73, + 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x1a, 0x76, 0x0a, 0x0d, 0x53, 0x65, 0x63, 0x75, 0x72, + 0x69, 0x74, 0x79, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x4f, 0x0a, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x67, 0x72, 0x70, 0x63, + 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, + 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x53, 0x63, + 0x68, 0x65, 0x6d, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, + 0xff, 0x06, 0x0a, 0x0e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x53, 0x63, 0x68, 0x65, + 0x6d, 0x65, 0x12, 0x52, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x3e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, + 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x65, 0x63, + 0x75, 0x72, 0x69, 0x74, 0x79, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x2e, 0x54, 0x79, 0x70, 0x65, + 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x4c, 0x0a, 0x02, + 0x69, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x3c, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, + 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, + 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x53, 0x63, 0x68, + 0x65, 0x6d, 0x65, 0x2e, 0x49, 0x6e, 0x52, 0x02, 0x69, 0x6e, 0x12, 0x52, 0x0a, 0x04, 0x66, 0x6c, + 0x6f, 0x77, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x3e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, + 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, + 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x53, 0x63, 0x68, + 0x65, 0x6d, 0x65, 0x2e, 0x46, 0x6c, 0x6f, 0x77, 0x52, 0x04, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x2b, + 0x0a, 0x11, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, + 0x75, 0x72, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x61, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x72, 0x6c, 0x12, 0x1b, 0x0a, 0x09, 0x74, + 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x55, 0x72, 0x6c, 0x12, 0x49, 0x0a, 0x06, 0x73, 0x63, 0x6f, 0x70, + 0x65, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, + 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, + 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x52, 0x06, 0x73, 0x63, 0x6f, + 0x70, 0x65, 0x73, 0x12, 0x69, 0x0a, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, + 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x49, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, + 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, + 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x53, 0x63, 0x68, 0x65, + 0x6d, 0x65, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x55, + 0x0a, 0x0f, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, + 0x6b, 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x4b, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, + 0x0c, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x00, 0x12, + 0x0e, 0x0a, 0x0a, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x42, 0x41, 0x53, 0x49, 0x43, 0x10, 0x01, 0x12, + 0x10, 0x0a, 0x0c, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x41, 0x50, 0x49, 0x5f, 0x4b, 0x45, 0x59, 0x10, + 0x02, 0x12, 0x0f, 0x0a, 0x0b, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4f, 0x41, 0x55, 0x54, 0x48, 0x32, + 0x10, 0x03, 0x22, 0x31, 0x0a, 0x02, 0x49, 0x6e, 0x12, 0x0e, 0x0a, 0x0a, 0x49, 0x4e, 0x5f, 0x49, + 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x49, 0x4e, 0x5f, 0x51, + 0x55, 0x45, 0x52, 0x59, 0x10, 0x01, 0x12, 0x0d, 0x0a, 0x09, 0x49, 0x4e, 0x5f, 0x48, 0x45, 0x41, + 0x44, 0x45, 0x52, 0x10, 0x02, 0x22, 0x6a, 0x0a, 0x04, 0x46, 0x6c, 0x6f, 0x77, 0x12, 0x10, 0x0a, + 0x0c, 0x46, 0x4c, 0x4f, 0x57, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x00, 0x12, + 0x11, 0x0a, 0x0d, 0x46, 0x4c, 0x4f, 0x57, 0x5f, 0x49, 0x4d, 0x50, 0x4c, 0x49, 0x43, 0x49, 0x54, + 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x46, 0x4c, 0x4f, 0x57, 0x5f, 0x50, 0x41, 0x53, 0x53, 0x57, + 0x4f, 0x52, 0x44, 0x10, 0x02, 0x12, 0x14, 0x0a, 0x10, 0x46, 0x4c, 0x4f, 0x57, 0x5f, 0x41, 0x50, + 0x50, 0x4c, 0x49, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x03, 0x12, 0x14, 0x0a, 0x10, 0x46, + 0x4c, 0x4f, 0x57, 0x5f, 0x41, 0x43, 0x43, 0x45, 0x53, 0x53, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x10, + 0x04, 0x22, 0xf6, 0x02, 0x0a, 0x13, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, + 0x71, 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x8a, 0x01, 0x0a, 0x14, 0x73, 0x65, + 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, + 0x6e, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x57, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, + 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, + 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, + 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, + 0x79, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x52, 0x13, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x69, + 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x1a, 0x30, 0x0a, 0x18, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, + 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x1a, 0x9f, 0x01, 0x0a, 0x18, 0x53, 0x65, 0x63, + 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x6d, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x57, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, + 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, + 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x69, + 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, + 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x96, 0x01, 0x0a, 0x06, 0x53, + 0x63, 0x6f, 0x70, 0x65, 0x73, 0x12, 0x52, 0x0a, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3c, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, + 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, + 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x52, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x1a, 0x38, 0x0a, 0x0a, 0x53, 0x63, 0x6f, + 0x70, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, + 0x02, 0x38, 0x01, 0x2a, 0x3b, 0x0a, 0x06, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x12, 0x0b, 0x0a, + 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x54, + 0x54, 0x50, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x48, 0x54, 0x54, 0x50, 0x53, 0x10, 0x02, 0x12, + 0x06, 0x0a, 0x02, 0x57, 0x53, 0x10, 0x03, 0x12, 0x07, 0x0a, 0x03, 0x57, 0x53, 0x53, 0x10, 0x04, + 0x42, 0x4b, 0x5a, 0x49, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, + 0x69, 0x6e, 0x63, 0x68, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x65, 0x61, 0x73, 0x65, + 0x2d, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2f, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, + 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x6f, 0x70, 0x65, 0x6e, + 0x61, 0x70, 0x69, 0x76, 0x32, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescOnce sync.Once + file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescData = file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDesc +) + +func file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP() []byte { + file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescOnce.Do(func() { + file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescData = protoimpl.X.CompressGZIP(file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescData) + }) + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescData +} + +var file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_enumTypes = make([]protoimpl.EnumInfo, 5) +var file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes = make([]protoimpl.MessageInfo, 26) +var file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_goTypes = []interface{}{ + (Scheme)(0), // 0: grpc.gateway.protoc_gen_openapiv2.options.Scheme + (JSONSchema_JSONSchemaSimpleTypes)(0), // 1: grpc.gateway.protoc_gen_openapiv2.options.JSONSchema.JSONSchemaSimpleTypes + (SecurityScheme_Type)(0), // 2: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.Type + (SecurityScheme_In)(0), // 3: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.In + (SecurityScheme_Flow)(0), // 4: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.Flow + (*Swagger)(nil), // 5: grpc.gateway.protoc_gen_openapiv2.options.Swagger + (*Operation)(nil), // 6: grpc.gateway.protoc_gen_openapiv2.options.Operation + (*Response)(nil), // 7: grpc.gateway.protoc_gen_openapiv2.options.Response + (*Info)(nil), // 8: grpc.gateway.protoc_gen_openapiv2.options.Info + (*Contact)(nil), // 9: grpc.gateway.protoc_gen_openapiv2.options.Contact + (*License)(nil), // 10: grpc.gateway.protoc_gen_openapiv2.options.License + (*ExternalDocumentation)(nil), // 11: grpc.gateway.protoc_gen_openapiv2.options.ExternalDocumentation + (*Schema)(nil), // 12: grpc.gateway.protoc_gen_openapiv2.options.Schema + (*JSONSchema)(nil), // 13: grpc.gateway.protoc_gen_openapiv2.options.JSONSchema + (*Tag)(nil), // 14: grpc.gateway.protoc_gen_openapiv2.options.Tag + (*SecurityDefinitions)(nil), // 15: grpc.gateway.protoc_gen_openapiv2.options.SecurityDefinitions + (*SecurityScheme)(nil), // 16: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme + (*SecurityRequirement)(nil), // 17: grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement + (*Scopes)(nil), // 18: grpc.gateway.protoc_gen_openapiv2.options.Scopes + nil, // 19: grpc.gateway.protoc_gen_openapiv2.options.Swagger.ResponsesEntry + nil, // 20: grpc.gateway.protoc_gen_openapiv2.options.Swagger.ExtensionsEntry + nil, // 21: grpc.gateway.protoc_gen_openapiv2.options.Operation.ResponsesEntry + nil, // 22: grpc.gateway.protoc_gen_openapiv2.options.Operation.ExtensionsEntry + nil, // 23: grpc.gateway.protoc_gen_openapiv2.options.Response.ExamplesEntry + nil, // 24: grpc.gateway.protoc_gen_openapiv2.options.Response.ExtensionsEntry + nil, // 25: grpc.gateway.protoc_gen_openapiv2.options.Info.ExtensionsEntry + nil, // 26: grpc.gateway.protoc_gen_openapiv2.options.SecurityDefinitions.SecurityEntry + nil, // 27: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.ExtensionsEntry + (*SecurityRequirement_SecurityRequirementValue)(nil), // 28: grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement.SecurityRequirementValue + nil, // 29: grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement.SecurityRequirementEntry + nil, // 30: grpc.gateway.protoc_gen_openapiv2.options.Scopes.ScopeEntry + (*_struct.Value)(nil), // 31: google.protobuf.Value +} +var file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_depIdxs = []int32{ + 8, // 0: grpc.gateway.protoc_gen_openapiv2.options.Swagger.info:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Info + 0, // 1: grpc.gateway.protoc_gen_openapiv2.options.Swagger.schemes:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Scheme + 19, // 2: grpc.gateway.protoc_gen_openapiv2.options.Swagger.responses:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Swagger.ResponsesEntry + 15, // 3: grpc.gateway.protoc_gen_openapiv2.options.Swagger.security_definitions:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityDefinitions + 17, // 4: grpc.gateway.protoc_gen_openapiv2.options.Swagger.security:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement + 11, // 5: grpc.gateway.protoc_gen_openapiv2.options.Swagger.external_docs:type_name -> grpc.gateway.protoc_gen_openapiv2.options.ExternalDocumentation + 20, // 6: grpc.gateway.protoc_gen_openapiv2.options.Swagger.extensions:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Swagger.ExtensionsEntry + 11, // 7: grpc.gateway.protoc_gen_openapiv2.options.Operation.external_docs:type_name -> grpc.gateway.protoc_gen_openapiv2.options.ExternalDocumentation + 21, // 8: grpc.gateway.protoc_gen_openapiv2.options.Operation.responses:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Operation.ResponsesEntry + 0, // 9: grpc.gateway.protoc_gen_openapiv2.options.Operation.schemes:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Scheme + 17, // 10: grpc.gateway.protoc_gen_openapiv2.options.Operation.security:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement + 22, // 11: grpc.gateway.protoc_gen_openapiv2.options.Operation.extensions:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Operation.ExtensionsEntry + 12, // 12: grpc.gateway.protoc_gen_openapiv2.options.Response.schema:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Schema + 23, // 13: grpc.gateway.protoc_gen_openapiv2.options.Response.examples:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Response.ExamplesEntry + 24, // 14: grpc.gateway.protoc_gen_openapiv2.options.Response.extensions:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Response.ExtensionsEntry + 9, // 15: grpc.gateway.protoc_gen_openapiv2.options.Info.contact:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Contact + 10, // 16: grpc.gateway.protoc_gen_openapiv2.options.Info.license:type_name -> grpc.gateway.protoc_gen_openapiv2.options.License + 25, // 17: grpc.gateway.protoc_gen_openapiv2.options.Info.extensions:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Info.ExtensionsEntry + 13, // 18: grpc.gateway.protoc_gen_openapiv2.options.Schema.json_schema:type_name -> grpc.gateway.protoc_gen_openapiv2.options.JSONSchema + 11, // 19: grpc.gateway.protoc_gen_openapiv2.options.Schema.external_docs:type_name -> grpc.gateway.protoc_gen_openapiv2.options.ExternalDocumentation + 1, // 20: grpc.gateway.protoc_gen_openapiv2.options.JSONSchema.type:type_name -> grpc.gateway.protoc_gen_openapiv2.options.JSONSchema.JSONSchemaSimpleTypes + 11, // 21: grpc.gateway.protoc_gen_openapiv2.options.Tag.external_docs:type_name -> grpc.gateway.protoc_gen_openapiv2.options.ExternalDocumentation + 26, // 22: grpc.gateway.protoc_gen_openapiv2.options.SecurityDefinitions.security:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityDefinitions.SecurityEntry + 2, // 23: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.type:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.Type + 3, // 24: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.in:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.In + 4, // 25: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.flow:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.Flow + 18, // 26: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.scopes:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Scopes + 27, // 27: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.extensions:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.ExtensionsEntry + 29, // 28: grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement.security_requirement:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement.SecurityRequirementEntry + 30, // 29: grpc.gateway.protoc_gen_openapiv2.options.Scopes.scope:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Scopes.ScopeEntry + 7, // 30: grpc.gateway.protoc_gen_openapiv2.options.Swagger.ResponsesEntry.value:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Response + 31, // 31: grpc.gateway.protoc_gen_openapiv2.options.Swagger.ExtensionsEntry.value:type_name -> google.protobuf.Value + 7, // 32: grpc.gateway.protoc_gen_openapiv2.options.Operation.ResponsesEntry.value:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Response + 31, // 33: grpc.gateway.protoc_gen_openapiv2.options.Operation.ExtensionsEntry.value:type_name -> google.protobuf.Value + 31, // 34: grpc.gateway.protoc_gen_openapiv2.options.Response.ExtensionsEntry.value:type_name -> google.protobuf.Value + 31, // 35: grpc.gateway.protoc_gen_openapiv2.options.Info.ExtensionsEntry.value:type_name -> google.protobuf.Value + 16, // 36: grpc.gateway.protoc_gen_openapiv2.options.SecurityDefinitions.SecurityEntry.value:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme + 31, // 37: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.ExtensionsEntry.value:type_name -> google.protobuf.Value + 28, // 38: grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement.SecurityRequirementEntry.value:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement.SecurityRequirementValue + 39, // [39:39] is the sub-list for method output_type + 39, // [39:39] is the sub-list for method input_type + 39, // [39:39] is the sub-list for extension type_name + 39, // [39:39] is the sub-list for extension extendee + 0, // [0:39] is the sub-list for field type_name +} + +func init() { file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_init() } +func file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_init() { + if File_gateway_protoc_gen_openapiv2_options_openapiv2_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Swagger); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Operation); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Response); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Info); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Contact); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*License); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ExternalDocumentation); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Schema); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*JSONSchema); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Tag); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SecurityDefinitions); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SecurityScheme); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SecurityRequirement); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Scopes); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SecurityRequirement_SecurityRequirementValue); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDesc, + NumEnums: 5, + NumMessages: 26, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_goTypes, + DependencyIndexes: file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_depIdxs, + EnumInfos: file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_enumTypes, + MessageInfos: file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes, + }.Build() + File_gateway_protoc_gen_openapiv2_options_openapiv2_proto = out.File + file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDesc = nil + file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_goTypes = nil + file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_depIdxs = nil +} diff --git a/gateway/protoc-gen-openapiv2/options/openapiv2.proto b/gateway/protoc-gen-openapiv2/options/openapiv2.proto index f0040d6..41add95 100644 --- a/gateway/protoc-gen-openapiv2/options/openapiv2.proto +++ b/gateway/protoc-gen-openapiv2/options/openapiv2.proto @@ -4,7 +4,6 @@ package grpc.gateway.protoc_gen_openapiv2.options; option go_package = "github.com/binchencoder/ease-gateway/gateway/protoc-gen-openapiv2/options"; -import "google/protobuf/any.proto"; import "google/protobuf/struct.proto"; // Scheme describes the schemes supported by the OpenAPI Swagger @@ -336,8 +335,9 @@ message Schema { reserved 4; // Additional external documentation for this schema. ExternalDocumentation external_docs = 5; - // A free-form property to include an example of an instance for this schema. - google.protobuf.Any example = 6; + // A free-form property to include an example of an instance for this schema in JSON. + // This is copied verbatim to the output. + string example = 6; } // `JSONSchema` represents properties from JSON Schema taken, and as used, in diff --git a/gateway/runtime/BUILD.bazel b/gateway/runtime/BUILD.bazel index 30ab37b..1d6c372 100644 --- a/gateway/runtime/BUILD.bazel +++ b/gateway/runtime/BUILD.bazel @@ -19,8 +19,8 @@ go_library( "@com_github_binchencoder_skylb_api//proto:go_default_library", "@com_github_golang_protobuf//ptypes:go_default_library_gen", "@com_github_grpc_ecosystem_grpc_gateway//utilities:go_default_library", - "@com_github_grpc_ecosystem_grpc_gateway//internal/httprule:go_default_library", - "@com_github_pborman_uuid//:go_default_library", + "@com_github_grpc_ecosystem_grpc_gateway//internal/httprule:go_default_library", + "@com_github_pborman_uuid//:go_default_library", "@com_github_golang_protobuf//jsonpb:go_default_library_gen", "@go_googleapis//google/api:httpbody_go_proto", "@io_bazel_rules_go//proto/wkt:duration_go_proto", @@ -35,7 +35,7 @@ go_library( "@org_golang_google_protobuf//proto:go_default_library", "@org_golang_google_protobuf//reflect/protoreflect:go_default_library", "@org_golang_google_protobuf//reflect/protoregistry:go_default_library", - "@org_golang_google_grpc//:go_default_library", + "@org_golang_google_grpc//:go_default_library", "@org_golang_x_net//context:go_default_library", ], ) @@ -59,12 +59,12 @@ go_test( deps = [ "//examples/proto:go_default_library", "//gateway/internal:go_default_library", - "//gateway/runtime/internal/examplepb:go_default_library", + "//gateway/runtime/internal/examplepb:go_default_library", "//httpoptions:go_default_library", "@com_github_binchencoder_letsgo//hashring:go_default_library", "@com_github_binchencoder_skylb_api//proto:go_default_library", "@com_github_grpc_ecosystem_grpc_gateway//utilities:go_default_library", - "@com_github_grpc_ecosystem_grpc_gateway//runtime/internal/examplepb:go_default_library", + "@com_github_grpc_ecosystem_grpc_gateway//runtime/internal/examplepb:go_default_library", "@com_github_golang_protobuf//ptypes:go_default_library_gen", "@com_github_golang_protobuf//proto:go_default_library", "@com_github_google_go_cmp//cmp:go_default_library", @@ -84,7 +84,7 @@ go_test( "@org_golang_google_protobuf//encoding/protojson:go_default_library", "@org_golang_google_protobuf//proto:go_default_library", "@org_golang_google_protobuf//testing/protocmp:go_default_library", - "@org_golang_google_grpc//:go_default_library", + "@org_golang_google_grpc//:go_default_library", "@org_golang_x_net//context:go_default_library", ], ) diff --git a/gateway/runtime/context.go b/gateway/runtime/context.go index bb52a37..2c249eb 100644 --- a/gateway/runtime/context.go +++ b/gateway/runtime/context.go @@ -9,10 +9,10 @@ import ( "net/textproto" "strconv" "strings" + "sync" "time" "google.golang.org/grpc/codes" - "google.golang.org/grpc/grpclog" "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" ) @@ -97,8 +97,8 @@ func annotateContext(ctx context.Context, mux *ServeMux, req *http.Request, rpcM } for key, vals := range req.Header { + key = textproto.CanonicalMIMEHeaderKey(key) for _, val := range vals { - key = textproto.CanonicalMIMEHeaderKey(key) // For backwards-compatibility, pass through 'authorization' header with no prefix. if key == "Authorization" { pairs = append(pairs, "authorization", val) @@ -131,8 +131,6 @@ func annotateContext(ctx context.Context, mux *ServeMux, req *http.Request, rpcM } else { pairs = append(pairs, strings.ToLower(xForwardedFor), fmt.Sprintf("%s, %s", fwd, remoteIP)) } - } else { - grpclog.Infof("invalid remote addr: %s", addr) } } @@ -168,6 +166,63 @@ func ServerMetadataFromContext(ctx context.Context) (md ServerMetadata, ok bool) return } +// ServerTransportStream implements grpc.ServerTransportStream. +// It should only be used by the generated files to support grpc.SendHeader +// outside of gRPC server use. +type ServerTransportStream struct { + mu sync.Mutex + header metadata.MD + trailer metadata.MD +} + +// Method returns the method for the stream. +func (s *ServerTransportStream) Method() string { + return "" +} + +// Header returns the header metadata of the stream. +func (s *ServerTransportStream) Header() metadata.MD { + s.mu.Lock() + defer s.mu.Unlock() + return s.header.Copy() +} + +// SetHeader sets the header metadata. +func (s *ServerTransportStream) SetHeader(md metadata.MD) error { + if md.Len() == 0 { + return nil + } + + s.mu.Lock() + s.header = metadata.Join(s.header, md) + s.mu.Unlock() + return nil +} + +// SendHeader sets the header metadata. +func (s *ServerTransportStream) SendHeader(md metadata.MD) error { + return s.SetHeader(md) +} + +// Trailer returns the cached trailer metadata. +func (s *ServerTransportStream) Trailer() metadata.MD { + s.mu.Lock() + defer s.mu.Unlock() + return s.trailer.Copy() +} + +// SetTrailer sets the trailer metadata. +func (s *ServerTransportStream) SetTrailer(md metadata.MD) error { + if md.Len() == 0 { + return nil + } + + s.mu.Lock() + s.trailer = metadata.Join(s.trailer, md) + s.mu.Unlock() + return nil +} + func timeoutDecode(s string) (time.Duration, error) { size := len(s) if size < 2 { diff --git a/gateway/runtime/errors.go b/gateway/runtime/errors.go index ed7603d..2374a6e 100644 --- a/gateway/runtime/errors.go +++ b/gateway/runtime/errors.go @@ -23,6 +23,9 @@ type ErrorHandlerFunc func(context.Context, *ServeMux, Marshaler, http.ResponseW // StreamErrorHandlerFunc is the signature used to configure stream error handling. type StreamErrorHandlerFunc func(context.Context, error) *status.Status +// RoutingErrorHandlerFunc is the signature used to configure error handling for routing errors. +type RoutingErrorHandlerFunc func(context.Context, *ServeMux, Marshaler, http.ResponseWriter, *http.Request, int) + // HTTPStatusFromCode converts a gRPC error code into the corresponding HTTP response status. // See: https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto func HTTPStatusFromCode(code codes.Code) int { @@ -148,3 +151,22 @@ func DefaultHTTPErrorHandler(ctx context.Context, mux *ServeMux, marshaler Marsh func DefaultStreamErrorHandler(_ context.Context, err error) *status.Status { return status.Convert(err) } + +// DefaultRoutingErrorHandler is our default handler for routing errors. +// By default http error codes mapped on the following error codes: +// NotFound -> grpc.NotFound +// StatusBadRequest -> grpc.InvalidArgument +// MethodNotAllowed -> grpc.Unimplemented +// Other -> grpc.Internal, method is not expecting to be called for anything else +func DefaultRoutingErrorHandler(ctx context.Context, mux *ServeMux, marshaler Marshaler, w http.ResponseWriter, r *http.Request, httpStatus int) { + sterr := status.Error(codes.Internal, "Unexpected routing error") + switch httpStatus { + case http.StatusBadRequest: + sterr = status.Error(codes.InvalidArgument, http.StatusText(httpStatus)) + case http.StatusMethodNotAllowed: + sterr = status.Error(codes.Unimplemented, http.StatusText(httpStatus)) + case http.StatusNotFound: + sterr = status.Error(codes.NotFound, http.StatusText(httpStatus)) + } + mux.errorHandler(ctx, mux, marshaler, w, r, sterr) +} diff --git a/gateway/runtime/fieldmask.go b/gateway/runtime/fieldmask.go index 5cd931a..bdaa79d 100644 --- a/gateway/runtime/fieldmask.go +++ b/gateway/runtime/fieldmask.go @@ -4,7 +4,6 @@ import ( "encoding/json" "fmt" "io" - "strings" "google.golang.org/genproto/protobuf/field_mask" "google.golang.org/protobuf/proto" @@ -52,10 +51,27 @@ func FieldMaskFromRequestBody(r io.Reader, msg proto.Message) (*field_mask.Field if fd == nil { return nil, fmt.Errorf("could not find field %q in %q", k, item.msg.Descriptor().FullName()) } + + if isDynamicProtoMessage(fd.Message()) { + for _, p := range buildPathsBlindly(k, v) { + newPath := p + if item.path != "" { + newPath = item.path + "." + newPath + } + queue = append(queue, fieldMaskPathItem{path: newPath}) + } + continue + } + child := fieldMaskPathItem{ - path: append(item.path, string(fd.FullName().Name())), node: v, } + if item.path == "" { + child.path = string(fd.FullName().Name()) + } else { + child.path = item.path + "." + string(fd.FullName().Name()) + } + switch { case fd.IsList(), fd.IsMap(): if repeatedChild != nil { @@ -75,23 +91,63 @@ func FieldMaskFromRequestBody(r io.Reader, msg proto.Message) (*field_mask.Field } case len(item.path) > 0: // otherwise, it's a leaf node so print its path - fm.Paths = append(fm.Paths, strings.Join(item.path, ".")) + fm.Paths = append(fm.Paths, item.path) } } // Add any repeated fields last, as per // https://github.com/protocolbuffers/protobuf/blob/6b0ff74ecf63e26c7315f6745de36aff66deb59d/src/google/protobuf/field_mask.proto#L85-L86 if repeatedChild != nil { - fm.Paths = append(fm.Paths, strings.Join(repeatedChild.path, ".")) + fm.Paths = append(fm.Paths, repeatedChild.path) } return fm, nil } +func isDynamicProtoMessage(md protoreflect.MessageDescriptor) bool { + return md != nil && (md.FullName() == "google.protobuf.Struct" || md.FullName() == "google.protobuf.Value") +} + +// buildPathsBlindly does not attempt to match proto field names to the +// json value keys. Instead it relies completely on the structure of +// the unmarshalled json contained within in. +// Returns a slice containing all subpaths with the root at the +// passed in name and json value. +func buildPathsBlindly(name string, in interface{}) []string { + m, ok := in.(map[string]interface{}) + if !ok { + return []string{name} + } + + var paths []string + queue := []fieldMaskPathItem{{path: name, node: m}} + for len(queue) > 0 { + cur := queue[0] + queue = queue[1:] + + m, ok := cur.node.(map[string]interface{}) + if !ok { + // This should never happen since we should always check that we only add + // nodes of type map[string]interface{} to the queue. + continue + } + for k, v := range m { + if mi, ok := v.(map[string]interface{}); ok { + queue = append(queue, fieldMaskPathItem{path: cur.path + "." + k, node: mi}) + } else { + // This is not a struct, so there are no more levels to descend. + curPath := cur.path + "." + k + paths = append(paths, curPath) + } + } + } + return paths +} + // fieldMaskPathItem stores a in-progress deconstruction of a path for a fieldmask type fieldMaskPathItem struct { - // the list of prior fields leading up to node - path []string + // the list of prior fields leading up to node connected by dots + path string // a generic decoded json object the current item to inspect for further path extraction node interface{} diff --git a/gateway/runtime/mux.go b/gateway/runtime/mux.go index ebfbae7..289bcca 100644 --- a/gateway/runtime/mux.go +++ b/gateway/runtime/mux.go @@ -31,6 +31,7 @@ type ServeMux struct { metadataAnnotators []func(context.Context, *http.Request) metadata.MD errorHandler ErrorHandlerFunc streamErrorHandler StreamErrorHandlerFunc + routingErrorHandler RoutingErrorHandlerFunc disablePathLengthFallback bool } @@ -128,6 +129,16 @@ func WithStreamErrorHandler(fn StreamErrorHandlerFunc) ServeMuxOption { } } +// WithRoutingErrorHandler returns a ServeMuxOption for configuring a custom error handler to handle http routing errors. +// +// Method called for errors which can happen before gRPC route selected or executed. +// The following error codes: StatusMethodNotAllowed StatusNotFound StatusBadRequest +func WithRoutingErrorHandler(fn RoutingErrorHandlerFunc) ServeMuxOption { + return func(serveMux *ServeMux) { + serveMux.routingErrorHandler = fn + } +} + // WithDisablePathLengthFallback returns a ServeMuxOption for disable path length fallback. func WithDisablePathLengthFallback() ServeMuxOption { return func(serveMux *ServeMux) { @@ -143,6 +154,7 @@ func NewServeMux(opts ...ServeMuxOption) *ServeMux { marshalers: makeMarshalerMIMERegistry(), errorHandler: DefaultHTTPErrorHandler, streamErrorHandler: DefaultStreamErrorHandler, + routingErrorHandler: DefaultRoutingErrorHandler, } for _, opt := range opts { @@ -194,8 +206,7 @@ func (s *ServeMux) ServeHTTP(w http.ResponseWriter, r *http.Request) { path := r.URL.Path if !strings.HasPrefix(path, "/") { _, outboundMarshaler := MarshalerForRequest(s, r) - sterr := status.Error(codes.InvalidArgument, http.StatusText(http.StatusBadRequest)) - s.errorHandler(ctx, s, outboundMarshaler, w, r, sterr) + s.routingErrorHandler(ctx, s, outboundMarshaler, w, r, http.StatusBadRequest) return } @@ -205,8 +216,7 @@ func (s *ServeMux) ServeHTTP(w http.ResponseWriter, r *http.Request) { idx := strings.LastIndex(components[l-1], ":") if idx == 0 { _, outboundMarshaler := MarshalerForRequest(s, r) - sterr := status.Error(codes.NotFound, http.StatusText(http.StatusNotFound)) - s.errorHandler(ctx, s, outboundMarshaler, w, r, sterr) + s.routingErrorHandler(ctx, s, outboundMarshaler, w, r, http.StatusNotFound) return } if idx > 0 { @@ -255,16 +265,13 @@ func (s *ServeMux) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } _, outboundMarshaler := MarshalerForRequest(s, r) - // codes.Unimplemented is the closes we have to MethodNotAllowed - sterr := status.Error(codes.Unimplemented, http.StatusText(http.StatusNotImplemented)) - s.errorHandler(ctx, s, outboundMarshaler, w, r, sterr) + s.routingErrorHandler(ctx, s, outboundMarshaler, w, r, http.StatusMethodNotAllowed) return } } _, outboundMarshaler := MarshalerForRequest(s, r) - sterr := status.Error(codes.NotFound, http.StatusText(http.StatusNotFound)) - s.errorHandler(ctx, s, outboundMarshaler, w, r, sterr) + s.routingErrorHandler(ctx, s, outboundMarshaler, w, r, http.StatusNotFound) } // GetForwardResponseOptions returns the ForwardResponseOptions associated with this ServeMux. diff --git a/gateway/runtime/mux_test.go b/gateway/runtime/mux_test.go index 7218376..b73be95 100644 --- a/gateway/runtime/mux_test.go +++ b/gateway/runtime/mux_test.go @@ -295,6 +295,21 @@ func TestMuxServeHTTP(t *testing.T) { respStatus: http.StatusOK, respContent: "POST /foo/{id=*}:verb", }, + { + patterns: []stubPattern{ + { + method: "GET", + ops: []int{int(utilities.OpLitPush), 0}, + pool: []string{"foo"}, + }, + }, + reqMethod: "POST", + reqPath: "foo", + headers: map[string]string{ + "Content-Type": "application/json", + }, + respStatus: http.StatusBadRequest, + }, } { t.Run(strconv.Itoa(i), func(t *testing.T) { var opts []runtime.ServeMuxOption @@ -377,8 +392,6 @@ func TestDefaultHeaderMatcher(t *testing.T) { } } - - var defaultRouteMatcherTests = []struct { name string method string diff --git a/integrate/BUILD.bazel b/integrate/BUILD.bazel index 477ee7c..4e1bdfc 100755 --- a/integrate/BUILD.bazel +++ b/integrate/BUILD.bazel @@ -18,11 +18,11 @@ go_library( "@com_github_binchencoder_gateway_proto//frontend:go_default_library", "@com_github_binchencoder_letsgo//grpc:go_default_library", "@com_github_binchencoder_letsgo//trace:go_default_library", - "@com_github_golang_protobuf//proto:go_default_library", "@com_github_klauspost_compress//gzip:go_default_library", "@org_golang_google_grpc//:go_default_library", "@org_golang_google_grpc//codes:go_default_library", "@org_golang_google_grpc//metadata:go_default_library", + "@org_golang_google_protobuf//proto:go_default_library", "@org_golang_x_net//context:go_default_library", ], ) diff --git a/repositories.bzl b/repositories.bzl index a73ce5e..a5b356f 100644 --- a/repositories.bzl +++ b/repositories.bzl @@ -219,8 +219,8 @@ def go_repositories(): go_repository( name = "org_golang_google_genproto", importpath = "google.golang.org/genproto", - sum = "h1:d4k3uIU763E31Rk4UZPA47oOoBymMsDImV3U4mGhX9E=", - version = "v0.0.0-20201026171402-d4b8fe4fd877", + sum = "h1:7RoRaOmOAXwqnurgQ5g5/d0yCi9ha2UxuTZULXudK7A=", + version = "v0.0.0-20201028140639-c77dae4b0522", ) go_repository( name = "org_golang_google_grpc", @@ -228,6 +228,7 @@ def go_repositories(): sum = "h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk=", version = "v1.27.1", ) + go_repository( name = "org_golang_google_grpc_cmd_protoc_gen_go_grpc", importpath = "google.golang.org/grpc/cmd/protoc-gen-go-grpc", @@ -241,20 +242,96 @@ def go_repositories(): version = "v1.25.0", ) go_repository( - name = "org_golang_x_xerrors", - importpath = "golang.org/x/xerrors", - sum = "h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=", - version = "v0.0.0-20191204190536-9bdfabe68543", + name = "org_uber_go_atomic", + importpath = "go.uber.org/atomic", + sum = "h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=", + version = "v1.6.0", + ) + go_repository( + name = "org_golang_x_crypto", + importpath = "golang.org/x/crypto", + sum = "h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=", + version = "v0.0.0-20200622213623-75b288015ac9", + ) + go_repository( + name = "org_golang_x_exp", + importpath = "golang.org/x/exp", + sum = "h1:QE6XYQK6naiK1EPAe1g/ILLxN5RBoH5xkJk3CqlMI/Y=", + version = "v0.0.0-20200224162631-6cc2880d07d6", + ) + + go_repository( + name = "org_golang_x_image", + importpath = "golang.org/x/image", + sum = "h1:+qEpEAPhDZ1o0x3tHzZTQDArnOixOzGD9HUJfcg0mb4=", + version = "v0.0.0-20190802002840-cff245a6509b", + ) + go_repository( + name = "org_golang_x_lint", + importpath = "golang.org/x/lint", + sum = "h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k=", + version = "v0.0.0-20200302205851-738671d3881b", + ) + + go_repository( + name = "org_golang_x_mobile", + importpath = "golang.org/x/mobile", + sum = "h1:4+4C/Iv2U4fMZBiMCc98MG1In4gJY5YRhtpDNeDeHWs=", + version = "v0.0.0-20190719004257-d2bd2a29d028", + ) + go_repository( + name = "org_golang_x_mod", + importpath = "golang.org/x/mod", + sum = "h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=", + version = "v0.3.0", + ) + go_repository( + name = "org_golang_x_net", + importpath = "golang.org/x/net", + sum = "h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA=", + version = "v0.0.0-20200822124328-c89045814202", ) go_repository( name = "org_golang_x_oauth2", importpath = "golang.org/x/oauth2", - sum = "h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=", - version = "v0.0.0-20200107190931-bf48bf16ab8d", + sum = "h1:ld7aEMNHoBnnDAX15v1T6z31v8HwR2A9FYOuAhWqkwc=", + version = "v0.0.0-20200902213428-5d25da1a8d43", ) go_repository( - name = "org_uber_go_atomic", - importpath = "go.uber.org/atomic", - sum = "h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=", - version = "v1.6.0", + name = "org_golang_x_sync", + importpath = "golang.org/x/sync", + sum = "h1:qwRHBd0NqMbJxfbotnDhm2ByMI1Shq4Y6oRJo21SGJA=", + version = "v0.0.0-20200625203802-6e8e738ad208", + ) + go_repository( + name = "org_golang_x_sys", + importpath = "golang.org/x/sys", + sum = "h1:B6caxRw+hozq68X2MY7jEpZh/cr4/aHLv9xU8Kkadrw=", + version = "v0.0.0-20200803210538-64077c9b5642", + ) + go_repository( + name = "org_golang_x_text", + importpath = "golang.org/x/text", + sum = "h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=", + version = "v0.3.3", + ) + + go_repository( + name = "org_golang_x_time", + importpath = "golang.org/x/time", + sum = "h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs=", + version = "v0.0.0-20191024005414-555d28b269f0", + ) + go_repository( + name = "org_golang_x_tools", + importpath = "golang.org/x/tools", + sum = "h1:W07d4xkoAUSNOkOzdzXCdFGxT7o2rW4q8M34tB2i//k=", + version = "v0.0.0-20200825202427-b303f430e36d", + ) + + go_repository( + name = "org_golang_x_xerrors", + importpath = "golang.org/x/xerrors", + sum = "h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=", + version = "v0.0.0-20200804184101-5ec99f83aff1", ) \ No newline at end of file From 0a73dcf95f4ad1698d7ea126707db98e4d0ea868 Mon Sep 17 00:00:00 2001 From: binchen Date: Thu, 29 Oct 2020 16:19:17 +0800 Subject: [PATCH 26/56] Update github.com/grpc-ecosystem/grpc-gateway commit hash to 4c0eb48d8af04ffff04a53a6824ac625f0f62945. --- repositories.bzl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/repositories.bzl b/repositories.bzl index a5b356f..db7a589 100644 --- a/repositories.bzl +++ b/repositories.bzl @@ -30,9 +30,9 @@ def go_repositories(): name = "com_github_grpc_ecosystem_grpc_gateway", importpath = "github.com/grpc-ecosystem/grpc-gateway", urls = [ - "https://codeload.github.com/grpc-ecosystem/grpc-gateway/tar.gz/5c1639cccb7d6abc747643ed07321b0052b809d5", + "https://codeload.github.com/grpc-ecosystem/grpc-gateway/tar.gz/4c0eb48d8af04ffff04a53a6824ac625f0f62945", ], - strip_prefix = "grpc-gateway-5c1639cccb7d6abc747643ed07321b0052b809d5", + strip_prefix = "grpc-gateway-4c0eb48d8af04ffff04a53a6824ac625f0f62945", type = "tar.gz", ) go_repository( From cfc1ede402dccb86a963dce1c14921b09023cd1d Mon Sep 17 00:00:00 2001 From: binchen Date: Thu, 29 Oct 2020 16:33:29 +0800 Subject: [PATCH 27/56] Format BUILD.bazel, Sync from github.com/grpc-ecosystem/grpc-gateway on master branch. --- .bazelversion | 1 + .goreleaser.yml | 10 +++++----- BUILD | 1 + gateway/internal/descriptor/BUILD.bazel | 6 +++--- .../internal/gengateway/BUILD.bazel | 2 +- gateway/runtime/BUILD.bazel | 2 +- gateway/runtime/internal/examplepb/BUILD.bazel | 1 + 7 files changed, 13 insertions(+), 10 deletions(-) create mode 100644 .bazelversion diff --git a/.bazelversion b/.bazelversion new file mode 100644 index 0000000..1545d96 --- /dev/null +++ b/.bazelversion @@ -0,0 +1 @@ +3.5.0 diff --git a/.goreleaser.yml b/.goreleaser.yml index 7987166..02aad00 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -21,9 +21,9 @@ builds: - windows goarch: - amd64 -archive: - name_template: "{{ .Binary }}-{{ .Tag }}-{{ .Os }}-{{ .Arch }}" - format: binary - replacements: - amd64: x86_64 +archives: + - name_template: "{{ .Binary }}-{{ .Tag }}-{{ .Os }}-{{ .Arch }}" + format: binary + replacements: + amd64: x86_64 dist: _output diff --git a/BUILD b/BUILD index c76517b..8d283d0 100644 --- a/BUILD +++ b/BUILD @@ -58,6 +58,7 @@ go_proto_compiler( name = "go_grpc", options = [ "paths=source_relative", + "require_unimplemented_servers=false", ], plugin = "@org_golang_google_grpc_cmd_protoc_gen_go_grpc//:protoc-gen-go-grpc", suffix = "_grpc.pb.go", diff --git a/gateway/internal/descriptor/BUILD.bazel b/gateway/internal/descriptor/BUILD.bazel index 2b766e2..9a9269c 100644 --- a/gateway/internal/descriptor/BUILD.bazel +++ b/gateway/internal/descriptor/BUILD.bazel @@ -14,9 +14,9 @@ go_library( importpath = "github.com/binchencoder/ease-gateway/gateway/internal/descriptor", deps = [ "//gateway/internal/casing:go_default_library", - "//gateway/internal/descriptor/apiconfig:go_default_library", - "//gateway/internal/descriptor/openapiconfig:go_default_library", - "//gateway/protoc-gen-openapiv2/options:go_default_library", + "//gateway/internal/descriptor/apiconfig:go_default_library", + "//gateway/internal/descriptor/openapiconfig:go_default_library", + "//gateway/protoc-gen-openapiv2/options:go_default_library", "//httpoptions:go_default_library", "@com_github_binchencoder_gateway_proto//data:go_default_library", "@com_github_ghodss_yaml//:go_default_library", diff --git a/gateway/protoc-gen-grpc-gateway/internal/gengateway/BUILD.bazel b/gateway/protoc-gen-grpc-gateway/internal/gengateway/BUILD.bazel index 665a4bb..2e868bb 100644 --- a/gateway/protoc-gen-grpc-gateway/internal/gengateway/BUILD.bazel +++ b/gateway/protoc-gen-grpc-gateway/internal/gengateway/BUILD.bazel @@ -31,7 +31,7 @@ go_test( ], embed = [":go_default_library"], deps = [ - "//gateway/internal/descriptor:go_default_library", + "//gateway/internal/descriptor:go_default_library", "@com_github_grpc_ecosystem_grpc_gateway//internal/httprule:go_default_library", "@org_golang_google_protobuf//proto:go_default_library", "@org_golang_google_protobuf//types/descriptorpb:go_default_library", diff --git a/gateway/runtime/BUILD.bazel b/gateway/runtime/BUILD.bazel index 1d6c372..9351e00 100644 --- a/gateway/runtime/BUILD.bazel +++ b/gateway/runtime/BUILD.bazel @@ -85,6 +85,6 @@ go_test( "@org_golang_google_protobuf//proto:go_default_library", "@org_golang_google_protobuf//testing/protocmp:go_default_library", "@org_golang_google_grpc//:go_default_library", - "@org_golang_x_net//context:go_default_library", + "@org_golang_x_net//context:go_default_library", ], ) diff --git a/gateway/runtime/internal/examplepb/BUILD.bazel b/gateway/runtime/internal/examplepb/BUILD.bazel index dbd8d9a..c6f1a1d 100644 --- a/gateway/runtime/internal/examplepb/BUILD.bazel +++ b/gateway/runtime/internal/examplepb/BUILD.bazel @@ -15,6 +15,7 @@ proto_library( "@com_google_protobuf//:duration_proto", "@com_google_protobuf//:empty_proto", "@com_google_protobuf//:field_mask_proto", + "@com_google_protobuf//:struct_proto", "@com_google_protobuf//:timestamp_proto", "@com_google_protobuf//:wrappers_proto", "@go_googleapis//google/api:annotations_proto", From e25b87d2ab13fd799cde95abaeea77f0c0df1006 Mon Sep 17 00:00:00 2001 From: binchen Date: Thu, 29 Oct 2020 17:37:35 +0800 Subject: [PATCH 28/56] Rename package, add examples/internal/integration/main_test.go. --- .bazelci/presubmit.yml | 32 +++++ .gitignore | 3 + cmd/custom-gateway/BUILD.bazel | 2 +- cmd/custom-gateway/registrydemo.go | 2 +- examples/{ => internal}/README.md | 0 .../cmd/example-gateway-server/BUILD.bazel | 4 +- .../cmd/example-gateway-server/main.go | 6 +- .../cmd/example-grpc-server/BUILD.bazel | 6 +- .../cmd/example-grpc-server/main.go | 4 +- .../cmd/grpc-server/BUILD.bazel | 2 +- .../{ => internal}/cmd/grpc-server/echo.go | 0 .../{ => internal}/cmd/grpc-server/main.go | 0 examples/{ => internal}/gateway/BUILD.bazel | 4 +- examples/{ => internal}/gateway/doc.go | 0 examples/{ => internal}/gateway/gateway.go | 25 ++-- examples/{ => internal}/gateway/handlers.go | 10 +- examples/{ => internal}/gateway/main.go | 12 +- examples/internal/integration/BUILD.bazel | 25 ++++ examples/internal/integration/main_test.go | 100 ++++++++++++++++ examples/internal/proto/examplepb/BUILD.bazel | 113 ++++++++++++++++++ .../proto/examplepb}/echo_service.pb.go | 2 +- .../proto/examplepb}/echo_service.pb.gw.go | 2 +- .../proto/examplepb}/echo_service.proto | 30 ++++- .../examplepb}/echo_service.swagger.json | 2 +- .../proto/examplepb}/echo_service_grpc.pb.go | 2 +- .../proto/examplepb/generated_input.proto | 20 ++++ examples/internal/server/BUILD.bazel | 31 +++++ examples/{ => internal}/server/echo.go | 10 +- examples/internal/server/main.go | 61 ++++++++++ examples/proto/BUILD.bazel | 64 ---------- examples/server/BUILD.bazel | 18 --- examples/server/main.go | 33 ----- gateway/runtime/BUILD.bazel | 2 +- gateway/runtime/handler_test.go | 2 +- proto/examples/echo_service.pb.go | 2 +- proto/examples/echo_service.pb.gw.go | 2 +- proto/examples/echo_service.swagger.json | 2 +- proto/examples/echo_service_grpc.pb.go | 2 +- proto/examples/pom.xml | 4 +- repositories.bzl | 7 ++ 40 files changed, 475 insertions(+), 173 deletions(-) create mode 100644 .bazelci/presubmit.yml rename examples/{ => internal}/README.md (100%) rename examples/{ => internal}/cmd/example-gateway-server/BUILD.bazel (83%) rename examples/{ => internal}/cmd/example-gateway-server/main.go (74%) rename examples/{ => internal}/cmd/example-grpc-server/BUILD.bazel (80%) rename examples/{ => internal}/cmd/example-grpc-server/main.go (86%) rename examples/{ => internal}/cmd/grpc-server/BUILD.bazel (95%) rename examples/{ => internal}/cmd/grpc-server/echo.go (100%) rename examples/{ => internal}/cmd/grpc-server/main.go (100%) rename examples/{ => internal}/gateway/BUILD.bazel (87%) rename examples/{ => internal}/gateway/doc.go (100%) rename examples/{ => internal}/gateway/gateway.go (65%) rename examples/{ => internal}/gateway/handlers.go (85%) rename examples/{ => internal}/gateway/main.go (85%) create mode 100644 examples/internal/integration/BUILD.bazel create mode 100644 examples/internal/integration/main_test.go create mode 100644 examples/internal/proto/examplepb/BUILD.bazel rename examples/{proto => internal/proto/examplepb}/echo_service.pb.go (99%) rename examples/{proto => internal/proto/examplepb}/echo_service.pb.gw.go (99%) rename examples/{proto => internal/proto/examplepb}/echo_service.proto (68%) rename examples/{proto => internal/proto/examplepb}/echo_service.swagger.json (99%) rename examples/{proto => internal/proto/examplepb}/echo_service_grpc.pb.go (98%) create mode 100644 examples/internal/proto/examplepb/generated_input.proto create mode 100644 examples/internal/server/BUILD.bazel rename examples/{ => internal}/server/echo.go (74%) create mode 100644 examples/internal/server/main.go delete mode 100644 examples/proto/BUILD.bazel delete mode 100644 examples/server/BUILD.bazel delete mode 100644 examples/server/main.go diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml new file mode 100644 index 0000000..a0da2fc --- /dev/null +++ b/.bazelci/presubmit.yml @@ -0,0 +1,32 @@ +--- +platforms: + ubuntu1804: + build_flags: + - "--build_tag_filters=-nolinux" + build_targets: + - "..." + test_flags: + - "--features=race" + - "--test_tag_filters=-nolinux" + test_targets: + - "..." + ubuntu1604: + build_flags: + - "--build_tag_filters=-nolinux" + build_targets: + - "..." + test_flags: + - "--features=race" + - "--test_tag_filters=-nolinux" + test_targets: + - "..." + macos: + build_flags: + - "--build_tag_filters=-nomacos" + build_targets: + - "..." + test_flags: + - "--features=race" + - "--test_tag_filters=-nomacos" + test_targets: + - "..." diff --git a/.gitignore b/.gitignore index 9bb694f..649d93d 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,6 @@ bin/ # Java files *.exe target/ + +# vscode +.vscode/ diff --git a/cmd/custom-gateway/BUILD.bazel b/cmd/custom-gateway/BUILD.bazel index a98d5c1..3215f79 100644 --- a/cmd/custom-gateway/BUILD.bazel +++ b/cmd/custom-gateway/BUILD.bazel @@ -15,7 +15,7 @@ go_library( ], importpath = "github.com/binchencoder/ease-gateway/cmd/custom-gateway", deps = [ - "//examples/proto:go_default_library", + "//examples/internal/proto/examplepb:go_default_library", "//gateway/runtime:go_default_library", "//integrate:go_default_library", "@com_github_binchencoder_gateway_proto//data:go_default_library", diff --git a/cmd/custom-gateway/registrydemo.go b/cmd/custom-gateway/registrydemo.go index 19dc9c1..af7e752 100755 --- a/cmd/custom-gateway/registrydemo.go +++ b/cmd/custom-gateway/registrydemo.go @@ -2,5 +2,5 @@ package main // Import so that applications register themselves to gateway. import ( - _ "github.com/binchencoder/ease-gateway/examples/proto" + _ "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb" ) diff --git a/examples/README.md b/examples/internal/README.md similarity index 100% rename from examples/README.md rename to examples/internal/README.md diff --git a/examples/cmd/example-gateway-server/BUILD.bazel b/examples/internal/cmd/example-gateway-server/BUILD.bazel similarity index 83% rename from examples/cmd/example-gateway-server/BUILD.bazel rename to examples/internal/cmd/example-gateway-server/BUILD.bazel index 066cd18..c5df729 100644 --- a/examples/cmd/example-gateway-server/BUILD.bazel +++ b/examples/internal/cmd/example-gateway-server/BUILD.bazel @@ -3,10 +3,10 @@ load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library") go_library( name = "go_default_library", srcs = ["main.go"], - importpath = "github.com/binchencoder/ease-gateway/examples/cmd/example-gateway-server", + importpath = "github.com/binchencoder/ease-gateway/examples/internal/cmd/example-gateway-server", visibility = ["//visibility:private"], deps = [ - "//examples/gateway:go_default_library", + "//examples/internal/gateway:go_default_library", "//gateway/runtime:go_default_library", "@com_github_golang_glog//:go_default_library", ], diff --git a/examples/cmd/example-gateway-server/main.go b/examples/internal/cmd/example-gateway-server/main.go similarity index 74% rename from examples/cmd/example-gateway-server/main.go rename to examples/internal/cmd/example-gateway-server/main.go index 1cbf62c..313bd51 100644 --- a/examples/cmd/example-gateway-server/main.go +++ b/examples/internal/cmd/example-gateway-server/main.go @@ -8,14 +8,14 @@ import ( "context" "flag" - "github.com/binchencoder/ease-gateway/examples/gateway" "github.com/golang/glog" + "github.com/binchencoder/ease-gateway/examples/internal/gateway" ) var ( endpoint = flag.String("endpoint", "localhost:9090", "endpoint of the gRPC service") network = flag.String("network", "tcp", `one of "tcp" or "unix". Must be consistent to -endpoint`) - swaggerDir = flag.String("swagger_dir", "examples/proto/", "path to the directory which contains swagger definitions") + openAPIDir = flag.String("openapi_dir", "examples/internal/proto/examplepb", "path to the directory which contains OpenAPI definitions") ) func main() { @@ -29,7 +29,7 @@ func main() { Network: *network, Addr: *endpoint, }, - SwaggerDir: *swaggerDir, + OpenAPIDir: *openAPIDir, } if err := gateway.Run(ctx, opts); err != nil { glog.Fatal(err) diff --git a/examples/cmd/example-grpc-server/BUILD.bazel b/examples/internal/cmd/example-grpc-server/BUILD.bazel similarity index 80% rename from examples/cmd/example-grpc-server/BUILD.bazel rename to examples/internal/cmd/example-grpc-server/BUILD.bazel index 1c63a55..2c690d0 100644 --- a/examples/cmd/example-grpc-server/BUILD.bazel +++ b/examples/internal/cmd/example-grpc-server/BUILD.bazel @@ -5,10 +5,10 @@ package(default_visibility = ["//visibility:private"]) go_library( name = "go_default_library", srcs = ["main.go"], - importpath = "github.com/binchencoder/ease-gateway/examples/cmd/example-grpc-server", + importpath = "github.com/binchencoder/ease-gateway/examples/internal/cmd/example-grpc-server", deps = [ - "//examples/proto:go_default_library", - "//examples/server:go_default_library", + "//examples/internal/proto/examplepb:go_default_library", + "//examples/internal/server:go_default_library", "@com_github_binchencoder_gateway_proto//data:go_default_library", "@com_github_binchencoder_skylb_api//server:go_default_library", "@com_github_golang_glog//:go_default_library", diff --git a/examples/cmd/example-grpc-server/main.go b/examples/internal/cmd/example-grpc-server/main.go similarity index 86% rename from examples/cmd/example-grpc-server/main.go rename to examples/internal/cmd/example-grpc-server/main.go index ec93493..79d17b0 100644 --- a/examples/cmd/example-grpc-server/main.go +++ b/examples/internal/cmd/example-grpc-server/main.go @@ -8,8 +8,8 @@ import ( "context" "flag" - // examples "github.com/binchencoder/ease-gateway/examples/proto" - "github.com/binchencoder/ease-gateway/examples/server" + // examples "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb" + "github.com/binchencoder/ease-gateway/examples/internal/server" // "github.com/binchencoder/gateway-proto/data" // skylb "github.com/binchencoder/skylb-api/server" "github.com/golang/glog" diff --git a/examples/cmd/grpc-server/BUILD.bazel b/examples/internal/cmd/grpc-server/BUILD.bazel similarity index 95% rename from examples/cmd/grpc-server/BUILD.bazel rename to examples/internal/cmd/grpc-server/BUILD.bazel index bd75490..493438a 100644 --- a/examples/cmd/grpc-server/BUILD.bazel +++ b/examples/internal/cmd/grpc-server/BUILD.bazel @@ -8,7 +8,7 @@ go_library( "main.go", "echo.go", ], - importpath = "github.com/binchencoder/ease-gateway/examples/cmd/custom-grpc-server", + importpath = "github.com/binchencoder/ease-gateway/examples/internal/cmd/custom-grpc-server", deps = [ "//proto/examples:go_default_library", "@com_github_binchencoder_gateway_proto//data:go_default_library", diff --git a/examples/cmd/grpc-server/echo.go b/examples/internal/cmd/grpc-server/echo.go similarity index 100% rename from examples/cmd/grpc-server/echo.go rename to examples/internal/cmd/grpc-server/echo.go diff --git a/examples/cmd/grpc-server/main.go b/examples/internal/cmd/grpc-server/main.go similarity index 100% rename from examples/cmd/grpc-server/main.go rename to examples/internal/cmd/grpc-server/main.go diff --git a/examples/gateway/BUILD.bazel b/examples/internal/gateway/BUILD.bazel similarity index 87% rename from examples/gateway/BUILD.bazel rename to examples/internal/gateway/BUILD.bazel index 927e73c..d0712e2 100644 --- a/examples/gateway/BUILD.bazel +++ b/examples/internal/gateway/BUILD.bazel @@ -8,10 +8,10 @@ go_library( "handlers.go", "main.go", ], - importpath = "github.com/binchencoder/ease-gateway/examples/gateway", + importpath = "github.com/binchencoder/ease-gateway/examples/internal/gateway", visibility = ["//visibility:public"], deps = [ - "//examples/proto:go_default_library", + "//examples/internal/proto/examplepb:go_default_library", "//gateway/runtime:go_default_library", "//util:go_default_library", "@com_github_golang_glog//:go_default_library", diff --git a/examples/gateway/doc.go b/examples/internal/gateway/doc.go similarity index 100% rename from examples/gateway/doc.go rename to examples/internal/gateway/doc.go diff --git a/examples/gateway/gateway.go b/examples/internal/gateway/gateway.go similarity index 65% rename from examples/gateway/gateway.go rename to examples/internal/gateway/gateway.go index 92c64ea..f58921b 100644 --- a/examples/gateway/gateway.go +++ b/examples/internal/gateway/gateway.go @@ -5,17 +5,16 @@ import ( "fmt" "net" "net/http" - "time" - "github.com/binchencoder/ease-gateway/examples/proto" - "github.com/binchencoder/ease-gateway/gateway/runtime" + "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb" + gwruntime "github.com/binchencoder/ease-gateway/gateway/runtime" "google.golang.org/grpc" ) // newGateway returns a new gateway server which translates HTTP into gRPC. -func newGateway(ctx context.Context, conn *grpc.ClientConn, opts []runtime.ServeMuxOption) (http.Handler, error) { - sgs := runtime.GetServicGroups() - fmt.Printf("runtime.GetServicGroups: %v", sgs) +func newGateway(ctx context.Context, conn *grpc.ClientConn, opts []gwruntime.ServeMuxOption) (http.Handler, error) { + sgs := gwruntime.GetServicGroups() + fmt.Printf("gwruntime.GetServicGroups: %v", sgs) for _, sg := range sgs { go sg.Enable() spec := sg.Spec @@ -23,11 +22,11 @@ func newGateway(ctx context.Context, conn *grpc.ClientConn, opts []runtime.Serve spec.ServiceName, spec.Namespace, spec.PortName) } - mux := runtime.NewServeMux(opts...) + mux := gwruntime.NewServeMux(opts...) - // proto.Enable_CUSTOM_EASE_GATEWAY_TEST__default__grpc_ServiceGroup() - for _, f := range []func(context.Context, *runtime.ServeMux, *grpc.ClientConn) error{ - proto.RegisterEchoServiceHandler, + // examplepb.Enable_CUSTOM_EASE_GATEWAY_TEST__default__grpc_ServiceGroup() + for _, f := range []func(context.Context, *gwruntime.ServeMux, *grpc.ClientConn) error{ + examplepb.RegisterEchoServiceHandler, } { if err := f(ctx, mux, conn); err != nil { return nil, err @@ -56,8 +55,8 @@ func dialTCP(ctx context.Context, addr string) (*grpc.ClientConn, error) { // dialUnix creates a client connection via a unix domain socket. // "addr" must be a valid path to the socket. func dialUnix(ctx context.Context, addr string) (*grpc.ClientConn, error) { - d := func(addr string, timeout time.Duration) (net.Conn, error) { - return net.DialTimeout("unix", addr, timeout) + d := func(ctx context.Context, addr string) (net.Conn, error) { + return (&net.Dialer{}).DialContext(ctx, "unix", addr) } - return grpc.DialContext(ctx, addr, grpc.WithInsecure(), grpc.WithDialer(d)) + return grpc.DialContext(ctx, addr, grpc.WithInsecure(), grpc.WithContextDialer(d)) } diff --git a/examples/gateway/handlers.go b/examples/internal/gateway/handlers.go similarity index 85% rename from examples/gateway/handlers.go rename to examples/internal/gateway/handlers.go index ceb3839..1f617b1 100644 --- a/examples/gateway/handlers.go +++ b/examples/internal/gateway/handlers.go @@ -11,8 +11,8 @@ import ( "google.golang.org/grpc/connectivity" ) -// swaggerServer returns swagger specification files located under "/swagger/" -func swaggerServer(dir string) http.HandlerFunc { +// openAPIServer returns OpenAPI specification files located under "/openapiv2/" +func openAPIServer(dir string) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if !strings.HasSuffix(r.URL.Path, ".swagger.json") { glog.Errorf("Not Found: %s", r.URL.Path) @@ -21,10 +21,8 @@ func swaggerServer(dir string) http.HandlerFunc { } glog.Infof("Serving %s", r.URL.Path) - p := strings.TrimPrefix(r.URL.Path, "/swagger/") - fmt.Printf("serve file trim path: %s\n", p) + p := strings.TrimPrefix(r.URL.Path, "/openapiv2/") p = path.Join(dir, p) - fmt.Printf("serve file join path: %s\n", p) http.ServeFile(w, r, p) } } @@ -48,7 +46,7 @@ func allowCORS(h http.Handler) http.Handler { // CORS from any origin using the methods "GET", "HEAD", "POST", "PUT", "DELETE" // We insist, don't do this without consideration in production systems. func preflightHandler(w http.ResponseWriter, r *http.Request) { - headers := []string{"Content-Type", "Accept"} + headers := []string{"Content-Type", "Accept", "Authorization"} w.Header().Set("Access-Control-Allow-Headers", strings.Join(headers, ",")) methods := []string{"GET", "HEAD", "POST", "PUT", "DELETE"} w.Header().Set("Access-Control-Allow-Methods", strings.Join(methods, ",")) diff --git a/examples/gateway/main.go b/examples/internal/gateway/main.go similarity index 85% rename from examples/gateway/main.go rename to examples/internal/gateway/main.go index b981ebb..8d4f3cd 100644 --- a/examples/gateway/main.go +++ b/examples/internal/gateway/main.go @@ -5,7 +5,7 @@ import ( "net/http" "github.com/golang/glog" - "github.com/binchencoder/ease-gateway/gateway/runtime" + gwruntime "github.com/binchencoder/ease-gateway/gateway/runtime" ) // Endpoint describes a gRPC endpoint @@ -21,12 +21,12 @@ type Options struct { // GRPCServer defines an endpoint of a gRPC service GRPCServer Endpoint - // SwaggerDir is a path to a directory from which the server - // serves swagger specs. - SwaggerDir string + // OpenAPIDir is a path to a directory from which the server + // serves OpenAPI specs. + OpenAPIDir string // Mux is a list of options to be passed to the grpc-gateway multiplexer - Mux []runtime.ServeMuxOption + Mux []gwruntime.ServeMuxOption } // Run starts a HTTP server and blocks while running if successful. @@ -47,7 +47,7 @@ func Run(ctx context.Context, opts Options) error { }() mux := http.NewServeMux() - mux.HandleFunc("/swagger/", swaggerServer(opts.SwaggerDir)) + mux.HandleFunc("/openapiv2/", openAPIServer(opts.OpenAPIDir)) mux.HandleFunc("/healthz", healthzServer(conn)) gw, err := newGateway(ctx, conn, opts.Mux) diff --git a/examples/internal/integration/BUILD.bazel b/examples/internal/integration/BUILD.bazel new file mode 100644 index 0000000..0c6289a --- /dev/null +++ b/examples/internal/integration/BUILD.bazel @@ -0,0 +1,25 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_test") + +go_test( + name = "go_default_test", + srcs = [ + "main_test.go", + ], + deps = [ + "//examples/internal/gateway:go_default_library", + "//examples/internal/proto/examplepb:go_default_library", + "//examples/internal/server:go_default_library", + "//gateway/runtime:go_default_library", + "//httpoptions:go_default_library", + "@com_github_golang_glog//:go_default_library", + "@com_github_google_go_cmp//cmp:go_default_library", + "@go_googleapis//google/rpc:status_go_proto", + "@io_bazel_rules_go//proto/wkt:empty_go_proto", + "@io_bazel_rules_go//proto/wkt:field_mask_go_proto", + "@org_golang_google_grpc//codes:go_default_library", + "@org_golang_google_protobuf//encoding/protojson:go_default_library", + "@org_golang_google_protobuf//proto:go_default_library", + "@org_golang_google_protobuf//testing/protocmp:go_default_library", + "@org_golang_google_protobuf//types/known/structpb:go_default_library", + ], +) diff --git a/examples/internal/integration/main_test.go b/examples/internal/integration/main_test.go new file mode 100644 index 0000000..e795158 --- /dev/null +++ b/examples/internal/integration/main_test.go @@ -0,0 +1,100 @@ +package integration_test + +import ( + "context" + "flag" + "fmt" + "net/http" + "os" + "testing" + "time" + + "github.com/golang/glog" + "github.com/binchencoder/ease-gateway/examples/internal/gateway" + server "github.com/binchencoder/ease-gateway/examples/internal/server" + gwruntime "github.com/binchencoder/ease-gateway/gateway/runtime" +) + +var ( + endpoint = flag.String("endpoint", "localhost:9090", "endpoint of the gRPC service") + network = flag.String("network", "tcp", `one of "tcp" or "unix". Must be consistent to -endpoint`) + openAPIDir = flag.String("openapi_dir", "examples/internal/proto/examplepb", "path to the directory which contains OpenAPI definitions") +) + +func runGateway(ctx context.Context, addr string, opts ...gwruntime.ServeMuxOption) error { + return gateway.Run(ctx, gateway.Options{ + Addr: addr, + GRPCServer: gateway.Endpoint{ + Network: *network, + Addr: *endpoint, + }, + OpenAPIDir: *openAPIDir, + Mux: opts, + }) +} + +func waitForGateway(ctx context.Context, port uint16) error { + ch := time.After(10 * time.Second) + + for { + r, err := http.Get(fmt.Sprintf("http://localhost:%d/healthz", port)) + if err == nil && r.StatusCode == http.StatusOK { + return nil + } + + glog.Infof("Waiting for localhost:%d to get ready", port) + select { + case <-ctx.Done(): + return err + case <-ch: + return err + case <-time.After(10 * time.Millisecond): + } + } +} + +func runServers(ctx context.Context) <-chan error { + ch := make(chan error, 3) + go func() { + if err := server.Run(ctx, *network, *endpoint); err != nil { + ch <- fmt.Errorf("cannot run grpc service: %v", err) + } + }() + go func() { + if err := runGateway(ctx, ":8088"); err != nil { + ch <- fmt.Errorf("cannot run gateway service: %v", err) + } + }() + go func() { + if err := server.RunInProcessGateway(ctx, ":8089"); err != nil { + ch <- fmt.Errorf("cannot run in process gateway service: %v", err) + } + }() + return ch +} + +func TestMain(m *testing.M) { + flag.Parse() + defer glog.Flush() + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + errCh := runServers(ctx) + + ch := make(chan int, 1) + go func() { + if err := waitForGateway(ctx, 8088); err != nil { + glog.Errorf("waitForGateway(ctx, 8088) failed with %v; want success", err) + } + ch <- m.Run() + }() + + select { + case err := <-errCh: + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + case status := <-ch: + cancel() + os.Exit(status) + } +} diff --git a/examples/internal/proto/examplepb/BUILD.bazel b/examples/internal/proto/examplepb/BUILD.bazel new file mode 100644 index 0000000..df609cb --- /dev/null +++ b/examples/internal/proto/examplepb/BUILD.bazel @@ -0,0 +1,113 @@ +load("@rules_proto//proto:defs.bzl", "proto_library") +load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@com_github_binchencoder_ease_gateway//gateway/protoc-gen-openapiv2:defs.bzl", "protoc_gen_openapiv2") + +package(default_visibility = ["//visibility:public"]) + +# TODO(yannic): Add examples/tests that use import_prefix/strip_import_prefix. + +# gazelle:exclude a_bit_of_everything.pb.gw.go +# gazelle:exclude a_bit_of_everything_grpc.pb.go +# gazelle:exclude echo_service.pb.gw.go +# gazelle:exclude echo_service_grpc.pb.go +# gazelle:exclude flow_combination.pb.gw.go +# gazelle:exclude flow_combination_grpc.pb.go +# gazelle:exclude generate_unbound_methods.pb.gw.go +# gazelle:exclude generate_unbound_methods_grpc.pb.go +# gazelle:exclude generated_input.proto +# gazelle:exclude non_standard_names.pb.gw.go +# gazelle:exclude non_standard_names_grpc.pb.go +# gazelle:exclude response_body_service.pb.gw.go +# gazelle:exclude response_body_service_grpc.pb.go +# gazelle:exclude stream.pb.gw.go +# gazelle:exclude stream_grpc.pb.go +# gazelle:exclude use_go_template.pb.gw.go +# gazelle:exclude use_go_template_grpc.pb.go +# gazelle:exclude wrappers.pb.gw.go +# gazelle:exclude wrappers_grpc.pb.go +# gazelle:exclude unannotated_echo_service.pb.gw.go +# gazelle:exclude unannotated_echo_service_grpc.pb.go +# gazelle:exclude openapi_merge_a.proto +# gazelle:exclude openapi_merge_b.proto +# gazelle:go_grpc_compilers //:go_apiv2, //:go_grpc, //protoc-gen-grpc-gateway:go_gen_grpc_gateway + +genrule( + name = "generated_proto", + srcs = ["generated_input.proto"], + outs = ["generated_output.proto"], + cmd = "cp $< $@", # A simple copy simulates a generated proto file. +) + +proto_library( + name = "examplepb_proto", + srcs = [ + "echo_service.proto", + ], + deps = [ + "//httpoptions:options_proto", + "@com_github_binchencoder_gateway_proto//data:data_proto", + "@com_github_binchencoder_gateway_proto//frontend:error_proto", + "@com_google_protobuf//:duration_proto", + "@com_google_protobuf//:empty_proto", + "@com_google_protobuf//:field_mask_proto", + "@com_google_protobuf//:struct_proto", + "@com_google_protobuf//:timestamp_proto", + "@com_google_protobuf//:wrappers_proto", + "@go_googleapis//google/api:annotations_proto", + "@go_googleapis//google/api:httpbody_proto", + "@go_googleapis//google/rpc:status_proto", + ], +) + +go_proto_library( + name = "examplepb_go_proto", + compilers = [ + "//:go_apiv2", + "//:go_grpc", + "//gateway/protoc-gen-grpc-gateway:go_gen_grpc_gateway", # keep + ], + importpath = "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb", + proto = ":examplepb_proto", + deps = [ + "//httpoptions:go_default_library", + "@com_github_binchencoder_letsgo//grpc:go_default_library", + "@com_github_binchencoder_skylb_api//balancer:go_default_library", + "@com_github_binchencoder_skylb_api//client:go_default_library", + "@com_github_binchencoder_skylb_api//client/option:go_default_library", + "@com_github_binchencoder_skylb_api//proto:go_default_library", + "//gateway/protoc-gen-openapiv2/options:go_default_library", + "@com_github_golang_protobuf//descriptor:go_default_library_gen", # keep + "@go_googleapis//google/api:annotations_go_proto", + "@go_googleapis//google/api:httpbody_go_proto", + "@go_googleapis//google/rpc:status_go_proto", + "@org_golang_google_protobuf//proto:go_default_library", # keep + "@org_golang_google_grpc//naming:go_default_library", + ], +) + +go_library( + name = "go_default_library", + embed = [":examplepb_go_proto"], + importpath = "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb", + deps = [ + "//httpoptions:go_default_library", + "//gateway/runtime:go_default_library", + "@com_github_binchencoder_gateway_proto//data:go_default_library", + "@com_github_binchencoder_gateway_proto//frontend:go_default_library", + "@com_github_binchencoder_skylb_api//balancer:go_default_library", + "@com_github_binchencoder_skylb_api//client:go_default_library", + ], +) + + +protoc_gen_openapiv2( + name = "examplepb_protoc_gen_openapiv2", + proto = ":examplepb_proto", +) + +protoc_gen_openapiv2( + name = "examplepb_protoc_gen_openapiv2_merged", + proto = ":examplepb_proto", + single_output = True, # Outputs a single swagger.json file. +) \ No newline at end of file diff --git a/examples/proto/echo_service.pb.go b/examples/internal/proto/examplepb/echo_service.pb.go similarity index 99% rename from examples/proto/echo_service.pb.go rename to examples/internal/proto/examplepb/echo_service.pb.go index e78df51..698286a 100755 --- a/examples/proto/echo_service.pb.go +++ b/examples/internal/proto/examplepb/echo_service.pb.go @@ -2,7 +2,7 @@ // versions: // protoc-gen-go v1.22.0 // protoc v3.8.0 -// source: examples/proto/echo_service.proto +// source: examples/internal/proto/examplepb/echo_service.proto package proto diff --git a/examples/proto/echo_service.pb.gw.go b/examples/internal/proto/examplepb/echo_service.pb.gw.go similarity index 99% rename from examples/proto/echo_service.pb.gw.go rename to examples/internal/proto/examplepb/echo_service.pb.gw.go index 42bec24..0bceda2 100755 --- a/examples/proto/echo_service.pb.gw.go +++ b/examples/internal/proto/examplepb/echo_service.pb.gw.go @@ -1,5 +1,5 @@ // Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. -// source: examples/proto/echo_service.proto +// source: examples/internal/proto/examplepb/echo_service.proto /* Package proto is a reverse proxy. diff --git a/examples/proto/echo_service.proto b/examples/internal/proto/examplepb/echo_service.proto similarity index 68% rename from examples/proto/echo_service.proto rename to examples/internal/proto/examplepb/echo_service.proto index 68c0edf..3cf3962 100644 --- a/examples/proto/echo_service.proto +++ b/examples/internal/proto/examplepb/echo_service.proto @@ -1,11 +1,16 @@ syntax = "proto3"; +option go_package = "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb"; -option go_package = "github.com/binchencoder/ease-gateway/examples/proto"; - -package grpc.gateway.examples.proto; +// Echo Service +// +// Echo Service API consists of a single service which returns +// a message. +package grpc.gateway.examples.internal.proto.examplepb; // import "google/api/annotations.proto"; import "httpoptions/annotations.proto"; +import "google/protobuf/field_mask.proto"; +import "google/protobuf/struct.proto"; // Embedded represents a message embedded in SimpleMessage. message Embedded { @@ -31,6 +36,18 @@ message SimpleMessage { } } +// DynamicMessage represents a message which can have its structure +// built dynamically using Struct and Values. +message DynamicMessage { + google.protobuf.Struct struct_field = 1; + google.protobuf.Value value_field = 2; +} + +message DynamicMessageUpdate { + DynamicMessage body = 1; + google.protobuf.FieldMask update_mask = 2; +} + // Echo service responds to incoming echo requests. service EchoService { option (ease.api.service_spec) = { @@ -74,4 +91,11 @@ service EchoService { delete: "/v1/example/echo_delete" }; } + // EchoPatch method receives a NonStandardUpdateRequest and returns it. + rpc EchoPatch(DynamicMessageUpdate) returns (DynamicMessageUpdate) { + option (ease.api.http) = { + patch: "/v1/example/echo_patch" + body: "body" + }; + } } diff --git a/examples/proto/echo_service.swagger.json b/examples/internal/proto/examplepb/echo_service.swagger.json similarity index 99% rename from examples/proto/echo_service.swagger.json rename to examples/internal/proto/examplepb/echo_service.swagger.json index 1e37053..7c903c1 100755 --- a/examples/proto/echo_service.swagger.json +++ b/examples/internal/proto/examplepb/echo_service.swagger.json @@ -1,7 +1,7 @@ { "swagger": "2.0", "info": { - "title": "examples/proto/echo_service.proto", + "title": "examples/internal/proto/examplepb/echo_service.proto", "version": "version not set" }, "consumes": [ diff --git a/examples/proto/echo_service_grpc.pb.go b/examples/internal/proto/examplepb/echo_service_grpc.pb.go similarity index 98% rename from examples/proto/echo_service_grpc.pb.go rename to examples/internal/proto/examplepb/echo_service_grpc.pb.go index 95e61da..1840d71 100755 --- a/examples/proto/echo_service_grpc.pb.go +++ b/examples/internal/proto/examplepb/echo_service_grpc.pb.go @@ -154,5 +154,5 @@ var _EchoService_serviceDesc = grpc.ServiceDesc{ }, }, Streams: []grpc.StreamDesc{}, - Metadata: "examples/proto/echo_service.proto", + Metadata: "examples/internal/proto/examplepb/echo_service.proto", } diff --git a/examples/internal/proto/examplepb/generated_input.proto b/examples/internal/proto/examplepb/generated_input.proto new file mode 100644 index 0000000..bd4ab5f --- /dev/null +++ b/examples/internal/proto/examplepb/generated_input.proto @@ -0,0 +1,20 @@ +syntax = "proto3"; +option go_package = "github.com/grpc-ecosystem/grpc-gateway/v2/examples/internal/proto/examplepb"; +package grpc.gateway.examples.internal.proto.examplepb; + +import "google/api/annotations.proto"; +import "google/protobuf/empty.proto"; +import "examples/internal/proto/examplepb/a_bit_of_everything.proto"; + +// This file is run through a genrule. + +// Defines some more operations to be added to ABitOfEverythingService +service GeneratedService { + rpc Create(ABitOfEverything) returns (google.protobuf.Empty) { + option (google.api.http) = { + post: "/v1/example/a_bit_of_everything/generated_create" + body: "*" + }; + } + +} diff --git a/examples/internal/server/BUILD.bazel b/examples/internal/server/BUILD.bazel new file mode 100644 index 0000000..84aea9b --- /dev/null +++ b/examples/internal/server/BUILD.bazel @@ -0,0 +1,31 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +package(default_visibility = ["//visibility:public"]) + +go_library( + name = "go_default_library", + srcs = [ + "echo.go", + "main.go", + ], + importpath = "github.com/binchencoder/ease-gateway/examples/internal/server", + deps = [ + "//examples/internal/proto/examplepb:go_default_library", + "//gateway/runtime:go_default_library", + "@com_github_golang_glog//:go_default_library", + "@com_github_rogpeppe_fastuuid//:go_default_library", + "@go_googleapis//google/api:httpbody_go_proto", + "@go_googleapis//google/rpc:errdetails_go_proto", + "@go_googleapis//google/rpc:status_go_proto", + "@io_bazel_rules_go//proto/wkt:duration_go_proto", + "@io_bazel_rules_go//proto/wkt:empty_go_proto", + "@io_bazel_rules_go//proto/wkt:field_mask_go_proto", + "@io_bazel_rules_go//proto/wkt:wrappers_go_proto", + "@org_golang_google_grpc//:go_default_library", + "@org_golang_google_grpc//codes:go_default_library", + "@org_golang_google_grpc//metadata:go_default_library", + "@org_golang_google_grpc//status:go_default_library", + "@org_golang_google_protobuf//proto:go_default_library", + "@org_golang_google_protobuf//reflect/protoreflect:go_default_library", + ], +) diff --git a/examples/server/echo.go b/examples/internal/server/echo.go similarity index 74% rename from examples/server/echo.go rename to examples/internal/server/echo.go index b0fd3a2..9197162 100644 --- a/examples/server/echo.go +++ b/examples/internal/server/echo.go @@ -3,8 +3,8 @@ package server import ( "context" - examples "github.com/binchencoder/ease-gateway/examples/proto" "github.com/golang/glog" + examples "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb" "google.golang.org/grpc" "google.golang.org/grpc/metadata" ) @@ -13,8 +13,7 @@ import ( type echoServer struct{} -// NewEchoServer new echo server -func NewEchoServer() examples.EchoServiceServer { +func newEchoServer() examples.EchoServiceServer { return new(echoServer) } @@ -40,3 +39,8 @@ func (s *echoServer) EchoDelete(ctx context.Context, msg *examples.SimpleMessage glog.Info(msg) return msg, nil } + +func (s *echoServer) EchoPatch(ctx context.Context, msg *examples.DynamicMessageUpdate) (*examples.DynamicMessageUpdate, error) { + glog.Info(msg) + return msg, nil +} diff --git a/examples/internal/server/main.go b/examples/internal/server/main.go new file mode 100644 index 0000000..b17ae8e --- /dev/null +++ b/examples/internal/server/main.go @@ -0,0 +1,61 @@ +package server + +import ( + "context" + "net" + "net/http" + + "github.com/golang/glog" + examples "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb" + "github.com/binchencoder/ease-gateway/gateway/runtime" + "google.golang.org/grpc" +) + +// Run starts the example gRPC service. +// "network" and "address" are passed to net.Listen. +func Run(ctx context.Context, network, address string) error { + l, err := net.Listen(network, address) + if err != nil { + return err + } + defer func() { + if err := l.Close(); err != nil { + glog.Errorf("Failed to close %s %s: %v", network, address, err) + } + }() + + s := grpc.NewServer() + examples.RegisterEchoServiceServer(s, newEchoServer()) + + go func() { + defer s.GracefulStop() + <-ctx.Done() + }() + return s.Serve(l) +} + +// RunInProcessGateway starts the invoke in process http gateway. +func RunInProcessGateway(ctx context.Context, addr string, opts ...runtime.ServeMuxOption) error { + mux := runtime.NewServeMux(opts...) + + examples.RegisterEchoServiceHandlerServer(ctx, mux, newEchoServer()) + s := &http.Server{ + Addr: addr, + Handler: mux, + } + + go func() { + <-ctx.Done() + glog.Infof("Shutting down the http gateway server") + if err := s.Shutdown(context.Background()); err != nil { + glog.Errorf("Failed to shutdown http gateway server: %v", err) + } + }() + + if err := s.ListenAndServe(); err != http.ErrServerClosed { + glog.Errorf("Failed to listen and serve: %v", err) + return err + } + return nil + +} diff --git a/examples/proto/BUILD.bazel b/examples/proto/BUILD.bazel deleted file mode 100644 index c5fc231..0000000 --- a/examples/proto/BUILD.bazel +++ /dev/null @@ -1,64 +0,0 @@ -load("@io_bazel_rules_go//go:def.bzl", "go_library") -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") -load("//gateway/protoc-gen-openapiv2:defs.bzl", "protoc_gen_openapiv2") - -package(default_visibility = ["//visibility:public"]) - -# gazelle:exclude echo_service.pb.gw.go - -proto_library( - name = "examplepb_proto", - srcs = glob(["*.proto"]), - deps = [ - "//httpoptions:options_proto", - "@com_github_binchencoder_gateway_proto//data:data_proto", - "@com_github_binchencoder_gateway_proto//frontend:error_proto", - "@com_google_protobuf//:duration_proto", - "@com_google_protobuf//:empty_proto", - "@com_google_protobuf//:field_mask_proto", - "@com_google_protobuf//:timestamp_proto", - "@com_google_protobuf//:wrappers_proto", - "@go_googleapis//google/api:annotations_proto", - ], -) - -go_proto_library( - name = "examplepb_go_proto", - compilers = [ - "//:go_apiv2", - "//:go_grpc", - "//gateway/protoc-gen-grpc-gateway:go_gen_grpc_gateway", # keep - ], - importpath = "github.com/binchencoder/ease-gateway/examples/proto", - proto = ":examplepb_proto", - deps = [ - "//httpoptions:go_default_library", - "//gateway/runtime:go_default_library", - "@com_github_binchencoder_letsgo//grpc:go_default_library", - "@com_github_binchencoder_skylb_api//balancer:go_default_library", - "@com_github_binchencoder_skylb_api//client:go_default_library", - "@com_github_binchencoder_skylb_api//client/option:go_default_library", - "@com_github_binchencoder_skylb_api//proto:go_default_library", - "@org_golang_google_grpc//naming:go_default_library", - ], -) - -go_library( - name = "go_default_library", - embed = [":examplepb_go_proto"], - importpath = "github.com/binchencoder/ease-gateway/examples/proto", - deps = [ - "//httpoptions:go_default_library", - "//gateway/runtime:go_default_library", - "@com_github_binchencoder_gateway_proto//data:go_default_library", - "@com_github_binchencoder_gateway_proto//frontend:go_default_library", - "@com_github_binchencoder_skylb_api//balancer:go_default_library", - "@com_github_binchencoder_skylb_api//client:go_default_library", - ], -) - -protoc_gen_openapiv2( - name = "expamplepb_protoc_gen_openapiv2", - proto = ":examplepb_proto", - single_output = False, # Outputs a single swagger.json file. -) \ No newline at end of file diff --git a/examples/server/BUILD.bazel b/examples/server/BUILD.bazel deleted file mode 100644 index 8de0df1..0000000 --- a/examples/server/BUILD.bazel +++ /dev/null @@ -1,18 +0,0 @@ -load("@io_bazel_rules_go//go:def.bzl", "go_library") - -package(default_visibility = ["//visibility:public"]) - -go_library( - name = "go_default_library", - srcs = [ - "echo.go", - "main.go", - ], - importpath = "github.com/binchencoder/ease-gateway/examples/server", - deps = [ - "//examples/proto:go_default_library", - "@com_github_golang_glog//:go_default_library", - "@org_golang_google_grpc//:go_default_library", - "@org_golang_google_grpc//metadata:go_default_library", - ], -) diff --git a/examples/server/main.go b/examples/server/main.go deleted file mode 100644 index dd12155..0000000 --- a/examples/server/main.go +++ /dev/null @@ -1,33 +0,0 @@ -package server - -import ( - "context" - "net" - - examples "github.com/binchencoder/ease-gateway/examples/proto" - "github.com/golang/glog" - "google.golang.org/grpc" -) - -// Run starts the example gRPC service. -// "network" and "address" are passed to net.Listen. -func Run(ctx context.Context, network, address string) error { - l, err := net.Listen(network, address) - if err != nil { - return err - } - defer func() { - if err := l.Close(); err != nil { - glog.Errorf("Failed to close %s %s: %v", network, address, err) - } - }() - - s := grpc.NewServer() - examples.RegisterEchoServiceServer(s, NewEchoServer()) - - go func() { - defer s.GracefulStop() - <-ctx.Done() - }() - return s.Serve(l) -} diff --git a/gateway/runtime/BUILD.bazel b/gateway/runtime/BUILD.bazel index 9351e00..e55634d 100644 --- a/gateway/runtime/BUILD.bazel +++ b/gateway/runtime/BUILD.bazel @@ -57,7 +57,7 @@ go_test( ], embed = [":go_default_library"], deps = [ - "//examples/proto:go_default_library", + "//examples/internal/proto/examplepb:go_default_library", "//gateway/internal:go_default_library", "//gateway/runtime/internal/examplepb:go_default_library", "//httpoptions:go_default_library", diff --git a/gateway/runtime/handler_test.go b/gateway/runtime/handler_test.go index e4e9768..d0c171e 100644 --- a/gateway/runtime/handler_test.go +++ b/gateway/runtime/handler_test.go @@ -11,7 +11,7 @@ import ( // "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" "github.com/binchencoder/ease-gateway/gateway/runtime" // pb "github.com/grpc-ecosystem/grpc-gateway/v2/runtime/internal/examplepb" - pb "github.com/binchencoder/ease-gateway/examples/proto" + pb "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "google.golang.org/protobuf/proto" diff --git a/proto/examples/echo_service.pb.go b/proto/examples/echo_service.pb.go index a1e64fe..bdda4c4 100755 --- a/proto/examples/echo_service.pb.go +++ b/proto/examples/echo_service.pb.go @@ -2,7 +2,7 @@ // versions: // protoc-gen-go v1.22.0 // protoc v3.8.0 -// source: proto/examples/echo_service.proto +// source: proto/examples/internal/echo_service.proto package examples diff --git a/proto/examples/echo_service.pb.gw.go b/proto/examples/echo_service.pb.gw.go index f6d0b6a..a97a509 100755 --- a/proto/examples/echo_service.pb.gw.go +++ b/proto/examples/echo_service.pb.gw.go @@ -1,5 +1,5 @@ // Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. -// source: proto/examples/echo_service.proto +// source: proto/examples/internal/echo_service.proto /* Package examples is a reverse proxy. diff --git a/proto/examples/echo_service.swagger.json b/proto/examples/echo_service.swagger.json index 8031bf2..111bd6e 100755 --- a/proto/examples/echo_service.swagger.json +++ b/proto/examples/echo_service.swagger.json @@ -1,7 +1,7 @@ { "swagger": "2.0", "info": { - "title": "proto/examples/echo_service.proto", + "title": "proto/examples/internal/echo_service.proto", "version": "version not set" }, "consumes": [ diff --git a/proto/examples/echo_service_grpc.pb.go b/proto/examples/echo_service_grpc.pb.go index be3e2a5..91e6993 100755 --- a/proto/examples/echo_service_grpc.pb.go +++ b/proto/examples/echo_service_grpc.pb.go @@ -154,5 +154,5 @@ var _EchoService_serviceDesc = grpc.ServiceDesc{ }, }, Streams: []grpc.StreamDesc{}, - Metadata: "proto/examples/echo_service.proto", + Metadata: "proto/examples/internal/echo_service.proto", } diff --git a/proto/examples/pom.xml b/proto/examples/pom.xml index 3eee815..68446a2 100755 --- a/proto/examples/pom.xml +++ b/proto/examples/pom.xml @@ -55,8 +55,8 @@ ../ - proto/examples/*.proto - proto/examples/*/*.proto + proto/examples/internal/*.proto + proto/examples/internal/*/*.proto diff --git a/repositories.bzl b/repositories.bzl index db7a589..f2035e8 100644 --- a/repositories.bzl +++ b/repositories.bzl @@ -203,6 +203,13 @@ def go_repositories(): sum = "h1:F0+tqvhOksq22sc6iCHF5WGlWjdwj92p0udFh1VFBS8=", version = "v0.1.3", ) + go_repository( + name = "com_github_rogpeppe_fastuuid", + importpath = "github.com/rogpeppe/fastuuid", + sum = "h1:Ppwyp6VYCF1nvBTXL3trRso7mXMlRrw9ooo375wvi2s=", + version = "v1.2.0", + ) + go_repository( name = "in_gopkg_yaml_v2", importpath = "gopkg.in/yaml.v2", From 7fd52eab125b1f959097809ebf0f0194be063b98 Mon Sep 17 00:00:00 2001 From: binchen Date: Thu, 29 Oct 2020 18:14:33 +0800 Subject: [PATCH 29/56] Delete examples/internal/proto/examplepb/generated_input.proto --- examples/internal/proto/examplepb/BUILD.bazel | 7 ------- .../proto/examplepb/generated_input.proto | 20 ------------------- 2 files changed, 27 deletions(-) delete mode 100644 examples/internal/proto/examplepb/generated_input.proto diff --git a/examples/internal/proto/examplepb/BUILD.bazel b/examples/internal/proto/examplepb/BUILD.bazel index df609cb..4f7afe5 100644 --- a/examples/internal/proto/examplepb/BUILD.bazel +++ b/examples/internal/proto/examplepb/BUILD.bazel @@ -32,13 +32,6 @@ package(default_visibility = ["//visibility:public"]) # gazelle:exclude openapi_merge_b.proto # gazelle:go_grpc_compilers //:go_apiv2, //:go_grpc, //protoc-gen-grpc-gateway:go_gen_grpc_gateway -genrule( - name = "generated_proto", - srcs = ["generated_input.proto"], - outs = ["generated_output.proto"], - cmd = "cp $< $@", # A simple copy simulates a generated proto file. -) - proto_library( name = "examplepb_proto", srcs = [ diff --git a/examples/internal/proto/examplepb/generated_input.proto b/examples/internal/proto/examplepb/generated_input.proto deleted file mode 100644 index bd4ab5f..0000000 --- a/examples/internal/proto/examplepb/generated_input.proto +++ /dev/null @@ -1,20 +0,0 @@ -syntax = "proto3"; -option go_package = "github.com/grpc-ecosystem/grpc-gateway/v2/examples/internal/proto/examplepb"; -package grpc.gateway.examples.internal.proto.examplepb; - -import "google/api/annotations.proto"; -import "google/protobuf/empty.proto"; -import "examples/internal/proto/examplepb/a_bit_of_everything.proto"; - -// This file is run through a genrule. - -// Defines some more operations to be added to ABitOfEverythingService -service GeneratedService { - rpc Create(ABitOfEverything) returns (google.protobuf.Empty) { - option (google.api.http) = { - post: "/v1/example/a_bit_of_everything/generated_create" - body: "*" - }; - } - -} From cacbf5cabf97fbc2f89dfec40ea6d7e0080f9138 Mon Sep 17 00:00:00 2001 From: binchen Date: Thu, 29 Oct 2020 18:34:33 +0800 Subject: [PATCH 30/56] Format code. --- examples/internal/proto/examplepb/BUILD.bazel | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/internal/proto/examplepb/BUILD.bazel b/examples/internal/proto/examplepb/BUILD.bazel index 4f7afe5..f251f97 100644 --- a/examples/internal/proto/examplepb/BUILD.bazel +++ b/examples/internal/proto/examplepb/BUILD.bazel @@ -65,17 +65,17 @@ go_proto_library( deps = [ "//httpoptions:go_default_library", "@com_github_binchencoder_letsgo//grpc:go_default_library", - "@com_github_binchencoder_skylb_api//balancer:go_default_library", - "@com_github_binchencoder_skylb_api//client:go_default_library", - "@com_github_binchencoder_skylb_api//client/option:go_default_library", - "@com_github_binchencoder_skylb_api//proto:go_default_library", + "@com_github_binchencoder_skylb_api//balancer:go_default_library", + "@com_github_binchencoder_skylb_api//client:go_default_library", + "@com_github_binchencoder_skylb_api//client/option:go_default_library", + "@com_github_binchencoder_skylb_api//proto:go_default_library", "//gateway/protoc-gen-openapiv2/options:go_default_library", "@com_github_golang_protobuf//descriptor:go_default_library_gen", # keep "@go_googleapis//google/api:annotations_go_proto", "@go_googleapis//google/api:httpbody_go_proto", "@go_googleapis//google/rpc:status_go_proto", "@org_golang_google_protobuf//proto:go_default_library", # keep - "@org_golang_google_grpc//naming:go_default_library", + "@org_golang_google_grpc//naming:go_default_library", ], ) From 639b90e3523af49431c9c29ffbc2758b714b4101 Mon Sep 17 00:00:00 2001 From: binchen Date: Fri, 30 Oct 2020 18:20:51 +0800 Subject: [PATCH 31/56] Add examples/internal/integration test --- .circleci/Dockerfile | 41 ++ .circleci/README.md | 8 + .circleci/config.yml | 218 +++++++ examples/internal/gateway/gateway.go | 2 +- examples/internal/integration/BUILD.bazel | 2 + examples/internal/integration/README.md | 11 + .../internal/integration/integration_test.go | 252 +++++++ examples/internal/proto/examplepb/BUILD.bazel | 34 + .../proto/examplepb/echo_service.proto | 2 +- .../examplepb/unannotated_echo_service.pb.go | 616 ++++++++++++++++++ .../unannotated_echo_service.pb.gw.go | 3 + .../examplepb/unannotated_echo_service.proto | 54 ++ .../unannotated_echo_service_grpc.pb.go | 158 +++++ examples/internal/server/main.go | 2 +- gateway/runtime/errors.go | 3 +- go.mod | 4 +- go.sum | 8 +- repositories.bzl | 19 +- 18 files changed, 1413 insertions(+), 24 deletions(-) create mode 100644 .circleci/Dockerfile create mode 100644 .circleci/README.md create mode 100644 .circleci/config.yml create mode 100644 examples/internal/integration/README.md create mode 100644 examples/internal/integration/integration_test.go create mode 100644 examples/internal/proto/examplepb/unannotated_echo_service.pb.go create mode 100755 examples/internal/proto/examplepb/unannotated_echo_service.pb.gw.go create mode 100644 examples/internal/proto/examplepb/unannotated_echo_service.proto create mode 100755 examples/internal/proto/examplepb/unannotated_echo_service_grpc.pb.go diff --git a/.circleci/Dockerfile b/.circleci/Dockerfile new file mode 100644 index 0000000..0c649ac --- /dev/null +++ b/.circleci/Dockerfile @@ -0,0 +1,41 @@ +FROM golang:1.15.3 + +# Warm apt cache and install dependencies +# bzip2 is required by the node_tests (to extract its dependencies). +# patch is required by bazel tests +RUN apt-get update && \ + apt-get install -y wget unzip \ + openjdk-11-jre \ + bzip2 \ + patch + +# Install swagger-codegen +ENV SWAGGER_CODEGEN_VERSION=2.4.8 +RUN wget https://repo1.maven.org/maven2/io/swagger/swagger-codegen-cli/${SWAGGER_CODEGEN_VERSION}/swagger-codegen-cli-${SWAGGER_CODEGEN_VERSION}.jar \ + -O /usr/local/bin/swagger-codegen-cli.jar + +# Wrap the jar for swagger-codgen +RUN echo -e '#!/bin/bash\njava -jar /usr/local/bin/swagger-codegen-cli.jar "$@"' > /usr/local/bin/swagger-codegen && \ + chmod +x /usr/local/bin/swagger-codegen + +# Install protoc +ENV PROTOC_VERSION=3.12.0 +RUN wget https://github.com/google/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-linux-x86_64.zip \ + -O /protoc-${PROTOC_VERSION}-linux-x86_64.zip && \ + unzip /protoc-${PROTOC_VERSION}-linux-x86_64.zip -d /usr/local/ && \ + rm -f /protoc-${PROTOC_VERSION}-linux-x86_64.zip + +# Install node, used by NVM +ENV NODE_VERSION=v10.16.3 +ENV NVM_VERSION=v0.35.0 +RUN wget -qO- https://raw.githubusercontent.com/creationix/nvm/${NVM_VERSION}/install.sh | bash + +# Install Bazelisk as bazel to manage Bazel +RUN go get github.com/bazelbuild/bazelisk && \ + mv $(which bazelisk) /usr/local/bin/bazel + +# Clean up +RUN apt-get autoremove -y && \ + apt-get remove -y wget \ + unzip && \ + rm -rf /var/lib/apt/lists/* diff --git a/.circleci/README.md b/.circleci/README.md new file mode 100644 index 0000000..70cf33b --- /dev/null +++ b/.circleci/README.md @@ -0,0 +1,8 @@ +## gRPC-Gateway CI testing setup + +Contained within is the CI test setup for the Gateway. It runs on Circle CI. + +### Whats up with the Dockerfile? + +The `Dockerfile` in this folder is used as the build environment when regenerating the files (see CONTRIBUTING.md). +The canonical repository for this Dockerfile is `docker.pkg.github.com/binchencoder/ease-gateway/build-env`. diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 0000000..4556a74 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,218 @@ +version: 2.1 + +commands: + configure_bazel: + description: Create Bazel config file (.bazelrc) + steps: + - run: | + cat > .bazelrc \<< EOF + startup --output_base /root/.cache/_grpc_gateway_bazel + build --test_output errors + build --features race + # Workaround https://github.com/bazelbuild/bazel/issues/3645 + # See https://docs.bazel.build/versions/0.23.0/command-line-reference.html + build --local_ram_resources=4096 # Circle Docker runners have 4G of memory + build --local_cpu_resources=2 # Circle Docker runners have 2 vCPU + EOF + generate: + steps: + - run: make realclean + - run: make examples + - run: make testproto + - run: go mod tidy + renovate_git_amend_push: + description: Git amend and push changes + steps: + - run: | + git add . + if output=$(git status --porcelain) && [ ! -z "$output" ]; then + git config user.name "Renovate Bot" + git config user.email "bot@renovateapp.com" + git remote set-url origin https://x-access-token:${GITHUB_TOKEN}@github.com/binchencoder/ease-gateway.git + git commit --amend --no-edit + git push --force-with-lease origin ${CIRCLE_BRANCH} + fi + +executors: + build-env: + environment: + ## Split key to avoid github revoking it + password0: '99544cdcb19ad4e3fd64' + password1: '3ec86b2e5a431be2d72c' + GLOG_logtostderr: '1' + docker: + - image: docker.pkg.github.com/binchencoder/ease-gateway/build-env:1.15 + auth: + username: gateway-ci-user + password: ${password0}${password1} + +jobs: + build: + executor: build-env + working_directory: /src/ease-gateway + steps: + - checkout + - run: go build ./... + test: + executor: build-env + working_directory: /src/ease-gateway + steps: + - checkout + - run: go test -race -coverprofile=coverage.txt ./... + - run: bash <(curl -s https://codecov.io/bash) + node_test: + executor: build-env + working_directory: /src/ease-gateway + steps: + - checkout + - run: go mod vendor + - run: > + . $HOME/.nvm/nvm.sh && + cd examples/internal/browser && + npm install gulp-cli && + npm install && + ./node_modules/.bin/gulp + generate: + executor: build-env + working_directory: /src/ease-gateway + steps: + - checkout + - generate + - run: git diff --exit-code + lint: + executor: build-env + working_directory: /src/ease-gateway + steps: + - checkout + - restore_cache: + keys: + - v1-staticcheck-cache-{{ checksum "go.sum" }} + - v1-staticcheck-cache- + - run: + name: Install staticcheck outside local module + command: | + cd $(mktemp -d) && + go mod init tmp && + go get honnef.co/go/tools/cmd/staticcheck + - run: staticcheck ./... + - save_cache: + key: v1-staticcheck-cache-{{ checksum "go.sum" }} + paths: + - /root/.cache/go-build + - /root/.cache/staticcheck + fuzzit: + docker: + - image: fuzzitdev/fuzzit:golang1.12-stretch-llvm9 + working_directory: /src/ease-gateway + steps: + - checkout + - setup_remote_docker + - run: ./fuzzit.sh + bazel: + executor: build-env + working_directory: /src/ease-gateway + steps: + - checkout + - restore_cache: + keys: + - v2-bazel-cache-{{ checksum "repositories.bzl" }} + - v2-bazel-cache- + - configure_bazel + - run: + name: Check that Bazel BUILD files are up-to-date + command: | + bazel run //:gazelle && + git diff --exit-code + - run: + name: Check that repositories.bzl is up-to-date + command: | + bazel run //:gazelle -- update-repos -from_file=go.mod -to_macro=repositories.bzl%go_repositories && + git diff --exit-code + - run: + name: Check formatting of Bazel BUILD files + command: | + bazel run //:buildifier && + git diff --exit-code + - run: + name: Run tests with Bazel + command: bazel test //... + - save_cache: + key: v2-bazel-cache-{{ checksum "repositories.bzl" }} + paths: + - /root/.cache/_grpc_gateway_bazel + gorelease: + executor: build-env + working_directory: /src/ease-gateway + steps: + - checkout + - run: + name: Install gorelease outside local module + command: | + cd $(mktemp -d) && + go mod init tmp && + go get golang.org/x/exp/cmd/gorelease@latest + - run: gorelease -base=v2.0.0 + release: + executor: build-env + working_directory: /src/ease-gateway + steps: + - checkout + - run: go mod vendor + - run: curl -sL https://git.io/goreleaser | bash + update-repositoriesbzl: + executor: build-env + working_directory: /src/ease-gateway + steps: + - checkout + - restore_cache: + keys: + - v2-bazel-cache-{{ checksum "repositories.bzl" }} + - v2-bazel-cache- + - configure_bazel + - run: + name: Update repositories.bzl + command: | + bazel run //:gazelle -- update-repos -from_file=go.mod -to_macro=repositories.bzl%go_repositories + - renovate_git_amend_push + regenerate: + executor: build-env + working_directory: /src/ease-gateway + steps: + - checkout + - generate + - renovate_git_amend_push +workflows: + version: 2 + all: + jobs: + - build + - test + - fuzzit + - node_test + - generate + - lint + - bazel + - gorelease + - release: + filters: + branches: + ignore: /.*/ + tags: + only: /v[0-9]+(\.[0-9]+)*(-.*)*/ + - update-repositoriesbzl: + filters: + branches: + only: /renovate\/master-.+/ + tags: + ignore: /.*/ + - regenerate: + requires: + # Run after update-repositoriesbzl to avoid + # git conflicts + - update-repositoriesbzl + filters: + branches: + only: /renovate\/master-.+/ + tags: + ignore: /.*/ + diff --git a/examples/internal/gateway/gateway.go b/examples/internal/gateway/gateway.go index f58921b..65b42ff 100644 --- a/examples/internal/gateway/gateway.go +++ b/examples/internal/gateway/gateway.go @@ -14,7 +14,7 @@ import ( // newGateway returns a new gateway server which translates HTTP into gRPC. func newGateway(ctx context.Context, conn *grpc.ClientConn, opts []gwruntime.ServeMuxOption) (http.Handler, error) { sgs := gwruntime.GetServicGroups() - fmt.Printf("gwruntime.GetServicGroups: %v", sgs) + fmt.Printf("gwruntime.GetServicGroups: %v \n", sgs) for _, sg := range sgs { go sg.Enable() spec := sg.Spec diff --git a/examples/internal/integration/BUILD.bazel b/examples/internal/integration/BUILD.bazel index 0c6289a..017125d 100644 --- a/examples/internal/integration/BUILD.bazel +++ b/examples/internal/integration/BUILD.bazel @@ -3,11 +3,13 @@ load("@io_bazel_rules_go//go:def.bzl", "go_test") go_test( name = "go_default_test", srcs = [ + "integration_test.go", "main_test.go", ], deps = [ "//examples/internal/gateway:go_default_library", "//examples/internal/proto/examplepb:go_default_library", + "//examples/internal/proto/examplepb:unannotated_go_default_library", "//examples/internal/server:go_default_library", "//gateway/runtime:go_default_library", "//httpoptions:go_default_library", diff --git a/examples/internal/integration/README.md b/examples/internal/integration/README.md new file mode 100644 index 0000000..6e10b57 --- /dev/null +++ b/examples/internal/integration/README.md @@ -0,0 +1,11 @@ +# Run test + +## Bazel test + +```shell +bazel test examples/internal/integration/... --test_arg=--skylb-endpoints="" --test_arg=--debug-svc-endpoint=custom-ease-gateway-test=localhost:9090 +``` + +> 通过bazel test 执行integration test +> +> 因为引入skylb-api, 运行时需要指定skylb-endpoints \ No newline at end of file diff --git a/examples/internal/integration/integration_test.go b/examples/internal/integration/integration_test.go new file mode 100644 index 0000000..326e583 --- /dev/null +++ b/examples/internal/integration/integration_test.go @@ -0,0 +1,252 @@ +package integration_test + +import ( + "bytes" + "fmt" + "io/ioutil" + "net/http" + "strings" + "testing" + + "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb" + "github.com/binchencoder/ease-gateway/gateway/runtime" + "github.com/google/go-cmp/cmp" + "google.golang.org/protobuf/testing/protocmp" +) + +var marshaler = &runtime.JSONPb{} + +func TestEcho(t *testing.T) { + if testing.Short() { + t.Skip() + return + } + + for _, apiPrefix := range []string{"v1", "v2"} { + t.Run(apiPrefix, func(t *testing.T) { + testEcho(t, 8088, apiPrefix, "application/json") + testEchoOneof(t, 8088, apiPrefix, "application/json") + testEchoOneof1(t, 8088, apiPrefix, "application/json") + testEchoOneof2(t, 8088, apiPrefix, "application/json") + testEchoBody(t, 8088, apiPrefix) + // Use SendHeader/SetTrailer without gRPC server https://github.com/grpc-ecosystem/grpc-gateway/issues/517#issuecomment-684625645 + testEchoBody(t, 8089, apiPrefix) + }) + } +} + +func testEcho(t *testing.T, port int, apiPrefix string, contentType string) { + apiURL := fmt.Sprintf("http://localhost:%d/%s/example/echo/myid", port, apiPrefix) + resp, err := http.Post(apiURL, "application/json", strings.NewReader("{}")) + if err != nil { + t.Errorf("http.Post(%q) failed with %v; want success", apiURL, err) + return + } + defer resp.Body.Close() + buf, err := ioutil.ReadAll(resp.Body) + if err != nil { + t.Errorf("ioutil.ReadAll(resp.Body) failed with %v; want success", err) + return + } + + if apiPrefix == "v2" { + if got, want := resp.StatusCode, http.StatusNotFound; got != want { + t.Errorf("resp.StatusCode = %d; want %d", got, want) + t.Logf("%s", buf) + } + } else { + if got, want := resp.StatusCode, http.StatusOK; got != want { + t.Errorf("resp.StatusCode = %d; want %d", got, want) + t.Logf("%s", buf) + } + } + + msg := new(examplepb.UnannotatedSimpleMessage) + if err := marshaler.Unmarshal(buf, msg); err != nil { + t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) + return + } + if got, want := msg.Id, "myid"; got != want { + t.Errorf("msg.Id = %q; want %q", got, want) + } + + if value := resp.Header.Get("Content-Type"); value != contentType { + t.Errorf("Content-Type was %s, wanted %s", value, contentType) + } +} + +func testEchoOneof(t *testing.T, port int, apiPrefix string, contentType string) { + apiURL := fmt.Sprintf("http://localhost:%d/%s/example/echo/myid/10/golang", port, apiPrefix) + resp, err := http.Get(apiURL) + if err != nil { + t.Errorf("http.Get(%q) failed with %v; want success", apiURL, err) + return + } + defer resp.Body.Close() + buf, err := ioutil.ReadAll(resp.Body) + if err != nil { + t.Errorf("ioutil.ReadAll(resp.Body) failed with %v; want success", err) + return + } + + if apiPrefix == "v2" { + if got, want := resp.StatusCode, http.StatusNotFound; got != want { + t.Errorf("resp.StatusCode = %d; want %d", got, want) + t.Logf("%s", buf) + } + } else { + if got, want := resp.StatusCode, http.StatusOK; got != want { + t.Errorf("resp.StatusCode = %d; want %d", got, want) + t.Logf("%s", buf) + } + } + + msg := new(examplepb.UnannotatedSimpleMessage) + if err := marshaler.Unmarshal(buf, msg); err != nil { + t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) + return + } + if got, want := msg.GetLang(), "golang"; got != want { + t.Errorf("msg.GetLang() = %q; want %q", got, want) + } + + if value := resp.Header.Get("Content-Type"); value != contentType { + t.Errorf("Content-Type was %s, wanted %s", value, contentType) + } +} + +func testEchoOneof1(t *testing.T, port int, apiPrefix string, contentType string) { + apiURL := fmt.Sprintf("http://localhost:%d/%s/example/echo1/myid/10/golang", port, apiPrefix) + resp, err := http.Get(apiURL) + if err != nil { + t.Errorf("http.Get(%q) failed with %v; want success", apiURL, err) + return + } + defer resp.Body.Close() + buf, err := ioutil.ReadAll(resp.Body) + if err != nil { + t.Errorf("ioutil.ReadAll(resp.Body) failed with %v; want success", err) + return + } + + if apiPrefix == "v2" { + if got, want := resp.StatusCode, http.StatusNotFound; got != want { + t.Errorf("resp.StatusCode = %d; want %d", got, want) + t.Logf("%s", buf) + } + } else { + if got, want := resp.StatusCode, http.StatusOK; got != want { + t.Errorf("resp.StatusCode = %d; want %d", got, want) + t.Logf("%s", buf) + } + } + + msg := new(examplepb.UnannotatedSimpleMessage) + if err := marshaler.Unmarshal(buf, msg); err != nil { + t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) + return + } + if got, want := msg.GetStatus().GetNote(), "golang"; got != want { + t.Errorf("msg.GetStatus().GetNote() = %q; want %q", got, want) + } + + if value := resp.Header.Get("Content-Type"); value != contentType { + t.Errorf("Content-Type was %s, wanted %s", value, contentType) + } +} + +func testEchoOneof2(t *testing.T, port int, apiPrefix string, contentType string) { + apiURL := fmt.Sprintf("http://localhost:%d/%s/example/echo2/golang", port, apiPrefix) + resp, err := http.Get(apiURL) + if err != nil { + t.Errorf("http.Get(%q) failed with %v; want success", apiURL, err) + return + } + defer resp.Body.Close() + buf, err := ioutil.ReadAll(resp.Body) + if err != nil { + t.Errorf("ioutil.ReadAll(resp.Body) failed with %v; want success", err) + return + } + + if apiPrefix == "v2" { + if got, want := resp.StatusCode, http.StatusNotFound; got != want { + t.Errorf("resp.StatusCode = %d; want %d", got, want) + t.Logf("%s", buf) + } + } else { + if got, want := resp.StatusCode, http.StatusOK; got != want { + t.Errorf("resp.StatusCode = %d; want %d", got, want) + t.Logf("%s", buf) + } + } + + msg := new(examplepb.UnannotatedSimpleMessage) + if err := marshaler.Unmarshal(buf, msg); err != nil { + t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) + return + } + if got, want := msg.GetNo().GetNote(), "golang"; got != want { + t.Errorf("msg.GetNo().GetNote() = %q; want %q", got, want) + } + + if value := resp.Header.Get("Content-Type"); value != contentType { + t.Errorf("Content-Type was %s, wanted %s", value, contentType) + } +} + +func testEchoBody(t *testing.T, port int, apiPrefix string) { + sent := examplepb.UnannotatedSimpleMessage{Id: "example"} + payload, err := marshaler.Marshal(&sent) + if err != nil { + t.Fatalf("marshaler.Marshal(%#v) failed with %v; want success", payload, err) + } + + apiURL := fmt.Sprintf("http://localhost:%d/%s/example/echo_body", port, apiPrefix) + resp, err := http.Post(apiURL, "", bytes.NewReader(payload)) + if err != nil { + t.Errorf("http.Post(%q) failed with %v; want success", apiURL, err) + return + } + defer resp.Body.Close() + buf, err := ioutil.ReadAll(resp.Body) + if err != nil { + t.Errorf("ioutil.ReadAll(resp.Body) failed with %v; want success", err) + return + } + + if apiPrefix == "v2" { + if got, want := resp.StatusCode, http.StatusNotFound; got != want { + t.Errorf("resp.StatusCode = %d; want %d", got, want) + t.Logf("%s", buf) + } + } else { + if got, want := resp.StatusCode, http.StatusOK; got != want { + t.Errorf("resp.StatusCode = %d; want %d", got, want) + t.Logf("%s", buf) + } + } + + var received examplepb.UnannotatedSimpleMessage + if err := marshaler.Unmarshal(buf, &received); err != nil { + t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) + return + } + if diff := cmp.Diff(&received, &sent, protocmp.Transform()); diff != "" { + t.Errorf(diff) + } + + if got, want := resp.Header.Get("Grpc-Metadata-Foo"), "foo1"; got != want { + t.Errorf("Grpc-Metadata-Foo was %q, wanted %q", got, want) + } + if got, want := resp.Header.Get("Grpc-Metadata-Bar"), "bar1"; got != want { + t.Errorf("Grpc-Metadata-Bar was %q, wanted %q", got, want) + } + + if got, want := resp.Trailer.Get("Grpc-Trailer-Foo"), "foo2"; got != want { + t.Errorf("Grpc-Trailer-Foo was %q, wanted %q", got, want) + } + if got, want := resp.Trailer.Get("Grpc-Trailer-Bar"), "bar2"; got != want { + t.Errorf("Grpc-Trailer-Bar was %q, wanted %q", got, want) + } +} diff --git a/examples/internal/proto/examplepb/BUILD.bazel b/examples/internal/proto/examplepb/BUILD.bazel index f251f97..ea15ffa 100644 --- a/examples/internal/proto/examplepb/BUILD.bazel +++ b/examples/internal/proto/examplepb/BUILD.bazel @@ -53,6 +53,16 @@ proto_library( ], ) +proto_library( + name = "examplepb_unannotated_proto", + srcs = [ + "unannotated_echo_service.proto", + ], + deps = [ + "@com_google_protobuf//:duration_proto", + ], +) + go_proto_library( name = "examplepb_go_proto", compilers = [ @@ -79,6 +89,25 @@ go_proto_library( ], ) +go_proto_library( + name = "examplepb_unannotated_go_proto", + compilers = [ + "//:go_apiv2", + "//:go_grpc", + "@com_github_grpc_ecosystem_grpc_gateway//protoc-gen-grpc-gateway:go_gen_grpc_gateway", # keep + ], + importpath = "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb", + proto = ":examplepb_unannotated_proto", + deps = [ + "//gateway/protoc-gen-openapiv2/options:go_default_library", + "@com_github_golang_protobuf//descriptor:go_default_library_gen", # keep + "@go_googleapis//google/api:annotations_go_proto", + "@go_googleapis//google/api:httpbody_go_proto", + "@go_googleapis//google/rpc:status_go_proto", + "@org_golang_google_protobuf//proto:go_default_library", # keep + ], +) + go_library( name = "go_default_library", embed = [":examplepb_go_proto"], @@ -93,6 +122,11 @@ go_library( ], ) +go_library( + name = "unannotated_go_default_library", + embed = [":examplepb_unannotated_go_proto"], + importpath = "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb", +) protoc_gen_openapiv2( name = "examplepb_protoc_gen_openapiv2", diff --git a/examples/internal/proto/examplepb/echo_service.proto b/examples/internal/proto/examplepb/echo_service.proto index 3cf3962..ad19963 100644 --- a/examples/internal/proto/examplepb/echo_service.proto +++ b/examples/internal/proto/examplepb/echo_service.proto @@ -1,5 +1,5 @@ syntax = "proto3"; -option go_package = "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb"; +option go_package = "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb;examplepb"; // Echo Service // diff --git a/examples/internal/proto/examplepb/unannotated_echo_service.pb.go b/examples/internal/proto/examplepb/unannotated_echo_service.pb.go new file mode 100644 index 0000000..4b6663b --- /dev/null +++ b/examples/internal/proto/examplepb/unannotated_echo_service.pb.go @@ -0,0 +1,616 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.23.0 +// protoc v3.12.3 +// source: examples/internal/proto/examplepb/unannotated_echo_service.proto + +// Unannotated Echo Service +// Similar to echo_service.proto but without annotations. See +// unannotated_echo_service.yaml for the equivalent of the annotations in +// gRPC API configuration format. +// +// Echo Service API consists of a single service which returns +// a message. + +package examplepb + +import ( + context "context" + proto "github.com/golang/protobuf/proto" + duration "github.com/golang/protobuf/ptypes/duration" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// This is a compile-time assertion that a sufficiently up-to-date version +// of the legacy proto package is being used. +const _ = proto.ProtoPackageIsVersion4 + +// Embedded represents a message embedded in SimpleMessage. +type UnannotatedEmbedded struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Mark: + // *UnannotatedEmbedded_Progress + // *UnannotatedEmbedded_Note + Mark isUnannotatedEmbedded_Mark `protobuf_oneof:"mark"` +} + +func (x *UnannotatedEmbedded) Reset() { + *x = UnannotatedEmbedded{} + if protoimpl.UnsafeEnabled { + mi := &file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UnannotatedEmbedded) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UnannotatedEmbedded) ProtoMessage() {} + +func (x *UnannotatedEmbedded) ProtoReflect() protoreflect.Message { + mi := &file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UnannotatedEmbedded.ProtoReflect.Descriptor instead. +func (*UnannotatedEmbedded) Descriptor() ([]byte, []int) { + return file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDescGZIP(), []int{0} +} + +func (m *UnannotatedEmbedded) GetMark() isUnannotatedEmbedded_Mark { + if m != nil { + return m.Mark + } + return nil +} + +func (x *UnannotatedEmbedded) GetProgress() int64 { + if x, ok := x.GetMark().(*UnannotatedEmbedded_Progress); ok { + return x.Progress + } + return 0 +} + +func (x *UnannotatedEmbedded) GetNote() string { + if x, ok := x.GetMark().(*UnannotatedEmbedded_Note); ok { + return x.Note + } + return "" +} + +type isUnannotatedEmbedded_Mark interface { + isUnannotatedEmbedded_Mark() +} + +type UnannotatedEmbedded_Progress struct { + Progress int64 `protobuf:"varint,1,opt,name=progress,proto3,oneof"` +} + +type UnannotatedEmbedded_Note struct { + Note string `protobuf:"bytes,2,opt,name=note,proto3,oneof"` +} + +func (*UnannotatedEmbedded_Progress) isUnannotatedEmbedded_Mark() {} + +func (*UnannotatedEmbedded_Note) isUnannotatedEmbedded_Mark() {} + +// UnannotatedSimpleMessage represents a simple message sent to the unannotated Echo service. +type UnannotatedSimpleMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Id represents the message identifier. + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Num int64 `protobuf:"varint,2,opt,name=num,proto3" json:"num,omitempty"` + Duration *duration.Duration `protobuf:"bytes,3,opt,name=duration,proto3" json:"duration,omitempty"` + // Types that are assignable to Code: + // *UnannotatedSimpleMessage_LineNum + // *UnannotatedSimpleMessage_Lang + Code isUnannotatedSimpleMessage_Code `protobuf_oneof:"code"` + Status *UnannotatedEmbedded `protobuf:"bytes,6,opt,name=status,proto3" json:"status,omitempty"` + // Types that are assignable to Ext: + // *UnannotatedSimpleMessage_En + // *UnannotatedSimpleMessage_No + Ext isUnannotatedSimpleMessage_Ext `protobuf_oneof:"ext"` +} + +func (x *UnannotatedSimpleMessage) Reset() { + *x = UnannotatedSimpleMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UnannotatedSimpleMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UnannotatedSimpleMessage) ProtoMessage() {} + +func (x *UnannotatedSimpleMessage) ProtoReflect() protoreflect.Message { + mi := &file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UnannotatedSimpleMessage.ProtoReflect.Descriptor instead. +func (*UnannotatedSimpleMessage) Descriptor() ([]byte, []int) { + return file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDescGZIP(), []int{1} +} + +func (x *UnannotatedSimpleMessage) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *UnannotatedSimpleMessage) GetNum() int64 { + if x != nil { + return x.Num + } + return 0 +} + +func (x *UnannotatedSimpleMessage) GetDuration() *duration.Duration { + if x != nil { + return x.Duration + } + return nil +} + +func (m *UnannotatedSimpleMessage) GetCode() isUnannotatedSimpleMessage_Code { + if m != nil { + return m.Code + } + return nil +} + +func (x *UnannotatedSimpleMessage) GetLineNum() int64 { + if x, ok := x.GetCode().(*UnannotatedSimpleMessage_LineNum); ok { + return x.LineNum + } + return 0 +} + +func (x *UnannotatedSimpleMessage) GetLang() string { + if x, ok := x.GetCode().(*UnannotatedSimpleMessage_Lang); ok { + return x.Lang + } + return "" +} + +func (x *UnannotatedSimpleMessage) GetStatus() *UnannotatedEmbedded { + if x != nil { + return x.Status + } + return nil +} + +func (m *UnannotatedSimpleMessage) GetExt() isUnannotatedSimpleMessage_Ext { + if m != nil { + return m.Ext + } + return nil +} + +func (x *UnannotatedSimpleMessage) GetEn() int64 { + if x, ok := x.GetExt().(*UnannotatedSimpleMessage_En); ok { + return x.En + } + return 0 +} + +func (x *UnannotatedSimpleMessage) GetNo() *UnannotatedEmbedded { + if x, ok := x.GetExt().(*UnannotatedSimpleMessage_No); ok { + return x.No + } + return nil +} + +type isUnannotatedSimpleMessage_Code interface { + isUnannotatedSimpleMessage_Code() +} + +type UnannotatedSimpleMessage_LineNum struct { + LineNum int64 `protobuf:"varint,4,opt,name=line_num,json=lineNum,proto3,oneof"` +} + +type UnannotatedSimpleMessage_Lang struct { + Lang string `protobuf:"bytes,5,opt,name=lang,proto3,oneof"` +} + +func (*UnannotatedSimpleMessage_LineNum) isUnannotatedSimpleMessage_Code() {} + +func (*UnannotatedSimpleMessage_Lang) isUnannotatedSimpleMessage_Code() {} + +type isUnannotatedSimpleMessage_Ext interface { + isUnannotatedSimpleMessage_Ext() +} + +type UnannotatedSimpleMessage_En struct { + En int64 `protobuf:"varint,7,opt,name=en,proto3,oneof"` +} + +type UnannotatedSimpleMessage_No struct { + No *UnannotatedEmbedded `protobuf:"bytes,8,opt,name=no,proto3,oneof"` +} + +func (*UnannotatedSimpleMessage_En) isUnannotatedSimpleMessage_Ext() {} + +func (*UnannotatedSimpleMessage_No) isUnannotatedSimpleMessage_Ext() {} + +var File_examples_internal_proto_examplepb_unannotated_echo_service_proto protoreflect.FileDescriptor + +var file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDesc = []byte{ + 0x0a, 0x40, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, + 0x65, 0x70, 0x62, 0x2f, 0x75, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x5f, + 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x12, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, + 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, + 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, + 0x70, 0x62, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x22, 0x51, 0x0a, 0x13, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, + 0x64, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x12, 0x1c, 0x0a, 0x08, 0x70, 0x72, 0x6f, + 0x67, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x08, 0x70, + 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x14, 0x0a, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x42, 0x06, 0x0a, + 0x04, 0x6d, 0x61, 0x72, 0x6b, 0x22, 0xfb, 0x02, 0x0a, 0x18, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, + 0x74, 0x61, 0x74, 0x65, 0x64, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, + 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x6e, 0x75, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x03, 0x6e, 0x75, 0x6d, 0x12, 0x35, 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x08, 0x6c, + 0x69, 0x6e, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, + 0x07, 0x6c, 0x69, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x12, 0x14, 0x0a, 0x04, 0x6c, 0x61, 0x6e, 0x67, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x6c, 0x61, 0x6e, 0x67, 0x12, 0x5b, + 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x43, + 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, + 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, + 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x45, 0x6d, 0x62, 0x65, 0x64, + 0x64, 0x65, 0x64, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x10, 0x0a, 0x02, 0x65, + 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x48, 0x01, 0x52, 0x02, 0x65, 0x6e, 0x12, 0x55, 0x0a, + 0x02, 0x6e, 0x6f, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x43, 0x2e, 0x67, 0x72, 0x70, 0x63, + 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, + 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x55, 0x6e, 0x61, 0x6e, 0x6e, + 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x48, 0x01, + 0x52, 0x02, 0x6e, 0x6f, 0x42, 0x06, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x42, 0x05, 0x0a, 0x03, + 0x65, 0x78, 0x74, 0x32, 0xf9, 0x03, 0x0a, 0x16, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, + 0x74, 0x65, 0x64, 0x45, 0x63, 0x68, 0x6f, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x9a, + 0x01, 0x0a, 0x04, 0x45, 0x63, 0x68, 0x6f, 0x12, 0x48, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, + 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, + 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, + 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, + 0x61, 0x74, 0x65, 0x64, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x1a, 0x48, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, + 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, + 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, + 0x70, 0x62, 0x2e, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x53, 0x69, + 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x9e, 0x01, 0x0a, 0x08, + 0x45, 0x63, 0x68, 0x6f, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x48, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, + 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, + 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, + 0x74, 0x61, 0x74, 0x65, 0x64, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x1a, 0x48, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, + 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, + 0x65, 0x70, 0x62, 0x2e, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x53, + 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0xa0, 0x01, 0x0a, + 0x0a, 0x45, 0x63, 0x68, 0x6f, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x48, 0x2e, 0x67, 0x72, + 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, + 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x55, 0x6e, 0x61, + 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x48, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, + 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, + 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, + 0x65, 0x64, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, + 0x52, 0x5a, 0x50, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x69, + 0x6e, 0x63, 0x68, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x65, 0x61, 0x73, 0x65, 0x2d, + 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, + 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, + 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x3b, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, + 0x65, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDescOnce sync.Once + file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDescData = file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDesc +) + +func file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDescGZIP() []byte { + file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDescOnce.Do(func() { + file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDescData = protoimpl.X.CompressGZIP(file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDescData) + }) + return file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDescData +} + +var file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_examples_internal_proto_examplepb_unannotated_echo_service_proto_goTypes = []interface{}{ + (*UnannotatedEmbedded)(nil), // 0: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEmbedded + (*UnannotatedSimpleMessage)(nil), // 1: grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage + (*duration.Duration)(nil), // 2: google.protobuf.Duration +} +var file_examples_internal_proto_examplepb_unannotated_echo_service_proto_depIdxs = []int32{ + 2, // 0: grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage.duration:type_name -> google.protobuf.Duration + 0, // 1: grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage.status:type_name -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedEmbedded + 0, // 2: grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage.no:type_name -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedEmbedded + 1, // 3: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.Echo:input_type -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage + 1, // 4: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.EchoBody:input_type -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage + 1, // 5: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.EchoDelete:input_type -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage + 1, // 6: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.Echo:output_type -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage + 1, // 7: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.EchoBody:output_type -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage + 1, // 8: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.EchoDelete:output_type -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage + 6, // [6:9] is the sub-list for method output_type + 3, // [3:6] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name +} + +func init() { file_examples_internal_proto_examplepb_unannotated_echo_service_proto_init() } +func file_examples_internal_proto_examplepb_unannotated_echo_service_proto_init() { + if File_examples_internal_proto_examplepb_unannotated_echo_service_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UnannotatedEmbedded); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UnannotatedSimpleMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes[0].OneofWrappers = []interface{}{ + (*UnannotatedEmbedded_Progress)(nil), + (*UnannotatedEmbedded_Note)(nil), + } + file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes[1].OneofWrappers = []interface{}{ + (*UnannotatedSimpleMessage_LineNum)(nil), + (*UnannotatedSimpleMessage_Lang)(nil), + (*UnannotatedSimpleMessage_En)(nil), + (*UnannotatedSimpleMessage_No)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDesc, + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_examples_internal_proto_examplepb_unannotated_echo_service_proto_goTypes, + DependencyIndexes: file_examples_internal_proto_examplepb_unannotated_echo_service_proto_depIdxs, + MessageInfos: file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes, + }.Build() + File_examples_internal_proto_examplepb_unannotated_echo_service_proto = out.File + file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDesc = nil + file_examples_internal_proto_examplepb_unannotated_echo_service_proto_goTypes = nil + file_examples_internal_proto_examplepb_unannotated_echo_service_proto_depIdxs = nil +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConnInterface + +// 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.SupportPackageIsVersion6 + +// UnannotatedEchoServiceClient is the client API for UnannotatedEchoService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type UnannotatedEchoServiceClient interface { + // Echo method receives a simple message and returns it. + // + // The message posted as the id parameter will also be + // returned. + Echo(ctx context.Context, in *UnannotatedSimpleMessage, opts ...grpc.CallOption) (*UnannotatedSimpleMessage, error) + // EchoBody method receives a simple message and returns it. + EchoBody(ctx context.Context, in *UnannotatedSimpleMessage, opts ...grpc.CallOption) (*UnannotatedSimpleMessage, error) + // EchoDelete method receives a simple message and returns it. + EchoDelete(ctx context.Context, in *UnannotatedSimpleMessage, opts ...grpc.CallOption) (*UnannotatedSimpleMessage, error) +} + +type unannotatedEchoServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewUnannotatedEchoServiceClient(cc grpc.ClientConnInterface) UnannotatedEchoServiceClient { + return &unannotatedEchoServiceClient{cc} +} + +func (c *unannotatedEchoServiceClient) Echo(ctx context.Context, in *UnannotatedSimpleMessage, opts ...grpc.CallOption) (*UnannotatedSimpleMessage, error) { + out := new(UnannotatedSimpleMessage) + err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService/Echo", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *unannotatedEchoServiceClient) EchoBody(ctx context.Context, in *UnannotatedSimpleMessage, opts ...grpc.CallOption) (*UnannotatedSimpleMessage, error) { + out := new(UnannotatedSimpleMessage) + err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService/EchoBody", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *unannotatedEchoServiceClient) EchoDelete(ctx context.Context, in *UnannotatedSimpleMessage, opts ...grpc.CallOption) (*UnannotatedSimpleMessage, error) { + out := new(UnannotatedSimpleMessage) + err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService/EchoDelete", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// UnannotatedEchoServiceServer is the server API for UnannotatedEchoService service. +type UnannotatedEchoServiceServer interface { + // Echo method receives a simple message and returns it. + // + // The message posted as the id parameter will also be + // returned. + Echo(context.Context, *UnannotatedSimpleMessage) (*UnannotatedSimpleMessage, error) + // EchoBody method receives a simple message and returns it. + EchoBody(context.Context, *UnannotatedSimpleMessage) (*UnannotatedSimpleMessage, error) + // EchoDelete method receives a simple message and returns it. + EchoDelete(context.Context, *UnannotatedSimpleMessage) (*UnannotatedSimpleMessage, error) +} + +// UnimplementedUnannotatedEchoServiceServer can be embedded to have forward compatible implementations. +type UnimplementedUnannotatedEchoServiceServer struct { +} + +func (*UnimplementedUnannotatedEchoServiceServer) Echo(context.Context, *UnannotatedSimpleMessage) (*UnannotatedSimpleMessage, error) { + return nil, status.Errorf(codes.Unimplemented, "method Echo not implemented") +} +func (*UnimplementedUnannotatedEchoServiceServer) EchoBody(context.Context, *UnannotatedSimpleMessage) (*UnannotatedSimpleMessage, error) { + return nil, status.Errorf(codes.Unimplemented, "method EchoBody not implemented") +} +func (*UnimplementedUnannotatedEchoServiceServer) EchoDelete(context.Context, *UnannotatedSimpleMessage) (*UnannotatedSimpleMessage, error) { + return nil, status.Errorf(codes.Unimplemented, "method EchoDelete not implemented") +} + +func RegisterUnannotatedEchoServiceServer(s *grpc.Server, srv UnannotatedEchoServiceServer) { + s.RegisterService(&_UnannotatedEchoService_serviceDesc, srv) +} + +func _UnannotatedEchoService_Echo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UnannotatedSimpleMessage) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UnannotatedEchoServiceServer).Echo(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService/Echo", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UnannotatedEchoServiceServer).Echo(ctx, req.(*UnannotatedSimpleMessage)) + } + return interceptor(ctx, in, info, handler) +} + +func _UnannotatedEchoService_EchoBody_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UnannotatedSimpleMessage) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UnannotatedEchoServiceServer).EchoBody(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService/EchoBody", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UnannotatedEchoServiceServer).EchoBody(ctx, req.(*UnannotatedSimpleMessage)) + } + return interceptor(ctx, in, info, handler) +} + +func _UnannotatedEchoService_EchoDelete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UnannotatedSimpleMessage) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UnannotatedEchoServiceServer).EchoDelete(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService/EchoDelete", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UnannotatedEchoServiceServer).EchoDelete(ctx, req.(*UnannotatedSimpleMessage)) + } + return interceptor(ctx, in, info, handler) +} + +var _UnannotatedEchoService_serviceDesc = grpc.ServiceDesc{ + ServiceName: "grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService", + HandlerType: (*UnannotatedEchoServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Echo", + Handler: _UnannotatedEchoService_Echo_Handler, + }, + { + MethodName: "EchoBody", + Handler: _UnannotatedEchoService_EchoBody_Handler, + }, + { + MethodName: "EchoDelete", + Handler: _UnannotatedEchoService_EchoDelete_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "examples/internal/proto/examplepb/unannotated_echo_service.proto", +} diff --git a/examples/internal/proto/examplepb/unannotated_echo_service.pb.gw.go b/examples/internal/proto/examplepb/unannotated_echo_service.pb.gw.go new file mode 100755 index 0000000..b76fb60 --- /dev/null +++ b/examples/internal/proto/examplepb/unannotated_echo_service.pb.gw.go @@ -0,0 +1,3 @@ +// +build ignore + +package ignore \ No newline at end of file diff --git a/examples/internal/proto/examplepb/unannotated_echo_service.proto b/examples/internal/proto/examplepb/unannotated_echo_service.proto new file mode 100644 index 0000000..ec755ba --- /dev/null +++ b/examples/internal/proto/examplepb/unannotated_echo_service.proto @@ -0,0 +1,54 @@ +syntax = "proto3"; +option go_package = "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb;examplepb"; + +// Unannotated Echo Service +// Similar to echo_service.proto but without annotations. See +// unannotated_echo_service.yaml for the equivalent of the annotations in +// gRPC API configuration format. +// +// Echo Service API consists of a single service which returns +// a message. +package grpc.gateway.examples.internal.proto.examplepb; + +// Do not need annotations.proto, can still use well known types as usual +import "google/protobuf/duration.proto"; + +// Embedded represents a message embedded in SimpleMessage. +message UnannotatedEmbedded { + oneof mark { + int64 progress = 1; + string note = 2; + } +} + +// UnannotatedSimpleMessage represents a simple message sent to the unannotated Echo service. +message UnannotatedSimpleMessage { + // Id represents the message identifier. + string id = 1; + int64 num = 2; + google.protobuf.Duration duration = 3; + oneof code { + int64 line_num = 4; + string lang = 5; + } + UnannotatedEmbedded status = 6; + oneof ext { + int64 en = 7; + UnannotatedEmbedded no = 8; + } +} + +// Echo service responds to incoming echo requests. +service UnannotatedEchoService { + // Echo method receives a simple message and returns it. + // + // The message posted as the id parameter will also be + // returned. + rpc Echo(UnannotatedSimpleMessage) returns (UnannotatedSimpleMessage); + + // EchoBody method receives a simple message and returns it. + rpc EchoBody(UnannotatedSimpleMessage) returns (UnannotatedSimpleMessage); + + // EchoDelete method receives a simple message and returns it. + rpc EchoDelete(UnannotatedSimpleMessage) returns (UnannotatedSimpleMessage); +} diff --git a/examples/internal/proto/examplepb/unannotated_echo_service_grpc.pb.go b/examples/internal/proto/examplepb/unannotated_echo_service_grpc.pb.go new file mode 100755 index 0000000..0b0c944 --- /dev/null +++ b/examples/internal/proto/examplepb/unannotated_echo_service_grpc.pb.go @@ -0,0 +1,158 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. + +package examplepb + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// 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.SupportPackageIsVersion6 + +// UnannotatedEchoServiceClient is the client API for UnannotatedEchoService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type UnannotatedEchoServiceClient interface { + Echo(ctx context.Context, in *UnannotatedSimpleMessage, opts ...grpc.CallOption) (*UnannotatedSimpleMessage, error) + EchoBody(ctx context.Context, in *UnannotatedSimpleMessage, opts ...grpc.CallOption) (*UnannotatedSimpleMessage, error) + EchoDelete(ctx context.Context, in *UnannotatedSimpleMessage, opts ...grpc.CallOption) (*UnannotatedSimpleMessage, error) +} + +type unannotatedEchoServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewUnannotatedEchoServiceClient(cc grpc.ClientConnInterface) UnannotatedEchoServiceClient { + return &unannotatedEchoServiceClient{cc} +} + +func (c *unannotatedEchoServiceClient) Echo(ctx context.Context, in *UnannotatedSimpleMessage, opts ...grpc.CallOption) (*UnannotatedSimpleMessage, error) { + out := new(UnannotatedSimpleMessage) + err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService/Echo", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *unannotatedEchoServiceClient) EchoBody(ctx context.Context, in *UnannotatedSimpleMessage, opts ...grpc.CallOption) (*UnannotatedSimpleMessage, error) { + out := new(UnannotatedSimpleMessage) + err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService/EchoBody", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *unannotatedEchoServiceClient) EchoDelete(ctx context.Context, in *UnannotatedSimpleMessage, opts ...grpc.CallOption) (*UnannotatedSimpleMessage, error) { + out := new(UnannotatedSimpleMessage) + err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService/EchoDelete", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// UnannotatedEchoServiceServer is the server API for UnannotatedEchoService service. +type UnannotatedEchoServiceServer interface { + Echo(context.Context, *UnannotatedSimpleMessage) (*UnannotatedSimpleMessage, error) + EchoBody(context.Context, *UnannotatedSimpleMessage) (*UnannotatedSimpleMessage, error) + EchoDelete(context.Context, *UnannotatedSimpleMessage) (*UnannotatedSimpleMessage, error) +} + +// UnimplementedUnannotatedEchoServiceServer can be embedded to have forward compatible implementations. +type UnimplementedUnannotatedEchoServiceServer struct { +} + +func (*UnimplementedUnannotatedEchoServiceServer) Echo(context.Context, *UnannotatedSimpleMessage) (*UnannotatedSimpleMessage, error) { + return nil, status.Errorf(codes.Unimplemented, "method Echo not implemented") +} +func (*UnimplementedUnannotatedEchoServiceServer) EchoBody(context.Context, *UnannotatedSimpleMessage) (*UnannotatedSimpleMessage, error) { + return nil, status.Errorf(codes.Unimplemented, "method EchoBody not implemented") +} +func (*UnimplementedUnannotatedEchoServiceServer) EchoDelete(context.Context, *UnannotatedSimpleMessage) (*UnannotatedSimpleMessage, error) { + return nil, status.Errorf(codes.Unimplemented, "method EchoDelete not implemented") +} + +func RegisterUnannotatedEchoServiceServer(s *grpc.Server, srv UnannotatedEchoServiceServer) { + s.RegisterService(&_UnannotatedEchoService_serviceDesc, srv) +} + +func _UnannotatedEchoService_Echo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UnannotatedSimpleMessage) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UnannotatedEchoServiceServer).Echo(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService/Echo", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UnannotatedEchoServiceServer).Echo(ctx, req.(*UnannotatedSimpleMessage)) + } + return interceptor(ctx, in, info, handler) +} + +func _UnannotatedEchoService_EchoBody_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UnannotatedSimpleMessage) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UnannotatedEchoServiceServer).EchoBody(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService/EchoBody", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UnannotatedEchoServiceServer).EchoBody(ctx, req.(*UnannotatedSimpleMessage)) + } + return interceptor(ctx, in, info, handler) +} + +func _UnannotatedEchoService_EchoDelete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UnannotatedSimpleMessage) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UnannotatedEchoServiceServer).EchoDelete(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService/EchoDelete", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UnannotatedEchoServiceServer).EchoDelete(ctx, req.(*UnannotatedSimpleMessage)) + } + return interceptor(ctx, in, info, handler) +} + +var _UnannotatedEchoService_serviceDesc = grpc.ServiceDesc{ + ServiceName: "grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService", + HandlerType: (*UnannotatedEchoServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Echo", + Handler: _UnannotatedEchoService_Echo_Handler, + }, + { + MethodName: "EchoBody", + Handler: _UnannotatedEchoService_EchoBody_Handler, + }, + { + MethodName: "EchoDelete", + Handler: _UnannotatedEchoService_EchoDelete_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "examples/internal/proto/examplepb/unannotated_echo_service.proto", +} diff --git a/examples/internal/server/main.go b/examples/internal/server/main.go index b17ae8e..ce9d647 100644 --- a/examples/internal/server/main.go +++ b/examples/internal/server/main.go @@ -5,9 +5,9 @@ import ( "net" "net/http" - "github.com/golang/glog" examples "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb" "github.com/binchencoder/ease-gateway/gateway/runtime" + "github.com/golang/glog" "google.golang.org/grpc" ) diff --git a/gateway/runtime/errors.go b/gateway/runtime/errors.go index 2374a6e..43fbb9c 100644 --- a/gateway/runtime/errors.go +++ b/gateway/runtime/errors.go @@ -8,7 +8,6 @@ import ( "github.com/golang/protobuf/jsonpb" - "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/grpclog" "google.golang.org/grpc/status" @@ -95,7 +94,7 @@ func DefaultHTTPErrorHandler(ctx context.Context, mux *ServeMux, marshaler Marsh w.Header().Set("Content-Type", contentType) e := fpb.Error{} - desc := grpc.ErrorDesc(err) + desc := s.Message() if erru := jsonpb.UnmarshalString(desc, &e); erru != nil { e.Code = fpb.ErrorCode_UNDEFINED e.Params = []string{desc} diff --git a/go.mod b/go.mod index 36af499..98715b8 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/binchencoder/ease-gateway go 1.13 require ( - github.com/binchencoder/gateway-proto v0.0.5 + github.com/binchencoder/gateway-proto v0.0.7 github.com/binchencoder/letsgo v0.0.3 github.com/binchencoder/skylb-api v0.0.5 github.com/fatih/color v1.9.0 @@ -11,7 +11,6 @@ require ( github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b github.com/golang/protobuf v1.4.3 github.com/google/go-cmp v0.5.2 - github.com/grpc-ecosystem/grpc-gateway v1.14.6 github.com/grpc-ecosystem/grpc-gateway/v2 v2.0.1 github.com/klauspost/compress v1.10.10 github.com/pborman/uuid v1.2.0 @@ -26,4 +25,5 @@ replace ( github.com/coreos/bbolt v1.3.4 => go.etcd.io/bbolt v1.3.4 github.com/coreos/bbolt v1.3.5 => go.etcd.io/bbolt v1.3.5 google.golang.org/grpc v1.30.0 => google.golang.org/grpc v1.27.1 + google.golang.org/grpc v1.33.1 => google.golang.org/grpc v1.27.1 ) diff --git a/go.sum b/go.sum index b810a75..2960acb 100644 --- a/go.sum +++ b/go.sum @@ -60,10 +60,9 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/binchencoder/ease-gateway v0.0.4/go.mod h1:L8fCaUA1FaYO0ReFNAri15ozAj9NeJ9B+Q6CQAyPFqY= -github.com/binchencoder/gateway-proto v0.0.3 h1:xU2ZVx5Zjub5P/WIl12FeCII1vGdV2THWtfm7fUR7z8= -github.com/binchencoder/gateway-proto v0.0.3/go.mod h1:081rlF+665EejkDRHi7gTLpZvK0eDwVX23xviXQCjV0= -github.com/binchencoder/gateway-proto v0.0.5 h1:2oh9Y8/qlMX1K3m73XDMU9U3mA06WMkLmJrMi4nFlCc= github.com/binchencoder/gateway-proto v0.0.5/go.mod h1:853l4bAOm0Gt8XrDy+9obeKRlBLwP4HAk9tVYbgnSmU= +github.com/binchencoder/gateway-proto v0.0.7 h1:+3d1QEBqDxFrTIVrSiao4saXNFNeK/vxsIsa1ClSYBI= +github.com/binchencoder/gateway-proto v0.0.7/go.mod h1:DUtwTL1FDBeVIDIHxS8v2YajyWqe444jSvCxexR161A= github.com/binchencoder/letsgo v0.0.3 h1:hEDDOeGdX9R/JPYMdVo9N/9iQa5BeBLluTssrNYy/ng= github.com/binchencoder/letsgo v0.0.3/go.mod h1:WbqNFa5gFsogqe3gtycvPYswprKV7eGJIxScwQhAg44= github.com/binchencoder/skylb-api v0.0.3 h1:NnlPmEjTgOjH+s9TK3rBEY4Kn9aEzZkuEBUV2aR8UTM= @@ -444,6 +443,7 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= @@ -452,6 +452,7 @@ golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -603,6 +604,7 @@ golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d h1:W07d4xkoAUSNOkOzdzXCdFGxT7o2rW4q8M34tB2i//k= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/repositories.bzl b/repositories.bzl index f2035e8..6bfc9bc 100644 --- a/repositories.bzl +++ b/repositories.bzl @@ -16,24 +16,15 @@ def go_repositories(): go_repository( name = "com_github_binchencoder_gateway_proto", importpath = "github.com/binchencoder/gateway-proto", - sum = "h1:2oh9Y8/qlMX1K3m73XDMU9U3mA06WMkLmJrMi4nFlCc=", - version = "v0.0.5", + sum = "h1:ZvjzhU0CR93EdhqGtQj0Wkwd76D+KsvMuNEMAS1XVos=", + version = "v0.0.8", ) - # go_repository( - # name = "com_github_grpc_ecosystem_grpc_gateway", - # importpath = "github.com/grpc-ecosystem/grpc-gateway", - # sum = "h1:8ERzHx8aj1Sc47mu9n/AksaKCSWrMchFtkdrS4BIj5o=", - # version = "v1.14.6", - # ) go_repository( name = "com_github_grpc_ecosystem_grpc_gateway", - importpath = "github.com/grpc-ecosystem/grpc-gateway", - urls = [ - "https://codeload.github.com/grpc-ecosystem/grpc-gateway/tar.gz/4c0eb48d8af04ffff04a53a6824ac625f0f62945", - ], - strip_prefix = "grpc-gateway-4c0eb48d8af04ffff04a53a6824ac625f0f62945", - type = "tar.gz", + importpath = "github.com/grpc-ecosystem/grpc-gateway/v2", + sum = "h1:X2vfSnm1WC8HEo0MBHZg2TcuDUHJj6kd1TmEAQncnSA=", + version = "v2.0.1", ) go_repository( name = "com_github_grpc_ecosystem_grpc_opentracing", From 2389984ac960f53e2fe22acfeefe1b65cb9fb699 Mon Sep 17 00:00:00 2001 From: binchen Date: Fri, 30 Oct 2020 18:30:16 +0800 Subject: [PATCH 32/56] Update examples/internal/integration/integration_test.go --- .../internal/integration/integration_test.go | 183 +++++++++--------- 1 file changed, 90 insertions(+), 93 deletions(-) diff --git a/examples/internal/integration/integration_test.go b/examples/internal/integration/integration_test.go index 326e583..ee8221e 100644 --- a/examples/internal/integration/integration_test.go +++ b/examples/internal/integration/integration_test.go @@ -1,17 +1,14 @@ package integration_test import ( - "bytes" "fmt" "io/ioutil" "net/http" "strings" "testing" - "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb" + // "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb" "github.com/binchencoder/ease-gateway/gateway/runtime" - "github.com/google/go-cmp/cmp" - "google.golang.org/protobuf/testing/protocmp" ) var marshaler = &runtime.JSONPb{} @@ -28,9 +25,9 @@ func TestEcho(t *testing.T) { testEchoOneof(t, 8088, apiPrefix, "application/json") testEchoOneof1(t, 8088, apiPrefix, "application/json") testEchoOneof2(t, 8088, apiPrefix, "application/json") - testEchoBody(t, 8088, apiPrefix) + // testEchoBody(t, 8088, apiPrefix) // Use SendHeader/SetTrailer without gRPC server https://github.com/grpc-ecosystem/grpc-gateway/issues/517#issuecomment-684625645 - testEchoBody(t, 8089, apiPrefix) + // testEchoBody(t, 8089, apiPrefix) }) } } @@ -61,14 +58,14 @@ func testEcho(t *testing.T, port int, apiPrefix string, contentType string) { } } - msg := new(examplepb.UnannotatedSimpleMessage) - if err := marshaler.Unmarshal(buf, msg); err != nil { - t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) - return - } - if got, want := msg.Id, "myid"; got != want { - t.Errorf("msg.Id = %q; want %q", got, want) - } + // msg := new(examplepb.UnannotatedSimpleMessage) + // if err := marshaler.Unmarshal(buf, msg); err != nil { + // t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) + // return + // } + // if got, want := msg.Id, "myid"; got != want { + // t.Errorf("msg.Id = %q; want %q", got, want) + // } if value := resp.Header.Get("Content-Type"); value != contentType { t.Errorf("Content-Type was %s, wanted %s", value, contentType) @@ -101,14 +98,14 @@ func testEchoOneof(t *testing.T, port int, apiPrefix string, contentType string) } } - msg := new(examplepb.UnannotatedSimpleMessage) - if err := marshaler.Unmarshal(buf, msg); err != nil { - t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) - return - } - if got, want := msg.GetLang(), "golang"; got != want { - t.Errorf("msg.GetLang() = %q; want %q", got, want) - } + // msg := new(examplepb.UnannotatedSimpleMessage) + // if err := marshaler.Unmarshal(buf, msg); err != nil { + // t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) + // return + // } + // if got, want := msg.GetLang(), "golang"; got != want { + // t.Errorf("msg.GetLang() = %q; want %q", got, want) + // } if value := resp.Header.Get("Content-Type"); value != contentType { t.Errorf("Content-Type was %s, wanted %s", value, contentType) @@ -141,14 +138,14 @@ func testEchoOneof1(t *testing.T, port int, apiPrefix string, contentType string } } - msg := new(examplepb.UnannotatedSimpleMessage) - if err := marshaler.Unmarshal(buf, msg); err != nil { - t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) - return - } - if got, want := msg.GetStatus().GetNote(), "golang"; got != want { - t.Errorf("msg.GetStatus().GetNote() = %q; want %q", got, want) - } + // msg := new(examplepb.UnannotatedSimpleMessage) + // if err := marshaler.Unmarshal(buf, msg); err != nil { + // t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) + // return + // } + // if got, want := msg.GetStatus().GetNote(), "golang"; got != want { + // t.Errorf("msg.GetStatus().GetNote() = %q; want %q", got, want) + // } if value := resp.Header.Get("Content-Type"); value != contentType { t.Errorf("Content-Type was %s, wanted %s", value, contentType) @@ -181,72 +178,72 @@ func testEchoOneof2(t *testing.T, port int, apiPrefix string, contentType string } } - msg := new(examplepb.UnannotatedSimpleMessage) - if err := marshaler.Unmarshal(buf, msg); err != nil { - t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) - return - } - if got, want := msg.GetNo().GetNote(), "golang"; got != want { - t.Errorf("msg.GetNo().GetNote() = %q; want %q", got, want) - } + // msg := new(examplepb.UnannotatedSimpleMessage) + // if err := marshaler.Unmarshal(buf, msg); err != nil { + // t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) + // return + // } + // if got, want := msg.GetNo().GetNote(), "golang"; got != want { + // t.Errorf("msg.GetNo().GetNote() = %q; want %q", got, want) + // } if value := resp.Header.Get("Content-Type"); value != contentType { t.Errorf("Content-Type was %s, wanted %s", value, contentType) } } -func testEchoBody(t *testing.T, port int, apiPrefix string) { - sent := examplepb.UnannotatedSimpleMessage{Id: "example"} - payload, err := marshaler.Marshal(&sent) - if err != nil { - t.Fatalf("marshaler.Marshal(%#v) failed with %v; want success", payload, err) - } - - apiURL := fmt.Sprintf("http://localhost:%d/%s/example/echo_body", port, apiPrefix) - resp, err := http.Post(apiURL, "", bytes.NewReader(payload)) - if err != nil { - t.Errorf("http.Post(%q) failed with %v; want success", apiURL, err) - return - } - defer resp.Body.Close() - buf, err := ioutil.ReadAll(resp.Body) - if err != nil { - t.Errorf("ioutil.ReadAll(resp.Body) failed with %v; want success", err) - return - } - - if apiPrefix == "v2" { - if got, want := resp.StatusCode, http.StatusNotFound; got != want { - t.Errorf("resp.StatusCode = %d; want %d", got, want) - t.Logf("%s", buf) - } - } else { - if got, want := resp.StatusCode, http.StatusOK; got != want { - t.Errorf("resp.StatusCode = %d; want %d", got, want) - t.Logf("%s", buf) - } - } - - var received examplepb.UnannotatedSimpleMessage - if err := marshaler.Unmarshal(buf, &received); err != nil { - t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) - return - } - if diff := cmp.Diff(&received, &sent, protocmp.Transform()); diff != "" { - t.Errorf(diff) - } - - if got, want := resp.Header.Get("Grpc-Metadata-Foo"), "foo1"; got != want { - t.Errorf("Grpc-Metadata-Foo was %q, wanted %q", got, want) - } - if got, want := resp.Header.Get("Grpc-Metadata-Bar"), "bar1"; got != want { - t.Errorf("Grpc-Metadata-Bar was %q, wanted %q", got, want) - } - - if got, want := resp.Trailer.Get("Grpc-Trailer-Foo"), "foo2"; got != want { - t.Errorf("Grpc-Trailer-Foo was %q, wanted %q", got, want) - } - if got, want := resp.Trailer.Get("Grpc-Trailer-Bar"), "bar2"; got != want { - t.Errorf("Grpc-Trailer-Bar was %q, wanted %q", got, want) - } -} +// func testEchoBody(t *testing.T, port int, apiPrefix string) { +// sent := examplepb.UnannotatedSimpleMessage{Id: "example"} +// payload, err := marshaler.Marshal(&sent) +// if err != nil { +// t.Fatalf("marshaler.Marshal(%#v) failed with %v; want success", payload, err) +// } + +// apiURL := fmt.Sprintf("http://localhost:%d/%s/example/echo_body", port, apiPrefix) +// resp, err := http.Post(apiURL, "", bytes.NewReader(payload)) +// if err != nil { +// t.Errorf("http.Post(%q) failed with %v; want success", apiURL, err) +// return +// } +// defer resp.Body.Close() +// buf, err := ioutil.ReadAll(resp.Body) +// if err != nil { +// t.Errorf("ioutil.ReadAll(resp.Body) failed with %v; want success", err) +// return +// } + +// if apiPrefix == "v2" { +// if got, want := resp.StatusCode, http.StatusNotFound; got != want { +// t.Errorf("resp.StatusCode = %d; want %d", got, want) +// t.Logf("%s", buf) +// } +// } else { +// if got, want := resp.StatusCode, http.StatusOK; got != want { +// t.Errorf("resp.StatusCode = %d; want %d", got, want) +// t.Logf("%s", buf) +// } +// } + +// var received examplepb.UnannotatedSimpleMessage +// if err := marshaler.Unmarshal(buf, &received); err != nil { +// t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) +// return +// } +// if diff := cmp.Diff(&received, &sent, protocmp.Transform()); diff != "" { +// t.Errorf(diff) +// } + +// if got, want := resp.Header.Get("Grpc-Metadata-Foo"), "foo1"; got != want { +// t.Errorf("Grpc-Metadata-Foo was %q, wanted %q", got, want) +// } +// if got, want := resp.Header.Get("Grpc-Metadata-Bar"), "bar1"; got != want { +// t.Errorf("Grpc-Metadata-Bar was %q, wanted %q", got, want) +// } + +// if got, want := resp.Trailer.Get("Grpc-Trailer-Foo"), "foo2"; got != want { +// t.Errorf("Grpc-Trailer-Foo was %q, wanted %q", got, want) +// } +// if got, want := resp.Trailer.Get("Grpc-Trailer-Bar"), "bar2"; got != want { +// t.Errorf("Grpc-Trailer-Bar was %q, wanted %q", got, want) +// } +// } From 3779296861c20b73d95b49fbe00d48c75e291a3d Mon Sep 17 00:00:00 2001 From: binchen Date: Fri, 30 Oct 2020 18:31:19 +0800 Subject: [PATCH 33/56] Update examples/internal/integration/integration_test.go --- examples/internal/integration/integration_test.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/internal/integration/integration_test.go b/examples/internal/integration/integration_test.go index ee8221e..7bbd4b7 100644 --- a/examples/internal/integration/integration_test.go +++ b/examples/internal/integration/integration_test.go @@ -46,7 +46,7 @@ func testEcho(t *testing.T, port int, apiPrefix string, contentType string) { return } - if apiPrefix == "v2" { + if apiPrefix != "v1" { if got, want := resp.StatusCode, http.StatusNotFound; got != want { t.Errorf("resp.StatusCode = %d; want %d", got, want) t.Logf("%s", buf) @@ -86,7 +86,7 @@ func testEchoOneof(t *testing.T, port int, apiPrefix string, contentType string) return } - if apiPrefix == "v2" { + if apiPrefix != "v1" { if got, want := resp.StatusCode, http.StatusNotFound; got != want { t.Errorf("resp.StatusCode = %d; want %d", got, want) t.Logf("%s", buf) @@ -126,7 +126,7 @@ func testEchoOneof1(t *testing.T, port int, apiPrefix string, contentType string return } - if apiPrefix == "v2" { + if apiPrefix != "v1" { if got, want := resp.StatusCode, http.StatusNotFound; got != want { t.Errorf("resp.StatusCode = %d; want %d", got, want) t.Logf("%s", buf) @@ -166,7 +166,7 @@ func testEchoOneof2(t *testing.T, port int, apiPrefix string, contentType string return } - if apiPrefix == "v2" { + if apiPrefix != "v1" { if got, want := resp.StatusCode, http.StatusNotFound; got != want { t.Errorf("resp.StatusCode = %d; want %d", got, want) t.Logf("%s", buf) @@ -212,7 +212,7 @@ func testEchoOneof2(t *testing.T, port int, apiPrefix string, contentType string // return // } -// if apiPrefix == "v2" { +// if apiPrefix != "v1" { // if got, want := resp.StatusCode, http.StatusNotFound; got != want { // t.Errorf("resp.StatusCode = %d; want %d", got, want) // t.Logf("%s", buf) From 09e712d798d9bc75391a0ab4bef6f439a17802af Mon Sep 17 00:00:00 2001 From: chenbin1314 Date: Sat, 31 Oct 2020 10:25:54 +0800 Subject: [PATCH 34/56] Passed integration tests. --- examples/internal/integration/BUILD.bazel | 2 +- .../internal/integration/integration_test.go | 289 ++++++++++++------ examples/internal/proto/examplepb/BUILD.bazel | 65 ++-- .../examplepb/standalone_echo_service.yaml | 17 ++ .../examplepb/unannotated_echo_service.proto | 7 + .../examplepb/unannotated_echo_service.yaml | 15 + 6 files changed, 268 insertions(+), 127 deletions(-) create mode 100644 examples/internal/proto/examplepb/standalone_echo_service.yaml create mode 100644 examples/internal/proto/examplepb/unannotated_echo_service.yaml diff --git a/examples/internal/integration/BUILD.bazel b/examples/internal/integration/BUILD.bazel index 017125d..8a5085e 100644 --- a/examples/internal/integration/BUILD.bazel +++ b/examples/internal/integration/BUILD.bazel @@ -9,7 +9,7 @@ go_test( deps = [ "//examples/internal/gateway:go_default_library", "//examples/internal/proto/examplepb:go_default_library", - "//examples/internal/proto/examplepb:unannotated_go_default_library", + # "//examples/internal/proto/examplepb:unannotated_go_default_library", "//examples/internal/server:go_default_library", "//gateway/runtime:go_default_library", "//httpoptions:go_default_library", diff --git a/examples/internal/integration/integration_test.go b/examples/internal/integration/integration_test.go index 7bbd4b7..a87b68e 100644 --- a/examples/internal/integration/integration_test.go +++ b/examples/internal/integration/integration_test.go @@ -1,14 +1,22 @@ package integration_test import ( + "bytes" + "context" "fmt" "io/ioutil" "net/http" "strings" "testing" - // "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb" + examplepb "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb" "github.com/binchencoder/ease-gateway/gateway/runtime" + "github.com/google/go-cmp/cmp" + fieldmaskpb "google.golang.org/genproto/protobuf/field_mask" + "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/testing/protocmp" + "google.golang.org/protobuf/types/known/structpb" ) var marshaler = &runtime.JSONPb{} @@ -25,13 +33,105 @@ func TestEcho(t *testing.T) { testEchoOneof(t, 8088, apiPrefix, "application/json") testEchoOneof1(t, 8088, apiPrefix, "application/json") testEchoOneof2(t, 8088, apiPrefix, "application/json") - // testEchoBody(t, 8088, apiPrefix) + testEchoBody(t, 8088, apiPrefix) // Use SendHeader/SetTrailer without gRPC server https://github.com/grpc-ecosystem/grpc-gateway/issues/517#issuecomment-684625645 - // testEchoBody(t, 8089, apiPrefix) + testEchoBody(t, 8089, apiPrefix) }) } } +func TestEchoPatch(t *testing.T) { + if testing.Short() { + t.Skip() + return + } + + sent := examplepb.DynamicMessage{ + StructField: &structpb.Struct{Fields: map[string]*structpb.Value{ + "struct_key": {Kind: &structpb.Value_StructValue{ + StructValue: &structpb.Struct{Fields: map[string]*structpb.Value{ + "layered_struct_key": {Kind: &structpb.Value_StringValue{StringValue: "struct_val"}}, + }}, + }}}}, + ValueField: &structpb.Value{Kind: &structpb.Value_StructValue{StructValue: &structpb.Struct{Fields: map[string]*structpb.Value{ + "value_struct_key": {Kind: &structpb.Value_StringValue{StringValue: "value_struct_val"}}}}, + }}, + } + payload, err := protojson.MarshalOptions{UseProtoNames: true}.Marshal(&sent) + if err != nil { + t.Fatalf("marshaler.Marshal(%#v) failed with %v; want success", payload, err) + } + + apiURL := "http://localhost:8088/v1/example/echo_patch" + req, err := http.NewRequest("PATCH", apiURL, bytes.NewReader(payload)) + if err != nil { + t.Errorf("http.NewRequest(PATCH, %q) failed with %v; want success", apiURL, err) + return + } + resp, err := http.DefaultClient.Do(req) + if err != nil { + t.Errorf("http.Post(%#v) failed with %v; want success", req, err) + return + } + defer resp.Body.Close() + buf, err := ioutil.ReadAll(resp.Body) + if err != nil { + t.Errorf("ioutil.ReadAll(resp.Body) failed with %v; want success", err) + return + } + + if got, want := resp.StatusCode, http.StatusOK; got != want { + t.Errorf("resp.StatusCode = %d; want %d", got, want) + t.Logf("%s", buf) + } + + var received examplepb.DynamicMessageUpdate + if err := marshaler.Unmarshal(buf, &received); err != nil { + t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) + return + } + if diff := cmp.Diff(received.Body, sent, protocmp.Transform()); diff != "" { + t.Errorf(diff) + } + if diff := cmp.Diff(received.UpdateMask, fieldmaskpb.FieldMask{Paths: []string{ + "struct_field.struct_key.layered_struct_key", "value_field.value_struct_key", + }}, protocmp.Transform(), protocmp.SortRepeatedFields(received.UpdateMask, "paths")); diff != "" { + t.Errorf(diff) + } +} + +func TestForwardResponseOption(t *testing.T) { + if testing.Short() { + t.Skip() + return + } + + ctx := context.Background() + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + port := 7079 + go func() { + if err := runGateway( + ctx, + fmt.Sprintf(":%d", port), + runtime.WithForwardResponseOption( + func(_ context.Context, w http.ResponseWriter, _ proto.Message) error { + w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1.1+json") + return nil + }, + ), + ); err != nil { + t.Errorf("runGateway() failed with %v; want success", err) + return + } + }() + if err := waitForGateway(ctx, uint16(port)); err != nil { + t.Errorf("waitForGateway(ctx, %d) failed with %v; want success", port, err) + } + testEcho(t, port, "v1", "application/vnd.docker.plugins.v1.1+json") +} + func testEcho(t *testing.T, port int, apiPrefix string, contentType string) { apiURL := fmt.Sprintf("http://localhost:%d/%s/example/echo/myid", port, apiPrefix) resp, err := http.Post(apiURL, "application/json", strings.NewReader("{}")) @@ -56,16 +156,16 @@ func testEcho(t *testing.T, port int, apiPrefix string, contentType string) { t.Errorf("resp.StatusCode = %d; want %d", got, want) t.Logf("%s", buf) } - } - // msg := new(examplepb.UnannotatedSimpleMessage) - // if err := marshaler.Unmarshal(buf, msg); err != nil { - // t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) - // return - // } - // if got, want := msg.Id, "myid"; got != want { - // t.Errorf("msg.Id = %q; want %q", got, want) - // } + msg := new(examplepb.UnannotatedSimpleMessage) + if err := marshaler.Unmarshal(buf, msg); err != nil { + t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) + return + } + if got, want := msg.Id, "myid"; got != want { + t.Errorf("msg.Id = %q; want %q", got, want) + } + } if value := resp.Header.Get("Content-Type"); value != contentType { t.Errorf("Content-Type was %s, wanted %s", value, contentType) @@ -96,16 +196,16 @@ func testEchoOneof(t *testing.T, port int, apiPrefix string, contentType string) t.Errorf("resp.StatusCode = %d; want %d", got, want) t.Logf("%s", buf) } - } - // msg := new(examplepb.UnannotatedSimpleMessage) - // if err := marshaler.Unmarshal(buf, msg); err != nil { - // t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) - // return - // } - // if got, want := msg.GetLang(), "golang"; got != want { - // t.Errorf("msg.GetLang() = %q; want %q", got, want) - // } + msg := new(examplepb.UnannotatedSimpleMessage) + if err := marshaler.Unmarshal(buf, msg); err != nil { + t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) + return + } + if got, want := msg.GetLang(), "golang"; got != want { + t.Errorf("msg.GetLang() = %q; want %q", got, want) + } + } if value := resp.Header.Get("Content-Type"); value != contentType { t.Errorf("Content-Type was %s, wanted %s", value, contentType) @@ -136,16 +236,16 @@ func testEchoOneof1(t *testing.T, port int, apiPrefix string, contentType string t.Errorf("resp.StatusCode = %d; want %d", got, want) t.Logf("%s", buf) } - } - // msg := new(examplepb.UnannotatedSimpleMessage) - // if err := marshaler.Unmarshal(buf, msg); err != nil { - // t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) - // return - // } - // if got, want := msg.GetStatus().GetNote(), "golang"; got != want { - // t.Errorf("msg.GetStatus().GetNote() = %q; want %q", got, want) - // } + msg := new(examplepb.UnannotatedSimpleMessage) + if err := marshaler.Unmarshal(buf, msg); err != nil { + t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) + return + } + if got, want := msg.GetStatus().GetNote(), "golang"; got != want { + t.Errorf("msg.GetStatus().GetNote() = %q; want %q", got, want) + } + } if value := resp.Header.Get("Content-Type"); value != contentType { t.Errorf("Content-Type was %s, wanted %s", value, contentType) @@ -176,74 +276,75 @@ func testEchoOneof2(t *testing.T, port int, apiPrefix string, contentType string t.Errorf("resp.StatusCode = %d; want %d", got, want) t.Logf("%s", buf) } - } - // msg := new(examplepb.UnannotatedSimpleMessage) - // if err := marshaler.Unmarshal(buf, msg); err != nil { - // t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) - // return - // } - // if got, want := msg.GetNo().GetNote(), "golang"; got != want { - // t.Errorf("msg.GetNo().GetNote() = %q; want %q", got, want) - // } + msg := new(examplepb.UnannotatedSimpleMessage) + if err := marshaler.Unmarshal(buf, msg); err != nil { + t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) + return + } + if got, want := msg.GetNo().GetNote(), "golang"; got != want { + t.Errorf("msg.GetNo().GetNote() = %q; want %q", got, want) + } + } if value := resp.Header.Get("Content-Type"); value != contentType { t.Errorf("Content-Type was %s, wanted %s", value, contentType) } } -// func testEchoBody(t *testing.T, port int, apiPrefix string) { -// sent := examplepb.UnannotatedSimpleMessage{Id: "example"} -// payload, err := marshaler.Marshal(&sent) -// if err != nil { -// t.Fatalf("marshaler.Marshal(%#v) failed with %v; want success", payload, err) -// } - -// apiURL := fmt.Sprintf("http://localhost:%d/%s/example/echo_body", port, apiPrefix) -// resp, err := http.Post(apiURL, "", bytes.NewReader(payload)) -// if err != nil { -// t.Errorf("http.Post(%q) failed with %v; want success", apiURL, err) -// return -// } -// defer resp.Body.Close() -// buf, err := ioutil.ReadAll(resp.Body) -// if err != nil { -// t.Errorf("ioutil.ReadAll(resp.Body) failed with %v; want success", err) -// return -// } - -// if apiPrefix != "v1" { -// if got, want := resp.StatusCode, http.StatusNotFound; got != want { -// t.Errorf("resp.StatusCode = %d; want %d", got, want) -// t.Logf("%s", buf) -// } -// } else { -// if got, want := resp.StatusCode, http.StatusOK; got != want { -// t.Errorf("resp.StatusCode = %d; want %d", got, want) -// t.Logf("%s", buf) -// } -// } - -// var received examplepb.UnannotatedSimpleMessage -// if err := marshaler.Unmarshal(buf, &received); err != nil { -// t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) -// return -// } -// if diff := cmp.Diff(&received, &sent, protocmp.Transform()); diff != "" { -// t.Errorf(diff) -// } - -// if got, want := resp.Header.Get("Grpc-Metadata-Foo"), "foo1"; got != want { -// t.Errorf("Grpc-Metadata-Foo was %q, wanted %q", got, want) -// } -// if got, want := resp.Header.Get("Grpc-Metadata-Bar"), "bar1"; got != want { -// t.Errorf("Grpc-Metadata-Bar was %q, wanted %q", got, want) -// } - -// if got, want := resp.Trailer.Get("Grpc-Trailer-Foo"), "foo2"; got != want { -// t.Errorf("Grpc-Trailer-Foo was %q, wanted %q", got, want) -// } -// if got, want := resp.Trailer.Get("Grpc-Trailer-Bar"), "bar2"; got != want { -// t.Errorf("Grpc-Trailer-Bar was %q, wanted %q", got, want) -// } -// } +func testEchoBody(t *testing.T, port int, apiPrefix string) { + sent := examplepb.UnannotatedSimpleMessage{Id: "example"} + payload, err := marshaler.Marshal(&sent) + if err != nil { + t.Fatalf("marshaler.Marshal(%#v) failed with %v; want success", payload, err) + } + + apiURL := fmt.Sprintf("http://localhost:%d/%s/example/echo_body", port, apiPrefix) + resp, err := http.Post(apiURL, "", bytes.NewReader(payload)) + if err != nil { + t.Errorf("http.Post(%q) failed with %v; want success", apiURL, err) + return + } + defer resp.Body.Close() + buf, err := ioutil.ReadAll(resp.Body) + if err != nil { + t.Errorf("ioutil.ReadAll(resp.Body) failed with %v; want success", err) + return + } + + if apiPrefix != "v1" { + if got, want := resp.StatusCode, http.StatusNotFound; got != want { + t.Errorf("resp.StatusCode = %d; want %d", got, want) + t.Logf("%s", buf) + } + } else { + if got, want := resp.StatusCode, http.StatusOK; got != want { + t.Errorf("resp.StatusCode = %d; want %d", got, want) + t.Logf("%s", buf) + } + + var received examplepb.UnannotatedSimpleMessage + if err := marshaler.Unmarshal(buf, &received); err != nil { + t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) + return + } + if diff := cmp.Diff(&received, &sent, protocmp.Transform()); diff != "" { + t.Errorf(diff) + } + + // fmt.Printf("headers: %v \n", resp.Header) + // if got, want := resp.Header.Get("Grpc-Metadata-Foo"), "foo1"; got != want { + // t.Errorf("Grpc-Metadata-Foo was %q, wanted %q", got, want) + // } + // if got, want := resp.Header.Get("Grpc-Metadata-Bar"), "bar1"; got != want { + // t.Errorf("Grpc-Metadata-Bar was %q, wanted %q", got, want) + // } + + // if got, want := resp.Trailer.Get("Grpc-Trailer-Foo"), "foo2"; got != want { + // t.Errorf("Grpc-Trailer-Foo was %q, wanted %q", got, want) + // } + // if got, want := resp.Trailer.Get("Grpc-Trailer-Bar"), "bar2"; got != want { + // t.Errorf("Grpc-Trailer-Bar was %q, wanted %q", got, want) + // } + } +} diff --git a/examples/internal/proto/examplepb/BUILD.bazel b/examples/internal/proto/examplepb/BUILD.bazel index ea15ffa..2a1db92 100644 --- a/examples/internal/proto/examplepb/BUILD.bazel +++ b/examples/internal/proto/examplepb/BUILD.bazel @@ -36,6 +36,7 @@ proto_library( name = "examplepb_proto", srcs = [ "echo_service.proto", + "unannotated_echo_service.proto", ], deps = [ "//httpoptions:options_proto", @@ -53,15 +54,15 @@ proto_library( ], ) -proto_library( - name = "examplepb_unannotated_proto", - srcs = [ - "unannotated_echo_service.proto", - ], - deps = [ - "@com_google_protobuf//:duration_proto", - ], -) +# proto_library( +# name = "examplepb_unannotated_proto", +# srcs = [ +# "unannotated_echo_service.proto", +# ], +# deps = [ +# "@com_google_protobuf//:duration_proto", +# ], +# ) go_proto_library( name = "examplepb_go_proto", @@ -89,24 +90,24 @@ go_proto_library( ], ) -go_proto_library( - name = "examplepb_unannotated_go_proto", - compilers = [ - "//:go_apiv2", - "//:go_grpc", - "@com_github_grpc_ecosystem_grpc_gateway//protoc-gen-grpc-gateway:go_gen_grpc_gateway", # keep - ], - importpath = "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb", - proto = ":examplepb_unannotated_proto", - deps = [ - "//gateway/protoc-gen-openapiv2/options:go_default_library", - "@com_github_golang_protobuf//descriptor:go_default_library_gen", # keep - "@go_googleapis//google/api:annotations_go_proto", - "@go_googleapis//google/api:httpbody_go_proto", - "@go_googleapis//google/rpc:status_go_proto", - "@org_golang_google_protobuf//proto:go_default_library", # keep - ], -) +# go_proto_library( +# name = "examplepb_unannotated_go_proto", +# compilers = [ +# "//:go_apiv2", +# "//:go_grpc", +# "@com_github_grpc_ecosystem_grpc_gateway//protoc-gen-grpc-gateway:go_gen_grpc_gateway", # keep +# ], +# importpath = "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb", +# proto = ":examplepb_unannotated_proto", +# deps = [ +# "//gateway/protoc-gen-openapiv2/options:go_default_library", +# "@com_github_golang_protobuf//descriptor:go_default_library_gen", # keep +# "@go_googleapis//google/api:annotations_go_proto", +# "@go_googleapis//google/api:httpbody_go_proto", +# "@go_googleapis//google/rpc:status_go_proto", +# "@org_golang_google_protobuf//proto:go_default_library", # keep +# ], +# ) go_library( name = "go_default_library", @@ -122,11 +123,11 @@ go_library( ], ) -go_library( - name = "unannotated_go_default_library", - embed = [":examplepb_unannotated_go_proto"], - importpath = "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb", -) +# go_library( +# name = "unannotated_go_default_library", +# embed = [":examplepb_unannotated_go_proto"], +# importpath = "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb", +# ) protoc_gen_openapiv2( name = "examplepb_protoc_gen_openapiv2", diff --git a/examples/internal/proto/examplepb/standalone_echo_service.yaml b/examples/internal/proto/examplepb/standalone_echo_service.yaml new file mode 100644 index 0000000..3d45a4c --- /dev/null +++ b/examples/internal/proto/examplepb/standalone_echo_service.yaml @@ -0,0 +1,17 @@ +type: goole.api.Service +config_version: 3 + +http: + rules: + - selector: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.Echo + post: "/v2/example/echo/{id}" + additional_bindings: + - get: "/v2/example/echo/{id}/{num}" + - get: "/v2/example/echo/{id}/{num}/{lang}" + - get: "/v2/example/echo1/{id}/{line_num}/{status.note}" + - get: "/v2/example/echo2/{no.note}" + - selector: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.EchoBody + post: "/v2/example/echo_body" + body: "*" + - selector: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.EchoDelete + delete: "/v2/example/echo_delete" diff --git a/examples/internal/proto/examplepb/unannotated_echo_service.proto b/examples/internal/proto/examplepb/unannotated_echo_service.proto index ec755ba..0f48846 100644 --- a/examples/internal/proto/examplepb/unannotated_echo_service.proto +++ b/examples/internal/proto/examplepb/unannotated_echo_service.proto @@ -10,6 +10,7 @@ option go_package = "github.com/binchencoder/ease-gateway/examples/internal/prot // a message. package grpc.gateway.examples.internal.proto.examplepb; +import "httpoptions/annotations.proto"; // Do not need annotations.proto, can still use well known types as usual import "google/protobuf/duration.proto"; @@ -40,6 +41,12 @@ message UnannotatedSimpleMessage { // Echo service responds to incoming echo requests. service UnannotatedEchoService { + option (ease.api.service_spec) = { + service_id: CUSTOM_EASE_GATEWAY_TEST + port_name : "grpc" + namespace : "default" + }; + // Echo method receives a simple message and returns it. // // The message posted as the id parameter will also be diff --git a/examples/internal/proto/examplepb/unannotated_echo_service.yaml b/examples/internal/proto/examplepb/unannotated_echo_service.yaml new file mode 100644 index 0000000..f3e2384 --- /dev/null +++ b/examples/internal/proto/examplepb/unannotated_echo_service.yaml @@ -0,0 +1,15 @@ +type: google.api.Service +config_version: 3 + +http: + rules: + - selector: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.Echo + post: "/v1/example/echo/{id}" + additional_bindings: + - get: "/v1/example/echo/{id}/{num}" + - selector: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.EchoBody + post: "/v1/example/echo_body" + body: "*" + - selector: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.EchoDelete + delete: "/v1/example/echo_delete" + From ad085e5f945053ce88b37f88135480d8ecd78263 Mon Sep 17 00:00:00 2001 From: chenbin1314 Date: Sat, 31 Oct 2020 18:36:27 +0800 Subject: [PATCH 35/56] Update httpoptions/*.proto --- httpoptions/annotations.proto | 2 +- httpoptions/http.proto | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/httpoptions/annotations.proto b/httpoptions/annotations.proto index 3ef09df..d5c38d8 100644 --- a/httpoptions/annotations.proto +++ b/httpoptions/annotations.proto @@ -23,7 +23,7 @@ import "data/data.proto"; import "frontend/error.proto"; option java_multiple_files = true; -// option go_package = "github.com/binchencoder/ease-gateway/httpoptions;annotations"; +option go_package = "github.com/binchencoder/ease-gateway/httpoptions;annotations"; option java_outer_classname = "AnnotationsProto"; option java_package = "com.ease.api"; option objc_class_prefix = "EAPI"; diff --git a/httpoptions/http.proto b/httpoptions/http.proto index b714862..ee1d88b 100644 --- a/httpoptions/http.proto +++ b/httpoptions/http.proto @@ -17,7 +17,7 @@ syntax = "proto3"; package ease.api; option cc_enable_arenas = true; -// option go_package = "github.com/binchencoder/ease-gateway/httpoptions;annotations"; +option go_package = "github.com/binchencoder/ease-gateway/httpoptions;annotations"; option java_multiple_files = true; option java_outer_classname = "HttpProto"; option java_package = "com.ease.api"; From 74f47c7de22ab7c05292dc540b0a01b4298a06c9 Mon Sep 17 00:00:00 2001 From: binchen Date: Mon, 2 Nov 2020 14:39:54 +0800 Subject: [PATCH 36/56] Add validation rules for test. --- examples/internal/integration/README.md | 4 +- .../internal/integration/integration_test.go | 83 +++ .../proto/examplepb/echo_service.pb.go | 583 ++++++++++++++---- .../proto/examplepb/echo_service.pb.gw.go | 321 +++++++++- .../proto/examplepb/echo_service.proto | 50 +- .../proto/examplepb/echo_service.swagger.json | 252 +++++++- .../proto/examplepb/echo_service_grpc.pb.go | 88 ++- examples/internal/server/echo.go | 15 +- examples/internal/server/main.go | 1 - proto/examples/echo_service.proto | 54 +- 10 files changed, 1258 insertions(+), 193 deletions(-) diff --git a/examples/internal/integration/README.md b/examples/internal/integration/README.md index 6e10b57..2c55f9e 100644 --- a/examples/internal/integration/README.md +++ b/examples/internal/integration/README.md @@ -3,9 +3,9 @@ ## Bazel test ```shell -bazel test examples/internal/integration/... --test_arg=--skylb-endpoints="" --test_arg=--debug-svc-endpoint=custom-ease-gateway-test=localhost:9090 +bazel run examples/internal/integration/... --test_arg=--skylb-endpoints="" --test_arg=--debug-svc-endpoint=custom-ease-gateway-test=localhost:9090 ``` -> 通过bazel test 执行integration test +> 通过bazel run 执行integration test > > 因为引入skylb-api, 运行时需要指定skylb-endpoints \ No newline at end of file diff --git a/examples/internal/integration/integration_test.go b/examples/internal/integration/integration_test.go index a87b68e..daa5486 100644 --- a/examples/internal/integration/integration_test.go +++ b/examples/internal/integration/integration_test.go @@ -38,6 +38,9 @@ func TestEcho(t *testing.T) { testEchoBody(t, 8089, apiPrefix) }) } + t.Run("testEchoValidationRules", func(t *testing.T) { + testEchoValidationRules(t, 8088, "application/json") + }) } func TestEchoPatch(t *testing.T) { @@ -165,6 +168,20 @@ func testEcho(t *testing.T, port int, apiPrefix string, contentType string) { if got, want := msg.Id, "myid"; got != want { t.Errorf("msg.Id = %q; want %q", got, want) } + + if got, want := resp.Header.Get("Grpc-Metadata-Foo"), "foo1"; got != want { + t.Errorf("Grpc-Metadata-Foo was %q, wanted %q", got, want) + } + if got, want := resp.Header.Get("Grpc-Metadata-Bar"), "bar1"; got != want { + t.Errorf("Grpc-Metadata-Bar was %q, wanted %q", got, want) + } + + if got, want := resp.Trailer.Get("Grpc-Trailer-Foo"), "foo2"; got != want { + t.Errorf("Grpc-Trailer-Foo was %q, wanted %q", got, want) + } + if got, want := resp.Trailer.Get("Grpc-Trailer-Bar"), "bar2"; got != want { + t.Errorf("Grpc-Trailer-Bar was %q, wanted %q", got, want) + } } if value := resp.Header.Get("Content-Type"); value != contentType { @@ -332,7 +349,12 @@ func testEchoBody(t *testing.T, port int, apiPrefix string) { t.Errorf(diff) } + if value := resp.Header.Get("Content-Type"); value != "application/json" { + t.Errorf("Content-Type was %s, wanted %s", value, "application/json") + } + // fmt.Printf("headers: %v \n", resp.Header) + // fmt.Printf("apiURL: %s \n", apiURL) // if got, want := resp.Header.Get("Grpc-Metadata-Foo"), "foo1"; got != want { // t.Errorf("Grpc-Metadata-Foo was %q, wanted %q", got, want) // } @@ -348,3 +370,64 @@ func testEchoBody(t *testing.T, port int, apiPrefix string) { // } } } + +func testEchoValidationRules(t *testing.T, port int, contentType string) { + sent := examplepb.ValidationRuleTestRequest{ + Id: "example", // rules: NON_NIL, LEN_GT:2, LEN_LT: 61 + Num: 11, // rules: GT:0 + } + payload, err := marshaler.Marshal(&sent) + if err != nil { + t.Fatalf("marshaler.Marshal(%#v) failed with %v; want success", payload, err) + } + + apiURL := fmt.Sprintf("http://localhost:%d/v1/example/echo:validationRules", port) + resp, err := http.Post(apiURL, "", bytes.NewReader(payload)) + if err != nil { + t.Errorf("http.Post(%q) failed with %v; want success", apiURL, err) + return + } + defer resp.Body.Close() + buf, err := ioutil.ReadAll(resp.Body) + if err != nil { + t.Errorf("ioutil.ReadAll(resp.Body) failed with %v; want success", err) + return + } + + if got, want := resp.StatusCode, http.StatusOK; got != want { + t.Errorf("resp.StatusCode = %d; want %d", got, want) + t.Logf("%s", buf) + } + + // Test validation error + sent = examplepb.ValidationRuleTestRequest{ + Id: "a", // rules: NON_NIL, LEN_GT:2, LEN_LT: 61 + Num: 0, // rules: GT:0 + } + payload, err = marshaler.Marshal(&sent) + if err != nil { + t.Fatalf("marshaler.Marshal(%#v) failed with %v; want success", payload, err) + } + + apiURL = fmt.Sprintf("http://localhost:%d/v1/example/echo:validationRules", port) + resp, err = http.Post(apiURL, "", bytes.NewReader(payload)) + if err != nil { + t.Errorf("http.Post(%q) failed with %v; want success", apiURL, err) + return + } + defer resp.Body.Close() + buf, err = ioutil.ReadAll(resp.Body) + if err != nil { + t.Errorf("ioutil.ReadAll(resp.Body) failed with %v; want success", err) + return + } + + if got, want := resp.StatusCode, http.StatusBadRequest; got != want { + t.Errorf("resp.StatusCode = %d; want %d", got, want) + t.Logf("%s", buf) + } + + if value := resp.Header.Get("Content-Type"); value != contentType { + t.Errorf("Content-Type was %s, wanted %s", value, contentType) + } +} diff --git a/examples/internal/proto/examplepb/echo_service.pb.go b/examples/internal/proto/examplepb/echo_service.pb.go index 698286a..73bfcac 100755 --- a/examples/internal/proto/examplepb/echo_service.pb.go +++ b/examples/internal/proto/examplepb/echo_service.pb.go @@ -1,14 +1,16 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.22.0 -// protoc v3.8.0 +// protoc-gen-go v1.25.0 +// protoc v3.9.0 // source: examples/internal/proto/examplepb/echo_service.proto -package proto +package examplepb import ( _ "github.com/binchencoder/ease-gateway/httpoptions" proto "github.com/golang/protobuf/proto" + _struct "github.com/golang/protobuf/ptypes/struct" + field_mask "google.golang.org/genproto/protobuf/field_mask" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" @@ -40,7 +42,7 @@ type Embedded struct { func (x *Embedded) Reset() { *x = Embedded{} if protoimpl.UnsafeEnabled { - mi := &file_examples_proto_echo_service_proto_msgTypes[0] + mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -53,7 +55,7 @@ func (x *Embedded) String() string { func (*Embedded) ProtoMessage() {} func (x *Embedded) ProtoReflect() protoreflect.Message { - mi := &file_examples_proto_echo_service_proto_msgTypes[0] + mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -66,7 +68,7 @@ func (x *Embedded) ProtoReflect() protoreflect.Message { // Deprecated: Use Embedded.ProtoReflect.Descriptor instead. func (*Embedded) Descriptor() ([]byte, []int) { - return file_examples_proto_echo_service_proto_rawDescGZIP(), []int{0} + return file_examples_internal_proto_examplepb_echo_service_proto_rawDescGZIP(), []int{0} } func (m *Embedded) GetMark() isEmbedded_Mark { @@ -127,7 +129,7 @@ type SimpleMessage struct { func (x *SimpleMessage) Reset() { *x = SimpleMessage{} if protoimpl.UnsafeEnabled { - mi := &file_examples_proto_echo_service_proto_msgTypes[1] + mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -140,7 +142,7 @@ func (x *SimpleMessage) String() string { func (*SimpleMessage) ProtoMessage() {} func (x *SimpleMessage) ProtoReflect() protoreflect.Message { - mi := &file_examples_proto_echo_service_proto_msgTypes[1] + mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[1] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -153,7 +155,7 @@ func (x *SimpleMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use SimpleMessage.ProtoReflect.Descriptor instead. func (*SimpleMessage) Descriptor() ([]byte, []int) { - return file_examples_proto_echo_service_proto_rawDescGZIP(), []int{1} + return file_examples_internal_proto_examplepb_echo_service_proto_rawDescGZIP(), []int{1} } func (x *SimpleMessage) GetId() string { @@ -251,119 +253,408 @@ func (*SimpleMessage_En) isSimpleMessage_Ext() {} func (*SimpleMessage_No) isSimpleMessage_Ext() {} -var File_examples_proto_echo_service_proto protoreflect.FileDescriptor - -var file_examples_proto_echo_service_proto_rawDesc = []byte{ - 0x0a, 0x21, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x12, 0x1b, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, - 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x1a, 0x1d, 0x68, 0x74, 0x74, 0x70, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x61, 0x6e, - 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, - 0x46, 0x0a, 0x08, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x12, 0x1c, 0x0a, 0x08, 0x70, - 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, - 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x14, 0x0a, 0x04, 0x6e, 0x6f, 0x74, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x42, - 0x06, 0x0a, 0x04, 0x6d, 0x61, 0x72, 0x6b, 0x22, 0xfd, 0x01, 0x0a, 0x0d, 0x53, 0x69, 0x6d, 0x70, - 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x6e, 0x75, 0x6d, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x6e, 0x75, 0x6d, 0x12, 0x1b, 0x0a, 0x08, 0x6c, - 0x69, 0x6e, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, - 0x07, 0x6c, 0x69, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x12, 0x14, 0x0a, 0x04, 0x6c, 0x61, 0x6e, 0x67, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x6c, 0x61, 0x6e, 0x67, 0x12, 0x3d, - 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, +type ValidationRuleTestRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Num int64 `protobuf:"varint,2,opt,name=num,proto3" json:"num,omitempty"` +} + +func (x *ValidationRuleTestRequest) Reset() { + *x = ValidationRuleTestRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ValidationRuleTestRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ValidationRuleTestRequest) ProtoMessage() {} + +func (x *ValidationRuleTestRequest) ProtoReflect() protoreflect.Message { + mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ValidationRuleTestRequest.ProtoReflect.Descriptor instead. +func (*ValidationRuleTestRequest) Descriptor() ([]byte, []int) { + return file_examples_internal_proto_examplepb_echo_service_proto_rawDescGZIP(), []int{2} +} + +func (x *ValidationRuleTestRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *ValidationRuleTestRequest) GetNum() int64 { + if x != nil { + return x.Num + } + return 0 +} + +type ValidationRuleTestResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *ValidationRuleTestResponse) Reset() { + *x = ValidationRuleTestResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ValidationRuleTestResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ValidationRuleTestResponse) ProtoMessage() {} + +func (x *ValidationRuleTestResponse) ProtoReflect() protoreflect.Message { + mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ValidationRuleTestResponse.ProtoReflect.Descriptor instead. +func (*ValidationRuleTestResponse) Descriptor() ([]byte, []int) { + return file_examples_internal_proto_examplepb_echo_service_proto_rawDescGZIP(), []int{3} +} + +type DynamicMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + StructField *_struct.Struct `protobuf:"bytes,1,opt,name=struct_field,json=structField,proto3" json:"struct_field,omitempty"` + ValueField *_struct.Value `protobuf:"bytes,2,opt,name=value_field,json=valueField,proto3" json:"value_field,omitempty"` +} + +func (x *DynamicMessage) Reset() { + *x = DynamicMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DynamicMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DynamicMessage) ProtoMessage() {} + +func (x *DynamicMessage) ProtoReflect() protoreflect.Message { + mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DynamicMessage.ProtoReflect.Descriptor instead. +func (*DynamicMessage) Descriptor() ([]byte, []int) { + return file_examples_internal_proto_examplepb_echo_service_proto_rawDescGZIP(), []int{4} +} + +func (x *DynamicMessage) GetStructField() *_struct.Struct { + if x != nil { + return x.StructField + } + return nil +} + +func (x *DynamicMessage) GetValueField() *_struct.Value { + if x != nil { + return x.ValueField + } + return nil +} + +type DynamicMessageUpdate struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Body *DynamicMessage `protobuf:"bytes,1,opt,name=body,proto3" json:"body,omitempty"` + UpdateMask *field_mask.FieldMask `protobuf:"bytes,2,opt,name=update_mask,json=updateMask,proto3" json:"update_mask,omitempty"` +} + +func (x *DynamicMessageUpdate) Reset() { + *x = DynamicMessageUpdate{} + if protoimpl.UnsafeEnabled { + mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DynamicMessageUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DynamicMessageUpdate) ProtoMessage() {} + +func (x *DynamicMessageUpdate) ProtoReflect() protoreflect.Message { + mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DynamicMessageUpdate.ProtoReflect.Descriptor instead. +func (*DynamicMessageUpdate) Descriptor() ([]byte, []int) { + return file_examples_internal_proto_examplepb_echo_service_proto_rawDescGZIP(), []int{5} +} + +func (x *DynamicMessageUpdate) GetBody() *DynamicMessage { + if x != nil { + return x.Body + } + return nil +} + +func (x *DynamicMessageUpdate) GetUpdateMask() *field_mask.FieldMask { + if x != nil { + return x.UpdateMask + } + return nil +} + +var File_examples_internal_proto_examplepb_echo_service_proto protoreflect.FileDescriptor + +var file_examples_internal_proto_examplepb_echo_service_proto_rawDesc = []byte{ + 0x0a, 0x34, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, + 0x65, 0x70, 0x62, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, + 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, + 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x1a, 0x1d, 0x68, 0x74, 0x74, 0x70, 0x6f, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x73, + 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x46, 0x0a, 0x08, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, + 0x64, 0x12, 0x1c, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, + 0x14, 0x0a, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, + 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x42, 0x06, 0x0a, 0x04, 0x6d, 0x61, 0x72, 0x6b, 0x22, 0xa3, 0x02, + 0x0a, 0x0d, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, + 0x10, 0x0a, 0x03, 0x6e, 0x75, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x6e, 0x75, + 0x6d, 0x12, 0x1b, 0x0a, 0x08, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x07, 0x6c, 0x69, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x12, 0x14, + 0x0a, 0x04, 0x6c, 0x61, 0x6e, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, + 0x6c, 0x61, 0x6e, 0x67, 0x12, 0x50, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, + 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, + 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x52, 0x06, + 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x10, 0x0a, 0x02, 0x65, 0x6e, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x03, 0x48, 0x01, 0x52, 0x02, 0x65, 0x6e, 0x12, 0x4a, 0x0a, 0x02, 0x6e, 0x6f, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, + 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, + 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x48, 0x01, + 0x52, 0x02, 0x6e, 0x6f, 0x42, 0x06, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x42, 0x05, 0x0a, 0x03, + 0x65, 0x78, 0x74, 0x22, 0x6f, 0x0a, 0x19, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x75, 0x6c, 0x65, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x31, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x21, 0xb2, 0xe4, + 0x34, 0x1d, 0x0a, 0x04, 0x08, 0x05, 0x10, 0x02, 0x0a, 0x09, 0x08, 0x06, 0x10, 0x02, 0x1a, 0x01, + 0x32, 0x20, 0x01, 0x0a, 0x0a, 0x08, 0x07, 0x10, 0x02, 0x1a, 0x02, 0x36, 0x31, 0x20, 0x01, 0x52, + 0x02, 0x69, 0x64, 0x12, 0x1f, 0x0a, 0x03, 0x6e, 0x75, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, + 0x42, 0x0d, 0xb2, 0xe4, 0x34, 0x09, 0x0a, 0x07, 0x08, 0x01, 0x10, 0x01, 0x1a, 0x01, 0x30, 0x52, + 0x03, 0x6e, 0x75, 0x6d, 0x22, 0x1c, 0x0a, 0x1a, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x75, 0x6c, 0x65, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x85, 0x01, 0x0a, 0x0e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3a, 0x0a, 0x0c, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x5f, + 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, + 0x72, 0x75, 0x63, 0x74, 0x52, 0x0b, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x46, 0x69, 0x65, 0x6c, + 0x64, 0x12, 0x37, 0x0a, 0x0b, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0a, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x22, 0xa7, 0x01, 0x0a, 0x14, 0x44, + 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x12, 0x52, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x3e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, + 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, + 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, + 0x70, 0x62, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x12, 0x3b, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, + 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x4d, 0x61, 0x73, 0x6b, 0x32, 0xd5, 0x08, 0x0a, 0x0b, 0x45, 0x63, 0x68, 0x6f, 0x53, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x12, 0xba, 0x02, 0x0a, 0x04, 0x45, 0x63, 0x68, 0x6f, 0x12, 0x3d, 0x2e, + 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, + 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x53, + 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x3d, 0x2e, 0x67, + 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x53, 0x69, + 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xb3, 0x01, 0xca, 0xf3, + 0x34, 0xae, 0x01, 0x22, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, + 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x5a, 0x1d, 0x12, 0x1b, 0x2f, 0x76, + 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x2f, 0x7b, + 0x69, 0x64, 0x7d, 0x2f, 0x7b, 0x6e, 0x75, 0x6d, 0x7d, 0x5a, 0x24, 0x12, 0x22, 0x2f, 0x76, 0x31, + 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x2f, 0x7b, 0x69, + 0x64, 0x7d, 0x2f, 0x7b, 0x6e, 0x75, 0x6d, 0x7d, 0x2f, 0x7b, 0x6c, 0x61, 0x6e, 0x67, 0x7d, 0x5a, + 0x31, 0x12, 0x2f, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, + 0x63, 0x68, 0x6f, 0x31, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x2f, 0x7b, 0x6c, 0x69, 0x6e, 0x65, 0x5f, + 0x6e, 0x75, 0x6d, 0x7d, 0x2f, 0x7b, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x6e, 0x6f, 0x74, + 0x65, 0x7d, 0x5a, 0x1d, 0x12, 0x1b, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, + 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x32, 0x2f, 0x7b, 0x6e, 0x6f, 0x2e, 0x6e, 0x6f, 0x74, 0x65, + 0x7d, 0x12, 0xa8, 0x01, 0x0a, 0x08, 0x45, 0x63, 0x68, 0x6f, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x3d, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, - 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x6d, 0x62, - 0x65, 0x64, 0x64, 0x65, 0x64, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x10, 0x0a, - 0x02, 0x65, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x48, 0x01, 0x52, 0x02, 0x65, 0x6e, 0x12, - 0x37, 0x0a, 0x02, 0x6e, 0x6f, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x67, 0x72, + 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, + 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x3d, 0x2e, + 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, + 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x53, + 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x1e, 0xca, 0xf3, + 0x34, 0x1a, 0x22, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, + 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x62, 0x6f, 0x64, 0x79, 0x3a, 0x01, 0x2a, 0x12, 0xa9, 0x01, 0x0a, + 0x0a, 0x45, 0x63, 0x68, 0x6f, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x3d, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, - 0x6c, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, - 0x65, 0x64, 0x48, 0x01, 0x52, 0x02, 0x6e, 0x6f, 0x42, 0x06, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, - 0x42, 0x05, 0x0a, 0x03, 0x65, 0x78, 0x74, 0x32, 0xcc, 0x04, 0x0a, 0x0b, 0x45, 0x63, 0x68, 0x6f, - 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x94, 0x02, 0x0a, 0x04, 0x45, 0x63, 0x68, 0x6f, - 0x12, 0x2a, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, - 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, - 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x2a, 0x2e, 0x67, + 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x53, 0x69, 0x6d, + 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x3d, 0x2e, 0x67, 0x72, 0x70, + 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, + 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x53, 0x69, 0x6d, 0x70, + 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x1d, 0xca, 0xf3, 0x34, 0x19, 0x2a, + 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, + 0x6f, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0xbb, 0x01, 0x0a, 0x09, 0x45, 0x63, 0x68, + 0x6f, 0x50, 0x61, 0x74, 0x63, 0x68, 0x12, 0x44, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, + 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, + 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, + 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x1a, 0x44, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, - 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, - 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xb3, 0x01, 0xca, 0xf3, 0x34, 0xae, 0x01, - 0x22, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, - 0x68, 0x6f, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x5a, 0x1d, 0x12, 0x1b, 0x2f, 0x76, 0x31, 0x2f, 0x65, - 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x2f, 0x7b, 0x69, 0x64, 0x7d, - 0x2f, 0x7b, 0x6e, 0x75, 0x6d, 0x7d, 0x5a, 0x24, 0x12, 0x22, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, - 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x2f, - 0x7b, 0x6e, 0x75, 0x6d, 0x7d, 0x2f, 0x7b, 0x6c, 0x61, 0x6e, 0x67, 0x7d, 0x5a, 0x31, 0x12, 0x2f, - 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, - 0x31, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x2f, 0x7b, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x6e, 0x75, 0x6d, - 0x7d, 0x2f, 0x7b, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x6e, 0x6f, 0x74, 0x65, 0x7d, 0x5a, - 0x1d, 0x12, 0x1b, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, - 0x63, 0x68, 0x6f, 0x32, 0x2f, 0x7b, 0x6e, 0x6f, 0x2e, 0x6e, 0x6f, 0x74, 0x65, 0x7d, 0x12, 0x82, - 0x01, 0x0a, 0x08, 0x45, 0x63, 0x68, 0x6f, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x2a, 0x2e, 0x67, 0x72, - 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, - 0x6c, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x2a, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, - 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x22, 0x1e, 0xca, 0xf3, 0x34, 0x1a, 0x22, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x65, - 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x62, 0x6f, 0x64, 0x79, - 0x3a, 0x01, 0x2a, 0x12, 0x83, 0x01, 0x0a, 0x0a, 0x45, 0x63, 0x68, 0x6f, 0x44, 0x65, 0x6c, 0x65, - 0x74, 0x65, 0x12, 0x2a, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, - 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x2a, - 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, - 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x69, 0x6d, - 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x1d, 0xca, 0xf3, 0x34, 0x19, - 0x2a, 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, - 0x68, 0x6f, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x1a, 0x1b, 0xea, 0xf3, 0x34, 0x17, 0x08, - 0xb6, 0x95, 0xff, 0xff, 0x07, 0x12, 0x04, 0x67, 0x72, 0x70, 0x63, 0x1a, 0x07, 0x64, 0x65, 0x66, - 0x61, 0x75, 0x6c, 0x74, 0x20, 0x01, 0x42, 0x35, 0x5a, 0x33, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, - 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x69, 0x6e, 0x63, 0x68, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, - 0x72, 0x2f, 0x65, 0x61, 0x73, 0x65, 0x2d, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2f, 0x65, - 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x44, 0x79, + 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x22, 0x22, 0xca, 0xf3, 0x34, 0x1e, 0x32, 0x16, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, + 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x70, 0x61, 0x74, 0x63, 0x68, + 0x3a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x12, 0xd6, 0x01, 0x0a, 0x12, 0x45, 0x63, 0x68, 0x6f, 0x56, + 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x49, 0x2e, + 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, + 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x56, + 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x75, 0x6c, 0x65, 0x54, 0x65, 0x73, + 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x4a, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, + 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, + 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x75, 0x6c, 0x65, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x29, 0xca, 0xf3, 0x34, 0x25, 0x22, 0x20, 0x2f, 0x76, 0x31, 0x2f, + 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x3a, 0x76, 0x61, 0x6c, + 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x3a, 0x01, 0x2a, 0x1a, + 0x1b, 0xea, 0xf3, 0x34, 0x17, 0x08, 0xb6, 0x95, 0xff, 0xff, 0x07, 0x12, 0x04, 0x67, 0x72, 0x70, + 0x63, 0x1a, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x01, 0x42, 0x52, 0x5a, 0x50, + 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x69, 0x6e, 0x63, 0x68, + 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x65, 0x61, 0x73, 0x65, 0x2d, 0x67, 0x61, 0x74, + 0x65, 0x77, 0x61, 0x79, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x78, 0x61, + 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x3b, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( - file_examples_proto_echo_service_proto_rawDescOnce sync.Once - file_examples_proto_echo_service_proto_rawDescData = file_examples_proto_echo_service_proto_rawDesc + file_examples_internal_proto_examplepb_echo_service_proto_rawDescOnce sync.Once + file_examples_internal_proto_examplepb_echo_service_proto_rawDescData = file_examples_internal_proto_examplepb_echo_service_proto_rawDesc ) -func file_examples_proto_echo_service_proto_rawDescGZIP() []byte { - file_examples_proto_echo_service_proto_rawDescOnce.Do(func() { - file_examples_proto_echo_service_proto_rawDescData = protoimpl.X.CompressGZIP(file_examples_proto_echo_service_proto_rawDescData) +func file_examples_internal_proto_examplepb_echo_service_proto_rawDescGZIP() []byte { + file_examples_internal_proto_examplepb_echo_service_proto_rawDescOnce.Do(func() { + file_examples_internal_proto_examplepb_echo_service_proto_rawDescData = protoimpl.X.CompressGZIP(file_examples_internal_proto_examplepb_echo_service_proto_rawDescData) }) - return file_examples_proto_echo_service_proto_rawDescData -} - -var file_examples_proto_echo_service_proto_msgTypes = make([]protoimpl.MessageInfo, 2) -var file_examples_proto_echo_service_proto_goTypes = []interface{}{ - (*Embedded)(nil), // 0: grpc.gateway.examples.proto.Embedded - (*SimpleMessage)(nil), // 1: grpc.gateway.examples.proto.SimpleMessage -} -var file_examples_proto_echo_service_proto_depIdxs = []int32{ - 0, // 0: grpc.gateway.examples.proto.SimpleMessage.status:type_name -> grpc.gateway.examples.proto.Embedded - 0, // 1: grpc.gateway.examples.proto.SimpleMessage.no:type_name -> grpc.gateway.examples.proto.Embedded - 1, // 2: grpc.gateway.examples.proto.EchoService.Echo:input_type -> grpc.gateway.examples.proto.SimpleMessage - 1, // 3: grpc.gateway.examples.proto.EchoService.EchoBody:input_type -> grpc.gateway.examples.proto.SimpleMessage - 1, // 4: grpc.gateway.examples.proto.EchoService.EchoDelete:input_type -> grpc.gateway.examples.proto.SimpleMessage - 1, // 5: grpc.gateway.examples.proto.EchoService.Echo:output_type -> grpc.gateway.examples.proto.SimpleMessage - 1, // 6: grpc.gateway.examples.proto.EchoService.EchoBody:output_type -> grpc.gateway.examples.proto.SimpleMessage - 1, // 7: grpc.gateway.examples.proto.EchoService.EchoDelete:output_type -> grpc.gateway.examples.proto.SimpleMessage - 5, // [5:8] is the sub-list for method output_type - 2, // [2:5] is the sub-list for method input_type - 2, // [2:2] is the sub-list for extension type_name - 2, // [2:2] is the sub-list for extension extendee - 0, // [0:2] is the sub-list for field type_name -} - -func init() { file_examples_proto_echo_service_proto_init() } -func file_examples_proto_echo_service_proto_init() { - if File_examples_proto_echo_service_proto != nil { + return file_examples_internal_proto_examplepb_echo_service_proto_rawDescData +} + +var file_examples_internal_proto_examplepb_echo_service_proto_msgTypes = make([]protoimpl.MessageInfo, 6) +var file_examples_internal_proto_examplepb_echo_service_proto_goTypes = []interface{}{ + (*Embedded)(nil), // 0: grpc.gateway.examples.internal.proto.examplepb.Embedded + (*SimpleMessage)(nil), // 1: grpc.gateway.examples.internal.proto.examplepb.SimpleMessage + (*ValidationRuleTestRequest)(nil), // 2: grpc.gateway.examples.internal.proto.examplepb.ValidationRuleTestRequest + (*ValidationRuleTestResponse)(nil), // 3: grpc.gateway.examples.internal.proto.examplepb.ValidationRuleTestResponse + (*DynamicMessage)(nil), // 4: grpc.gateway.examples.internal.proto.examplepb.DynamicMessage + (*DynamicMessageUpdate)(nil), // 5: grpc.gateway.examples.internal.proto.examplepb.DynamicMessageUpdate + (*_struct.Struct)(nil), // 6: google.protobuf.Struct + (*_struct.Value)(nil), // 7: google.protobuf.Value + (*field_mask.FieldMask)(nil), // 8: google.protobuf.FieldMask +} +var file_examples_internal_proto_examplepb_echo_service_proto_depIdxs = []int32{ + 0, // 0: grpc.gateway.examples.internal.proto.examplepb.SimpleMessage.status:type_name -> grpc.gateway.examples.internal.proto.examplepb.Embedded + 0, // 1: grpc.gateway.examples.internal.proto.examplepb.SimpleMessage.no:type_name -> grpc.gateway.examples.internal.proto.examplepb.Embedded + 6, // 2: grpc.gateway.examples.internal.proto.examplepb.DynamicMessage.struct_field:type_name -> google.protobuf.Struct + 7, // 3: grpc.gateway.examples.internal.proto.examplepb.DynamicMessage.value_field:type_name -> google.protobuf.Value + 4, // 4: grpc.gateway.examples.internal.proto.examplepb.DynamicMessageUpdate.body:type_name -> grpc.gateway.examples.internal.proto.examplepb.DynamicMessage + 8, // 5: grpc.gateway.examples.internal.proto.examplepb.DynamicMessageUpdate.update_mask:type_name -> google.protobuf.FieldMask + 1, // 6: grpc.gateway.examples.internal.proto.examplepb.EchoService.Echo:input_type -> grpc.gateway.examples.internal.proto.examplepb.SimpleMessage + 1, // 7: grpc.gateway.examples.internal.proto.examplepb.EchoService.EchoBody:input_type -> grpc.gateway.examples.internal.proto.examplepb.SimpleMessage + 1, // 8: grpc.gateway.examples.internal.proto.examplepb.EchoService.EchoDelete:input_type -> grpc.gateway.examples.internal.proto.examplepb.SimpleMessage + 5, // 9: grpc.gateway.examples.internal.proto.examplepb.EchoService.EchoPatch:input_type -> grpc.gateway.examples.internal.proto.examplepb.DynamicMessageUpdate + 2, // 10: grpc.gateway.examples.internal.proto.examplepb.EchoService.EchoValidationRule:input_type -> grpc.gateway.examples.internal.proto.examplepb.ValidationRuleTestRequest + 1, // 11: grpc.gateway.examples.internal.proto.examplepb.EchoService.Echo:output_type -> grpc.gateway.examples.internal.proto.examplepb.SimpleMessage + 1, // 12: grpc.gateway.examples.internal.proto.examplepb.EchoService.EchoBody:output_type -> grpc.gateway.examples.internal.proto.examplepb.SimpleMessage + 1, // 13: grpc.gateway.examples.internal.proto.examplepb.EchoService.EchoDelete:output_type -> grpc.gateway.examples.internal.proto.examplepb.SimpleMessage + 5, // 14: grpc.gateway.examples.internal.proto.examplepb.EchoService.EchoPatch:output_type -> grpc.gateway.examples.internal.proto.examplepb.DynamicMessageUpdate + 3, // 15: grpc.gateway.examples.internal.proto.examplepb.EchoService.EchoValidationRule:output_type -> grpc.gateway.examples.internal.proto.examplepb.ValidationRuleTestResponse + 11, // [11:16] is the sub-list for method output_type + 6, // [6:11] is the sub-list for method input_type + 6, // [6:6] is the sub-list for extension type_name + 6, // [6:6] is the sub-list for extension extendee + 0, // [0:6] is the sub-list for field type_name +} + +func init() { file_examples_internal_proto_examplepb_echo_service_proto_init() } +func file_examples_internal_proto_examplepb_echo_service_proto_init() { + if File_examples_internal_proto_examplepb_echo_service_proto != nil { return } if !protoimpl.UnsafeEnabled { - file_examples_proto_echo_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Embedded); i { case 0: return &v.state @@ -375,7 +666,7 @@ func file_examples_proto_echo_service_proto_init() { return nil } } - file_examples_proto_echo_service_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*SimpleMessage); i { case 0: return &v.state @@ -387,12 +678,60 @@ func file_examples_proto_echo_service_proto_init() { return nil } } + file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ValidationRuleTestRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ValidationRuleTestResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DynamicMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DynamicMessageUpdate); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } - file_examples_proto_echo_service_proto_msgTypes[0].OneofWrappers = []interface{}{ + file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[0].OneofWrappers = []interface{}{ (*Embedded_Progress)(nil), (*Embedded_Note)(nil), } - file_examples_proto_echo_service_proto_msgTypes[1].OneofWrappers = []interface{}{ + file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[1].OneofWrappers = []interface{}{ (*SimpleMessage_LineNum)(nil), (*SimpleMessage_Lang)(nil), (*SimpleMessage_En)(nil), @@ -402,18 +741,18 @@ func file_examples_proto_echo_service_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_examples_proto_echo_service_proto_rawDesc, + RawDescriptor: file_examples_internal_proto_examplepb_echo_service_proto_rawDesc, NumEnums: 0, - NumMessages: 2, + NumMessages: 6, NumExtensions: 0, NumServices: 1, }, - GoTypes: file_examples_proto_echo_service_proto_goTypes, - DependencyIndexes: file_examples_proto_echo_service_proto_depIdxs, - MessageInfos: file_examples_proto_echo_service_proto_msgTypes, + GoTypes: file_examples_internal_proto_examplepb_echo_service_proto_goTypes, + DependencyIndexes: file_examples_internal_proto_examplepb_echo_service_proto_depIdxs, + MessageInfos: file_examples_internal_proto_examplepb_echo_service_proto_msgTypes, }.Build() - File_examples_proto_echo_service_proto = out.File - file_examples_proto_echo_service_proto_rawDesc = nil - file_examples_proto_echo_service_proto_goTypes = nil - file_examples_proto_echo_service_proto_depIdxs = nil + File_examples_internal_proto_examplepb_echo_service_proto = out.File + file_examples_internal_proto_examplepb_echo_service_proto_rawDesc = nil + file_examples_internal_proto_examplepb_echo_service_proto_goTypes = nil + file_examples_internal_proto_examplepb_echo_service_proto_depIdxs = nil } diff --git a/examples/internal/proto/examplepb/echo_service.pb.gw.go b/examples/internal/proto/examplepb/echo_service.pb.gw.go index 0bceda2..7b6896c 100755 --- a/examples/internal/proto/examplepb/echo_service.pb.gw.go +++ b/examples/internal/proto/examplepb/echo_service.pb.gw.go @@ -2,11 +2,11 @@ // source: examples/internal/proto/examplepb/echo_service.proto /* -Package proto is a reverse proxy. +Package examplepb is a reverse proxy. It translates gRPC into RESTful JSON APIs. */ -package proto +package examplepb import ( "context" @@ -57,10 +57,48 @@ var _ strings.Reader var _ = utf8.UTFMax // TODO (jiezmo): check if there is any rule before create this var. -var examples_proto_echo_service_error = lgr.ToGrpcError(codes.InvalidArgument, &fpb.Error{Code: fpb.ErrorCode_BADPARAM_ERROR, Params: []string{"Validation error"}}) +var examples_internal_proto_examplepb_echo_service_error = lgr.ToGrpcError(codes.InvalidArgument, &fpb.Error{Code: fpb.ErrorCode_BADPARAM_ERROR, Params: []string{"Validation error"}}) // Validation methods start +func Validate__grpc_gateway_examples_internal_proto_examplepb_ValidationRuleTestRequest(v *ValidationRuleTestRequest) error { + if v == nil { + return nil + } + // Validation for each Fields + + { + vv2 := v.Id + + // Validation Field: Id + + // TODO(jiezmo): fail the build + // Err + + if utf8.RuneCountInString(strings.TrimSpace(vv2)) <= 2 { + return examples_internal_proto_examplepb_echo_service_error + } + + if utf8.RuneCountInString(strings.TrimSpace(vv2)) >= 61 { + return examples_internal_proto_examplepb_echo_service_error + } + + } + + { + vv2 := v.Num + + // Validation Field: Num + + if vv2 <= 0 { + return examples_internal_proto_examplepb_echo_service_error + } + + } + + return nil +} + // Validation methods done var ( @@ -677,6 +715,133 @@ func local_request_EchoService_EchoDelete_0(ctx context.Context, marshaler runti } +var ( + filter_EchoService_EchoPatch_0 = &utilities.DoubleArray{Encoding: map[string]int{"body": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} +) + +func request_EchoService_EchoPatch_0(ctx context.Context, marshaler runtime.Marshaler, client EchoServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq DynamicMessageUpdate + var metadata runtime.ServerMetadata + spec := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.Body); err != nil && err != io.EOF { + runtime.RequestHandled(ctx, spec, "EchoService", "EchoPatch", nil, &metadata, err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if protoReq.UpdateMask == nil || len(protoReq.UpdateMask.GetPaths()) == 0 { + if fieldMask, err := runtime.FieldMaskFromRequestBody(newReader(), protoReq.Body); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } else { + protoReq.UpdateMask = fieldMask + } + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EchoService_EchoPatch_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + // Only hook up for non-stream call for now. + + runtime.RequestParsed(ctx, spec, "EchoService", "EchoPatch", &protoReq, &metadata) + ctx = runtime.PreLoadBalance(ctx, "ROUND_ROBIN", "", &protoReq) + msg, err := client.EchoPatch(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + // if err != nil { + // grpclog.Errorf("client.%s returns error: %v", "EchoPatch", err) + // } + runtime.RequestHandled(ctx, spec, "EchoService", "EchoPatch", msg, &metadata, err) + return msg, metadata, err + +} + +func local_request_EchoService_EchoPatch_0(ctx context.Context, marshaler runtime.Marshaler, server EchoServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq DynamicMessageUpdate + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.Body); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if protoReq.UpdateMask == nil || len(protoReq.UpdateMask.GetPaths()) == 0 { + if fieldMask, err := runtime.FieldMaskFromRequestBody(newReader(), protoReq.Body); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } else { + protoReq.UpdateMask = fieldMask + } + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EchoService_EchoPatch_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.EchoPatch(ctx, &protoReq) + return msg, metadata, err + +} + +func request_EchoService_EchoValidationRule_0(ctx context.Context, marshaler runtime.Marshaler, client EchoServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq ValidationRuleTestRequest + var metadata runtime.ServerMetadata + spec := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + runtime.RequestHandled(ctx, spec, "EchoService", "EchoValidationRule", nil, &metadata, err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + // Only hook up for non-stream call for now. + + // Validate + // ValidationRuleTestRequest + if err := Validate__grpc_gateway_examples_internal_proto_examplepb_ValidationRuleTestRequest(&protoReq); err != nil { + runtime.RequestHandled(ctx, spec, "EchoService", "EchoValidationRule", nil, &metadata, err) + return nil, metadata, err + } + + runtime.RequestParsed(ctx, spec, "EchoService", "EchoValidationRule", &protoReq, &metadata) + ctx = runtime.PreLoadBalance(ctx, "ROUND_ROBIN", "", &protoReq) + msg, err := client.EchoValidationRule(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + // if err != nil { + // grpclog.Errorf("client.%s returns error: %v", "EchoValidationRule", err) + // } + runtime.RequestHandled(ctx, spec, "EchoService", "EchoValidationRule", msg, &metadata, err) + return msg, metadata, err + +} + +func local_request_EchoService_EchoValidationRule_0(ctx context.Context, marshaler runtime.Marshaler, server EchoServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq ValidationRuleTestRequest + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.EchoValidationRule(ctx, &protoReq) + return msg, metadata, err + +} + // RegisterEchoServiceHandlerServer registers the http handlers for service EchoService to "mux". // UnaryRPC :call EchoServiceServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. @@ -687,7 +852,7 @@ func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.proto.EchoService/Echo") + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo") if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -707,7 +872,7 @@ func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.proto.EchoService/Echo") + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo") if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -727,7 +892,7 @@ func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.proto.EchoService/Echo") + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo") if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -747,7 +912,7 @@ func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.proto.EchoService/Echo") + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo") if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -767,7 +932,7 @@ func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.proto.EchoService/Echo") + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo") if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -787,7 +952,7 @@ func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.proto.EchoService/EchoBody") + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoBody") if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -807,7 +972,7 @@ func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.proto.EchoService/EchoDelete") + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoDelete") if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -823,6 +988,46 @@ func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux }) + mux.Handle("PATCH", pattern_EchoService_EchoPatch_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoPatch") + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_EchoService_EchoPatch_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_EchoService_EchoPatch_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("POST", pattern_EchoService_EchoValidationRule_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoValidationRule") + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_EchoService_EchoValidationRule_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_EchoService_EchoValidationRule_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -908,7 +1113,7 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux } ctx, cancel := context.WithCancel(req.Context()) defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.proto.EchoService/Echo") + rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo") if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -945,7 +1150,7 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux } ctx, cancel := context.WithCancel(req.Context()) defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.proto.EchoService/Echo") + rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo") if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -982,7 +1187,7 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux } ctx, cancel := context.WithCancel(req.Context()) defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.proto.EchoService/Echo") + rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo") if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -1019,7 +1224,7 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux } ctx, cancel := context.WithCancel(req.Context()) defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.proto.EchoService/Echo") + rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo") if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -1056,7 +1261,7 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux } ctx, cancel := context.WithCancel(req.Context()) defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.proto.EchoService/Echo") + rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo") if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -1093,7 +1298,7 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux } ctx, cancel := context.WithCancel(req.Context()) defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.proto.EchoService/EchoBody") + rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoBody") if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -1130,7 +1335,7 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux } ctx, cancel := context.WithCancel(req.Context()) defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.proto.EchoService/EchoDelete") + rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoDelete") if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -1146,6 +1351,80 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux }) + runtime.AddMethod(spec, "EchoService", "EchoPatch", "/v1/example/echo_patch", "PATCH", true, false, false, "UNSPECIFIED", "EASE_GATEWAY", "EASE_AUTH_TOKEN", "") + mux.Handle("PATCH", pattern_EchoService_EchoPatch_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + // TODO(mojz): review all locking/unlocking logic. + // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() + // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() + client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + if client == nil { + err := status.Error(codes.Internal, "service disabled") + runtime.HTTPError(inctx, mux, outboundMarshaler, w, req, err) + return + } + + ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "EchoPatch", w, req) + if err != nil { + grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoPatch") + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_EchoService_EchoPatch_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_EchoService_EchoPatch_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + runtime.AddMethod(spec, "EchoService", "EchoValidationRule", "/v1/example/echo:validationRules", "POST", true, false, false, "UNSPECIFIED", "EASE_GATEWAY", "EASE_AUTH_TOKEN", "") + mux.Handle("POST", pattern_EchoService_EchoValidationRule_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + // TODO(mojz): review all locking/unlocking logic. + // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() + // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() + client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + if client == nil { + err := status.Error(codes.Internal, "service disabled") + runtime.HTTPError(inctx, mux, outboundMarshaler, w, req, err) + return + } + + ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "EchoValidationRule", w, req) + if err != nil { + grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoValidationRule") + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_EchoService_EchoValidationRule_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_EchoService_EchoValidationRule_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -1207,6 +1486,10 @@ var ( pattern_EchoService_EchoBody_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "example", "echo_body"}, "")) pattern_EchoService_EchoDelete_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "example", "echo_delete"}, "")) + + pattern_EchoService_EchoPatch_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "example", "echo_patch"}, "")) + + pattern_EchoService_EchoValidationRule_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "example", "echo"}, "validationRules")) ) var ( @@ -1223,6 +1506,10 @@ var ( forward_EchoService_EchoBody_0 = runtime.ForwardResponseMessage forward_EchoService_EchoDelete_0 = runtime.ForwardResponseMessage + + forward_EchoService_EchoPatch_0 = runtime.ForwardResponseMessage + + forward_EchoService_EchoValidationRule_0 = runtime.ForwardResponseMessage ) var ( diff --git a/examples/internal/proto/examplepb/echo_service.proto b/examples/internal/proto/examplepb/echo_service.proto index ad19963..216c78a 100644 --- a/examples/internal/proto/examplepb/echo_service.proto +++ b/examples/internal/proto/examplepb/echo_service.proto @@ -36,6 +36,46 @@ message SimpleMessage { } } +// ValidationRuleTestRequest represents a message for validation http rules integration test. +message ValidationRuleTestRequest { + // Id represents the message identifier. + string id = 1 + [ + (ease.api.rules) = { + rules: { + type: STRING, + operator: NON_NIL, + }, + rules: { + type: STRING, + function: TRIM, + operator: LEN_GT, + value: "2", + }, + rules: { + type: STRING, + function: TRIM, + operator: LEN_LT, + value: "61", + } + } + ]; + int64 num = 2 + [ + (ease.api.rules) = { + rules: { + type: NUMBER, + operator: GT, + value: "0", + } + } + ]; +} + +// ValidationRuleTestResponse represents a validation http rules integration test response. +message ValidationRuleTestResponse { +} + // DynamicMessage represents a message which can have its structure // built dynamically using Struct and Values. message DynamicMessage { @@ -97,5 +137,13 @@ service EchoService { patch: "/v1/example/echo_patch" body: "body" }; - } + } + + // EchoValidationRule method for validation http rules integration test. + rpc EchoValidationRule(ValidationRuleTestRequest) returns (ValidationRuleTestResponse) { + option (ease.api.http) = { + post: "/v1/example/echo:validationRules" + body: "*" + }; + }; } diff --git a/examples/internal/proto/examplepb/echo_service.swagger.json b/examples/internal/proto/examplepb/echo_service.swagger.json index 7c903c1..84fbd45 100755 --- a/examples/internal/proto/examplepb/echo_service.swagger.json +++ b/examples/internal/proto/examplepb/echo_service.swagger.json @@ -1,7 +1,8 @@ { "swagger": "2.0", "info": { - "title": "examples/internal/proto/examplepb/echo_service.proto", + "title": "Echo Service", + "description": "Echo Service API consists of a single service which returns\na message.", "version": "version not set" }, "consumes": [ @@ -20,7 +21,13 @@ "200": { "description": "A successful response.", "schema": { - "$ref": "#/definitions/protoSimpleMessage" + "$ref": "#/definitions/examplepbSimpleMessage" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" } } }, @@ -47,7 +54,13 @@ "200": { "description": "A successful response.", "schema": { - "$ref": "#/definitions/protoSimpleMessage" + "$ref": "#/definitions/examplepbSimpleMessage" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" } } }, @@ -127,7 +140,13 @@ "200": { "description": "A successful response.", "schema": { - "$ref": "#/definitions/protoSimpleMessage" + "$ref": "#/definitions/examplepbSimpleMessage" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" } } }, @@ -207,7 +226,13 @@ "200": { "description": "A successful response.", "schema": { - "$ref": "#/definitions/protoSimpleMessage" + "$ref": "#/definitions/examplepbSimpleMessage" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" } } }, @@ -281,7 +306,13 @@ "200": { "description": "A successful response.", "schema": { - "$ref": "#/definitions/protoSimpleMessage" + "$ref": "#/definitions/examplepbSimpleMessage" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" } } }, @@ -346,6 +377,39 @@ ] } }, + "/v1/example/echo:validationRules": { + "post": { + "summary": "EchoValidationRule method for validation http rules integration test.", + "operationId": "EchoService_EchoValidationRule", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/examplepbValidationRuleTestResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/examplepbValidationRuleTestRequest" + } + } + ], + "tags": [ + "EchoService" + ] + } + }, "/v1/example/echo_body": { "post": { "summary": "EchoBody method receives a simple message and returns it.", @@ -354,7 +418,13 @@ "200": { "description": "A successful response.", "schema": { - "$ref": "#/definitions/protoSimpleMessage" + "$ref": "#/definitions/examplepbSimpleMessage" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" } } }, @@ -364,7 +434,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/protoSimpleMessage" + "$ref": "#/definitions/examplepbSimpleMessage" } } ], @@ -381,7 +451,13 @@ "200": { "description": "A successful response.", "schema": { - "$ref": "#/definitions/protoSimpleMessage" + "$ref": "#/definitions/examplepbSimpleMessage" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" } } }, @@ -451,10 +527,79 @@ "EchoService" ] } + }, + "/v1/example/echo_patch": { + "patch": { + "summary": "EchoPatch method receives a NonStandardUpdateRequest and returns it.", + "operationId": "EchoService_EchoPatch", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/examplepbDynamicMessageUpdate" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/examplepbDynamicMessage" + } + }, + { + "name": "updateMask", + "in": "query", + "required": false, + "type": "array", + "items": { + "type": "string" + }, + "collectionFormat": "multi" + } + ], + "tags": [ + "EchoService" + ] + } } }, "definitions": { - "protoEmbedded": { + "examplepbDynamicMessage": { + "type": "object", + "properties": { + "structField": { + "type": "object" + }, + "valueField": { + "type": "object" + } + }, + "description": "DynamicMessage represents a message which can have its structure\nbuilt dynamically using Struct and Values." + }, + "examplepbDynamicMessageUpdate": { + "type": "object", + "properties": { + "body": { + "$ref": "#/definitions/examplepbDynamicMessage" + }, + "updateMask": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "examplepbEmbedded": { "type": "object", "properties": { "progress": { @@ -467,7 +612,7 @@ }, "description": "Embedded represents a message embedded in SimpleMessage." }, - "protoSimpleMessage": { + "examplepbSimpleMessage": { "type": "object", "properties": { "id": { @@ -486,17 +631,98 @@ "type": "string" }, "status": { - "$ref": "#/definitions/protoEmbedded" + "$ref": "#/definitions/examplepbEmbedded" }, "en": { "type": "string", "format": "int64" }, "no": { - "$ref": "#/definitions/protoEmbedded" + "$ref": "#/definitions/examplepbEmbedded" } }, "description": "SimpleMessage represents a simple message sent to the Echo service." + }, + "examplepbValidationRuleTestRequest": { + "type": "object", + "properties": { + "id": { + "type": "string", + "rules": [ + { + "operator": 5, + "type": 2 + }, + { + "operator": 6, + "type": 2, + "value": "2", + "function": 1 + }, + { + "operator": 7, + "type": 2, + "value": "61", + "function": 1 + } + ], + "description": "Id represents the message identifier." + }, + "num": { + "type": "string", + "format": "int64", + "rules": [ + { + "operator": 1, + "type": 1, + "value": "0" + } + ] + } + }, + "description": "ValidationRuleTestRequest represents a message for validation http rules integration test." + }, + "examplepbValidationRuleTestResponse": { + "type": "object", + "description": "ValidationRuleTestResponse represents a validation http rules integration test response." + }, + "protobufAny": { + "type": "object", + "properties": { + "typeUrl": { + "type": "string" + }, + "value": { + "type": "string", + "format": "byte" + } + } + }, + "protobufNullValue": { + "type": "string", + "enum": [ + "NULL_VALUE" + ], + "default": "NULL_VALUE", + "description": "`NullValue` is a singleton enumeration to represent the null value for the\n`Value` type union.\n\n The JSON representation for `NullValue` is JSON `null`.\n\n - NULL_VALUE: Null value." + }, + "rpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "$ref": "#/definitions/protobufAny" + } + } + } } } } diff --git a/examples/internal/proto/examplepb/echo_service_grpc.pb.go b/examples/internal/proto/examplepb/echo_service_grpc.pb.go index 1840d71..ef29065 100755 --- a/examples/internal/proto/examplepb/echo_service_grpc.pb.go +++ b/examples/internal/proto/examplepb/echo_service_grpc.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. -package proto +package examplepb import ( context "context" @@ -20,6 +20,8 @@ type EchoServiceClient interface { Echo(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) EchoBody(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) EchoDelete(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) + EchoPatch(ctx context.Context, in *DynamicMessageUpdate, opts ...grpc.CallOption) (*DynamicMessageUpdate, error) + EchoValidationRule(ctx context.Context, in *ValidationRuleTestRequest, opts ...grpc.CallOption) (*ValidationRuleTestResponse, error) } type echoServiceClient struct { @@ -32,7 +34,7 @@ func NewEchoServiceClient(cc grpc.ClientConnInterface) EchoServiceClient { func (c *echoServiceClient) Echo(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) { out := new(SimpleMessage) - err := c.cc.Invoke(ctx, "/grpc.gateway.examples.proto.EchoService/Echo", in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo", in, out, opts...) if err != nil { return nil, err } @@ -41,7 +43,7 @@ func (c *echoServiceClient) Echo(ctx context.Context, in *SimpleMessage, opts .. func (c *echoServiceClient) EchoBody(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) { out := new(SimpleMessage) - err := c.cc.Invoke(ctx, "/grpc.gateway.examples.proto.EchoService/EchoBody", in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoBody", in, out, opts...) if err != nil { return nil, err } @@ -50,7 +52,25 @@ func (c *echoServiceClient) EchoBody(ctx context.Context, in *SimpleMessage, opt func (c *echoServiceClient) EchoDelete(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) { out := new(SimpleMessage) - err := c.cc.Invoke(ctx, "/grpc.gateway.examples.proto.EchoService/EchoDelete", in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoDelete", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *echoServiceClient) EchoPatch(ctx context.Context, in *DynamicMessageUpdate, opts ...grpc.CallOption) (*DynamicMessageUpdate, error) { + out := new(DynamicMessageUpdate) + err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoPatch", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *echoServiceClient) EchoValidationRule(ctx context.Context, in *ValidationRuleTestRequest, opts ...grpc.CallOption) (*ValidationRuleTestResponse, error) { + out := new(ValidationRuleTestResponse) + err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoValidationRule", in, out, opts...) if err != nil { return nil, err } @@ -62,6 +82,8 @@ type EchoServiceServer interface { Echo(context.Context, *SimpleMessage) (*SimpleMessage, error) EchoBody(context.Context, *SimpleMessage) (*SimpleMessage, error) EchoDelete(context.Context, *SimpleMessage) (*SimpleMessage, error) + EchoPatch(context.Context, *DynamicMessageUpdate) (*DynamicMessageUpdate, error) + EchoValidationRule(context.Context, *ValidationRuleTestRequest) (*ValidationRuleTestResponse, error) } // UnimplementedEchoServiceServer can be embedded to have forward compatible implementations. @@ -77,6 +99,12 @@ func (*UnimplementedEchoServiceServer) EchoBody(context.Context, *SimpleMessage) func (*UnimplementedEchoServiceServer) EchoDelete(context.Context, *SimpleMessage) (*SimpleMessage, error) { return nil, status.Errorf(codes.Unimplemented, "method EchoDelete not implemented") } +func (*UnimplementedEchoServiceServer) EchoPatch(context.Context, *DynamicMessageUpdate) (*DynamicMessageUpdate, error) { + return nil, status.Errorf(codes.Unimplemented, "method EchoPatch not implemented") +} +func (*UnimplementedEchoServiceServer) EchoValidationRule(context.Context, *ValidationRuleTestRequest) (*ValidationRuleTestResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method EchoValidationRule not implemented") +} func RegisterEchoServiceServer(s *grpc.Server, srv EchoServiceServer) { s.RegisterService(&_EchoService_serviceDesc, srv) @@ -92,7 +120,7 @@ func _EchoService_Echo_Handler(srv interface{}, ctx context.Context, dec func(in } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/grpc.gateway.examples.proto.EchoService/Echo", + FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(EchoServiceServer).Echo(ctx, req.(*SimpleMessage)) @@ -110,7 +138,7 @@ func _EchoService_EchoBody_Handler(srv interface{}, ctx context.Context, dec fun } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/grpc.gateway.examples.proto.EchoService/EchoBody", + FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoBody", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(EchoServiceServer).EchoBody(ctx, req.(*SimpleMessage)) @@ -128,7 +156,7 @@ func _EchoService_EchoDelete_Handler(srv interface{}, ctx context.Context, dec f } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/grpc.gateway.examples.proto.EchoService/EchoDelete", + FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoDelete", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(EchoServiceServer).EchoDelete(ctx, req.(*SimpleMessage)) @@ -136,8 +164,44 @@ func _EchoService_EchoDelete_Handler(srv interface{}, ctx context.Context, dec f return interceptor(ctx, in, info, handler) } +func _EchoService_EchoPatch_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DynamicMessageUpdate) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(EchoServiceServer).EchoPatch(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoPatch", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(EchoServiceServer).EchoPatch(ctx, req.(*DynamicMessageUpdate)) + } + return interceptor(ctx, in, info, handler) +} + +func _EchoService_EchoValidationRule_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ValidationRuleTestRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(EchoServiceServer).EchoValidationRule(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoValidationRule", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(EchoServiceServer).EchoValidationRule(ctx, req.(*ValidationRuleTestRequest)) + } + return interceptor(ctx, in, info, handler) +} + var _EchoService_serviceDesc = grpc.ServiceDesc{ - ServiceName: "grpc.gateway.examples.proto.EchoService", + ServiceName: "grpc.gateway.examples.internal.proto.examplepb.EchoService", HandlerType: (*EchoServiceServer)(nil), Methods: []grpc.MethodDesc{ { @@ -152,6 +216,14 @@ var _EchoService_serviceDesc = grpc.ServiceDesc{ MethodName: "EchoDelete", Handler: _EchoService_EchoDelete_Handler, }, + { + MethodName: "EchoPatch", + Handler: _EchoService_EchoPatch_Handler, + }, + { + MethodName: "EchoValidationRule", + Handler: _EchoService_EchoValidationRule_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "examples/internal/proto/examplepb/echo_service.proto", diff --git a/examples/internal/server/echo.go b/examples/internal/server/echo.go index 9197162..9cce632 100644 --- a/examples/internal/server/echo.go +++ b/examples/internal/server/echo.go @@ -3,8 +3,8 @@ package server import ( "context" - "github.com/golang/glog" examples "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb" + "github.com/golang/glog" "google.golang.org/grpc" "google.golang.org/grpc/metadata" ) @@ -19,6 +19,14 @@ func newEchoServer() examples.EchoServiceServer { func (s *echoServer) Echo(ctx context.Context, msg *examples.SimpleMessage) (*examples.SimpleMessage, error) { glog.Info(msg) + grpc.SendHeader(ctx, metadata.New(map[string]string{ + "foo": "foo1", + "bar": "bar1", + })) + grpc.SetTrailer(ctx, metadata.New(map[string]string{ + "foo": "foo2", + "bar": "bar2", + })) return msg, nil } @@ -44,3 +52,8 @@ func (s *echoServer) EchoPatch(ctx context.Context, msg *examples.DynamicMessage glog.Info(msg) return msg, nil } + +func (s *echoServer) EchoValidationRule(ctx context.Context, msg *examples.ValidationRuleTestRequest) (*examples.ValidationRuleTestResponse, error) { + glog.Info(msg) + return &examples.ValidationRuleTestResponse{}, nil +} diff --git a/examples/internal/server/main.go b/examples/internal/server/main.go index ce9d647..2971ae1 100644 --- a/examples/internal/server/main.go +++ b/examples/internal/server/main.go @@ -57,5 +57,4 @@ func RunInProcessGateway(ctx context.Context, addr string, opts ...runtime.Serve return err } return nil - } diff --git a/proto/examples/echo_service.proto b/proto/examples/echo_service.proto index c0eb95e..713c6a0 100644 --- a/proto/examples/echo_service.proto +++ b/proto/examples/echo_service.proto @@ -23,37 +23,35 @@ message SimpleMessage { // Id represents the message identifier. string id = 1 [ - (ease.api.rules) = { - rules: { - type: STRING, - operator: NON_NIL, - }, - rules: { - type: STRING, - function: TRIM, - operator: LEN_GT, - value: "2", - }, - rules: { - type: STRING, - function: TRIM, - operator: LEN_LT, - value: "61", - } - } - ] - ; + (ease.api.rules) = { + rules: { + type: STRING, + operator: NON_NIL, + }, + rules: { + type: STRING, + function: TRIM, + operator: LEN_GT, + value: "2", + }, + rules: { + type: STRING, + function: TRIM, + operator: LEN_LT, + value: "61", + } + } + ]; int64 num = 2 [ - (ease.api.rules) = { - rules: { - type: NUMBER, - operator: GT, + (ease.api.rules) = { + rules: { + type: NUMBER, + operator: GT, value: "0", - } - } - ] - ; + } + } + ]; oneof code { int64 line_num = 3; string lang = 4; From 72e2d5f3f8b064de357dc4206a33cf7230919a97 Mon Sep 17 00:00:00 2001 From: binchen Date: Mon, 2 Nov 2020 15:04:20 +0800 Subject: [PATCH 37/56] Update gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go --- .../internal/gengateway/generator.go | 1 + .../internal/gengateway/template.go | 37 +++++++++++-------- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator.go b/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator.go index a35a322..9e9e682 100644 --- a/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator.go +++ b/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator.go @@ -54,6 +54,7 @@ func New(reg *descriptor.Registry, useRequestContext bool, registerFuncSuffix st "google.golang.org/grpc/codes": "", "google.golang.org/grpc/naming": "", "google.golang.org/grpc/grpclog": "", + "google.golang.org/grpc/metadata": "", "google.golang.org/grpc/status": "", } { pkg := descriptor.GoPackage{ diff --git a/gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go b/gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go index aa6af49..5cd7480 100644 --- a/gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go +++ b/gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go @@ -243,11 +243,11 @@ var ( // Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. // source: {{.GetName}} -/* +{{if not .OmitPackageDoc}}/* Package {{.GoPkg.Name}} is a reverse proxy. It translates gRPC into RESTful JSON APIs. -*/ +*/{{end}} package {{.GoPkg.Name}} import ( {{range $i := .Imports}}{{if $i.Standard}}{{$i | printf "%s\n"}}{{end}}{{end}} @@ -261,6 +261,7 @@ var _ io.Reader var _ status.Status var _ = runtime.String var _ = utilities.NewDoubleArray +var _ = metadata.Join // var _ = descriptor.ForMessage var _ sync.RWMutex var _ proto.Message @@ -557,13 +558,13 @@ var ( return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", {{$param | printf "%q"}}, err) } {{if $enum}} - e{{if $param.IsRepeated}}s{{end}}, err = {{$param.ConvertFuncExpr}}(val{{if $param.IsRepeated}}, {{$binding.Registry.GetRepeatedPathParamSeparator | printf "%c" | printf "%q"}}{{end}}, {{$enum.GoType $param.Target.Message.File.GoPkg.Path}}_value) + 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) if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "could not parse path as enum value, parameter: %s, error: %v", {{$param | printf "%q"}}, err) } {{end}} {{else if $enum}} - e{{if $param.IsRepeated}}s{{end}}, err = {{$param.ConvertFuncExpr}}(val{{if $param.IsRepeated}}, {{$binding.Registry.GetRepeatedPathParamSeparator | printf "%c" | printf "%q"}}{{end}}, {{$enum.GoType $param.Target.Message.File.GoPkg.Path}}_value) + 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) if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", {{$param | printf "%q"}}, err) } @@ -574,13 +575,13 @@ var ( } {{end}} {{if and $enum $param.IsRepeated}} - s := make([]{{$enum.GoType $param.Target.Message.File.GoPkg.Path}}, len(es)) + s := make([]{{$enum.GoType $param.Method.Service.File.GoPkg.Path}}, len(es)) for i, v := range es { - s[i] = {{$enum.GoType $param.Target.Message.File.GoPkg.Path}}(v) + s[i] = {{$enum.GoType $param.Method.Service.File.GoPkg.Path}}(v) } {{$param.AssignableExpr "protoReq"}} = s {{else if $enum}} - {{$param.AssignableExpr "protoReq"}} = {{$enum.GoType $param.Target.Message.File.GoPkg.Path}}(e) + {{$param.AssignableExpr "protoReq"}} = {{$enum.GoType $param.Method.Service.File.GoPkg.Path}}(e) {{end}} {{end}} {{end}} @@ -743,13 +744,13 @@ func local_request_{{.Method.Service.GetName}}_{{.Method.GetName}}_{{.Index}}(ct return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", {{$param | printf "%q"}}, err) } {{if $enum}} - e{{if $param.IsRepeated}}s{{end}}, err = {{$param.ConvertFuncExpr}}(val{{if $param.IsRepeated}}, {{$binding.Registry.GetRepeatedPathParamSeparator | printf "%c" | printf "%q"}}{{end}}, {{$enum.GoType $param.Target.Message.File.GoPkg.Path}}_value) + 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) if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "could not parse path as enum value, parameter: %s, error: %v", {{$param | printf "%q"}}, err) } {{end}} {{else if $enum}} - e{{if $param.IsRepeated}}s{{end}}, err = {{$param.ConvertFuncExpr}}(val{{if $param.IsRepeated}}, {{$binding.Registry.GetRepeatedPathParamSeparator | printf "%c" | printf "%q"}}{{end}}, {{$enum.GoType $param.Target.Message.File.GoPkg.Path}}_value) + 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) if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", {{$param | printf "%q"}}, err) } @@ -761,13 +762,13 @@ func local_request_{{.Method.Service.GetName}}_{{.Method.GetName}}_{{.Index}}(ct {{end}} {{if and $enum $param.IsRepeated}} - s := make([]{{$enum.GoType $param.Target.Message.File.GoPkg.Path}}, len(es)) + s := make([]{{$enum.GoType $param.Method.Service.File.GoPkg.Path}}, len(es)) for i, v := range es { - s[i] = {{$enum.GoType $param.Target.Message.File.GoPkg.Path}}(v) + s[i] = {{$enum.GoType $param.Method.Service.File.GoPkg.Path}}(v) } {{$param.AssignableExpr "protoReq"}} = s {{else if $enum}} - {{$param.AssignableExpr "protoReq"}} = {{$enum.GoType $param.Target.Message.File.GoPkg.Path}}(e) + {{$param.AssignableExpr "protoReq"}} = {{$enum.GoType $param.Method.Service.File.GoPkg.Path}}(e) {{end}} {{end}} {{end}} @@ -793,7 +794,7 @@ func local_request_{{.Method.Service.GetName}}_{{.Method.GetName}}_{{.Index}}(ct // 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. -// Note that using this registration option will cause many gRPC library features (such as grpc.SendHeader, etc) to stop working. Consider using Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}FromEndpoint instead. +// Note that using this registration option will cause many gRPC library features to stop working. Consider using Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}FromEndpoint instead. func Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}Server(ctx context.Context, mux *runtime.ServeMux, server {{$svc.InstanceName}}Server) error { {{range $m := $svc.Methods}} {{range $b := $m.Bindings}} @@ -812,6 +813,8 @@ func Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}Server(ctx context.Context, ctx, cancel := context.WithCancel(ctx) {{- end }} defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/{{$svc.File.GetPackage}}.{{$svc.GetName}}/{{$m.GetName}}") if err != nil { @@ -819,6 +822,7 @@ func Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}Server(ctx context.Context, return } resp, md, err := local_request_{{$svc.GetName}}_{{$m.GetName}}_{{$b.Index}}(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) @@ -895,12 +899,12 @@ func Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}FromEndpoint(mux *runtime.S // 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)) + return Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}Client(ctx, mux, {{$svc.ClientConstructorName}}(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" +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "{{$svc.InstanceName}}Client". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "{{$svc.InstanceName}}Client" // doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in // "{{$svc.InstanceName}}Client" to call the correct interceptors. func Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}Client(ctx context.Context, mux *runtime.ServeMux, client {{$svc.InstanceName}}Client) error { @@ -934,6 +938,7 @@ func Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}Client(ctx context.Context, ctx, cancel := context.WithCancel(ctx) {{- end }} defer cancel() + // inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) rctx, err := runtime.AnnotateContext(ctx, mux, req, "/{{$svc.File.GetPackage}}.{{$svc.GetName}}/{{$m.GetName}}") if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) From 3a06db64dfa86b26726ba00a20a7dfc0aac451b1 Mon Sep 17 00:00:00 2001 From: binchen Date: Mon, 2 Nov 2020 16:56:42 +0800 Subject: [PATCH 38/56] Update google.golang.org/grpc version to v1.29.1 --- go.mod | 4 ++-- repositories.bzl | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 98715b8..5c9000c 100644 --- a/go.mod +++ b/go.mod @@ -24,6 +24,6 @@ require ( replace ( github.com/coreos/bbolt v1.3.4 => go.etcd.io/bbolt v1.3.4 github.com/coreos/bbolt v1.3.5 => go.etcd.io/bbolt v1.3.5 - google.golang.org/grpc v1.30.0 => google.golang.org/grpc v1.27.1 - google.golang.org/grpc v1.33.1 => google.golang.org/grpc v1.27.1 + google.golang.org/grpc v1.30.0 => google.golang.org/grpc v1.29.1 + google.golang.org/grpc v1.33.1 => google.golang.org/grpc v1.29.1 ) diff --git a/repositories.bzl b/repositories.bzl index 6bfc9bc..421c22b 100644 --- a/repositories.bzl +++ b/repositories.bzl @@ -223,8 +223,8 @@ def go_repositories(): go_repository( name = "org_golang_google_grpc", importpath = "google.golang.org/grpc", - sum = "h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk=", - version = "v1.27.1", + sum = "h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4=", + version = "v1.29.1", ) go_repository( From 0608f966104b72d792d1694326087dec66abeac6 Mon Sep 17 00:00:00 2001 From: binchen Date: Mon, 2 Nov 2020 17:18:38 +0800 Subject: [PATCH 39/56] Add LICENSE.txt --- LICENSE.txt | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 LICENSE.txt diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..3645162 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,27 @@ +Copyright (c) 2015, Gengo, Inc. +All rights reserved. + +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 Gengo, 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. From a6f39f1b24f25bea70d6a2bbce03cdb1129d4abb Mon Sep 17 00:00:00 2001 From: binchencoder <15811514091@163.com> Date: Sat, 19 Mar 2022 12:54:13 +0800 Subject: [PATCH 40/56] New branch for grpc-gateway-290 --- .bazelci/presubmit.yml | 18 +- .bazelversion | 2 +- .circleci/Dockerfile | 72 +- .circleci/config.yml | 126 +- .../protoc-gen-grpc-gateway/Dockerfile | 13 + .../plugins/protoc-gen-openapiv2/Dockerfile | 13 + .devcontainer/devcontainer.json | 25 + BUILD | 37 +- WORKSPACE | 80 +- examples/internal/integration/BUILD.bazel | 2 +- examples/internal/proto/examplepb/BUILD.bazel | 79 +- .../proto/examplepb/echo_service.pb.go | 758 ---- .../proto/examplepb/echo_service.pb.gw.go | 1522 ------- .../proto/examplepb/echo_service_grpc.pb.go | 230 - .../examplepb/standalone_echo_service.yaml | 2 +- .../examplepb/unannotated_echo_service.pb.go | 616 --- .../unannotated_echo_service.pb.gw.go | 3 - .../unannotated_echo_service_grpc.pb.go | 158 - gateway/internal/casing/BUILD.bazel | 8 +- gateway/internal/descriptor/BUILD.bazel | 59 +- .../internal/descriptor/apiconfig/BUILD.bazel | 10 +- .../descriptor/grpc_api_configuration.go | 2 +- .../descriptor/openapi_configuration.go | 2 +- .../descriptor/openapiconfig/BUILD.bazel | 10 +- .../openapiconfig/openapiconfig.pb.go | 18 +- gateway/internal/descriptor/registry.go | 135 +- gateway/internal/descriptor/registry_test.go | 117 +- gateway/internal/descriptor/services.go | 5 +- gateway/internal/descriptor/services_test.go | 98 + gateway/internal/descriptor/types.go | 30 +- gateway/internal/descriptor/types_test.go | 10 +- gateway/internal/generator/BUILD.bazel | 13 +- gateway/protoc-gen-grpc-gateway/BUILD.bazel | 19 +- .../internal/gengateway/BUILD.bazel | 36 +- .../internal/gengateway/generator.go | 15 +- .../internal/gengateway/generator_test.go | 1 + .../internal/gengateway/template.go | 44 +- .../internal/gengateway/template_test.go | 184 +- gateway/protoc-gen-grpc-gateway/main.go | 4 + gateway/protoc-gen-openapiv2/BUILD.bazel | 21 +- gateway/protoc-gen-openapiv2/defs.bzl | 179 +- .../internal/genopenapi/BUILD.bazel | 75 +- .../internal/genopenapi/cycle_test.go | 41 + .../internal/genopenapi/format.go | 43 + .../internal/genopenapi/generator.go | 37 +- .../internal/genopenapi/naming.go | 110 + .../internal/genopenapi/template.go | 1144 +++-- .../internal/genopenapi/template_test.go | 3702 ----------------- .../internal/genopenapi/types.go | 287 +- gateway/protoc-gen-openapiv2/main.go | 79 +- gateway/protoc-gen-openapiv2/main_test.go | 229 +- .../protoc-gen-openapiv2/options/BUILD.bazel | 8 +- .../options/annotations.pb.go | 76 +- .../options/annotations.proto | 10 +- .../options/openapiv2.pb.go | 1096 ++--- .../options/openapiv2.proto | 68 +- gateway/runtime/BUILD.bazel | 76 +- gateway/runtime/context.go | 58 +- gateway/runtime/context_test.go | 31 +- gateway/runtime/convert.go | 10 +- gateway/runtime/convert_test.go | 22 +- gateway/runtime/errors.go | 38 +- gateway/runtime/errors_test.go | 10 + gateway/runtime/fieldmask.go | 36 +- gateway/runtime/handler.go | 27 +- gateway/runtime/handler_test.go | 6 + .../runtime/internal/examplepb/BUILD.bazel | 9 +- .../runtime/internal/examplepb/proto3.pb.go | 650 +-- .../runtime/internal/examplepb/proto3.proto | 5 +- gateway/runtime/marshal_json_test.go | 255 -- gateway/runtime/marshal_jsonpb.go | 37 + gateway/runtime/marshal_jsonpb_test.go | 877 ---- gateway/runtime/marshal_proto_test.go | 91 - gateway/runtime/mux.go | 191 +- gateway/runtime/mux_test.go | 307 +- gateway/runtime/pattern.go | 158 +- gateway/runtime/pattern_test.go | 590 --- gateway/runtime/proto2_convert.go | 80 - gateway/runtime/query.go | 16 +- gateway/runtime/query_test.go | 610 --- go.mod | 40 +- go.sum | 26 + httpoptions/BUILD.bazel | 32 +- httpoptions/annotations.pb.go | 185 +- httpoptions/http.pb.go | 364 +- renovate.json | 53 + repositories.bzl | 104 +- 87 files changed, 4683 insertions(+), 12092 deletions(-) create mode 100644 .circleci/plugins/protoc-gen-grpc-gateway/Dockerfile create mode 100644 .circleci/plugins/protoc-gen-openapiv2/Dockerfile create mode 100644 .devcontainer/devcontainer.json delete mode 100755 examples/internal/proto/examplepb/echo_service.pb.go delete mode 100755 examples/internal/proto/examplepb/echo_service.pb.gw.go delete mode 100755 examples/internal/proto/examplepb/echo_service_grpc.pb.go delete mode 100644 examples/internal/proto/examplepb/unannotated_echo_service.pb.go delete mode 100755 examples/internal/proto/examplepb/unannotated_echo_service.pb.gw.go delete mode 100755 examples/internal/proto/examplepb/unannotated_echo_service_grpc.pb.go mode change 100644 => 100755 gateway/internal/descriptor/openapiconfig/openapiconfig.pb.go create mode 100644 gateway/protoc-gen-openapiv2/internal/genopenapi/cycle_test.go create mode 100644 gateway/protoc-gen-openapiv2/internal/genopenapi/format.go create mode 100644 gateway/protoc-gen-openapiv2/internal/genopenapi/naming.go delete mode 100644 gateway/protoc-gen-openapiv2/internal/genopenapi/template_test.go mode change 100644 => 100755 gateway/protoc-gen-openapiv2/options/annotations.pb.go mode change 100644 => 100755 gateway/protoc-gen-openapiv2/options/openapiv2.pb.go mode change 100644 => 100755 gateway/runtime/internal/examplepb/proto3.pb.go delete mode 100644 gateway/runtime/marshal_json_test.go delete mode 100644 gateway/runtime/marshal_jsonpb_test.go delete mode 100644 gateway/runtime/marshal_proto_test.go delete mode 100644 gateway/runtime/pattern_test.go delete mode 100644 gateway/runtime/proto2_convert.go delete mode 100644 gateway/runtime/query_test.go mode change 100644 => 100755 httpoptions/annotations.pb.go mode change 100644 => 100755 httpoptions/http.pb.go create mode 100644 renovate.json diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml index a0da2fc..58e328a 100644 --- a/.bazelci/presubmit.yml +++ b/.bazelci/presubmit.yml @@ -4,29 +4,19 @@ platforms: build_flags: - "--build_tag_filters=-nolinux" build_targets: - - "..." + - "//..." test_flags: - "--features=race" - "--test_tag_filters=-nolinux" test_targets: - - "..." - ubuntu1604: - build_flags: - - "--build_tag_filters=-nolinux" - build_targets: - - "..." - test_flags: - - "--features=race" - - "--test_tag_filters=-nolinux" - test_targets: - - "..." + - "//..." macos: build_flags: - "--build_tag_filters=-nomacos" build_targets: - - "..." + - "//..." test_flags: - "--features=race" - "--test_tag_filters=-nomacos" test_targets: - - "..." + - "//..." diff --git a/.bazelversion b/.bazelversion index 1545d96..af8c8ec 100644 --- a/.bazelversion +++ b/.bazelversion @@ -1 +1 @@ -3.5.0 +4.2.2 diff --git a/.circleci/Dockerfile b/.circleci/Dockerfile index 0c649ac..a3f1108 100644 --- a/.circleci/Dockerfile +++ b/.circleci/Dockerfile @@ -1,41 +1,53 @@ -FROM golang:1.15.3 +FROM golang:1.18.0 -# Warm apt cache and install dependencies -# bzip2 is required by the node_tests (to extract its dependencies). -# patch is required by bazel tests +ENV NVM_DIR="/usr/local/share/nvm" +ENV NVM_SYMLINK_CURRENT=true \ + PATH=${NVM_DIR}/current/bin:${PATH} + +ARG VSCODE_SCRIPTS_VERSION="v0.193.0" +ARG NODE_VERSION="10" +# Run some common installation scripts for a nicer dev environment. In order: +# Used to create non-root user and update system packages +# https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/common.md +# We use this to install Go tools used by gopls +# https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/go.md +# We use this to install Node +# https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/node.md RUN apt-get update && \ - apt-get install -y wget unzip \ - openjdk-11-jre \ - bzip2 \ - patch + wget "https://raw.githubusercontent.com/microsoft/vscode-dev-containers/${VSCODE_SCRIPTS_VERSION}/script-library/common-debian.sh" && \ + chmod +x ./common-debian.sh && \ + ./common-debian.sh false vscode automatic automatic true false && \ + wget "https://raw.githubusercontent.com/microsoft/vscode-dev-containers/${VSCODE_SCRIPTS_VERSION}/script-library/go-debian.sh" && \ + chmod +x ./go-debian.sh && \ + ./go-debian.sh none /usr/local/go /go vscode false true && \ + wget "https://raw.githubusercontent.com/microsoft/vscode-dev-containers/${VSCODE_SCRIPTS_VERSION}/script-library/node-debian.sh" && \ + chmod +x ./node-debian.sh && \ + ./node-debian.sh "${NVM_DIR}" "${NODE_VERSION}" vscode true && \ + rm common-debian.sh go-debian.sh node-debian.sh && \ + DEBIAN_FRONTEND=noninteractive apt-get -y install --no-install-recommends \ + wget \ + unzip \ + openjdk-11-jre \ + bzip2 \ + patch && \ + apt-get clean -y && \ + rm -rf /var/lib/apt/lists/* # Install swagger-codegen ENV SWAGGER_CODEGEN_VERSION=2.4.8 RUN wget https://repo1.maven.org/maven2/io/swagger/swagger-codegen-cli/${SWAGGER_CODEGEN_VERSION}/swagger-codegen-cli-${SWAGGER_CODEGEN_VERSION}.jar \ - -O /usr/local/bin/swagger-codegen-cli.jar - -# Wrap the jar for swagger-codgen -RUN echo -e '#!/bin/bash\njava -jar /usr/local/bin/swagger-codegen-cli.jar "$@"' > /usr/local/bin/swagger-codegen && \ + -O /usr/local/bin/swagger-codegen-cli.jar && \ + echo -e '#!/bin/bash\njava -jar /usr/local/bin/swagger-codegen-cli.jar "$@"' > /usr/local/bin/swagger-codegen && \ chmod +x /usr/local/bin/swagger-codegen -# Install protoc -ENV PROTOC_VERSION=3.12.0 -RUN wget https://github.com/google/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-linux-x86_64.zip \ - -O /protoc-${PROTOC_VERSION}-linux-x86_64.zip && \ - unzip /protoc-${PROTOC_VERSION}-linux-x86_64.zip -d /usr/local/ && \ - rm -f /protoc-${PROTOC_VERSION}-linux-x86_64.zip - -# Install node, used by NVM -ENV NODE_VERSION=v10.16.3 -ENV NVM_VERSION=v0.35.0 -RUN wget -qO- https://raw.githubusercontent.com/creationix/nvm/${NVM_VERSION}/install.sh | bash - # Install Bazelisk as bazel to manage Bazel -RUN go get github.com/bazelbuild/bazelisk && \ +RUN go install github.com/bazelbuild/bazelisk@latest && \ mv $(which bazelisk) /usr/local/bin/bazel -# Clean up -RUN apt-get autoremove -y && \ - apt-get remove -y wget \ - unzip && \ - rm -rf /var/lib/apt/lists/* +# Install buildifier for bazel formatting +RUN go install github.com/bazelbuild/buildtools/buildifier@latest + +# Give vscode ownership of GOPATH +RUN chown -R vscode: /go + +USER vscode diff --git a/.circleci/config.yml b/.circleci/config.yml index 4556a74..5894410 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -6,7 +6,7 @@ commands: steps: - run: | cat > .bazelrc \<< EOF - startup --output_base /root/.cache/_grpc_gateway_bazel + startup --output_base /home/vscode/.cache/_ease_gateway_bazel build --test_output errors build --features race # Workaround https://github.com/bazelbuild/bazel/issues/3645 @@ -16,9 +16,9 @@ commands: EOF generate: steps: - - run: make realclean - - run: make examples - - run: make testproto + - run: make install + - run: make clean + - run: make generate - run: go mod tidy renovate_git_amend_push: description: Git amend and push changes @@ -28,7 +28,7 @@ commands: if output=$(git status --porcelain) && [ ! -z "$output" ]; then git config user.name "Renovate Bot" git config user.email "bot@renovateapp.com" - git remote set-url origin https://x-access-token:${GITHUB_TOKEN}@github.com/binchencoder/ease-gateway.git + git remote set-url origin https://x-access-token:${GITHUB_TOKEN}@github.com/grpc-ecosystem/grpc-gateway.git git commit --amend --no-edit git push --force-with-lease origin ${CIRCLE_BRANCH} fi @@ -36,10 +36,10 @@ commands: executors: build-env: environment: - ## Split key to avoid github revoking it - password0: '99544cdcb19ad4e3fd64' - password1: '3ec86b2e5a431be2d72c' - GLOG_logtostderr: '1' + ## Split key to avoid github revoking it + password0: "99544cdcb19ad4e3fd64" + password1: "3ec86b2e5a431be2d72c" + GLOG_logtostderr: "1" docker: - image: docker.pkg.github.com/binchencoder/ease-gateway/build-env:1.15 auth: @@ -49,74 +49,44 @@ executors: jobs: build: executor: build-env - working_directory: /src/ease-gateway + working_directory: /home/vscode/src/ease-gateway steps: - checkout - run: go build ./... test: executor: build-env - working_directory: /src/ease-gateway + working_directory: /home/vscode/src/ease-gateway steps: - checkout - run: go test -race -coverprofile=coverage.txt ./... - run: bash <(curl -s https://codecov.io/bash) node_test: executor: build-env - working_directory: /src/ease-gateway + working_directory: /home/vscode/src/ease-gateway steps: - checkout - run: go mod vendor - run: > - . $HOME/.nvm/nvm.sh && cd examples/internal/browser && npm install gulp-cli && npm install && ./node_modules/.bin/gulp generate: executor: build-env - working_directory: /src/ease-gateway + working_directory: /home/vscode/src/ease-gateway steps: - checkout - generate - run: git diff --exit-code - lint: - executor: build-env - working_directory: /src/ease-gateway - steps: - - checkout - - restore_cache: - keys: - - v1-staticcheck-cache-{{ checksum "go.sum" }} - - v1-staticcheck-cache- - - run: - name: Install staticcheck outside local module - command: | - cd $(mktemp -d) && - go mod init tmp && - go get honnef.co/go/tools/cmd/staticcheck - - run: staticcheck ./... - - save_cache: - key: v1-staticcheck-cache-{{ checksum "go.sum" }} - paths: - - /root/.cache/go-build - - /root/.cache/staticcheck - fuzzit: - docker: - - image: fuzzitdev/fuzzit:golang1.12-stretch-llvm9 - working_directory: /src/ease-gateway - steps: - - checkout - - setup_remote_docker - - run: ./fuzzit.sh bazel: executor: build-env - working_directory: /src/ease-gateway + working_directory: /home/vscode/src/ease-gateway steps: - checkout - restore_cache: keys: - - v2-bazel-cache-{{ checksum "repositories.bzl" }} - - v2-bazel-cache- + - v3-bazel-cache-{{ checksum "repositories.bzl" }} + - v3-bazel-cache- - configure_bazel - run: name: Check that Bazel BUILD files are up-to-date @@ -137,12 +107,12 @@ jobs: name: Run tests with Bazel command: bazel test //... - save_cache: - key: v2-bazel-cache-{{ checksum "repositories.bzl" }} + key: v3-bazel-cache-{{ checksum "repositories.bzl" }} paths: - - /root/.cache/_grpc_gateway_bazel + - /home/vscode/.cache/_ease_gateway_bazel gorelease: executor: build-env - working_directory: /src/ease-gateway + working_directory: /home/vscode/src/ease-gateway steps: - checkout - run: @@ -151,23 +121,55 @@ jobs: cd $(mktemp -d) && go mod init tmp && go get golang.org/x/exp/cmd/gorelease@latest - - run: gorelease -base=v2.0.0 + - run: gorelease -base=v2.8.0 + push_bsr_plugins: + docker: + - image: circleci/golang + steps: + - setup_remote_docker + - checkout + - run: echo "${BUF_API_TOKEN}" | docker login --username grpcgatewaybot --password-stdin plugins.buf.build + - run: | + cd .circleci/plugins/protoc-gen-grpc-gateway && + docker build -t plugins.buf.build/grpc-ecosystem/grpc-gateway:${CIRCLE_TAG}-1 --build-arg=RELEASE_VERSION=${CIRCLE_TAG} . && + docker push plugins.buf.build/grpc-ecosystem/grpc-gateway:${CIRCLE_TAG}-1 + - run: | + cd .circleci/plugins/protoc-gen-openapiv2 && + docker build -t plugins.buf.build/grpc-ecosystem/openapiv2:${CIRCLE_TAG}-1 --build-arg=RELEASE_VERSION=${CIRCLE_TAG} . && + docker push plugins.buf.build/grpc-ecosystem/openapiv2:${CIRCLE_TAG}-1 + proto_lint: + docker: + - image: bufbuild/buf:1.1.0 + steps: + - checkout + - run: buf build + - run: buf lint + - run: buf breaking --path protoc-gen-openapiv2/ --against 'https://github.com/grpc-ecosystem/grpc-gateway.git#branch=master' + proto_push: + docker: + - image: bufbuild/buf:1.1.0 + steps: + - checkout + # Limit pushes to protoc-gen-openapiv2 files. This is a total hack. + # It excludes all the files that we don't want to publish, just for the push step. + - run: echo -e " - examples\n - internal\n - runtime" >> buf.yaml + - run: BUF_TOKEN="${BUF_API_TOKEN}" buf push --tag "$CIRCLE_SHA1" release: executor: build-env - working_directory: /src/ease-gateway + working_directory: /home/vscode/src/ease-gateway steps: - checkout - run: go mod vendor - run: curl -sL https://git.io/goreleaser | bash update-repositoriesbzl: executor: build-env - working_directory: /src/ease-gateway + working_directory: /home/vscode/src/ease-gateway steps: - checkout - restore_cache: keys: - - v2-bazel-cache-{{ checksum "repositories.bzl" }} - - v2-bazel-cache- + - v3-bazel-cache-{{ checksum "repositories.bzl" }} + - v3-bazel-cache- - configure_bazel - run: name: Update repositories.bzl @@ -176,7 +178,7 @@ jobs: - renovate_git_amend_push regenerate: executor: build-env - working_directory: /src/ease-gateway + working_directory: /home/vscode/src/ease-gateway steps: - checkout - generate @@ -187,18 +189,27 @@ workflows: jobs: - build - test - - fuzzit - node_test - generate - - lint - bazel - gorelease + - proto_lint + - proto_push: + filters: + branches: + only: /^master$/ - release: filters: branches: ignore: /.*/ tags: only: /v[0-9]+(\.[0-9]+)*(-.*)*/ + - push_bsr_plugins: + filters: + branches: + ignore: /.*/ + tags: + only: /v[0-9]+(\.[0-9]+)*(-.*)*/ - update-repositoriesbzl: filters: branches: @@ -215,4 +226,3 @@ workflows: only: /renovate\/master-.+/ tags: ignore: /.*/ - diff --git a/.circleci/plugins/protoc-gen-grpc-gateway/Dockerfile b/.circleci/plugins/protoc-gen-grpc-gateway/Dockerfile new file mode 100644 index 0000000..baf7d3a --- /dev/null +++ b/.circleci/plugins/protoc-gen-grpc-gateway/Dockerfile @@ -0,0 +1,13 @@ +FROM golang:1.18.0 as builder + +ARG RELEASE_VERSION + +# Buf plugins must be built for linux/amd64 +ENV GOOS=linux GOARCH=amd64 CGO_ENABLED=0 +RUN go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@${RELEASE_VERSION} + +FROM scratch + +COPY --from=builder /go/bin/protoc-gen-grpc-gateway /usr/local/bin/protoc-gen-grpc-gateway + +ENTRYPOINT ["/usr/local/bin/protoc-gen-grpc-gateway"] diff --git a/.circleci/plugins/protoc-gen-openapiv2/Dockerfile b/.circleci/plugins/protoc-gen-openapiv2/Dockerfile new file mode 100644 index 0000000..2b9115e --- /dev/null +++ b/.circleci/plugins/protoc-gen-openapiv2/Dockerfile @@ -0,0 +1,13 @@ +FROM golang:1.18.0 as builder + +ARG RELEASE_VERSION + +# Buf plugins must be built for linux/amd64 +ENV GOOS=linux GOARCH=amd64 CGO_ENABLED=0 +RUN go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2@${RELEASE_VERSION} + +FROM scratch + +COPY --from=builder /go/bin/protoc-gen-openapiv2 /usr/local/bin/protoc-gen-openapiv2 + +ENTRYPOINT ["/usr/local/bin/protoc-gen-openapiv2"] diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..0386e5f --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,25 @@ +// For format details, see https://aka.ms/devcontainer.json. +{ + "name": "Go", + "build": { + "dockerfile": "../.circleci/Dockerfile", + "args": { + "NODE_VERSION": "10" + } + }, + "settings": { + "editor.formatOnSave": true, + "go.toolsManagement.checkForUpdates": "local", + "go.useLanguageServer": true, + "go.gopath": "/go", + "go.goroot": "/usr/local/go", + "bazel.buildifierExecutable": "/go/bin/buildifier", + "bazel.buildifierFixOnFormat": true, + "bazel.enableCodeLens": true, + }, + "extensions": [ + "golang.Go", + "bazelbuild.vscode-bazel", + ], + "remoteUser": "vscode" +} diff --git a/BUILD b/BUILD index 8d283d0..cf3996f 100644 --- a/BUILD +++ b/BUILD @@ -1,6 +1,9 @@ load("@bazel_gazelle//:def.bzl", "gazelle") load("@com_github_bazelbuild_buildtools//buildifier:def.bzl", "buildifier") load("@io_bazel_rules_go//proto:compiler.bzl", "go_proto_compiler") +load("@io_bazel_rules_go//proto/wkt:well_known_types.bzl", "PROTO_RUNTIME_DEPS", "WELL_KNOWN_TYPES_APIV2") + +exports_files(["LICENSE.txt"]) buildifier( name = "buildifier", @@ -11,11 +14,11 @@ buildifier( mode = "check", ) -# gazelle:exclude third_party # gazelle:exclude _output # gazelle:prefix github.com/binchencoder/ease-gateway/gateway # gazelle:go_proto_compilers //:go_apiv2 # gazelle:go_grpc_compilers //:go_apiv2, //:go_grpc +# gazelle:go_naming_convention import_alias gazelle(name = "gazelle") @@ -35,23 +38,7 @@ go_proto_compiler( plugin = "@org_golang_google_protobuf//cmd/protoc-gen-go", suffix = ".pb.go", visibility = ["//visibility:public"], - deps = [ - "@com_github_golang_protobuf//proto:go_default_library", - "@io_bazel_rules_go//proto/wkt:any_go_proto", - "@io_bazel_rules_go//proto/wkt:api_go_proto", - "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", - "@io_bazel_rules_go//proto/wkt:descriptor_go_proto", - "@io_bazel_rules_go//proto/wkt:duration_go_proto", - "@io_bazel_rules_go//proto/wkt:empty_go_proto", - "@io_bazel_rules_go//proto/wkt:field_mask_go_proto", - "@io_bazel_rules_go//proto/wkt:source_context_go_proto", - "@io_bazel_rules_go//proto/wkt:struct_go_proto", - "@io_bazel_rules_go//proto/wkt:timestamp_go_proto", - "@io_bazel_rules_go//proto/wkt:type_go_proto", - "@io_bazel_rules_go//proto/wkt:wrappers_go_proto", - "@org_golang_google_protobuf//reflect/protoreflect:go_default_library", - "@org_golang_google_protobuf//runtime/protoimpl:go_default_library", - ], + deps = PROTO_RUNTIME_DEPS + WELL_KNOWN_TYPES_APIV2, ) go_proto_compiler( @@ -63,19 +50,7 @@ go_proto_compiler( plugin = "@org_golang_google_grpc_cmd_protoc_gen_go_grpc//:protoc-gen-go-grpc", suffix = "_grpc.pb.go", visibility = ["//visibility:public"], - deps = [ - "@io_bazel_rules_go//proto/wkt:any_go_proto", - "@io_bazel_rules_go//proto/wkt:api_go_proto", - "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", - "@io_bazel_rules_go//proto/wkt:descriptor_go_proto", - "@io_bazel_rules_go//proto/wkt:duration_go_proto", - "@io_bazel_rules_go//proto/wkt:empty_go_proto", - "@io_bazel_rules_go//proto/wkt:field_mask_go_proto", - "@io_bazel_rules_go//proto/wkt:source_context_go_proto", - "@io_bazel_rules_go//proto/wkt:struct_go_proto", - "@io_bazel_rules_go//proto/wkt:timestamp_go_proto", - "@io_bazel_rules_go//proto/wkt:type_go_proto", - "@io_bazel_rules_go//proto/wkt:wrappers_go_proto", + deps = PROTO_RUNTIME_DEPS + [ "@org_golang_google_grpc//:go_default_library", "@org_golang_google_grpc//codes:go_default_library", "@org_golang_google_grpc//status:go_default_library", diff --git a/WORKSPACE b/WORKSPACE index 8bf12d5..796ce44 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -1,13 +1,22 @@ workspace(name = "com_github_binchencoder_ease_gateway") load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") +load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") + +# Define before rules_proto, otherwise we receive the version of com_google_protobuf from there +http_archive( + name = "com_google_protobuf", + sha256 = "3bd7828aa5af4b13b99c191e8b1e884ebfa9ad371b0ce264605d347f135d2568", + strip_prefix = "protobuf-3.19.4", + urls = ["https://github.com/protocolbuffers/protobuf/archive/v3.19.4.tar.gz"], +) http_archive( name = "bazel_skylib", - sha256 = "1c531376ac7e5a180e0237938a2536de0c54d93f5c278634818e0efc952dd56c", + sha256 = "f7be3474d42aae265405a592bb7da8e171919d74c16f082a5457840f06054728", urls = [ - "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.0.3/bazel-skylib-1.0.3.tar.gz", - "https://github.com/bazelbuild/bazel-skylib/releases/download/1.0.3/bazel-skylib-1.0.3.tar.gz", + "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.2.1/bazel-skylib-1.2.1.tar.gz", + "https://github.com/bazelbuild/bazel-skylib/releases/download/1.2.1/bazel-skylib-1.2.1.tar.gz", ], ) @@ -17,11 +26,11 @@ bazel_skylib_workspace() http_archive( name = "rules_proto", - sha256 = "602e7161d9195e50246177e7c55b2f39950a9cf7366f74ed5f22fd45750cd208", - strip_prefix = "rules_proto-97d8af4dc474595af3900dd85cb3a29ad28cc313", + sha256 = "66bfdf8782796239d3875d37e7de19b1d94301e8972b3cbd2446b332429b4df1", + strip_prefix = "rules_proto-4.0.0", urls = [ - "https://mirror.bazel.build/github.com/bazelbuild/rules_proto/archive/97d8af4dc474595af3900dd85cb3a29ad28cc313.tar.gz", - "https://github.com/bazelbuild/rules_proto/archive/97d8af4dc474595af3900dd85cb3a29ad28cc313.tar.gz", + "https://mirror.bazel.build/github.com/bazelbuild/rules_proto/archive/refs/tags/4.0.0.tar.gz", + "https://github.com/bazelbuild/rules_proto/archive/refs/tags/4.0.0.tar.gz", ], ) @@ -33,33 +42,41 @@ rules_proto_toolchains() http_archive( name = "io_bazel_rules_go", - sha256 = "d1ffd055969c8f8d431e2d439813e42326961d0942bdf734d2c95dc30c369566", + sha256 = "d6b2513456fe2229811da7eb67a444be7785f5323c6708b38d851d2b51e54d83", urls = [ - "https://storage.googleapis.com/bazel-mirror/github.com/bazelbuild/rules_go/releases/download/v0.24.5/rules_go-v0.24.5.tar.gz", - "https://github.com/bazelbuild/rules_go/releases/download/v0.24.5/rules_go-v0.24.5.tar.gz", + "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.30.0/rules_go-v0.30.0.zip", + "https://github.com/bazelbuild/rules_go/releases/download/v0.30.0/rules_go-v0.30.0.zip", ], ) # ---------- bazel_gazelle ---------- # 一般来说都会使用gazelle工具来自动生成 BUILD 文件, 而不是手写. -http_archive( +# http_archive( +# name = "bazel_gazelle", +# sha256 = "b85f48fa105c4403326e9525ad2b2cc437babaa6e15a3fc0b1dbab0ab064bc7c", +# urls = [ +# "https://storage.googleapis.com/bazel-mirror/github.com/bazelbuild/bazel-gazelle/releases/download/v0.22.2/bazel-gazelle-v0.22.2.tar.gz", +# "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.22.2/bazel-gazelle-v0.22.2.tar.gz", +# ], +# ) + +# TODO: Revert https://github.com/grpc-ecosystem/grpc-gateway/pull/2578/commits/fb9b59be7f2408767657c83c5002bf700ac7c460 once +# https://github.com/bazelbuild/bazel-gazelle/pull/1194 is merged +git_repository( name = "bazel_gazelle", - sha256 = "b85f48fa105c4403326e9525ad2b2cc437babaa6e15a3fc0b1dbab0ab064bc7c", - urls = [ - "https://storage.googleapis.com/bazel-mirror/github.com/bazelbuild/bazel-gazelle/releases/download/v0.22.2/bazel-gazelle-v0.22.2.tar.gz", - "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.22.2/bazel-gazelle-v0.22.2.tar.gz", - ], + commit = "4a1aeae7cab962fd8088f42038d3a477cdca91a5", + remote = "https://github.com/johanbrandhorst/bazel-gazelle", + shallow_since = "1647116890 +0000", ) + # 从下载的扩展里载入 go_rules_dependencies go_register_toolchains 函数 load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies") # 注册一堆常用依赖 如github.com/google/protobuf golang.org/x/net go_rules_dependencies() # 下载golang工具链 -go_register_toolchains() +go_register_toolchains(version = "1.17.2") load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies", "go_repository") -# 加载gazelle依赖 -gazelle_dependencies() # Use gazelle to declare Go dependencies in Bazel. # gazelle:repository_macro repositories.bzl%go_repositories @@ -68,21 +85,12 @@ load("//:repositories.bzl", "go_repositories") go_repositories() -load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") - -git_repository( - name = "com_google_protobuf", - commit = "09745575a923640154bcf307fba8aedff47f240a", - remote = "https://github.com/protocolbuffers/protobuf", - shallow_since = "1558721209 -0700", -) +# 加载gazelle依赖 +# This must be invoked after our explicit dependencies +# See https://github.com/bazelbuild/bazel-gazelle/issues/1115. +gazelle_dependencies() -# go_repository( -# name = "com_google_protobuf", -# importpath = "github.com/protocolbuffers/protobuf", -# sum = "h1:pNPOCD+Nm4NY0R6gdOpwOPpRGUjbPo9SO/UlD56lH+0=", -# version = "v3.8.0+incompatible", -# ) +load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps") @@ -91,9 +99,9 @@ protobuf_deps() # ---------- com_github_bazelbuild_buildtools ---------- http_archive( name = "com_github_bazelbuild_buildtools", - sha256 = "a02ba93b96a8151b5d8d3466580f6c1f7e77212c4eb181cba53eb2cae7752a23", - strip_prefix = "buildtools-3.5.0", - urls = ["https://github.com/bazelbuild/buildtools/archive/3.5.0.tar.gz"], + sha256 = "7f43df3cca7bb4ea443b4159edd7a204c8d771890a69a50a190dc9543760ca21", + strip_prefix = "buildtools-5.0.1", + urls = ["https://github.com/bazelbuild/buildtools/archive/5.0.1.tar.gz"], ) load("@com_github_bazelbuild_buildtools//buildifier:deps.bzl", "buildifier_dependencies") diff --git a/examples/internal/integration/BUILD.bazel b/examples/internal/integration/BUILD.bazel index 8a5085e..6931ba2 100644 --- a/examples/internal/integration/BUILD.bazel +++ b/examples/internal/integration/BUILD.bazel @@ -12,7 +12,7 @@ go_test( # "//examples/internal/proto/examplepb:unannotated_go_default_library", "//examples/internal/server:go_default_library", "//gateway/runtime:go_default_library", - "//httpoptions:go_default_library", + "//httpoptions", "@com_github_golang_glog//:go_default_library", "@com_github_google_go_cmp//cmp:go_default_library", "@go_googleapis//google/rpc:status_go_proto", diff --git a/examples/internal/proto/examplepb/BUILD.bazel b/examples/internal/proto/examplepb/BUILD.bazel index 2a1db92..16e18c5 100644 --- a/examples/internal/proto/examplepb/BUILD.bazel +++ b/examples/internal/proto/examplepb/BUILD.bazel @@ -28,6 +28,8 @@ package(default_visibility = ["//visibility:public"]) # gazelle:exclude wrappers_grpc.pb.go # gazelle:exclude unannotated_echo_service.pb.gw.go # gazelle:exclude unannotated_echo_service_grpc.pb.go +# gazelle:exclude visibility_rule_echo_service.pb.gw.go +# gazelle:exclude visibility_rule_echo_service_grpc.pb.go # gazelle:exclude openapi_merge_a.proto # gazelle:exclude openapi_merge_b.proto # gazelle:go_grpc_compilers //:go_apiv2, //:go_grpc, //protoc-gen-grpc-gateway:go_gen_grpc_gateway @@ -36,9 +38,10 @@ proto_library( name = "examplepb_proto", srcs = [ "echo_service.proto", - "unannotated_echo_service.proto", + # "unannotated_echo_service.proto", ], deps = [ + "//gateway/protoc-gen-openapiv2/options:options_proto", "//httpoptions:options_proto", "@com_github_binchencoder_gateway_proto//data:data_proto", "@com_github_binchencoder_gateway_proto//frontend:error_proto", @@ -50,17 +53,21 @@ proto_library( "@com_google_protobuf//:wrappers_proto", "@go_googleapis//google/api:annotations_proto", "@go_googleapis//google/api:httpbody_proto", + "@go_googleapis//google/api:visibility_proto", "@go_googleapis//google/rpc:status_proto", ], ) +#keep # proto_library( -# name = "examplepb_unannotated_proto", +# name = "openapi_merge_proto", # srcs = [ -# "unannotated_echo_service.proto", +# "openapi_merge_a.proto", +# "openapi_merge_b.proto", # ], # deps = [ -# "@com_google_protobuf//:duration_proto", +# "@go_googleapis//google/api:annotations_proto", +# "@go_googleapis//google/api:httpbody_proto", # ], # ) @@ -69,66 +76,50 @@ go_proto_library( compilers = [ "//:go_apiv2", "//:go_grpc", - "//gateway/protoc-gen-grpc-gateway:go_gen_grpc_gateway", # keep + "//gateway/protoc-gen-grpc-gateway:go_gen_grpc_gateway", ], importpath = "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb", proto = ":examplepb_proto", deps = [ - "//httpoptions:go_default_library", + "//httpoptions", "@com_github_binchencoder_letsgo//grpc:go_default_library", "@com_github_binchencoder_skylb_api//balancer:go_default_library", "@com_github_binchencoder_skylb_api//client:go_default_library", "@com_github_binchencoder_skylb_api//client/option:go_default_library", "@com_github_binchencoder_skylb_api//proto:go_default_library", - "//gateway/protoc-gen-openapiv2/options:go_default_library", + "//gateway/protoc-gen-openapiv2/options", "@com_github_golang_protobuf//descriptor:go_default_library_gen", # keep "@go_googleapis//google/api:annotations_go_proto", "@go_googleapis//google/api:httpbody_go_proto", + "@go_googleapis//google/api:visibility_go_proto", "@go_googleapis//google/rpc:status_go_proto", "@org_golang_google_protobuf//proto:go_default_library", # keep - "@org_golang_google_grpc//naming:go_default_library", + # "@org_golang_google_grpc//naming:go_default_library", ], ) -# go_proto_library( -# name = "examplepb_unannotated_go_proto", -# compilers = [ -# "//:go_apiv2", -# "//:go_grpc", -# "@com_github_grpc_ecosystem_grpc_gateway//protoc-gen-grpc-gateway:go_gen_grpc_gateway", # keep -# ], -# importpath = "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb", -# proto = ":examplepb_unannotated_proto", -# deps = [ -# "//gateway/protoc-gen-openapiv2/options:go_default_library", -# "@com_github_golang_protobuf//descriptor:go_default_library_gen", # keep -# "@go_googleapis//google/api:annotations_go_proto", -# "@go_googleapis//google/api:httpbody_go_proto", -# "@go_googleapis//google/rpc:status_go_proto", -# "@org_golang_google_protobuf//proto:go_default_library", # keep -# ], -# ) - go_library( - name = "go_default_library", + name = "examplepb", embed = [":examplepb_go_proto"], importpath = "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb", deps = [ - "//httpoptions:go_default_library", - "//gateway/runtime:go_default_library", - "@com_github_binchencoder_gateway_proto//data:go_default_library", + "//httpoptions", + "//gateway/runtime", + "@com_github_grpc_ecosystem_grpc_gateway//utilities", "@com_github_binchencoder_gateway_proto//frontend:go_default_library", "@com_github_binchencoder_skylb_api//balancer:go_default_library", "@com_github_binchencoder_skylb_api//client:go_default_library", + "@org_golang_google_grpc//:go_default_library", + "@org_golang_google_grpc//codes", + "@org_golang_google_grpc//grpclog", + "@org_golang_google_grpc//metadata", + "@org_golang_google_grpc//status", + "@org_golang_google_protobuf//proto", + "@org_golang_google_protobuf//reflect/protoreflect", + "@org_golang_google_protobuf//runtime/protoimpl", ], ) -# go_library( -# name = "unannotated_go_default_library", -# embed = [":examplepb_unannotated_go_proto"], -# importpath = "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb", -# ) - protoc_gen_openapiv2( name = "examplepb_protoc_gen_openapiv2", proto = ":examplepb_proto", @@ -138,4 +129,16 @@ protoc_gen_openapiv2( name = "examplepb_protoc_gen_openapiv2_merged", proto = ":examplepb_proto", single_output = True, # Outputs a single swagger.json file. -) \ No newline at end of file +) + +# protoc_gen_openapiv2( +# name = "examplepb_openapi_merge", +# proto = ":openapi_merge_proto", +# single_output = True, # Outputs a single swagger.json file. +# ) + +alias( + name = "go_default_library", + actual = ":examplepb", + visibility = ["//examples:__subpackages__"], +) diff --git a/examples/internal/proto/examplepb/echo_service.pb.go b/examples/internal/proto/examplepb/echo_service.pb.go deleted file mode 100755 index 73bfcac..0000000 --- a/examples/internal/proto/examplepb/echo_service.pb.go +++ /dev/null @@ -1,758 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.25.0 -// protoc v3.9.0 -// source: examples/internal/proto/examplepb/echo_service.proto - -package examplepb - -import ( - _ "github.com/binchencoder/ease-gateway/httpoptions" - proto "github.com/golang/protobuf/proto" - _struct "github.com/golang/protobuf/ptypes/struct" - field_mask "google.golang.org/genproto/protobuf/field_mask" - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - reflect "reflect" - sync "sync" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - -type Embedded struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Types that are assignable to Mark: - // *Embedded_Progress - // *Embedded_Note - Mark isEmbedded_Mark `protobuf_oneof:"mark"` -} - -func (x *Embedded) Reset() { - *x = Embedded{} - if protoimpl.UnsafeEnabled { - mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Embedded) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Embedded) ProtoMessage() {} - -func (x *Embedded) ProtoReflect() protoreflect.Message { - mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Embedded.ProtoReflect.Descriptor instead. -func (*Embedded) Descriptor() ([]byte, []int) { - return file_examples_internal_proto_examplepb_echo_service_proto_rawDescGZIP(), []int{0} -} - -func (m *Embedded) GetMark() isEmbedded_Mark { - if m != nil { - return m.Mark - } - return nil -} - -func (x *Embedded) GetProgress() int64 { - if x, ok := x.GetMark().(*Embedded_Progress); ok { - return x.Progress - } - return 0 -} - -func (x *Embedded) GetNote() string { - if x, ok := x.GetMark().(*Embedded_Note); ok { - return x.Note - } - return "" -} - -type isEmbedded_Mark interface { - isEmbedded_Mark() -} - -type Embedded_Progress struct { - Progress int64 `protobuf:"varint,1,opt,name=progress,proto3,oneof"` -} - -type Embedded_Note struct { - Note string `protobuf:"bytes,2,opt,name=note,proto3,oneof"` -} - -func (*Embedded_Progress) isEmbedded_Mark() {} - -func (*Embedded_Note) isEmbedded_Mark() {} - -type SimpleMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Num int64 `protobuf:"varint,2,opt,name=num,proto3" json:"num,omitempty"` - // Types that are assignable to Code: - // *SimpleMessage_LineNum - // *SimpleMessage_Lang - Code isSimpleMessage_Code `protobuf_oneof:"code"` - Status *Embedded `protobuf:"bytes,5,opt,name=status,proto3" json:"status,omitempty"` - // Types that are assignable to Ext: - // *SimpleMessage_En - // *SimpleMessage_No - Ext isSimpleMessage_Ext `protobuf_oneof:"ext"` -} - -func (x *SimpleMessage) Reset() { - *x = SimpleMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *SimpleMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*SimpleMessage) ProtoMessage() {} - -func (x *SimpleMessage) ProtoReflect() protoreflect.Message { - mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use SimpleMessage.ProtoReflect.Descriptor instead. -func (*SimpleMessage) Descriptor() ([]byte, []int) { - return file_examples_internal_proto_examplepb_echo_service_proto_rawDescGZIP(), []int{1} -} - -func (x *SimpleMessage) GetId() string { - if x != nil { - return x.Id - } - return "" -} - -func (x *SimpleMessage) GetNum() int64 { - if x != nil { - return x.Num - } - return 0 -} - -func (m *SimpleMessage) GetCode() isSimpleMessage_Code { - if m != nil { - return m.Code - } - return nil -} - -func (x *SimpleMessage) GetLineNum() int64 { - if x, ok := x.GetCode().(*SimpleMessage_LineNum); ok { - return x.LineNum - } - return 0 -} - -func (x *SimpleMessage) GetLang() string { - if x, ok := x.GetCode().(*SimpleMessage_Lang); ok { - return x.Lang - } - return "" -} - -func (x *SimpleMessage) GetStatus() *Embedded { - if x != nil { - return x.Status - } - return nil -} - -func (m *SimpleMessage) GetExt() isSimpleMessage_Ext { - if m != nil { - return m.Ext - } - return nil -} - -func (x *SimpleMessage) GetEn() int64 { - if x, ok := x.GetExt().(*SimpleMessage_En); ok { - return x.En - } - return 0 -} - -func (x *SimpleMessage) GetNo() *Embedded { - if x, ok := x.GetExt().(*SimpleMessage_No); ok { - return x.No - } - return nil -} - -type isSimpleMessage_Code interface { - isSimpleMessage_Code() -} - -type SimpleMessage_LineNum struct { - LineNum int64 `protobuf:"varint,3,opt,name=line_num,json=lineNum,proto3,oneof"` -} - -type SimpleMessage_Lang struct { - Lang string `protobuf:"bytes,4,opt,name=lang,proto3,oneof"` -} - -func (*SimpleMessage_LineNum) isSimpleMessage_Code() {} - -func (*SimpleMessage_Lang) isSimpleMessage_Code() {} - -type isSimpleMessage_Ext interface { - isSimpleMessage_Ext() -} - -type SimpleMessage_En struct { - En int64 `protobuf:"varint,6,opt,name=en,proto3,oneof"` -} - -type SimpleMessage_No struct { - No *Embedded `protobuf:"bytes,7,opt,name=no,proto3,oneof"` -} - -func (*SimpleMessage_En) isSimpleMessage_Ext() {} - -func (*SimpleMessage_No) isSimpleMessage_Ext() {} - -type ValidationRuleTestRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Num int64 `protobuf:"varint,2,opt,name=num,proto3" json:"num,omitempty"` -} - -func (x *ValidationRuleTestRequest) Reset() { - *x = ValidationRuleTestRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ValidationRuleTestRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ValidationRuleTestRequest) ProtoMessage() {} - -func (x *ValidationRuleTestRequest) ProtoReflect() protoreflect.Message { - mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ValidationRuleTestRequest.ProtoReflect.Descriptor instead. -func (*ValidationRuleTestRequest) Descriptor() ([]byte, []int) { - return file_examples_internal_proto_examplepb_echo_service_proto_rawDescGZIP(), []int{2} -} - -func (x *ValidationRuleTestRequest) GetId() string { - if x != nil { - return x.Id - } - return "" -} - -func (x *ValidationRuleTestRequest) GetNum() int64 { - if x != nil { - return x.Num - } - return 0 -} - -type ValidationRuleTestResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *ValidationRuleTestResponse) Reset() { - *x = ValidationRuleTestResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ValidationRuleTestResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ValidationRuleTestResponse) ProtoMessage() {} - -func (x *ValidationRuleTestResponse) ProtoReflect() protoreflect.Message { - mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ValidationRuleTestResponse.ProtoReflect.Descriptor instead. -func (*ValidationRuleTestResponse) Descriptor() ([]byte, []int) { - return file_examples_internal_proto_examplepb_echo_service_proto_rawDescGZIP(), []int{3} -} - -type DynamicMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - StructField *_struct.Struct `protobuf:"bytes,1,opt,name=struct_field,json=structField,proto3" json:"struct_field,omitempty"` - ValueField *_struct.Value `protobuf:"bytes,2,opt,name=value_field,json=valueField,proto3" json:"value_field,omitempty"` -} - -func (x *DynamicMessage) Reset() { - *x = DynamicMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *DynamicMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*DynamicMessage) ProtoMessage() {} - -func (x *DynamicMessage) ProtoReflect() protoreflect.Message { - mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use DynamicMessage.ProtoReflect.Descriptor instead. -func (*DynamicMessage) Descriptor() ([]byte, []int) { - return file_examples_internal_proto_examplepb_echo_service_proto_rawDescGZIP(), []int{4} -} - -func (x *DynamicMessage) GetStructField() *_struct.Struct { - if x != nil { - return x.StructField - } - return nil -} - -func (x *DynamicMessage) GetValueField() *_struct.Value { - if x != nil { - return x.ValueField - } - return nil -} - -type DynamicMessageUpdate struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Body *DynamicMessage `protobuf:"bytes,1,opt,name=body,proto3" json:"body,omitempty"` - UpdateMask *field_mask.FieldMask `protobuf:"bytes,2,opt,name=update_mask,json=updateMask,proto3" json:"update_mask,omitempty"` -} - -func (x *DynamicMessageUpdate) Reset() { - *x = DynamicMessageUpdate{} - if protoimpl.UnsafeEnabled { - mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *DynamicMessageUpdate) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*DynamicMessageUpdate) ProtoMessage() {} - -func (x *DynamicMessageUpdate) ProtoReflect() protoreflect.Message { - mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use DynamicMessageUpdate.ProtoReflect.Descriptor instead. -func (*DynamicMessageUpdate) Descriptor() ([]byte, []int) { - return file_examples_internal_proto_examplepb_echo_service_proto_rawDescGZIP(), []int{5} -} - -func (x *DynamicMessageUpdate) GetBody() *DynamicMessage { - if x != nil { - return x.Body - } - return nil -} - -func (x *DynamicMessageUpdate) GetUpdateMask() *field_mask.FieldMask { - if x != nil { - return x.UpdateMask - } - return nil -} - -var File_examples_internal_proto_examplepb_echo_service_proto protoreflect.FileDescriptor - -var file_examples_internal_proto_examplepb_echo_service_proto_rawDesc = []byte{ - 0x0a, 0x34, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, - 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, - 0x65, 0x70, 0x62, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, - 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, - 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, - 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x1a, 0x1d, 0x68, 0x74, 0x74, 0x70, 0x6f, 0x70, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x73, - 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x46, 0x0a, 0x08, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, - 0x64, 0x12, 0x1c, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, - 0x14, 0x0a, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, - 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x42, 0x06, 0x0a, 0x04, 0x6d, 0x61, 0x72, 0x6b, 0x22, 0xa3, 0x02, - 0x0a, 0x0d, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, - 0x10, 0x0a, 0x03, 0x6e, 0x75, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x6e, 0x75, - 0x6d, 0x12, 0x1b, 0x0a, 0x08, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x07, 0x6c, 0x69, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x12, 0x14, - 0x0a, 0x04, 0x6c, 0x61, 0x6e, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, - 0x6c, 0x61, 0x6e, 0x67, 0x12, 0x50, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, - 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, - 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, - 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x52, 0x06, - 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x10, 0x0a, 0x02, 0x65, 0x6e, 0x18, 0x06, 0x20, 0x01, - 0x28, 0x03, 0x48, 0x01, 0x52, 0x02, 0x65, 0x6e, 0x12, 0x4a, 0x0a, 0x02, 0x6e, 0x6f, 0x18, 0x07, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, - 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, - 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, - 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x48, 0x01, - 0x52, 0x02, 0x6e, 0x6f, 0x42, 0x06, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x42, 0x05, 0x0a, 0x03, - 0x65, 0x78, 0x74, 0x22, 0x6f, 0x0a, 0x19, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x75, 0x6c, 0x65, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x31, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x21, 0xb2, 0xe4, - 0x34, 0x1d, 0x0a, 0x04, 0x08, 0x05, 0x10, 0x02, 0x0a, 0x09, 0x08, 0x06, 0x10, 0x02, 0x1a, 0x01, - 0x32, 0x20, 0x01, 0x0a, 0x0a, 0x08, 0x07, 0x10, 0x02, 0x1a, 0x02, 0x36, 0x31, 0x20, 0x01, 0x52, - 0x02, 0x69, 0x64, 0x12, 0x1f, 0x0a, 0x03, 0x6e, 0x75, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, - 0x42, 0x0d, 0xb2, 0xe4, 0x34, 0x09, 0x0a, 0x07, 0x08, 0x01, 0x10, 0x01, 0x1a, 0x01, 0x30, 0x52, - 0x03, 0x6e, 0x75, 0x6d, 0x22, 0x1c, 0x0a, 0x1a, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x75, 0x6c, 0x65, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x85, 0x01, 0x0a, 0x0e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3a, 0x0a, 0x0c, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x5f, - 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, - 0x72, 0x75, 0x63, 0x74, 0x52, 0x0b, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x46, 0x69, 0x65, 0x6c, - 0x64, 0x12, 0x37, 0x0a, 0x0b, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0a, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x22, 0xa7, 0x01, 0x0a, 0x14, 0x44, - 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x12, 0x52, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x3e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, - 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, - 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, - 0x70, 0x62, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x12, 0x3b, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, - 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x4d, 0x61, 0x73, 0x6b, 0x32, 0xd5, 0x08, 0x0a, 0x0b, 0x45, 0x63, 0x68, 0x6f, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x12, 0xba, 0x02, 0x0a, 0x04, 0x45, 0x63, 0x68, 0x6f, 0x12, 0x3d, 0x2e, - 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, - 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x53, - 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x3d, 0x2e, 0x67, - 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, - 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x53, 0x69, - 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xb3, 0x01, 0xca, 0xf3, - 0x34, 0xae, 0x01, 0x22, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, - 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x5a, 0x1d, 0x12, 0x1b, 0x2f, 0x76, - 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x2f, 0x7b, - 0x69, 0x64, 0x7d, 0x2f, 0x7b, 0x6e, 0x75, 0x6d, 0x7d, 0x5a, 0x24, 0x12, 0x22, 0x2f, 0x76, 0x31, - 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x2f, 0x7b, 0x69, - 0x64, 0x7d, 0x2f, 0x7b, 0x6e, 0x75, 0x6d, 0x7d, 0x2f, 0x7b, 0x6c, 0x61, 0x6e, 0x67, 0x7d, 0x5a, - 0x31, 0x12, 0x2f, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, - 0x63, 0x68, 0x6f, 0x31, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x2f, 0x7b, 0x6c, 0x69, 0x6e, 0x65, 0x5f, - 0x6e, 0x75, 0x6d, 0x7d, 0x2f, 0x7b, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x6e, 0x6f, 0x74, - 0x65, 0x7d, 0x5a, 0x1d, 0x12, 0x1b, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, - 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x32, 0x2f, 0x7b, 0x6e, 0x6f, 0x2e, 0x6e, 0x6f, 0x74, 0x65, - 0x7d, 0x12, 0xa8, 0x01, 0x0a, 0x08, 0x45, 0x63, 0x68, 0x6f, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x3d, - 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, - 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, - 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x3d, 0x2e, - 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, - 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x53, - 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x1e, 0xca, 0xf3, - 0x34, 0x1a, 0x22, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, - 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x62, 0x6f, 0x64, 0x79, 0x3a, 0x01, 0x2a, 0x12, 0xa9, 0x01, 0x0a, - 0x0a, 0x45, 0x63, 0x68, 0x6f, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x3d, 0x2e, 0x67, 0x72, - 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, - 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x53, 0x69, 0x6d, - 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x3d, 0x2e, 0x67, 0x72, 0x70, - 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, - 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x53, 0x69, 0x6d, 0x70, - 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x1d, 0xca, 0xf3, 0x34, 0x19, 0x2a, - 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, - 0x6f, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0xbb, 0x01, 0x0a, 0x09, 0x45, 0x63, 0x68, - 0x6f, 0x50, 0x61, 0x74, 0x63, 0x68, 0x12, 0x44, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, - 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, - 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, - 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x1a, 0x44, 0x2e, 0x67, - 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, - 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x44, 0x79, - 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x22, 0x22, 0xca, 0xf3, 0x34, 0x1e, 0x32, 0x16, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, - 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x70, 0x61, 0x74, 0x63, 0x68, - 0x3a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x12, 0xd6, 0x01, 0x0a, 0x12, 0x45, 0x63, 0x68, 0x6f, 0x56, - 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x49, 0x2e, - 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, - 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x56, - 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x75, 0x6c, 0x65, 0x54, 0x65, 0x73, - 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x4a, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, - 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, - 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, - 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x75, 0x6c, 0x65, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x29, 0xca, 0xf3, 0x34, 0x25, 0x22, 0x20, 0x2f, 0x76, 0x31, 0x2f, - 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x3a, 0x76, 0x61, 0x6c, - 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x3a, 0x01, 0x2a, 0x1a, - 0x1b, 0xea, 0xf3, 0x34, 0x17, 0x08, 0xb6, 0x95, 0xff, 0xff, 0x07, 0x12, 0x04, 0x67, 0x72, 0x70, - 0x63, 0x1a, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x01, 0x42, 0x52, 0x5a, 0x50, - 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x69, 0x6e, 0x63, 0x68, - 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x65, 0x61, 0x73, 0x65, 0x2d, 0x67, 0x61, 0x74, - 0x65, 0x77, 0x61, 0x79, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x69, 0x6e, - 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x78, 0x61, - 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x3b, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, - 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} - -var ( - file_examples_internal_proto_examplepb_echo_service_proto_rawDescOnce sync.Once - file_examples_internal_proto_examplepb_echo_service_proto_rawDescData = file_examples_internal_proto_examplepb_echo_service_proto_rawDesc -) - -func file_examples_internal_proto_examplepb_echo_service_proto_rawDescGZIP() []byte { - file_examples_internal_proto_examplepb_echo_service_proto_rawDescOnce.Do(func() { - file_examples_internal_proto_examplepb_echo_service_proto_rawDescData = protoimpl.X.CompressGZIP(file_examples_internal_proto_examplepb_echo_service_proto_rawDescData) - }) - return file_examples_internal_proto_examplepb_echo_service_proto_rawDescData -} - -var file_examples_internal_proto_examplepb_echo_service_proto_msgTypes = make([]protoimpl.MessageInfo, 6) -var file_examples_internal_proto_examplepb_echo_service_proto_goTypes = []interface{}{ - (*Embedded)(nil), // 0: grpc.gateway.examples.internal.proto.examplepb.Embedded - (*SimpleMessage)(nil), // 1: grpc.gateway.examples.internal.proto.examplepb.SimpleMessage - (*ValidationRuleTestRequest)(nil), // 2: grpc.gateway.examples.internal.proto.examplepb.ValidationRuleTestRequest - (*ValidationRuleTestResponse)(nil), // 3: grpc.gateway.examples.internal.proto.examplepb.ValidationRuleTestResponse - (*DynamicMessage)(nil), // 4: grpc.gateway.examples.internal.proto.examplepb.DynamicMessage - (*DynamicMessageUpdate)(nil), // 5: grpc.gateway.examples.internal.proto.examplepb.DynamicMessageUpdate - (*_struct.Struct)(nil), // 6: google.protobuf.Struct - (*_struct.Value)(nil), // 7: google.protobuf.Value - (*field_mask.FieldMask)(nil), // 8: google.protobuf.FieldMask -} -var file_examples_internal_proto_examplepb_echo_service_proto_depIdxs = []int32{ - 0, // 0: grpc.gateway.examples.internal.proto.examplepb.SimpleMessage.status:type_name -> grpc.gateway.examples.internal.proto.examplepb.Embedded - 0, // 1: grpc.gateway.examples.internal.proto.examplepb.SimpleMessage.no:type_name -> grpc.gateway.examples.internal.proto.examplepb.Embedded - 6, // 2: grpc.gateway.examples.internal.proto.examplepb.DynamicMessage.struct_field:type_name -> google.protobuf.Struct - 7, // 3: grpc.gateway.examples.internal.proto.examplepb.DynamicMessage.value_field:type_name -> google.protobuf.Value - 4, // 4: grpc.gateway.examples.internal.proto.examplepb.DynamicMessageUpdate.body:type_name -> grpc.gateway.examples.internal.proto.examplepb.DynamicMessage - 8, // 5: grpc.gateway.examples.internal.proto.examplepb.DynamicMessageUpdate.update_mask:type_name -> google.protobuf.FieldMask - 1, // 6: grpc.gateway.examples.internal.proto.examplepb.EchoService.Echo:input_type -> grpc.gateway.examples.internal.proto.examplepb.SimpleMessage - 1, // 7: grpc.gateway.examples.internal.proto.examplepb.EchoService.EchoBody:input_type -> grpc.gateway.examples.internal.proto.examplepb.SimpleMessage - 1, // 8: grpc.gateway.examples.internal.proto.examplepb.EchoService.EchoDelete:input_type -> grpc.gateway.examples.internal.proto.examplepb.SimpleMessage - 5, // 9: grpc.gateway.examples.internal.proto.examplepb.EchoService.EchoPatch:input_type -> grpc.gateway.examples.internal.proto.examplepb.DynamicMessageUpdate - 2, // 10: grpc.gateway.examples.internal.proto.examplepb.EchoService.EchoValidationRule:input_type -> grpc.gateway.examples.internal.proto.examplepb.ValidationRuleTestRequest - 1, // 11: grpc.gateway.examples.internal.proto.examplepb.EchoService.Echo:output_type -> grpc.gateway.examples.internal.proto.examplepb.SimpleMessage - 1, // 12: grpc.gateway.examples.internal.proto.examplepb.EchoService.EchoBody:output_type -> grpc.gateway.examples.internal.proto.examplepb.SimpleMessage - 1, // 13: grpc.gateway.examples.internal.proto.examplepb.EchoService.EchoDelete:output_type -> grpc.gateway.examples.internal.proto.examplepb.SimpleMessage - 5, // 14: grpc.gateway.examples.internal.proto.examplepb.EchoService.EchoPatch:output_type -> grpc.gateway.examples.internal.proto.examplepb.DynamicMessageUpdate - 3, // 15: grpc.gateway.examples.internal.proto.examplepb.EchoService.EchoValidationRule:output_type -> grpc.gateway.examples.internal.proto.examplepb.ValidationRuleTestResponse - 11, // [11:16] is the sub-list for method output_type - 6, // [6:11] is the sub-list for method input_type - 6, // [6:6] is the sub-list for extension type_name - 6, // [6:6] is the sub-list for extension extendee - 0, // [0:6] is the sub-list for field type_name -} - -func init() { file_examples_internal_proto_examplepb_echo_service_proto_init() } -func file_examples_internal_proto_examplepb_echo_service_proto_init() { - if File_examples_internal_proto_examplepb_echo_service_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Embedded); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SimpleMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ValidationRuleTestRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ValidationRuleTestResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DynamicMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DynamicMessageUpdate); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[0].OneofWrappers = []interface{}{ - (*Embedded_Progress)(nil), - (*Embedded_Note)(nil), - } - file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[1].OneofWrappers = []interface{}{ - (*SimpleMessage_LineNum)(nil), - (*SimpleMessage_Lang)(nil), - (*SimpleMessage_En)(nil), - (*SimpleMessage_No)(nil), - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_examples_internal_proto_examplepb_echo_service_proto_rawDesc, - NumEnums: 0, - NumMessages: 6, - NumExtensions: 0, - NumServices: 1, - }, - GoTypes: file_examples_internal_proto_examplepb_echo_service_proto_goTypes, - DependencyIndexes: file_examples_internal_proto_examplepb_echo_service_proto_depIdxs, - MessageInfos: file_examples_internal_proto_examplepb_echo_service_proto_msgTypes, - }.Build() - File_examples_internal_proto_examplepb_echo_service_proto = out.File - file_examples_internal_proto_examplepb_echo_service_proto_rawDesc = nil - file_examples_internal_proto_examplepb_echo_service_proto_goTypes = nil - file_examples_internal_proto_examplepb_echo_service_proto_depIdxs = nil -} diff --git a/examples/internal/proto/examplepb/echo_service.pb.gw.go b/examples/internal/proto/examplepb/echo_service.pb.gw.go deleted file mode 100755 index 7b6896c..0000000 --- a/examples/internal/proto/examplepb/echo_service.pb.gw.go +++ /dev/null @@ -1,1522 +0,0 @@ -// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. -// source: examples/internal/proto/examplepb/echo_service.proto - -/* -Package examplepb is a reverse proxy. - -It translates gRPC into RESTful JSON APIs. -*/ -package examplepb - -import ( - "context" - "io" - "net/http" - "regexp" - "strings" - "sync" - "unicode/utf8" - - "github.com/binchencoder/ease-gateway/gateway/runtime" - vexpb "github.com/binchencoder/gateway-proto/data" - fpb "github.com/binchencoder/gateway-proto/frontend" - lgr "github.com/binchencoder/letsgo/grpc" - "github.com/binchencoder/skylb-api/balancer" - "github.com/binchencoder/skylb-api/client" - "github.com/binchencoder/skylb-api/client/option" - skypb "github.com/binchencoder/skylb-api/proto" - "github.com/grpc-ecosystem/grpc-gateway/v2/utilities" - "google.golang.org/grpc" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/grpclog" - "google.golang.org/grpc/naming" - "google.golang.org/grpc/status" - "google.golang.org/protobuf/proto" -) - -// Suppress "imported and not used" errors -var _ codes.Code -var _ io.Reader -var _ status.Status -var _ = runtime.String -var _ = utilities.NewDoubleArray - -// var _ = descriptor.ForMessage -var _ sync.RWMutex -var _ proto.Message -var _ context.Context -var _ grpc.ClientConn -var _ client.ServiceCli -var _ vexpb.ServiceId -var _ = http.MethodGet -var _ regexp.Regexp -var _ = balancer.ConsistentHashing -var _ option.BalancerCreator -var _ naming.Resolver -var _ strings.Reader -var _ = utf8.UTFMax - -// TODO (jiezmo): check if there is any rule before create this var. -var examples_internal_proto_examplepb_echo_service_error = lgr.ToGrpcError(codes.InvalidArgument, &fpb.Error{Code: fpb.ErrorCode_BADPARAM_ERROR, Params: []string{"Validation error"}}) - -// Validation methods start - -func Validate__grpc_gateway_examples_internal_proto_examplepb_ValidationRuleTestRequest(v *ValidationRuleTestRequest) error { - if v == nil { - return nil - } - // Validation for each Fields - - { - vv2 := v.Id - - // Validation Field: Id - - // TODO(jiezmo): fail the build - // Err - - if utf8.RuneCountInString(strings.TrimSpace(vv2)) <= 2 { - return examples_internal_proto_examplepb_echo_service_error - } - - if utf8.RuneCountInString(strings.TrimSpace(vv2)) >= 61 { - return examples_internal_proto_examplepb_echo_service_error - } - - } - - { - vv2 := v.Num - - // Validation Field: Num - - if vv2 <= 0 { - return examples_internal_proto_examplepb_echo_service_error - } - - } - - return nil -} - -// Validation methods done - -var ( - filter_EchoService_Echo_0 = &utilities.DoubleArray{Encoding: map[string]int{"id": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} -) - -func request_EchoService_Echo_0(ctx context.Context, marshaler runtime.Marshaler, client EchoServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq SimpleMessage - var metadata runtime.ServerMetadata - spec := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["id"] - if !ok { - runtime.RequestHandled(ctx, spec, "EchoService", "Echo", nil, &metadata, err) - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") - } - - protoReq.Id, err = runtime.String(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) - } - - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EchoService_Echo_0); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - // Only hook up for non-stream call for now. - - runtime.RequestParsed(ctx, spec, "EchoService", "Echo", &protoReq, &metadata) - ctx = runtime.PreLoadBalance(ctx, "ROUND_ROBIN", "", &protoReq) - msg, err := client.Echo(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - // if err != nil { - // grpclog.Errorf("client.%s returns error: %v", "Echo", err) - // } - runtime.RequestHandled(ctx, spec, "EchoService", "Echo", msg, &metadata, err) - return msg, metadata, err - -} - -func local_request_EchoService_Echo_0(ctx context.Context, marshaler runtime.Marshaler, server EchoServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq SimpleMessage - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["id"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") - } - - protoReq.Id, err = runtime.String(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) - } - - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EchoService_Echo_0); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.Echo(ctx, &protoReq) - return msg, metadata, err - -} - -var ( - filter_EchoService_Echo_1 = &utilities.DoubleArray{Encoding: map[string]int{"id": 0, "num": 1}, Base: []int{1, 1, 2, 0, 0}, Check: []int{0, 1, 1, 2, 3}} -) - -func request_EchoService_Echo_1(ctx context.Context, marshaler runtime.Marshaler, client EchoServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq SimpleMessage - var metadata runtime.ServerMetadata - spec := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["id"] - if !ok { - runtime.RequestHandled(ctx, spec, "EchoService", "Echo", nil, &metadata, err) - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") - } - - protoReq.Id, err = runtime.String(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) - } - - val, ok = pathParams["num"] - if !ok { - runtime.RequestHandled(ctx, spec, "EchoService", "Echo", nil, &metadata, err) - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "num") - } - - protoReq.Num, err = runtime.Int64(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "num", err) - } - - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EchoService_Echo_1); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - // Only hook up for non-stream call for now. - - runtime.RequestParsed(ctx, spec, "EchoService", "Echo", &protoReq, &metadata) - ctx = runtime.PreLoadBalance(ctx, "ROUND_ROBIN", "", &protoReq) - msg, err := client.Echo(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - // if err != nil { - // grpclog.Errorf("client.%s returns error: %v", "Echo", err) - // } - runtime.RequestHandled(ctx, spec, "EchoService", "Echo", msg, &metadata, err) - return msg, metadata, err - -} - -func local_request_EchoService_Echo_1(ctx context.Context, marshaler runtime.Marshaler, server EchoServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq SimpleMessage - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["id"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") - } - - protoReq.Id, err = runtime.String(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) - } - - val, ok = pathParams["num"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "num") - } - - protoReq.Num, err = runtime.Int64(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "num", err) - } - - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EchoService_Echo_1); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.Echo(ctx, &protoReq) - return msg, metadata, err - -} - -var ( - filter_EchoService_Echo_2 = &utilities.DoubleArray{Encoding: map[string]int{"id": 0, "num": 1, "lang": 2}, Base: []int{1, 1, 2, 3, 0, 0, 0}, Check: []int{0, 1, 1, 1, 2, 3, 4}} -) - -func request_EchoService_Echo_2(ctx context.Context, marshaler runtime.Marshaler, client EchoServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq SimpleMessage - var metadata runtime.ServerMetadata - spec := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["id"] - if !ok { - runtime.RequestHandled(ctx, spec, "EchoService", "Echo", nil, &metadata, err) - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") - } - - protoReq.Id, err = runtime.String(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) - } - - val, ok = pathParams["num"] - if !ok { - runtime.RequestHandled(ctx, spec, "EchoService", "Echo", nil, &metadata, err) - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "num") - } - - protoReq.Num, err = runtime.Int64(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "num", err) - } - - val, ok = pathParams["lang"] - if !ok { - runtime.RequestHandled(ctx, spec, "EchoService", "Echo", nil, &metadata, err) - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "lang") - } - - if protoReq.Code == nil { - protoReq.Code = &SimpleMessage_Lang{} - } else if _, ok := protoReq.Code.(*SimpleMessage_Lang); !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "expect type: *SimpleMessage_Lang, but: %t\n", protoReq.Code) - } - protoReq.Code.(*SimpleMessage_Lang).Lang, err = runtime.String(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "lang", err) - } - - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EchoService_Echo_2); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - // Only hook up for non-stream call for now. - - runtime.RequestParsed(ctx, spec, "EchoService", "Echo", &protoReq, &metadata) - ctx = runtime.PreLoadBalance(ctx, "ROUND_ROBIN", "", &protoReq) - msg, err := client.Echo(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - // if err != nil { - // grpclog.Errorf("client.%s returns error: %v", "Echo", err) - // } - runtime.RequestHandled(ctx, spec, "EchoService", "Echo", msg, &metadata, err) - return msg, metadata, err - -} - -func local_request_EchoService_Echo_2(ctx context.Context, marshaler runtime.Marshaler, server EchoServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq SimpleMessage - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["id"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") - } - - protoReq.Id, err = runtime.String(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) - } - - val, ok = pathParams["num"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "num") - } - - protoReq.Num, err = runtime.Int64(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "num", err) - } - - val, ok = pathParams["lang"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "lang") - } - - if protoReq.Code == nil { - protoReq.Code = &SimpleMessage_Lang{} - } else if _, ok := protoReq.Code.(*SimpleMessage_Lang); !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "expect type: *SimpleMessage_Lang, but: %t\n", protoReq.Code) - } - protoReq.Code.(*SimpleMessage_Lang).Lang, err = runtime.String(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "lang", err) - } - - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EchoService_Echo_2); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.Echo(ctx, &protoReq) - return msg, metadata, err - -} - -var ( - filter_EchoService_Echo_3 = &utilities.DoubleArray{Encoding: map[string]int{"id": 0, "line_num": 1, "status": 2, "note": 3}, Base: []int{1, 1, 2, 1, 3, 0, 0, 0}, Check: []int{0, 1, 1, 1, 4, 2, 3, 5}} -) - -func request_EchoService_Echo_3(ctx context.Context, marshaler runtime.Marshaler, client EchoServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq SimpleMessage - var metadata runtime.ServerMetadata - spec := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["id"] - if !ok { - runtime.RequestHandled(ctx, spec, "EchoService", "Echo", nil, &metadata, err) - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") - } - - protoReq.Id, err = runtime.String(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) - } - - val, ok = pathParams["line_num"] - if !ok { - runtime.RequestHandled(ctx, spec, "EchoService", "Echo", nil, &metadata, err) - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "line_num") - } - - if protoReq.Code == nil { - protoReq.Code = &SimpleMessage_LineNum{} - } else if _, ok := protoReq.Code.(*SimpleMessage_LineNum); !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "expect type: *SimpleMessage_LineNum, but: %t\n", protoReq.Code) - } - protoReq.Code.(*SimpleMessage_LineNum).LineNum, err = runtime.Int64(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "line_num", err) - } - - val, ok = pathParams["status.note"] - if !ok { - runtime.RequestHandled(ctx, spec, "EchoService", "Echo", nil, &metadata, err) - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "status.note") - } - - err = runtime.PopulateFieldFromPath(&protoReq, "status.note", val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "status.note", err) - } - - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EchoService_Echo_3); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - // Only hook up for non-stream call for now. - - runtime.RequestParsed(ctx, spec, "EchoService", "Echo", &protoReq, &metadata) - ctx = runtime.PreLoadBalance(ctx, "ROUND_ROBIN", "", &protoReq) - msg, err := client.Echo(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - // if err != nil { - // grpclog.Errorf("client.%s returns error: %v", "Echo", err) - // } - runtime.RequestHandled(ctx, spec, "EchoService", "Echo", msg, &metadata, err) - return msg, metadata, err - -} - -func local_request_EchoService_Echo_3(ctx context.Context, marshaler runtime.Marshaler, server EchoServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq SimpleMessage - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["id"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") - } - - protoReq.Id, err = runtime.String(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) - } - - val, ok = pathParams["line_num"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "line_num") - } - - if protoReq.Code == nil { - protoReq.Code = &SimpleMessage_LineNum{} - } else if _, ok := protoReq.Code.(*SimpleMessage_LineNum); !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "expect type: *SimpleMessage_LineNum, but: %t\n", protoReq.Code) - } - protoReq.Code.(*SimpleMessage_LineNum).LineNum, err = runtime.Int64(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "line_num", err) - } - - val, ok = pathParams["status.note"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "status.note") - } - - err = runtime.PopulateFieldFromPath(&protoReq, "status.note", val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "status.note", err) - } - - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EchoService_Echo_3); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.Echo(ctx, &protoReq) - return msg, metadata, err - -} - -var ( - filter_EchoService_Echo_4 = &utilities.DoubleArray{Encoding: map[string]int{"no": 0, "note": 1}, Base: []int{1, 1, 1, 0}, Check: []int{0, 1, 2, 3}} -) - -func request_EchoService_Echo_4(ctx context.Context, marshaler runtime.Marshaler, client EchoServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq SimpleMessage - var metadata runtime.ServerMetadata - spec := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["no.note"] - if !ok { - runtime.RequestHandled(ctx, spec, "EchoService", "Echo", nil, &metadata, err) - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "no.note") - } - - err = runtime.PopulateFieldFromPath(&protoReq, "no.note", val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "no.note", err) - } - - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EchoService_Echo_4); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - // Only hook up for non-stream call for now. - - runtime.RequestParsed(ctx, spec, "EchoService", "Echo", &protoReq, &metadata) - ctx = runtime.PreLoadBalance(ctx, "ROUND_ROBIN", "", &protoReq) - msg, err := client.Echo(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - // if err != nil { - // grpclog.Errorf("client.%s returns error: %v", "Echo", err) - // } - runtime.RequestHandled(ctx, spec, "EchoService", "Echo", msg, &metadata, err) - return msg, metadata, err - -} - -func local_request_EchoService_Echo_4(ctx context.Context, marshaler runtime.Marshaler, server EchoServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq SimpleMessage - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["no.note"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "no.note") - } - - err = runtime.PopulateFieldFromPath(&protoReq, "no.note", val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "no.note", err) - } - - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EchoService_Echo_4); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.Echo(ctx, &protoReq) - return msg, metadata, err - -} - -func request_EchoService_EchoBody_0(ctx context.Context, marshaler runtime.Marshaler, client EchoServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq SimpleMessage - var metadata runtime.ServerMetadata - spec := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec - - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { - runtime.RequestHandled(ctx, spec, "EchoService", "EchoBody", nil, &metadata, err) - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - // Only hook up for non-stream call for now. - - runtime.RequestParsed(ctx, spec, "EchoService", "EchoBody", &protoReq, &metadata) - ctx = runtime.PreLoadBalance(ctx, "ROUND_ROBIN", "", &protoReq) - msg, err := client.EchoBody(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - // if err != nil { - // grpclog.Errorf("client.%s returns error: %v", "EchoBody", err) - // } - runtime.RequestHandled(ctx, spec, "EchoService", "EchoBody", msg, &metadata, err) - return msg, metadata, err - -} - -func local_request_EchoService_EchoBody_0(ctx context.Context, marshaler runtime.Marshaler, server EchoServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq SimpleMessage - var metadata runtime.ServerMetadata - - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.EchoBody(ctx, &protoReq) - return msg, metadata, err - -} - -var ( - filter_EchoService_EchoDelete_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} -) - -func request_EchoService_EchoDelete_0(ctx context.Context, marshaler runtime.Marshaler, client EchoServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq SimpleMessage - var metadata runtime.ServerMetadata - spec := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec - - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EchoService_EchoDelete_0); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - // Only hook up for non-stream call for now. - - runtime.RequestParsed(ctx, spec, "EchoService", "EchoDelete", &protoReq, &metadata) - ctx = runtime.PreLoadBalance(ctx, "ROUND_ROBIN", "", &protoReq) - msg, err := client.EchoDelete(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - // if err != nil { - // grpclog.Errorf("client.%s returns error: %v", "EchoDelete", err) - // } - runtime.RequestHandled(ctx, spec, "EchoService", "EchoDelete", msg, &metadata, err) - return msg, metadata, err - -} - -func local_request_EchoService_EchoDelete_0(ctx context.Context, marshaler runtime.Marshaler, server EchoServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq SimpleMessage - var metadata runtime.ServerMetadata - - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EchoService_EchoDelete_0); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.EchoDelete(ctx, &protoReq) - return msg, metadata, err - -} - -var ( - filter_EchoService_EchoPatch_0 = &utilities.DoubleArray{Encoding: map[string]int{"body": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} -) - -func request_EchoService_EchoPatch_0(ctx context.Context, marshaler runtime.Marshaler, client EchoServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq DynamicMessageUpdate - var metadata runtime.ServerMetadata - spec := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec - - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.Body); err != nil && err != io.EOF { - runtime.RequestHandled(ctx, spec, "EchoService", "EchoPatch", nil, &metadata, err) - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if protoReq.UpdateMask == nil || len(protoReq.UpdateMask.GetPaths()) == 0 { - if fieldMask, err := runtime.FieldMaskFromRequestBody(newReader(), protoReq.Body); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } else { - protoReq.UpdateMask = fieldMask - } - } - - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EchoService_EchoPatch_0); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - // Only hook up for non-stream call for now. - - runtime.RequestParsed(ctx, spec, "EchoService", "EchoPatch", &protoReq, &metadata) - ctx = runtime.PreLoadBalance(ctx, "ROUND_ROBIN", "", &protoReq) - msg, err := client.EchoPatch(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - // if err != nil { - // grpclog.Errorf("client.%s returns error: %v", "EchoPatch", err) - // } - runtime.RequestHandled(ctx, spec, "EchoService", "EchoPatch", msg, &metadata, err) - return msg, metadata, err - -} - -func local_request_EchoService_EchoPatch_0(ctx context.Context, marshaler runtime.Marshaler, server EchoServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq DynamicMessageUpdate - var metadata runtime.ServerMetadata - - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.Body); err != nil && err != io.EOF { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if protoReq.UpdateMask == nil || len(protoReq.UpdateMask.GetPaths()) == 0 { - if fieldMask, err := runtime.FieldMaskFromRequestBody(newReader(), protoReq.Body); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } else { - protoReq.UpdateMask = fieldMask - } - } - - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EchoService_EchoPatch_0); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.EchoPatch(ctx, &protoReq) - return msg, metadata, err - -} - -func request_EchoService_EchoValidationRule_0(ctx context.Context, marshaler runtime.Marshaler, client EchoServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq ValidationRuleTestRequest - var metadata runtime.ServerMetadata - spec := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec - - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { - runtime.RequestHandled(ctx, spec, "EchoService", "EchoValidationRule", nil, &metadata, err) - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - // Only hook up for non-stream call for now. - - // Validate - // ValidationRuleTestRequest - if err := Validate__grpc_gateway_examples_internal_proto_examplepb_ValidationRuleTestRequest(&protoReq); err != nil { - runtime.RequestHandled(ctx, spec, "EchoService", "EchoValidationRule", nil, &metadata, err) - return nil, metadata, err - } - - runtime.RequestParsed(ctx, spec, "EchoService", "EchoValidationRule", &protoReq, &metadata) - ctx = runtime.PreLoadBalance(ctx, "ROUND_ROBIN", "", &protoReq) - msg, err := client.EchoValidationRule(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - // if err != nil { - // grpclog.Errorf("client.%s returns error: %v", "EchoValidationRule", err) - // } - runtime.RequestHandled(ctx, spec, "EchoService", "EchoValidationRule", msg, &metadata, err) - return msg, metadata, err - -} - -func local_request_EchoService_EchoValidationRule_0(ctx context.Context, marshaler runtime.Marshaler, server EchoServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq ValidationRuleTestRequest - var metadata runtime.ServerMetadata - - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.EchoValidationRule(ctx, &protoReq) - return msg, metadata, err - -} - -// RegisterEchoServiceHandlerServer registers the http handlers for service EchoService to "mux". -// UnaryRPC :call EchoServiceServer directly. -// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. -// Note that using this registration option will cause many gRPC library features (such as grpc.SendHeader, etc) to stop working. Consider using RegisterEchoServiceHandlerFromEndpoint instead. -func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server EchoServiceServer) error { - - mux.Handle("POST", pattern_EchoService_Echo_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo") - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_EchoService_Echo_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_EchoService_Echo_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_EchoService_Echo_1, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo") - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_EchoService_Echo_1(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_EchoService_Echo_1(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_EchoService_Echo_2, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo") - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_EchoService_Echo_2(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_EchoService_Echo_2(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_EchoService_Echo_3, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo") - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_EchoService_Echo_3(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_EchoService_Echo_3(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_EchoService_Echo_4, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo") - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_EchoService_Echo_4(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_EchoService_Echo_4(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("POST", pattern_EchoService_EchoBody_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoBody") - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_EchoService_EchoBody_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_EchoService_EchoBody_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("DELETE", pattern_EchoService_EchoDelete_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoDelete") - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_EchoService_EchoDelete_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_EchoService_EchoDelete_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("PATCH", pattern_EchoService_EchoPatch_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoPatch") - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_EchoService_EchoPatch_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_EchoService_EchoPatch_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("POST", pattern_EchoService_EchoValidationRule_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoValidationRule") - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_EchoService_EchoValidationRule_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_EchoService_EchoValidationRule_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - return nil -} - -// Register itself to runtime. -func init() { - var s *runtime.Service - var spec *skypb.ServiceSpec - - _ = s - _ = spec - - spec = internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec - s = &runtime.Service{ - Spec: *spec, - Name: "EchoService", - Register: RegisterEchoServiceHandlerFromEndpoint, - Enable: EnableEchoService_Service, - Disable: DisableEchoService_Service, - } - - runtime.AddService(s, Enable_CUSTOM_EASE_GATEWAY_TEST__default__grpc_ServiceGroup, Disable_CUSTOM_EASE_GATEWAY_TEST__default__grpc_ServiceGroup) - -} - -// RegisterEchoServiceHandlerFromEndpoint is same as RegisterEchoServiceHandler but -// automatically dials to "endpoint" and closes the connection when "ctx" gets done. -func RegisterEchoServiceHandlerFromEndpoint(mux *runtime.ServeMux) (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 RegisterEchoServiceHandler(ctx, mux, conn) - return RegisterEchoServiceHandler(nil, mux, nil) -} - -// RegisterEchoServiceHandler registers the http handlers for service EchoService to "mux". -// The handlers forward requests to the grpc endpoint over "conn". -func RegisterEchoServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { - return RegisterEchoServiceHandlerClient(ctx, mux, NewEchoServiceClient(conn)) -} - -// RegisterEchoServiceHandlerClient registers the http handlers for service EchoService -// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "EchoServiceClient". -// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "EchoServiceClient" -// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in -// "EchoServiceClient" to call the correct interceptors. -func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client EchoServiceClient) error { - spec := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec - - runtime.AddMethod(spec, "EchoService", "Echo", "/v1/example/echo/{id}", "POST", true, false, false, "UNSPECIFIED", "EASE_GATEWAY", "EASE_AUTH_TOKEN", "") - mux.Handle("POST", pattern_EchoService_Echo_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - // TODO(mojz): review all locking/unlocking logic. - // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() - // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() - client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - if client == nil { - err := status.Error(codes.Internal, "service disabled") - runtime.HTTPError(inctx, mux, outboundMarshaler, w, req, err) - return - } - - ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) - if err != nil { - grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo") - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_EchoService_Echo_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_EchoService_Echo_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - runtime.AddMethod(spec, "EchoService", "Echo", "/v1/example/echo/{id}/{num}", "GET", true, false, false, "UNSPECIFIED", "EASE_GATEWAY", "EASE_AUTH_TOKEN", "") - mux.Handle("GET", pattern_EchoService_Echo_1, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - // TODO(mojz): review all locking/unlocking logic. - // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() - // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() - client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - if client == nil { - err := status.Error(codes.Internal, "service disabled") - runtime.HTTPError(inctx, mux, outboundMarshaler, w, req, err) - return - } - - ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) - if err != nil { - grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo") - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_EchoService_Echo_1(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_EchoService_Echo_1(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - runtime.AddMethod(spec, "EchoService", "Echo", "/v1/example/echo/{id}/{num}/{lang}", "GET", true, false, false, "UNSPECIFIED", "EASE_GATEWAY", "EASE_AUTH_TOKEN", "") - mux.Handle("GET", pattern_EchoService_Echo_2, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - // TODO(mojz): review all locking/unlocking logic. - // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() - // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() - client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - if client == nil { - err := status.Error(codes.Internal, "service disabled") - runtime.HTTPError(inctx, mux, outboundMarshaler, w, req, err) - return - } - - ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) - if err != nil { - grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo") - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_EchoService_Echo_2(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_EchoService_Echo_2(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - runtime.AddMethod(spec, "EchoService", "Echo", "/v1/example/echo1/{id}/{line_num}/{status.note}", "GET", true, false, false, "UNSPECIFIED", "EASE_GATEWAY", "EASE_AUTH_TOKEN", "") - mux.Handle("GET", pattern_EchoService_Echo_3, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - // TODO(mojz): review all locking/unlocking logic. - // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() - // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() - client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - if client == nil { - err := status.Error(codes.Internal, "service disabled") - runtime.HTTPError(inctx, mux, outboundMarshaler, w, req, err) - return - } - - ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) - if err != nil { - grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo") - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_EchoService_Echo_3(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_EchoService_Echo_3(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - runtime.AddMethod(spec, "EchoService", "Echo", "/v1/example/echo2/{no.note}", "GET", true, false, false, "UNSPECIFIED", "EASE_GATEWAY", "EASE_AUTH_TOKEN", "") - mux.Handle("GET", pattern_EchoService_Echo_4, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - // TODO(mojz): review all locking/unlocking logic. - // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() - // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() - client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - if client == nil { - err := status.Error(codes.Internal, "service disabled") - runtime.HTTPError(inctx, mux, outboundMarshaler, w, req, err) - return - } - - ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) - if err != nil { - grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo") - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_EchoService_Echo_4(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_EchoService_Echo_4(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - runtime.AddMethod(spec, "EchoService", "EchoBody", "/v1/example/echo_body", "POST", true, false, false, "UNSPECIFIED", "EASE_GATEWAY", "EASE_AUTH_TOKEN", "") - mux.Handle("POST", pattern_EchoService_EchoBody_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - // TODO(mojz): review all locking/unlocking logic. - // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() - // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() - client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - if client == nil { - err := status.Error(codes.Internal, "service disabled") - runtime.HTTPError(inctx, mux, outboundMarshaler, w, req, err) - return - } - - ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "EchoBody", w, req) - if err != nil { - grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoBody") - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_EchoService_EchoBody_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_EchoService_EchoBody_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - runtime.AddMethod(spec, "EchoService", "EchoDelete", "/v1/example/echo_delete", "DELETE", true, false, false, "UNSPECIFIED", "EASE_GATEWAY", "EASE_AUTH_TOKEN", "") - mux.Handle("DELETE", pattern_EchoService_EchoDelete_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - // TODO(mojz): review all locking/unlocking logic. - // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() - // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() - client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - if client == nil { - err := status.Error(codes.Internal, "service disabled") - runtime.HTTPError(inctx, mux, outboundMarshaler, w, req, err) - return - } - - ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "EchoDelete", w, req) - if err != nil { - grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoDelete") - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_EchoService_EchoDelete_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_EchoService_EchoDelete_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - runtime.AddMethod(spec, "EchoService", "EchoPatch", "/v1/example/echo_patch", "PATCH", true, false, false, "UNSPECIFIED", "EASE_GATEWAY", "EASE_AUTH_TOKEN", "") - mux.Handle("PATCH", pattern_EchoService_EchoPatch_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - // TODO(mojz): review all locking/unlocking logic. - // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() - // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() - client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - if client == nil { - err := status.Error(codes.Internal, "service disabled") - runtime.HTTPError(inctx, mux, outboundMarshaler, w, req, err) - return - } - - ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "EchoPatch", w, req) - if err != nil { - grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoPatch") - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_EchoService_EchoPatch_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_EchoService_EchoPatch_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - runtime.AddMethod(spec, "EchoService", "EchoValidationRule", "/v1/example/echo:validationRules", "POST", true, false, false, "UNSPECIFIED", "EASE_GATEWAY", "EASE_AUTH_TOKEN", "") - mux.Handle("POST", pattern_EchoService_EchoValidationRule_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - // TODO(mojz): review all locking/unlocking logic. - // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() - // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() - client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - if client == nil { - err := status.Error(codes.Internal, "service disabled") - runtime.HTTPError(inctx, mux, outboundMarshaler, w, req, err) - return - } - - ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "EchoValidationRule", w, req) - if err != nil { - grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoValidationRule") - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_EchoService_EchoValidationRule_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_EchoService_EchoValidationRule_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - return nil -} - -func Disable_CUSTOM_EASE_GATEWAY_TEST__default__grpc_ServiceGroup() { - // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.Lock() - // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.Unlock() - if internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_skycli != nil { - spec := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec - sg := runtime.GetServiceGroup(spec) - for _, svc := range sg.Services { - svc.Disable() - } - - internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client = nil - internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_skycli.Shutdown() - internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_skycli = nil - } -} - -func Enable_CUSTOM_EASE_GATEWAY_TEST__default__grpc_ServiceGroup() { - // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.Lock() - // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.Unlock() - - internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_skycli = client.NewServiceCli(runtime.CallerServiceId) - - // Resolve service - spec := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec - - internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_skycli.Resolve(spec) - - internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_skycli.EnableResolveFullEps() - internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_skycli.Start(func(spec *skypb.ServiceSpec, conn *grpc.ClientConn) { - sg := runtime.GetServiceGroup(spec) - for _, svc := range sg.Services { - svc.Enable(spec, conn) - } - }) -} - -func EnableEchoService_Service(spec *skypb.ServiceSpec, conn *grpc.ClientConn) { - internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client = NewEchoServiceClient(conn) -} - -func DisableEchoService_Service() { - internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client = nil -} - -var ( - pattern_EchoService_Echo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"v1", "example", "echo", "id"}, "")) - - pattern_EchoService_Echo_1 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 1, 0, 4, 1, 5, 4}, []string{"v1", "example", "echo", "id", "num"}, "")) - - pattern_EchoService_Echo_2 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5}, []string{"v1", "example", "echo", "id", "num", "lang"}, "")) - - pattern_EchoService_Echo_3 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5}, []string{"v1", "example", "echo1", "id", "line_num", "status.note"}, "")) - - pattern_EchoService_Echo_4 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"v1", "example", "echo2", "no.note"}, "")) - - pattern_EchoService_EchoBody_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "example", "echo_body"}, "")) - - pattern_EchoService_EchoDelete_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "example", "echo_delete"}, "")) - - pattern_EchoService_EchoPatch_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "example", "echo_patch"}, "")) - - pattern_EchoService_EchoValidationRule_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "example", "echo"}, "validationRules")) -) - -var ( - forward_EchoService_Echo_0 = runtime.ForwardResponseMessage - - forward_EchoService_Echo_1 = runtime.ForwardResponseMessage - - forward_EchoService_Echo_2 = runtime.ForwardResponseMessage - - forward_EchoService_Echo_3 = runtime.ForwardResponseMessage - - forward_EchoService_Echo_4 = runtime.ForwardResponseMessage - - forward_EchoService_EchoBody_0 = runtime.ForwardResponseMessage - - forward_EchoService_EchoDelete_0 = runtime.ForwardResponseMessage - - forward_EchoService_EchoPatch_0 = runtime.ForwardResponseMessage - - forward_EchoService_EchoValidationRule_0 = runtime.ForwardResponseMessage -) - -var ( - internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec = client.NewServiceSpec("default", vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, "grpc") - internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client EchoServiceClient - - internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_skycli client.ServiceCli - - internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock = sync.RWMutex{} -) diff --git a/examples/internal/proto/examplepb/echo_service_grpc.pb.go b/examples/internal/proto/examplepb/echo_service_grpc.pb.go deleted file mode 100755 index ef29065..0000000 --- a/examples/internal/proto/examplepb/echo_service_grpc.pb.go +++ /dev/null @@ -1,230 +0,0 @@ -// Code generated by protoc-gen-go-grpc. DO NOT EDIT. - -package examplepb - -import ( - context "context" - grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" -) - -// 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.SupportPackageIsVersion6 - -// EchoServiceClient is the client API for EchoService service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. -type EchoServiceClient interface { - Echo(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) - EchoBody(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) - EchoDelete(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) - EchoPatch(ctx context.Context, in *DynamicMessageUpdate, opts ...grpc.CallOption) (*DynamicMessageUpdate, error) - EchoValidationRule(ctx context.Context, in *ValidationRuleTestRequest, opts ...grpc.CallOption) (*ValidationRuleTestResponse, error) -} - -type echoServiceClient struct { - cc grpc.ClientConnInterface -} - -func NewEchoServiceClient(cc grpc.ClientConnInterface) EchoServiceClient { - return &echoServiceClient{cc} -} - -func (c *echoServiceClient) Echo(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) { - out := new(SimpleMessage) - err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *echoServiceClient) EchoBody(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) { - out := new(SimpleMessage) - err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoBody", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *echoServiceClient) EchoDelete(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) { - out := new(SimpleMessage) - err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoDelete", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *echoServiceClient) EchoPatch(ctx context.Context, in *DynamicMessageUpdate, opts ...grpc.CallOption) (*DynamicMessageUpdate, error) { - out := new(DynamicMessageUpdate) - err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoPatch", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *echoServiceClient) EchoValidationRule(ctx context.Context, in *ValidationRuleTestRequest, opts ...grpc.CallOption) (*ValidationRuleTestResponse, error) { - out := new(ValidationRuleTestResponse) - err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoValidationRule", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -// EchoServiceServer is the server API for EchoService service. -type EchoServiceServer interface { - Echo(context.Context, *SimpleMessage) (*SimpleMessage, error) - EchoBody(context.Context, *SimpleMessage) (*SimpleMessage, error) - EchoDelete(context.Context, *SimpleMessage) (*SimpleMessage, error) - EchoPatch(context.Context, *DynamicMessageUpdate) (*DynamicMessageUpdate, error) - EchoValidationRule(context.Context, *ValidationRuleTestRequest) (*ValidationRuleTestResponse, error) -} - -// UnimplementedEchoServiceServer can be embedded to have forward compatible implementations. -type UnimplementedEchoServiceServer struct { -} - -func (*UnimplementedEchoServiceServer) Echo(context.Context, *SimpleMessage) (*SimpleMessage, error) { - return nil, status.Errorf(codes.Unimplemented, "method Echo not implemented") -} -func (*UnimplementedEchoServiceServer) EchoBody(context.Context, *SimpleMessage) (*SimpleMessage, error) { - return nil, status.Errorf(codes.Unimplemented, "method EchoBody not implemented") -} -func (*UnimplementedEchoServiceServer) EchoDelete(context.Context, *SimpleMessage) (*SimpleMessage, error) { - return nil, status.Errorf(codes.Unimplemented, "method EchoDelete not implemented") -} -func (*UnimplementedEchoServiceServer) EchoPatch(context.Context, *DynamicMessageUpdate) (*DynamicMessageUpdate, error) { - return nil, status.Errorf(codes.Unimplemented, "method EchoPatch not implemented") -} -func (*UnimplementedEchoServiceServer) EchoValidationRule(context.Context, *ValidationRuleTestRequest) (*ValidationRuleTestResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method EchoValidationRule not implemented") -} - -func RegisterEchoServiceServer(s *grpc.Server, srv EchoServiceServer) { - s.RegisterService(&_EchoService_serviceDesc, srv) -} - -func _EchoService_Echo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(SimpleMessage) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(EchoServiceServer).Echo(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(EchoServiceServer).Echo(ctx, req.(*SimpleMessage)) - } - return interceptor(ctx, in, info, handler) -} - -func _EchoService_EchoBody_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(SimpleMessage) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(EchoServiceServer).EchoBody(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoBody", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(EchoServiceServer).EchoBody(ctx, req.(*SimpleMessage)) - } - return interceptor(ctx, in, info, handler) -} - -func _EchoService_EchoDelete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(SimpleMessage) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(EchoServiceServer).EchoDelete(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoDelete", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(EchoServiceServer).EchoDelete(ctx, req.(*SimpleMessage)) - } - return interceptor(ctx, in, info, handler) -} - -func _EchoService_EchoPatch_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(DynamicMessageUpdate) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(EchoServiceServer).EchoPatch(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoPatch", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(EchoServiceServer).EchoPatch(ctx, req.(*DynamicMessageUpdate)) - } - return interceptor(ctx, in, info, handler) -} - -func _EchoService_EchoValidationRule_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(ValidationRuleTestRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(EchoServiceServer).EchoValidationRule(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoValidationRule", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(EchoServiceServer).EchoValidationRule(ctx, req.(*ValidationRuleTestRequest)) - } - return interceptor(ctx, in, info, handler) -} - -var _EchoService_serviceDesc = grpc.ServiceDesc{ - ServiceName: "grpc.gateway.examples.internal.proto.examplepb.EchoService", - HandlerType: (*EchoServiceServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "Echo", - Handler: _EchoService_Echo_Handler, - }, - { - MethodName: "EchoBody", - Handler: _EchoService_EchoBody_Handler, - }, - { - MethodName: "EchoDelete", - Handler: _EchoService_EchoDelete_Handler, - }, - { - MethodName: "EchoPatch", - Handler: _EchoService_EchoPatch_Handler, - }, - { - MethodName: "EchoValidationRule", - Handler: _EchoService_EchoValidationRule_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "examples/internal/proto/examplepb/echo_service.proto", -} diff --git a/examples/internal/proto/examplepb/standalone_echo_service.yaml b/examples/internal/proto/examplepb/standalone_echo_service.yaml index 3d45a4c..fbd9192 100644 --- a/examples/internal/proto/examplepb/standalone_echo_service.yaml +++ b/examples/internal/proto/examplepb/standalone_echo_service.yaml @@ -1,4 +1,4 @@ -type: goole.api.Service +type: google.api.Service config_version: 3 http: diff --git a/examples/internal/proto/examplepb/unannotated_echo_service.pb.go b/examples/internal/proto/examplepb/unannotated_echo_service.pb.go deleted file mode 100644 index 4b6663b..0000000 --- a/examples/internal/proto/examplepb/unannotated_echo_service.pb.go +++ /dev/null @@ -1,616 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.23.0 -// protoc v3.12.3 -// source: examples/internal/proto/examplepb/unannotated_echo_service.proto - -// Unannotated Echo Service -// Similar to echo_service.proto but without annotations. See -// unannotated_echo_service.yaml for the equivalent of the annotations in -// gRPC API configuration format. -// -// Echo Service API consists of a single service which returns -// a message. - -package examplepb - -import ( - context "context" - proto "github.com/golang/protobuf/proto" - duration "github.com/golang/protobuf/ptypes/duration" - grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - reflect "reflect" - sync "sync" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - -// Embedded represents a message embedded in SimpleMessage. -type UnannotatedEmbedded struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Types that are assignable to Mark: - // *UnannotatedEmbedded_Progress - // *UnannotatedEmbedded_Note - Mark isUnannotatedEmbedded_Mark `protobuf_oneof:"mark"` -} - -func (x *UnannotatedEmbedded) Reset() { - *x = UnannotatedEmbedded{} - if protoimpl.UnsafeEnabled { - mi := &file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *UnannotatedEmbedded) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*UnannotatedEmbedded) ProtoMessage() {} - -func (x *UnannotatedEmbedded) ProtoReflect() protoreflect.Message { - mi := &file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use UnannotatedEmbedded.ProtoReflect.Descriptor instead. -func (*UnannotatedEmbedded) Descriptor() ([]byte, []int) { - return file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDescGZIP(), []int{0} -} - -func (m *UnannotatedEmbedded) GetMark() isUnannotatedEmbedded_Mark { - if m != nil { - return m.Mark - } - return nil -} - -func (x *UnannotatedEmbedded) GetProgress() int64 { - if x, ok := x.GetMark().(*UnannotatedEmbedded_Progress); ok { - return x.Progress - } - return 0 -} - -func (x *UnannotatedEmbedded) GetNote() string { - if x, ok := x.GetMark().(*UnannotatedEmbedded_Note); ok { - return x.Note - } - return "" -} - -type isUnannotatedEmbedded_Mark interface { - isUnannotatedEmbedded_Mark() -} - -type UnannotatedEmbedded_Progress struct { - Progress int64 `protobuf:"varint,1,opt,name=progress,proto3,oneof"` -} - -type UnannotatedEmbedded_Note struct { - Note string `protobuf:"bytes,2,opt,name=note,proto3,oneof"` -} - -func (*UnannotatedEmbedded_Progress) isUnannotatedEmbedded_Mark() {} - -func (*UnannotatedEmbedded_Note) isUnannotatedEmbedded_Mark() {} - -// UnannotatedSimpleMessage represents a simple message sent to the unannotated Echo service. -type UnannotatedSimpleMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Id represents the message identifier. - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Num int64 `protobuf:"varint,2,opt,name=num,proto3" json:"num,omitempty"` - Duration *duration.Duration `protobuf:"bytes,3,opt,name=duration,proto3" json:"duration,omitempty"` - // Types that are assignable to Code: - // *UnannotatedSimpleMessage_LineNum - // *UnannotatedSimpleMessage_Lang - Code isUnannotatedSimpleMessage_Code `protobuf_oneof:"code"` - Status *UnannotatedEmbedded `protobuf:"bytes,6,opt,name=status,proto3" json:"status,omitempty"` - // Types that are assignable to Ext: - // *UnannotatedSimpleMessage_En - // *UnannotatedSimpleMessage_No - Ext isUnannotatedSimpleMessage_Ext `protobuf_oneof:"ext"` -} - -func (x *UnannotatedSimpleMessage) Reset() { - *x = UnannotatedSimpleMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *UnannotatedSimpleMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*UnannotatedSimpleMessage) ProtoMessage() {} - -func (x *UnannotatedSimpleMessage) ProtoReflect() protoreflect.Message { - mi := &file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use UnannotatedSimpleMessage.ProtoReflect.Descriptor instead. -func (*UnannotatedSimpleMessage) Descriptor() ([]byte, []int) { - return file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDescGZIP(), []int{1} -} - -func (x *UnannotatedSimpleMessage) GetId() string { - if x != nil { - return x.Id - } - return "" -} - -func (x *UnannotatedSimpleMessage) GetNum() int64 { - if x != nil { - return x.Num - } - return 0 -} - -func (x *UnannotatedSimpleMessage) GetDuration() *duration.Duration { - if x != nil { - return x.Duration - } - return nil -} - -func (m *UnannotatedSimpleMessage) GetCode() isUnannotatedSimpleMessage_Code { - if m != nil { - return m.Code - } - return nil -} - -func (x *UnannotatedSimpleMessage) GetLineNum() int64 { - if x, ok := x.GetCode().(*UnannotatedSimpleMessage_LineNum); ok { - return x.LineNum - } - return 0 -} - -func (x *UnannotatedSimpleMessage) GetLang() string { - if x, ok := x.GetCode().(*UnannotatedSimpleMessage_Lang); ok { - return x.Lang - } - return "" -} - -func (x *UnannotatedSimpleMessage) GetStatus() *UnannotatedEmbedded { - if x != nil { - return x.Status - } - return nil -} - -func (m *UnannotatedSimpleMessage) GetExt() isUnannotatedSimpleMessage_Ext { - if m != nil { - return m.Ext - } - return nil -} - -func (x *UnannotatedSimpleMessage) GetEn() int64 { - if x, ok := x.GetExt().(*UnannotatedSimpleMessage_En); ok { - return x.En - } - return 0 -} - -func (x *UnannotatedSimpleMessage) GetNo() *UnannotatedEmbedded { - if x, ok := x.GetExt().(*UnannotatedSimpleMessage_No); ok { - return x.No - } - return nil -} - -type isUnannotatedSimpleMessage_Code interface { - isUnannotatedSimpleMessage_Code() -} - -type UnannotatedSimpleMessage_LineNum struct { - LineNum int64 `protobuf:"varint,4,opt,name=line_num,json=lineNum,proto3,oneof"` -} - -type UnannotatedSimpleMessage_Lang struct { - Lang string `protobuf:"bytes,5,opt,name=lang,proto3,oneof"` -} - -func (*UnannotatedSimpleMessage_LineNum) isUnannotatedSimpleMessage_Code() {} - -func (*UnannotatedSimpleMessage_Lang) isUnannotatedSimpleMessage_Code() {} - -type isUnannotatedSimpleMessage_Ext interface { - isUnannotatedSimpleMessage_Ext() -} - -type UnannotatedSimpleMessage_En struct { - En int64 `protobuf:"varint,7,opt,name=en,proto3,oneof"` -} - -type UnannotatedSimpleMessage_No struct { - No *UnannotatedEmbedded `protobuf:"bytes,8,opt,name=no,proto3,oneof"` -} - -func (*UnannotatedSimpleMessage_En) isUnannotatedSimpleMessage_Ext() {} - -func (*UnannotatedSimpleMessage_No) isUnannotatedSimpleMessage_Ext() {} - -var File_examples_internal_proto_examplepb_unannotated_echo_service_proto protoreflect.FileDescriptor - -var file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDesc = []byte{ - 0x0a, 0x40, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, - 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, - 0x65, 0x70, 0x62, 0x2f, 0x75, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x5f, - 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x12, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, - 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, - 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, - 0x70, 0x62, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x22, 0x51, 0x0a, 0x13, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, - 0x64, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x12, 0x1c, 0x0a, 0x08, 0x70, 0x72, 0x6f, - 0x67, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x08, 0x70, - 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x14, 0x0a, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x42, 0x06, 0x0a, - 0x04, 0x6d, 0x61, 0x72, 0x6b, 0x22, 0xfb, 0x02, 0x0a, 0x18, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, - 0x74, 0x61, 0x74, 0x65, 0x64, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, - 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x6e, 0x75, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x03, 0x6e, 0x75, 0x6d, 0x12, 0x35, 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x08, 0x6c, - 0x69, 0x6e, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, - 0x07, 0x6c, 0x69, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x12, 0x14, 0x0a, 0x04, 0x6c, 0x61, 0x6e, 0x67, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x6c, 0x61, 0x6e, 0x67, 0x12, 0x5b, - 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x43, - 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, - 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, - 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x45, 0x6d, 0x62, 0x65, 0x64, - 0x64, 0x65, 0x64, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x10, 0x0a, 0x02, 0x65, - 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x48, 0x01, 0x52, 0x02, 0x65, 0x6e, 0x12, 0x55, 0x0a, - 0x02, 0x6e, 0x6f, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x43, 0x2e, 0x67, 0x72, 0x70, 0x63, - 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, - 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x55, 0x6e, 0x61, 0x6e, 0x6e, - 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x48, 0x01, - 0x52, 0x02, 0x6e, 0x6f, 0x42, 0x06, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x42, 0x05, 0x0a, 0x03, - 0x65, 0x78, 0x74, 0x32, 0xf9, 0x03, 0x0a, 0x16, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, - 0x74, 0x65, 0x64, 0x45, 0x63, 0x68, 0x6f, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x9a, - 0x01, 0x0a, 0x04, 0x45, 0x63, 0x68, 0x6f, 0x12, 0x48, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, - 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, - 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, - 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, - 0x61, 0x74, 0x65, 0x64, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x1a, 0x48, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, - 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, - 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, - 0x70, 0x62, 0x2e, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x53, 0x69, - 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x9e, 0x01, 0x0a, 0x08, - 0x45, 0x63, 0x68, 0x6f, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x48, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, - 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, - 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, - 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, - 0x74, 0x61, 0x74, 0x65, 0x64, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x1a, 0x48, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, - 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, - 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, - 0x65, 0x70, 0x62, 0x2e, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x53, - 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0xa0, 0x01, 0x0a, - 0x0a, 0x45, 0x63, 0x68, 0x6f, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x48, 0x2e, 0x67, 0x72, - 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, - 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x55, 0x6e, 0x61, - 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x48, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, - 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, - 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, - 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, - 0x65, 0x64, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, - 0x52, 0x5a, 0x50, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x69, - 0x6e, 0x63, 0x68, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x65, 0x61, 0x73, 0x65, 0x2d, - 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, - 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, - 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x3b, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, - 0x65, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} - -var ( - file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDescOnce sync.Once - file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDescData = file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDesc -) - -func file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDescGZIP() []byte { - file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDescOnce.Do(func() { - file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDescData = protoimpl.X.CompressGZIP(file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDescData) - }) - return file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDescData -} - -var file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes = make([]protoimpl.MessageInfo, 2) -var file_examples_internal_proto_examplepb_unannotated_echo_service_proto_goTypes = []interface{}{ - (*UnannotatedEmbedded)(nil), // 0: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEmbedded - (*UnannotatedSimpleMessage)(nil), // 1: grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage - (*duration.Duration)(nil), // 2: google.protobuf.Duration -} -var file_examples_internal_proto_examplepb_unannotated_echo_service_proto_depIdxs = []int32{ - 2, // 0: grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage.duration:type_name -> google.protobuf.Duration - 0, // 1: grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage.status:type_name -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedEmbedded - 0, // 2: grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage.no:type_name -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedEmbedded - 1, // 3: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.Echo:input_type -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage - 1, // 4: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.EchoBody:input_type -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage - 1, // 5: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.EchoDelete:input_type -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage - 1, // 6: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.Echo:output_type -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage - 1, // 7: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.EchoBody:output_type -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage - 1, // 8: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.EchoDelete:output_type -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage - 6, // [6:9] is the sub-list for method output_type - 3, // [3:6] is the sub-list for method input_type - 3, // [3:3] is the sub-list for extension type_name - 3, // [3:3] is the sub-list for extension extendee - 0, // [0:3] is the sub-list for field type_name -} - -func init() { file_examples_internal_proto_examplepb_unannotated_echo_service_proto_init() } -func file_examples_internal_proto_examplepb_unannotated_echo_service_proto_init() { - if File_examples_internal_proto_examplepb_unannotated_echo_service_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UnannotatedEmbedded); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UnannotatedSimpleMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes[0].OneofWrappers = []interface{}{ - (*UnannotatedEmbedded_Progress)(nil), - (*UnannotatedEmbedded_Note)(nil), - } - file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes[1].OneofWrappers = []interface{}{ - (*UnannotatedSimpleMessage_LineNum)(nil), - (*UnannotatedSimpleMessage_Lang)(nil), - (*UnannotatedSimpleMessage_En)(nil), - (*UnannotatedSimpleMessage_No)(nil), - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDesc, - NumEnums: 0, - NumMessages: 2, - NumExtensions: 0, - NumServices: 1, - }, - GoTypes: file_examples_internal_proto_examplepb_unannotated_echo_service_proto_goTypes, - DependencyIndexes: file_examples_internal_proto_examplepb_unannotated_echo_service_proto_depIdxs, - MessageInfos: file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes, - }.Build() - File_examples_internal_proto_examplepb_unannotated_echo_service_proto = out.File - file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDesc = nil - file_examples_internal_proto_examplepb_unannotated_echo_service_proto_goTypes = nil - file_examples_internal_proto_examplepb_unannotated_echo_service_proto_depIdxs = nil -} - -// Reference imports to suppress errors if they are not otherwise used. -var _ context.Context -var _ grpc.ClientConnInterface - -// 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.SupportPackageIsVersion6 - -// UnannotatedEchoServiceClient is the client API for UnannotatedEchoService service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. -type UnannotatedEchoServiceClient interface { - // Echo method receives a simple message and returns it. - // - // The message posted as the id parameter will also be - // returned. - Echo(ctx context.Context, in *UnannotatedSimpleMessage, opts ...grpc.CallOption) (*UnannotatedSimpleMessage, error) - // EchoBody method receives a simple message and returns it. - EchoBody(ctx context.Context, in *UnannotatedSimpleMessage, opts ...grpc.CallOption) (*UnannotatedSimpleMessage, error) - // EchoDelete method receives a simple message and returns it. - EchoDelete(ctx context.Context, in *UnannotatedSimpleMessage, opts ...grpc.CallOption) (*UnannotatedSimpleMessage, error) -} - -type unannotatedEchoServiceClient struct { - cc grpc.ClientConnInterface -} - -func NewUnannotatedEchoServiceClient(cc grpc.ClientConnInterface) UnannotatedEchoServiceClient { - return &unannotatedEchoServiceClient{cc} -} - -func (c *unannotatedEchoServiceClient) Echo(ctx context.Context, in *UnannotatedSimpleMessage, opts ...grpc.CallOption) (*UnannotatedSimpleMessage, error) { - out := new(UnannotatedSimpleMessage) - err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService/Echo", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *unannotatedEchoServiceClient) EchoBody(ctx context.Context, in *UnannotatedSimpleMessage, opts ...grpc.CallOption) (*UnannotatedSimpleMessage, error) { - out := new(UnannotatedSimpleMessage) - err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService/EchoBody", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *unannotatedEchoServiceClient) EchoDelete(ctx context.Context, in *UnannotatedSimpleMessage, opts ...grpc.CallOption) (*UnannotatedSimpleMessage, error) { - out := new(UnannotatedSimpleMessage) - err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService/EchoDelete", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -// UnannotatedEchoServiceServer is the server API for UnannotatedEchoService service. -type UnannotatedEchoServiceServer interface { - // Echo method receives a simple message and returns it. - // - // The message posted as the id parameter will also be - // returned. - Echo(context.Context, *UnannotatedSimpleMessage) (*UnannotatedSimpleMessage, error) - // EchoBody method receives a simple message and returns it. - EchoBody(context.Context, *UnannotatedSimpleMessage) (*UnannotatedSimpleMessage, error) - // EchoDelete method receives a simple message and returns it. - EchoDelete(context.Context, *UnannotatedSimpleMessage) (*UnannotatedSimpleMessage, error) -} - -// UnimplementedUnannotatedEchoServiceServer can be embedded to have forward compatible implementations. -type UnimplementedUnannotatedEchoServiceServer struct { -} - -func (*UnimplementedUnannotatedEchoServiceServer) Echo(context.Context, *UnannotatedSimpleMessage) (*UnannotatedSimpleMessage, error) { - return nil, status.Errorf(codes.Unimplemented, "method Echo not implemented") -} -func (*UnimplementedUnannotatedEchoServiceServer) EchoBody(context.Context, *UnannotatedSimpleMessage) (*UnannotatedSimpleMessage, error) { - return nil, status.Errorf(codes.Unimplemented, "method EchoBody not implemented") -} -func (*UnimplementedUnannotatedEchoServiceServer) EchoDelete(context.Context, *UnannotatedSimpleMessage) (*UnannotatedSimpleMessage, error) { - return nil, status.Errorf(codes.Unimplemented, "method EchoDelete not implemented") -} - -func RegisterUnannotatedEchoServiceServer(s *grpc.Server, srv UnannotatedEchoServiceServer) { - s.RegisterService(&_UnannotatedEchoService_serviceDesc, srv) -} - -func _UnannotatedEchoService_Echo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(UnannotatedSimpleMessage) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(UnannotatedEchoServiceServer).Echo(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService/Echo", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(UnannotatedEchoServiceServer).Echo(ctx, req.(*UnannotatedSimpleMessage)) - } - return interceptor(ctx, in, info, handler) -} - -func _UnannotatedEchoService_EchoBody_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(UnannotatedSimpleMessage) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(UnannotatedEchoServiceServer).EchoBody(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService/EchoBody", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(UnannotatedEchoServiceServer).EchoBody(ctx, req.(*UnannotatedSimpleMessage)) - } - return interceptor(ctx, in, info, handler) -} - -func _UnannotatedEchoService_EchoDelete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(UnannotatedSimpleMessage) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(UnannotatedEchoServiceServer).EchoDelete(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService/EchoDelete", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(UnannotatedEchoServiceServer).EchoDelete(ctx, req.(*UnannotatedSimpleMessage)) - } - return interceptor(ctx, in, info, handler) -} - -var _UnannotatedEchoService_serviceDesc = grpc.ServiceDesc{ - ServiceName: "grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService", - HandlerType: (*UnannotatedEchoServiceServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "Echo", - Handler: _UnannotatedEchoService_Echo_Handler, - }, - { - MethodName: "EchoBody", - Handler: _UnannotatedEchoService_EchoBody_Handler, - }, - { - MethodName: "EchoDelete", - Handler: _UnannotatedEchoService_EchoDelete_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "examples/internal/proto/examplepb/unannotated_echo_service.proto", -} diff --git a/examples/internal/proto/examplepb/unannotated_echo_service.pb.gw.go b/examples/internal/proto/examplepb/unannotated_echo_service.pb.gw.go deleted file mode 100755 index b76fb60..0000000 --- a/examples/internal/proto/examplepb/unannotated_echo_service.pb.gw.go +++ /dev/null @@ -1,3 +0,0 @@ -// +build ignore - -package ignore \ No newline at end of file diff --git a/examples/internal/proto/examplepb/unannotated_echo_service_grpc.pb.go b/examples/internal/proto/examplepb/unannotated_echo_service_grpc.pb.go deleted file mode 100755 index 0b0c944..0000000 --- a/examples/internal/proto/examplepb/unannotated_echo_service_grpc.pb.go +++ /dev/null @@ -1,158 +0,0 @@ -// Code generated by protoc-gen-go-grpc. DO NOT EDIT. - -package examplepb - -import ( - context "context" - grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" -) - -// 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.SupportPackageIsVersion6 - -// UnannotatedEchoServiceClient is the client API for UnannotatedEchoService service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. -type UnannotatedEchoServiceClient interface { - Echo(ctx context.Context, in *UnannotatedSimpleMessage, opts ...grpc.CallOption) (*UnannotatedSimpleMessage, error) - EchoBody(ctx context.Context, in *UnannotatedSimpleMessage, opts ...grpc.CallOption) (*UnannotatedSimpleMessage, error) - EchoDelete(ctx context.Context, in *UnannotatedSimpleMessage, opts ...grpc.CallOption) (*UnannotatedSimpleMessage, error) -} - -type unannotatedEchoServiceClient struct { - cc grpc.ClientConnInterface -} - -func NewUnannotatedEchoServiceClient(cc grpc.ClientConnInterface) UnannotatedEchoServiceClient { - return &unannotatedEchoServiceClient{cc} -} - -func (c *unannotatedEchoServiceClient) Echo(ctx context.Context, in *UnannotatedSimpleMessage, opts ...grpc.CallOption) (*UnannotatedSimpleMessage, error) { - out := new(UnannotatedSimpleMessage) - err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService/Echo", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *unannotatedEchoServiceClient) EchoBody(ctx context.Context, in *UnannotatedSimpleMessage, opts ...grpc.CallOption) (*UnannotatedSimpleMessage, error) { - out := new(UnannotatedSimpleMessage) - err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService/EchoBody", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *unannotatedEchoServiceClient) EchoDelete(ctx context.Context, in *UnannotatedSimpleMessage, opts ...grpc.CallOption) (*UnannotatedSimpleMessage, error) { - out := new(UnannotatedSimpleMessage) - err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService/EchoDelete", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -// UnannotatedEchoServiceServer is the server API for UnannotatedEchoService service. -type UnannotatedEchoServiceServer interface { - Echo(context.Context, *UnannotatedSimpleMessage) (*UnannotatedSimpleMessage, error) - EchoBody(context.Context, *UnannotatedSimpleMessage) (*UnannotatedSimpleMessage, error) - EchoDelete(context.Context, *UnannotatedSimpleMessage) (*UnannotatedSimpleMessage, error) -} - -// UnimplementedUnannotatedEchoServiceServer can be embedded to have forward compatible implementations. -type UnimplementedUnannotatedEchoServiceServer struct { -} - -func (*UnimplementedUnannotatedEchoServiceServer) Echo(context.Context, *UnannotatedSimpleMessage) (*UnannotatedSimpleMessage, error) { - return nil, status.Errorf(codes.Unimplemented, "method Echo not implemented") -} -func (*UnimplementedUnannotatedEchoServiceServer) EchoBody(context.Context, *UnannotatedSimpleMessage) (*UnannotatedSimpleMessage, error) { - return nil, status.Errorf(codes.Unimplemented, "method EchoBody not implemented") -} -func (*UnimplementedUnannotatedEchoServiceServer) EchoDelete(context.Context, *UnannotatedSimpleMessage) (*UnannotatedSimpleMessage, error) { - return nil, status.Errorf(codes.Unimplemented, "method EchoDelete not implemented") -} - -func RegisterUnannotatedEchoServiceServer(s *grpc.Server, srv UnannotatedEchoServiceServer) { - s.RegisterService(&_UnannotatedEchoService_serviceDesc, srv) -} - -func _UnannotatedEchoService_Echo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(UnannotatedSimpleMessage) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(UnannotatedEchoServiceServer).Echo(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService/Echo", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(UnannotatedEchoServiceServer).Echo(ctx, req.(*UnannotatedSimpleMessage)) - } - return interceptor(ctx, in, info, handler) -} - -func _UnannotatedEchoService_EchoBody_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(UnannotatedSimpleMessage) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(UnannotatedEchoServiceServer).EchoBody(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService/EchoBody", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(UnannotatedEchoServiceServer).EchoBody(ctx, req.(*UnannotatedSimpleMessage)) - } - return interceptor(ctx, in, info, handler) -} - -func _UnannotatedEchoService_EchoDelete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(UnannotatedSimpleMessage) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(UnannotatedEchoServiceServer).EchoDelete(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService/EchoDelete", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(UnannotatedEchoServiceServer).EchoDelete(ctx, req.(*UnannotatedSimpleMessage)) - } - return interceptor(ctx, in, info, handler) -} - -var _UnannotatedEchoService_serviceDesc = grpc.ServiceDesc{ - ServiceName: "grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService", - HandlerType: (*UnannotatedEchoServiceServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "Echo", - Handler: _UnannotatedEchoService_Echo_Handler, - }, - { - MethodName: "EchoBody", - Handler: _UnannotatedEchoService_EchoBody_Handler, - }, - { - MethodName: "EchoDelete", - Handler: _UnannotatedEchoService_EchoDelete_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "examples/internal/proto/examplepb/unannotated_echo_service.proto", -} diff --git a/gateway/internal/casing/BUILD.bazel b/gateway/internal/casing/BUILD.bazel index 94c3fc4..f7ce84c 100644 --- a/gateway/internal/casing/BUILD.bazel +++ b/gateway/internal/casing/BUILD.bazel @@ -1,8 +1,14 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( - name = "go_default_library", + name = "casing", srcs = ["camel.go"], importpath = "github.com/binchencoder/ease-gateway/gateway/internal/casing", visibility = ["//:__subpackages__"], ) + +alias( + name = "go_default_library", + actual = ":casing", + visibility = ["//:__subpackages__"], +) diff --git a/gateway/internal/descriptor/BUILD.bazel b/gateway/internal/descriptor/BUILD.bazel index 9a9269c..0bff1b9 100644 --- a/gateway/internal/descriptor/BUILD.bazel +++ b/gateway/internal/descriptor/BUILD.bazel @@ -3,7 +3,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") package(default_visibility = ["//visibility:public"]) go_library( - name = "go_default_library", + name = "descriptor", srcs = [ "grpc_api_configuration.go", "openapi_configuration.go", @@ -13,42 +13,51 @@ go_library( ], importpath = "github.com/binchencoder/ease-gateway/gateway/internal/descriptor", deps = [ - "//gateway/internal/casing:go_default_library", - "//gateway/internal/descriptor/apiconfig:go_default_library", - "//gateway/internal/descriptor/openapiconfig:go_default_library", - "//gateway/protoc-gen-openapiv2/options:go_default_library", - "//httpoptions:go_default_library", + "//gateway/internal/casing", + "@com_github_grpc_ecosystem_grpc_gateway//internal/codegenerator", + "//gateway/internal/descriptor/apiconfig", + "//gateway/internal/descriptor/openapiconfig", + "//httpoptions", + "//gateway/protoc-gen-openapiv2/options", + "@com_github_binchencoder_gateway_proto//data:go_default_library", - "@com_github_ghodss_yaml//:go_default_library", - "@com_github_golang_glog//:go_default_library", - "@com_github_grpc_ecosystem_grpc_gateway//internal/httprule:go_default_library", - "@org_golang_google_protobuf//compiler/protogen:go_default_library", - "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", - "@io_bazel_rules_go//proto/wkt:descriptor_go_proto", - "@org_golang_google_protobuf//encoding/protojson:go_default_library", - "@org_golang_google_protobuf//proto:go_default_library", - "@org_golang_google_protobuf//types/descriptorpb:go_default_library", - "@org_golang_google_protobuf//types/pluginpb:go_default_library", + "@com_github_golang_glog//:glog", + "@com_github_grpc_ecosystem_grpc_gateway//internal/httprule", + "@go_googleapis//google/api:annotations_go_proto", + "@io_k8s_sigs_yaml//:yaml", + "@org_golang_google_protobuf//compiler/protogen", + "@org_golang_google_protobuf//encoding/protojson", + "@org_golang_google_protobuf//proto", + "@org_golang_google_protobuf//types/descriptorpb", + "@org_golang_google_protobuf//types/pluginpb", ], ) go_test( - name = "go_default_test", + name = "descriptor_test", size = "small", srcs = [ "grpc_api_configuration_test.go", + "openapi_configuration_test.go", "registry_test.go", "services_test.go", "types_test.go", ], - embed = [":go_default_library"], + embed = [":descriptor"], deps = [ - "@com_github_grpc_ecosystem_grpc_gateway//internal/httprule:go_default_library", - "//gateway/protoc-gen-openapiv2/options:go_default_library", - "@org_golang_google_protobuf//compiler/protogen:go_default_library", - "@org_golang_google_protobuf//encoding/prototext:go_default_library", - "@org_golang_google_protobuf//proto:go_default_library", - "@org_golang_google_protobuf//types/descriptorpb:go_default_library", - "@org_golang_google_protobuf//types/pluginpb:go_default_library", + "//gateway/internal/descriptor/openapiconfig", + "@com_github_grpc_ecosystem_grpc_gateway//internal/httprule", + "@com_github_grpc_ecosystem_grpc_gateway//protoc-gen-openapiv2/options", + "@org_golang_google_protobuf//compiler/protogen", + "@org_golang_google_protobuf//encoding/prototext", + "@org_golang_google_protobuf//proto", + "@org_golang_google_protobuf//types/descriptorpb", + "@org_golang_google_protobuf//types/pluginpb", ], ) + +alias( + name = "go_default_library", + actual = ":descriptor", + visibility = ["//:__subpackages__"], +) diff --git a/gateway/internal/descriptor/apiconfig/BUILD.bazel b/gateway/internal/descriptor/apiconfig/BUILD.bazel index 66a5dc1..98baaed 100644 --- a/gateway/internal/descriptor/apiconfig/BUILD.bazel +++ b/gateway/internal/descriptor/apiconfig/BUILD.bazel @@ -19,11 +19,17 @@ go_proto_library( compilers = ["//:go_apiv2"], importpath = "github.com/binchencoder/ease-gateway/gateway/internal/descriptor/apiconfig", proto = ":apiconfig_proto", - deps = ["//httpoptions:options_go_proto"], + deps = ["//httpoptions"], ) go_library( - name = "go_default_library", + name = "apiconfig", embed = [":apiconfig_go_proto"], importpath = "github.com/binchencoder/ease-gateway/gateway/internal/descriptor/apiconfig", ) + +alias( + name = "go_default_library", + actual = ":apiconfig", + visibility = ["//:__subpackages__"], +) diff --git a/gateway/internal/descriptor/grpc_api_configuration.go b/gateway/internal/descriptor/grpc_api_configuration.go index 3cbe319..e125b4c 100644 --- a/gateway/internal/descriptor/grpc_api_configuration.go +++ b/gateway/internal/descriptor/grpc_api_configuration.go @@ -5,10 +5,10 @@ import ( "io/ioutil" "strings" - "github.com/ghodss/yaml" // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor/apiconfig" "github.com/binchencoder/ease-gateway/gateway/internal/descriptor/apiconfig" "google.golang.org/protobuf/encoding/protojson" + "sigs.k8s.io/yaml" ) func loadGrpcAPIServiceFromYAML(yamlFileContents []byte, yamlSourceLogName string) (*apiconfig.GrpcAPIService, error) { diff --git a/gateway/internal/descriptor/openapi_configuration.go b/gateway/internal/descriptor/openapi_configuration.go index 5010128..d8d131d 100644 --- a/gateway/internal/descriptor/openapi_configuration.go +++ b/gateway/internal/descriptor/openapi_configuration.go @@ -4,10 +4,10 @@ import ( "fmt" "io/ioutil" - "github.com/ghodss/yaml" // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor/openapiconfig" "github.com/binchencoder/ease-gateway/gateway/internal/descriptor/openapiconfig" "google.golang.org/protobuf/encoding/protojson" + "sigs.k8s.io/yaml" ) func loadOpenAPIConfigFromYAML(yamlFileContents []byte, yamlSourceLogName string) (*openapiconfig.OpenAPIConfig, error) { diff --git a/gateway/internal/descriptor/openapiconfig/BUILD.bazel b/gateway/internal/descriptor/openapiconfig/BUILD.bazel index de3dbf7..c65a584 100644 --- a/gateway/internal/descriptor/openapiconfig/BUILD.bazel +++ b/gateway/internal/descriptor/openapiconfig/BUILD.bazel @@ -15,12 +15,18 @@ go_proto_library( importpath = "github.com/binchencoder/ease-gateway/gateway/internal/descriptor/openapiconfig", proto = ":openapiconfig_proto", visibility = ["//:__subpackages__"], - deps = ["//gateway/protoc-gen-openapiv2/options:go_default_library"], + deps = ["//gateway/protoc-gen-openapiv2/options"], ) go_library( - name = "go_default_library", + name = "openapiconfig", embed = [":openapiconfig_go_proto"], importpath = "github.com/binchencoder/ease-gateway/gateway/internal/descriptor/openapiconfig", visibility = ["//:__subpackages__"], ) + +alias( + name = "go_default_library", + actual = ":openapiconfig", + visibility = ["//:__subpackages__"], +) diff --git a/gateway/internal/descriptor/openapiconfig/openapiconfig.pb.go b/gateway/internal/descriptor/openapiconfig/openapiconfig.pb.go old mode 100644 new mode 100755 index 25e9f65..e792bd0 --- a/gateway/internal/descriptor/openapiconfig/openapiconfig.pb.go +++ b/gateway/internal/descriptor/openapiconfig/openapiconfig.pb.go @@ -1,14 +1,13 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.23.0 -// protoc v3.12.3 +// protoc-gen-go v1.27.1 +// protoc v3.19.4 // source: gateway/internal/descriptor/openapiconfig/openapiconfig.proto package openapiconfig import ( options "github.com/binchencoder/ease-gateway/gateway/protoc-gen-openapiv2/options" - proto "github.com/golang/protobuf/proto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" @@ -22,11 +21,6 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - -// OpenAPIFileOption represents OpenAPI options on a file type OpenAPIFileOption struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -82,7 +76,6 @@ func (x *OpenAPIFileOption) GetOption() *options.Swagger { return nil } -// OpenAPIMethodOption represents OpenAPI options on a method type OpenAPIMethodOption struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -138,7 +131,6 @@ func (x *OpenAPIMethodOption) GetOption() *options.Operation { return nil } -// OpenAPIMessageOption represents OpenAPI options on a message type OpenAPIMessageOption struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -194,13 +186,12 @@ func (x *OpenAPIMessageOption) GetOption() *options.Schema { return nil } -// OpenAPIServiceOption represents OpenAPI options on a service type OpenAPIServiceOption struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Service string `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"` // ex: Service + Service string `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"` Option *options.Tag `protobuf:"bytes,2,opt,name=option,proto3" json:"option,omitempty"` } @@ -250,7 +241,6 @@ func (x *OpenAPIServiceOption) GetOption() *options.Tag { return nil } -// OpenAPIFieldOption represents OpenAPI options on a field type OpenAPIFieldOption struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -306,7 +296,6 @@ func (x *OpenAPIFieldOption) GetOption() *options.JSONSchema { return nil } -// OpenAPIOptions represents OpenAPI protobuf options type OpenAPIOptions struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -386,7 +375,6 @@ func (x *OpenAPIOptions) GetField() []*OpenAPIFieldOption { return nil } -// OpenAPIConfig represents a set of OpenAPI options type OpenAPIConfig struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache diff --git a/gateway/internal/descriptor/registry.go b/gateway/internal/descriptor/registry.go index 0978e17..d4ff801 100644 --- a/gateway/internal/descriptor/registry.go +++ b/gateway/internal/descriptor/registry.go @@ -5,6 +5,8 @@ import ( "strings" "github.com/golang/glog" + "github.com/grpc-ecosystem/grpc-gateway/v2/internal/codegenerator" + // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor/openapiconfig" "github.com/binchencoder/ease-gateway/gateway/internal/descriptor/openapiconfig" // "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options" @@ -60,14 +62,21 @@ type Registry struct { // useJSONNamesForFields if true json tag name is used for generating fields in OpenAPI definitions, // otherwise the original proto name is used. It's helpful for synchronizing the OpenAPI definition - // with grpc-gateway response, if it uses json tags for marshaling. + // with gRPC-Gateway response, if it uses json tags for marshaling. useJSONNamesForFields bool - // useFQNForOpenAPIName if true OpenAPI names will use the full qualified name (FQN) from proto definition, - // and generate a dot-separated OpenAPI name concatenating all elements from the proto FQN. - // If false, the default behavior is to concat the last 2 elements of the FQN if they are unique, otherwise concat - // all the elements of the FQN without any separator - useFQNForOpenAPIName bool + // openAPINamingStrategy is the naming strategy to use for assigning OpenAPI field and parameter names. This can be one of the following: + // - `legacy`: use the legacy naming strategy from protoc-gen-swagger, that generates unique but not necessarily + // maximally concise names. Components are concatenated directly, e.g., `MyOuterMessageMyNestedMessage`. + // - `simple`: use a simple heuristic for generating unique and concise names. Components are concatenated using + // dots as a separator, e.g., `MyOuterMesage.MyNestedMessage` (if `MyNestedMessage` alone is unique, + // `MyNestedMessage` will be used as the OpenAPI name). + // - `fqn`: always use the fully-qualified name of the proto message (leading dot removed) as the OpenAPI + // name. + openAPINamingStrategy string + + // visibilityRestrictionSelectors is a map of selectors for `google.api.VisibilityRule`s that will be included in the OpenAPI output. + visibilityRestrictionSelectors map[string]bool // useGoTemplate determines whether you want to use GO templates // in your protofile comments @@ -76,6 +85,9 @@ type Registry struct { // enumsAsInts render enum as integer, as opposed to string enumsAsInts bool + // omitEnumDefaultValue omits default value of enum + omitEnumDefaultValue bool + // disableDefaultErrors disables the generation of the default error types. // This is useful for users who have defined custom error handling. disableDefaultErrors bool @@ -89,6 +101,9 @@ type Registry struct { // has no HttpRule annotation. warnOnUnboundMethods bool + // proto3OptionalNullable specifies whether Proto3 Optional fields should be marked as x-nullable. + proto3OptionalNullable bool + // fileOptions is a mapping of file name to additional OpenAPI file options fileOptions map[string]*options.Swagger @@ -111,6 +126,12 @@ type Registry struct { // omitPackageDoc, if false, causes a package comment to be included in the generated code. omitPackageDoc bool + + // recursiveDepth sets the maximum depth of a field parameter + recursiveDepth int + + // annotationMap is used to check for duplicate HTTP annotations + annotationMap map[annotationIdentifier]struct{} } type repeatedFieldSeparator struct { @@ -118,6 +139,12 @@ type repeatedFieldSeparator struct { sep rune } +type annotationIdentifier struct { + method string + pathTemplate string + service *Service +} + var ( // Reg is the global dictionary. Reg *Registry @@ -126,12 +153,14 @@ var ( // NewRegistry returns a new Registry. func NewRegistry() *Registry { return &Registry{ - msgs: make(map[string]*Message), - enums: make(map[string]*Enum), - files: make(map[string]*File), - pkgMap: make(map[string]string), - pkgAliases: make(map[string]string), - externalHTTPRules: make(map[string][]*annotations.HttpRule), + msgs: make(map[string]*Message), + enums: make(map[string]*Enum), + files: make(map[string]*File), + pkgMap: make(map[string]string), + pkgAliases: make(map[string]string), + externalHTTPRules: make(map[string][]*annotations.HttpRule), + openAPINamingStrategy: "legacy", + visibilityRestrictionSelectors: make(map[string]bool), repeatedPathParamSeparator: repeatedFieldSeparator{ name: "csv", sep: ',', @@ -141,6 +170,8 @@ func NewRegistry() *Registry { messageOptions: make(map[string]*options.Schema), serviceOptions: make(map[string]*options.Tag), fieldOptions: make(map[string]*options.JSONSchema), + annotationMap: make(map[annotationIdentifier]struct{}), + recursiveDepth: 1000, } } @@ -150,6 +181,10 @@ func (r *Registry) Load(req *pluginpb.CodeGeneratorRequest) error { if err != nil { return err } + // Note: keep in mind that this might be not enough because + // protogen.Plugin is used only to load files here. + // The support for features must be set on the pluginpb.CodeGeneratorResponse. + codegenerator.SetSupportedFeaturesOnPluginGen(gen) return r.load(gen) } @@ -367,6 +402,16 @@ func (r *Registry) SetStandalone(standalone bool) { r.standalone = standalone } +// SetRecursiveDepth records the max recursion count +func (r *Registry) SetRecursiveDepth(count int) { + r.recursiveDepth = count +} + +// GetRecursiveDepth returns the max recursion count +func (r *Registry) GetRecursiveDepth() int { + return r.recursiveDepth +} + // ReserveGoPackageAlias reserves the unique alias of go package. // If succeeded, the alias will be never used for other packages in generated go files. // If failed, the alias is already taken by another package, so you need to use another @@ -491,13 +536,15 @@ func (r *Registry) GetUseJSONNamesForFields() bool { } // SetUseFQNForOpenAPIName sets useFQNForOpenAPIName +// Deprecated: use SetOpenAPINamingStrategy instead. func (r *Registry) SetUseFQNForOpenAPIName(use bool) { - r.useFQNForOpenAPIName = use + r.openAPINamingStrategy = "fqn" } // GetUseFQNForOpenAPIName returns useFQNForOpenAPIName +// Deprecated: Use GetOpenAPINamingStrategy(). func (r *Registry) GetUseFQNForOpenAPIName() bool { - return r.useFQNForOpenAPIName + return r.openAPINamingStrategy == "fqn" } // GetMergeFileName return the target merge OpenAPI file name @@ -505,6 +552,16 @@ func (r *Registry) GetMergeFileName() string { return r.mergeFileName } +// SetOpenAPINamingStrategy sets the naming strategy to be used. +func (r *Registry) SetOpenAPINamingStrategy(strategy string) { + r.openAPINamingStrategy = strategy +} + +// GetOpenAPINamingStrategy retrieves the naming strategy that is in use. +func (r *Registry) GetOpenAPINamingStrategy() string { + return r.openAPINamingStrategy +} + // SetUseGoTemplate sets useGoTemplate func (r *Registry) SetUseGoTemplate(use bool) { r.useGoTemplate = use @@ -525,6 +582,29 @@ func (r *Registry) GetEnumsAsInts() bool { return r.enumsAsInts } +// SetOmitEnumDefaultValue sets omitEnumDefaultValue +func (r *Registry) SetOmitEnumDefaultValue(omit bool) { + r.omitEnumDefaultValue = omit +} + +// GetOmitEnumDefaultValue returns omitEnumDefaultValue +func (r *Registry) GetOmitEnumDefaultValue() bool { + return r.omitEnumDefaultValue +} + +// SetVisibilityRestrictionSelectors sets the visibility restriction selectors. +func (r *Registry) SetVisibilityRestrictionSelectors(selectors []string) { + r.visibilityRestrictionSelectors = make(map[string]bool) + for _, selector := range selectors { + r.visibilityRestrictionSelectors[strings.TrimSpace(selector)] = true + } +} + +// GetVisibilityRestrictionSelectors retrieves he visibility restriction selectors. +func (r *Registry) GetVisibilityRestrictionSelectors() map[string]bool { + return r.visibilityRestrictionSelectors +} + // SetDisableDefaultErrors sets disableDefaultErrors func (r *Registry) SetDisableDefaultErrors(use bool) { r.disableDefaultErrors = use @@ -565,6 +645,16 @@ func (r *Registry) GetOmitPackageDoc() bool { return r.omitPackageDoc } +// SetProto3OptionalNullable set proto3OtionalNullable +func (r *Registry) SetProto3OptionalNullable(proto3OtionalNullable bool) { + r.proto3OptionalNullable = proto3OtionalNullable +} + +// GetProto3OptionalNullable returns proto3OtionalNullable +func (r *Registry) GetProto3OptionalNullable() bool { + return r.proto3OptionalNullable +} + // RegisterOpenAPIOptions registers OpenAPI options func (r *Registry) RegisterOpenAPIOptions(opts *openapiconfig.OpenAPIOptions) error { if opts == nil { @@ -660,3 +750,20 @@ func (r *Registry) GetOpenAPIFieldOption(qualifiedField string) (*options.JSONSc opt, ok := r.fieldOptions[qualifiedField] return opt, ok } + +func (r *Registry) FieldName(f *Field) string { + if r.useJSONNamesForFields { + return f.GetJsonName() + } + return f.GetName() +} + +func (r *Registry) CheckDuplicateAnnotation(httpMethod string, httpTemplate string, svc *Service) error { + a := annotationIdentifier{method: httpMethod, pathTemplate: httpTemplate, service: svc} + _, ok := r.annotationMap[a] + if ok { + return fmt.Errorf("duplicate annotation: method=%s, template=%s", httpMethod, httpTemplate) + } + r.annotationMap[a] = struct{}{} + return nil +} diff --git a/gateway/internal/descriptor/registry_test.go b/gateway/internal/descriptor/registry_test.go index 39cdb92..a886063 100644 --- a/gateway/internal/descriptor/registry_test.go +++ b/gateway/internal/descriptor/registry_test.go @@ -25,6 +25,7 @@ func newGeneratorFromSources(req *pluginpb.CodeGeneratorRequest, sources ...stri } func loadFileWithCodeGeneratorRequest(t *testing.T, reg *Registry, req *pluginpb.CodeGeneratorRequest, sources ...string) []*descriptorpb.FileDescriptorProto { + t.Helper() plugin, err := newGeneratorFromSources(req, sources...) if err != nil { t.Fatalf("failed to create a generator: %v", err) @@ -37,6 +38,7 @@ func loadFileWithCodeGeneratorRequest(t *testing.T, reg *Registry, req *pluginpb } func loadFile(t *testing.T, reg *Registry, src string) *descriptorpb.FileDescriptorProto { + t.Helper() fds := loadFileWithCodeGeneratorRequest(t, reg, &pluginpb.CodeGeneratorRequest{}, src) return fds[0] } @@ -46,6 +48,7 @@ func TestLoadFile(t *testing.T) { fd := loadFile(t, reg, ` name: 'example.proto' package: 'example' + options < go_package: 'github.com/grpc-ecosystem/grpc-gateway/runtime/internal/example' > message_type < name: 'ExampleMessage' field < @@ -62,7 +65,7 @@ func TestLoadFile(t *testing.T) { t.Errorf("reg.files[%q] = nil; want non-nil", "example.proto") return } - wantPkg := GoPackage{Path: ".", Name: "example"} + wantPkg := GoPackage{Path: "github.com/grpc-ecosystem/grpc-gateway/runtime/internal/example", Name: "example"} if got, want := file.GoPkg, wantPkg; got != want { t.Errorf("file.GoPkg = %#v; want %#v", got, want) } @@ -102,6 +105,7 @@ func TestLoadFileNestedPackage(t *testing.T) { loadFile(t, reg, ` name: 'example.proto' package: 'example.nested.nested2' + options < go_package: 'github.com/grpc-ecosystem/grpc-gateway/runtime/internal/example.nested.nested2' > `) file := reg.files["example.proto"] @@ -109,7 +113,7 @@ func TestLoadFileNestedPackage(t *testing.T) { t.Errorf("reg.files[%q] = nil; want non-nil", "example.proto") return } - wantPkg := GoPackage{Path: ".", Name: "example_nested_nested2"} + wantPkg := GoPackage{Path: "github.com/grpc-ecosystem/grpc-gateway/runtime/internal/example.nested.nested2", Name: "example_nested_nested2"} if got, want := file.GoPkg, wantPkg; got != want { t.Errorf("file.GoPkg = %#v; want %#v", got, want) } @@ -120,6 +124,7 @@ func TestLoadFileWithDir(t *testing.T) { loadFile(t, reg, ` name: 'path/to/example.proto' package: 'example' + options < go_package: 'github.com/grpc-ecosystem/grpc-gateway/runtime/internal/example' > `) file := reg.files["path/to/example.proto"] @@ -127,7 +132,7 @@ func TestLoadFileWithDir(t *testing.T) { t.Errorf("reg.files[%q] = nil; want non-nil", "example.proto") return } - wantPkg := GoPackage{Path: "path/to", Name: "example"} + wantPkg := GoPackage{Path: "github.com/grpc-ecosystem/grpc-gateway/runtime/internal/example", Name: "example"} if got, want := file.GoPkg, wantPkg; got != want { t.Errorf("file.GoPkg = %#v; want %#v", got, want) } @@ -137,6 +142,7 @@ func TestLoadFileWithoutPackage(t *testing.T) { reg := NewRegistry() loadFile(t, reg, ` name: 'path/to/example_file.proto' + options < go_package: 'github.com/grpc-ecosystem/grpc-gateway/runtime/internal/example_file' > `) file := reg.files["path/to/example_file.proto"] @@ -144,7 +150,7 @@ func TestLoadFileWithoutPackage(t *testing.T) { t.Errorf("reg.files[%q] = nil; want non-nil", "example.proto") return } - wantPkg := GoPackage{Path: "path/to", Name: "example_file"} + wantPkg := GoPackage{Path: "github.com/grpc-ecosystem/grpc-gateway/runtime/internal/example_file", Name: "example_file"} if got, want := file.GoPkg, wantPkg; got != want { t.Errorf("file.GoPkg = %#v; want %#v", got, want) } @@ -157,6 +163,7 @@ func TestLoadFileWithMapping(t *testing.T) { }, ` name: 'path/to/example.proto' package: 'example' + options < go_package: 'github.com/grpc-ecosystem/grpc-gateway/runtime/internal/example' > `) file := reg.files["path/to/example.proto"] @@ -175,10 +182,12 @@ func TestLoadFileWithPackageNameCollision(t *testing.T) { loadFile(t, reg, ` name: 'path/to/another.proto' package: 'example' + options < go_package: 'github.com/grpc-ecosystem/grpc-gateway/runtime/internal/example' > `) loadFile(t, reg, ` name: 'path/to/example.proto' package: 'example' + options < go_package: 'github.com/grpc-ecosystem/grpc-gateway/runtime/internal/example' > `) if err := reg.ReserveGoPackageAlias("ioutil", "io/ioutil"); err != nil { t.Fatalf("reg.ReserveGoPackageAlias(%q) failed with %v; want success", "ioutil", err) @@ -186,6 +195,7 @@ func TestLoadFileWithPackageNameCollision(t *testing.T) { loadFile(t, reg, ` name: 'path/to/ioutil.proto' package: 'ioutil' + options < go_package: 'github.com/grpc-ecosystem/grpc-gateway/runtime/internal/ioutil' > `) file := reg.files["path/to/another.proto"] @@ -193,7 +203,7 @@ func TestLoadFileWithPackageNameCollision(t *testing.T) { t.Errorf("reg.files[%q] = nil; want non-nil", "path/to/another.proto") return } - wantPkg := GoPackage{Path: "path/to", Name: "example"} + wantPkg := GoPackage{Path: "github.com/grpc-ecosystem/grpc-gateway/runtime/internal/example", Name: "example"} if got, want := file.GoPkg, wantPkg; got != want { t.Errorf("file.GoPkg = %#v; want %#v", got, want) } @@ -203,7 +213,7 @@ func TestLoadFileWithPackageNameCollision(t *testing.T) { t.Errorf("reg.files[%q] = nil; want non-nil", "path/to/example.proto") return } - wantPkg = GoPackage{Path: "path/to", Name: "example", Alias: ""} + wantPkg = GoPackage{Path: "github.com/grpc-ecosystem/grpc-gateway/runtime/internal/example", Name: "example", Alias: ""} if got, want := file.GoPkg, wantPkg; got != want { t.Errorf("file.GoPkg = %#v; want %#v", got, want) } @@ -213,7 +223,7 @@ func TestLoadFileWithPackageNameCollision(t *testing.T) { t.Errorf("reg.files[%q] = nil; want non-nil", "path/to/ioutil.proto") return } - wantPkg = GoPackage{Path: "path/to", Name: "ioutil", Alias: "ioutil_0"} + wantPkg = GoPackage{Path: "github.com/grpc-ecosystem/grpc-gateway/runtime/internal/ioutil", Name: "ioutil", Alias: "ioutil_0"} if got, want := file.GoPkg, wantPkg; got != want { t.Errorf("file.GoPkg = %#v; want %#v", got, want) } @@ -226,9 +236,11 @@ func TestLoadFileWithIdenticalGoPkg(t *testing.T) { }, ` name: 'path/to/another.proto' package: 'example' + options < go_package: 'github.com/grpc-ecosystem/grpc-gateway/runtime/internal/example' > `, ` name: 'path/to/example.proto' package: 'example' + options < go_package: 'github.com/grpc-ecosystem/grpc-gateway/runtime/internal/example' > `) file := reg.files["path/to/example.proto"] @@ -259,6 +271,7 @@ func TestLookupMsgWithoutPackage(t *testing.T) { reg := NewRegistry() fd := loadFile(t, reg, ` name: 'example.proto' + options < go_package: 'github.com/grpc-ecosystem/grpc-gateway/runtime/internal/example' > message_type < name: 'ExampleMessage' field < @@ -285,6 +298,7 @@ func TestLookupMsgWithNestedPackage(t *testing.T) { fd := loadFile(t, reg, ` name: 'example.proto' package: 'nested.nested2.mypackage' + options < go_package: 'github.com/grpc-ecosystem/grpc-gateway/runtime/internal/example' > message_type < name: 'ExampleMessage' field < @@ -359,84 +373,6 @@ func TestLoadWithInconsistentTargetPackage(t *testing.T) { req string consistent bool }{ - // root package, no explicit go package - { - req: ` - file_to_generate: 'a.proto' - file_to_generate: 'b.proto' - proto_file < - name: 'a.proto' - message_type < name: 'A' > - service < - name: "AService" - method < - name: "Meth" - input_type: "A" - output_type: "A" - options < - [google.api.http] < post: "/v1/a" body: "*" > - > - > - > - > - proto_file < - name: 'b.proto' - message_type < name: 'B' > - service < - name: "BService" - method < - name: "Meth" - input_type: "B" - output_type: "B" - options < - [google.api.http] < post: "/v1/b" body: "*" > - > - > - > - > - `, - consistent: false, - }, - // named package, no explicit go package - { - req: ` - file_to_generate: 'a.proto' - file_to_generate: 'b.proto' - proto_file < - name: 'a.proto' - package: 'example.foo' - message_type < name: 'A' > - service < - name: "AService" - method < - name: "Meth" - input_type: "A" - output_type: "A" - options < - [google.api.http] < post: "/v1/a" body: "*" > - > - > - > - > - proto_file < - name: 'b.proto' - package: 'example.foo' - message_type < name: 'B' > - service < - name: "BService" - method < - name: "Meth" - input_type: "B" - output_type: "B" - options < - [google.api.http] < post: "/v1/b" body: "*" > - > - > - > - > - `, - consistent: true, - }, // root package, explicit go package { req: ` @@ -444,7 +380,7 @@ func TestLoadWithInconsistentTargetPackage(t *testing.T) { file_to_generate: 'b.proto' proto_file < name: 'a.proto' - options < go_package: 'foo' > + options < go_package: 'github.com/grpc-ecosystem/grpc-gateway/runtime/internal/example.foo' > message_type < name: 'A' > service < name: "AService" @@ -460,7 +396,7 @@ func TestLoadWithInconsistentTargetPackage(t *testing.T) { > proto_file < name: 'b.proto' - options < go_package: 'foo' > + options < go_package: 'github.com/grpc-ecosystem/grpc-gateway/runtime/internal/example.foo' > message_type < name: 'B' > service < name: "BService" @@ -485,7 +421,7 @@ func TestLoadWithInconsistentTargetPackage(t *testing.T) { proto_file < name: 'a.proto' package: 'example.foo' - options < go_package: 'foo' > + options < go_package: 'github.com/grpc-ecosystem/grpc-gateway/runtime/internal/example.foo' > message_type < name: 'A' > service < name: "AService" @@ -502,7 +438,7 @@ func TestLoadWithInconsistentTargetPackage(t *testing.T) { proto_file < name: 'b.proto' package: 'example.foo' - options < go_package: 'foo' > + options < go_package: 'github.com/grpc-ecosystem/grpc-gateway/runtime/internal/example.foo' > message_type < name: 'B' > service < name: "BService" @@ -580,6 +516,7 @@ func TestUnboundExternalHTTPRules(t *testing.T) { loadFile(t, reg, ` name: "path/to/example.proto", package: "example" + options < go_package: 'github.com/grpc-ecosystem/grpc-gateway/runtime/internal/example' > message_type < name: "StringMessage" field < @@ -606,7 +543,7 @@ func TestRegisterOpenAPIOptions(t *testing.T) { proto_file < name: 'a.proto' package: 'example.foo' - options < go_package: 'foo' > + options < go_package: 'github.com/grpc-ecosystem/grpc-gateway/runtime/internal/example' > message_type < name: 'ExampleMessage' field < diff --git a/gateway/internal/descriptor/services.go b/gateway/internal/descriptor/services.go index 8e5187c..6e2249e 100644 --- a/gateway/internal/descriptor/services.go +++ b/gateway/internal/descriptor/services.go @@ -328,7 +328,7 @@ func (r *Registry) newParam(meth *Method, path string) (Parameter, error) { if IsWellKnownType(*target.TypeName) { glog.V(2).Infoln("found well known aggregate type:", target) } else { - return Parameter{}, fmt.Errorf("aggregate type %s in parameter of %s.%s: %s", target.Type, meth.Service.GetName(), meth.GetName(), path) + return Parameter{}, fmt.Errorf("%s.%s: %s is a protobuf message type. Protobuf message types cannot be used as path parameters, use a scalar value type (such as string) instead", meth.Service.GetName(), meth.GetName(), path) } } return Parameter{ @@ -408,6 +408,9 @@ func (r *Registry) resolveFieldPath(msg *Message, path string, isPathParam bool) if !(isPathParam || r.allowRepeatedFieldsInBody) && f.GetLabel() == descriptorpb.FieldDescriptorProto_LABEL_REPEATED { return nil, fmt.Errorf("repeated field not allowed in field path: %s in %s", f.GetName(), path) } + if isPathParam && f.GetProto3Optional() { + return nil, fmt.Errorf("optional field not allowed in field path: %s in %s", f.GetName(), path) + } result = append(result, FieldPathComponent{Name: c, Target: f}) } return result, nil diff --git a/gateway/internal/descriptor/services_test.go b/gateway/internal/descriptor/services_test.go index 6214fcc..8ce91f1 100644 --- a/gateway/internal/descriptor/services_test.go +++ b/gateway/internal/descriptor/services_test.go @@ -2,6 +2,7 @@ package descriptor import ( "reflect" + "strings" "testing" "github.com/grpc-ecosystem/grpc-gateway/v2/internal/httprule" @@ -1347,3 +1348,100 @@ func TestExtractServicesWithDeleteBody(t *testing.T) { t.Log(err) } } + +func TestCauseErrorWithPathParam(t *testing.T) { + src := ` + name: "path/to/example.proto", + package: "example" + message_type < + name: "TypeMessage" + field < + name: "message" + type: TYPE_MESSAGE + type_name: 'ExampleMessage' + number: 1, + label: LABEL_OPTIONAL + > + > + service < + name: "ExampleService" + method < + name: "Echo" + input_type: "TypeMessage" + output_type: "TypeMessage" + options < + [google.api.http] < + get: "/v1/example/echo/{message=*}" + > + > + > + > + ` + var fd descriptorpb.FileDescriptorProto + if err := prototext.Unmarshal([]byte(src), &fd); err != nil { + t.Fatalf("proto.UnmarshalText(%s, &fd) failed with %v; want success", src, err) + } + target := "path/to/example.proto" + reg := NewRegistry() + input := []*descriptorpb.FileDescriptorProto{&fd} + reg.loadFile(fd.GetName(), &protogen.File{ + Proto: &fd, + }) + // switch this field to see the error + wantErr := true + err := reg.loadServices(reg.files[target]) + if got, want := err != nil, wantErr; got != want { + if want { + t.Errorf("loadServices(%q, %q) succeeded; want an error", target, input) + } + t.Errorf("loadServices(%q, %q) failed with %v; want success", target, input, err) + } +} + +func TestOptionalProto3URLPathMappingError(t *testing.T) { + src := ` + name: "path/to/example.proto" + package: "example" + message_type < + name: "StringMessage" + field < + name: "field1" + number: 1 + type: TYPE_STRING + proto3_optional: true + > + > + service < + name: "ExampleService" + method < + name: "Echo" + input_type: "StringMessage" + output_type: "StringMessage" + options < + [google.api.http] < + get: "/v1/example/echo/{field1=*}" + > + > + > + > + ` + var fd descriptorpb.FileDescriptorProto + if err := prototext.Unmarshal([]byte(src), &fd); err != nil { + t.Fatalf("proto.UnmarshalText(%s, &fd) failed with %v; want success", src, err) + } + target := "path/to/example.proto" + reg := NewRegistry() + input := []*descriptorpb.FileDescriptorProto{&fd} + reg.loadFile(fd.GetName(), &protogen.File{ + Proto: &fd, + }) + wantErrMsg := "field not allowed in field path: field1 in field1" + err := reg.loadServices(reg.files[target]) + if err != nil { + if !strings.Contains(err.Error(), wantErrMsg) { + t.Errorf("loadServices(%q, %q) failed with %v; want %s", target, input, err, wantErrMsg) + } + } else { + t.Errorf("loadServices(%q, %q) expcted an error %s, got nil", target, input, wantErrMsg) + } +} diff --git a/gateway/internal/descriptor/types.go b/gateway/internal/descriptor/types.go index ef2c0d7..f8b8626 100644 --- a/gateway/internal/descriptor/types.go +++ b/gateway/internal/descriptor/types.go @@ -27,7 +27,7 @@ type GoPackage struct { Path string // Name is the package name of the package Name string - // Alias is an alias of the package unique within the current invocation of grpc-gateway generator. + // Alias is an alias of the package unique within the current invocation of gRPC-Gateway generator. Alias string } @@ -509,6 +509,8 @@ func (p Parameter) ConvertFuncExpr() (string, error) { tbl := proto3ConvertFuncs if !p.IsProto2() && p.IsRepeated() { tbl = proto3RepeatedConvertFuncs + } else if !p.IsProto2() && p.IsOptionalProto3() { + tbl = proto3OptionalConvertFuncs } else if p.IsProto2() && !p.IsRepeated() { tbl = proto2ConvertFuncs } else if p.IsProto2() && p.IsRepeated() { @@ -574,6 +576,14 @@ func (p FieldPath) IsNestedProto3() bool { return false } +// IsOptionalProto3 indicates whether the FieldPath is a proto3 optional field. +func (p FieldPath) IsOptionalProto3() bool { + if len(p) == 0 { + return false + } + return p[0].Target.GetProto3Optional() +} + // AssignableExpr is an assignable expression in Go to be used to assign a value to the target field. // It starts with "msgExpr", which is the go expression of the method request object. func (p FieldPath) AssignableExpr(msgExpr string) string { @@ -585,8 +595,10 @@ func (p FieldPath) AssignableExpr(msgExpr string) string { var preparations []string components := msgExpr for i, c := range p { - // Check if it is a oneOf field. - if c.Target.OneofIndex != nil { + // We need to check if the target is not proto3_optional first. + // Under the hood, proto3_optional uses oneof to signal to old proto3 clients + // that presence is tracked for this field. This oneof is known as a "synthetic" oneof. + if !c.Target.GetProto3Optional() && c.Target.OneofIndex != nil { index := c.Target.OneofIndex msg := c.Target.Message oneOfName := casing.Camel(msg.GetOneofDecl()[*index].GetName()) @@ -662,6 +674,18 @@ var ( descriptorpb.FieldDescriptorProto_TYPE_SINT64: "runtime.Int64", } + proto3OptionalConvertFuncs = func() map[descriptorpb.FieldDescriptorProto_Type]string { + result := make(map[descriptorpb.FieldDescriptorProto_Type]string) + for typ, converter := range proto3ConvertFuncs { + // TODO: this will use convert functions from proto2. + // The converters returning pointers should be moved + // to a more generic file. + result[typ] = converter + "P" + } + return result + }() + + // TODO: replace it with a IIFE proto3RepeatedConvertFuncs = map[descriptorpb.FieldDescriptorProto_Type]string{ descriptorpb.FieldDescriptorProto_TYPE_DOUBLE: "runtime.Float64Slice", descriptorpb.FieldDescriptorProto_TYPE_FLOAT: "runtime.Float32Slice", diff --git a/gateway/internal/descriptor/types_test.go b/gateway/internal/descriptor/types_test.go index 60e5bc0..1887764 100644 --- a/gateway/internal/descriptor/types_test.go +++ b/gateway/internal/descriptor/types_test.go @@ -3,8 +3,8 @@ package descriptor import ( "testing" - descriptorpb "github.com/golang/protobuf/protoc-gen-go/descriptor" "google.golang.org/protobuf/encoding/prototext" + "google.golang.org/protobuf/types/descriptorpb" ) func TestGoPackageStandard(t *testing.T) { @@ -130,7 +130,7 @@ func TestFieldPath(t *testing.T) { } fds = append(fds, &fd) } - nest := &Message{ + nest1 := &Message{ DescriptorProto: fds[0].MessageType[0], Fields: []*Field{ {FieldDescriptorProto: fds[0].MessageType[0].Field[0]}, @@ -147,7 +147,7 @@ func TestFieldPath(t *testing.T) { file1 := &File{ FileDescriptorProto: fds[0], GoPkg: GoPackage{Path: "example", Name: "example"}, - Messages: []*Message{nest}, + Messages: []*Message{nest1}, } file2 := &File{ FileDescriptorProto: fds[1], @@ -170,7 +170,7 @@ func TestFieldPath(t *testing.T) { c2 := FieldPathComponent{ Name: "nest2_field", - Target: nest.Fields[0], + Target: nest1.Fields[0], } if got, want := c2.ValueExpr(), "Nest2Field"; got != want { t.Errorf("c2.ValueExpr() = %q; want %q", got, want) @@ -182,7 +182,7 @@ func TestFieldPath(t *testing.T) { fp := FieldPath{ c1, c2, c1, FieldPathComponent{ Name: "terminal_field", - Target: nest.Fields[1], + Target: nest1.Fields[1], }, } if got, want := fp.AssignableExpr("resp"), "resp.GetNestField().Nest2Field.GetNestField().TerminalField"; got != want { diff --git a/gateway/internal/generator/BUILD.bazel b/gateway/internal/generator/BUILD.bazel index c17f265..fec2a2c 100644 --- a/gateway/internal/generator/BUILD.bazel +++ b/gateway/internal/generator/BUILD.bazel @@ -3,11 +3,14 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library") package(default_visibility = ["//visibility:public"]) go_library( - name = "go_default_library", + name = "generator", srcs = ["generator.go"], importpath = "github.com/binchencoder/ease-gateway/gateway/internal/generator", - deps = [ - "//gateway/internal/descriptor:go_default_library", - "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", - ], + deps = ["//gateway/internal/descriptor:go_default_library"], +) + +alias( + name = "go_default_library", + actual = ":generator", + visibility = ["//:__subpackages__"], ) diff --git a/gateway/protoc-gen-grpc-gateway/BUILD.bazel b/gateway/protoc-gen-grpc-gateway/BUILD.bazel index edbd060..6d60b23 100644 --- a/gateway/protoc-gen-grpc-gateway/BUILD.bazel +++ b/gateway/protoc-gen-grpc-gateway/BUILD.bazel @@ -4,20 +4,21 @@ load("@io_bazel_rules_go//proto:compiler.bzl", "go_proto_compiler") package(default_visibility = ["//visibility:private"]) go_library( - name = "go_default_library", + name = "protoc-gen-grpc-gateway_lib", srcs = ["main.go"], importpath = "github.com/binchencoder/ease-gateway/gateway/protoc-gen-grpc-gateway", deps = [ + "@com_github_grpc_ecosystem_grpc_gateway//internal/codegenerator", "//gateway/internal/descriptor:go_default_library", - "//gateway/protoc-gen-grpc-gateway/internal/gengateway:go_default_library", - "@com_github_golang_glog//:go_default_library", - "@org_golang_google_protobuf//compiler/protogen:go_default_library", + "//gateway/protoc-gen-grpc-gateway/internal/gengateway", + "@com_github_golang_glog//:glog", + "@org_golang_google_protobuf//compiler/protogen", ], ) go_binary( name = "protoc-gen-grpc-gateway", - embed = [":go_default_library"], + embed = [":protoc-gen-grpc-gateway_lib"], visibility = ["//visibility:public"], ) @@ -34,7 +35,7 @@ go_proto_compiler( "//gateway/runtime:go_default_library", "@com_github_binchencoder_gateway_proto//data:go_default_library", "@com_github_binchencoder_gateway_proto//frontend:go_default_library", - "@com_github_grpc_ecosystem_grpc_gateway//utilities:go_default_library", + "@com_github_grpc_ecosystem_grpc_gateway//utilities", "@org_golang_google_grpc//:go_default_library", "@org_golang_google_grpc//codes:go_default_library", "@org_golang_google_grpc//grpclog:go_default_library", @@ -45,8 +46,8 @@ go_proto_compiler( ) go_test( - name = "go_default_test", + name = "protoc-gen-grpc-gateway_test", srcs = ["main_test.go"], - embed = [":go_default_library"], - deps = ["//gateway/internal/descriptor:go_default_library"], + embed = [":protoc-gen-grpc-gateway_lib"], + deps = ["//gateway/internal/descriptor"], ) diff --git a/gateway/protoc-gen-grpc-gateway/internal/gengateway/BUILD.bazel b/gateway/protoc-gen-grpc-gateway/internal/gengateway/BUILD.bazel index 2e868bb..555e8fa 100644 --- a/gateway/protoc-gen-grpc-gateway/internal/gengateway/BUILD.bazel +++ b/gateway/protoc-gen-grpc-gateway/internal/gengateway/BUILD.bazel @@ -3,7 +3,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") package(default_visibility = ["//visibility:public"]) go_library( - name = "go_default_library", + name = "gengateway", srcs = [ "doc.go", "generator.go", @@ -11,29 +11,35 @@ go_library( ], importpath = "github.com/binchencoder/ease-gateway/gateway/protoc-gen-grpc-gateway/internal/gengateway", deps = [ - "//httpoptions:go_default_library", - "//gateway/internal/casing:go_default_library", - "//gateway/internal/descriptor:go_default_library", - "//gateway/internal/generator:go_default_library", - "@com_github_grpc_ecosystem_grpc_gateway//utilities:go_default_library", - "@com_github_golang_glog//:go_default_library", - "@org_golang_google_protobuf//proto:go_default_library", - "@org_golang_google_protobuf//types/pluginpb:go_default_library", + "//httpoptions", + "//gateway/internal/casing", + "//gateway/internal/descriptor", + "//gateway/internal/generator", + "@com_github_grpc_ecosystem_grpc_gateway//utilities", + "@com_github_golang_glog//:glog", + "@org_golang_google_protobuf//proto", + "@org_golang_google_protobuf//types/pluginpb", ], ) go_test( - name = "go_default_test", + name = "gengateway_test", size = "small", srcs = [ "generator_test.go", "template_test.go", ], - embed = [":go_default_library"], + embed = [":gengateway"], deps = [ - "//gateway/internal/descriptor:go_default_library", - "@com_github_grpc_ecosystem_grpc_gateway//internal/httprule:go_default_library", - "@org_golang_google_protobuf//proto:go_default_library", - "@org_golang_google_protobuf//types/descriptorpb:go_default_library", + "//gateway/internal/descriptor", + "@com_github_grpc_ecosystem_grpc_gateway//internal/httprule", + "@org_golang_google_protobuf//proto", + "@org_golang_google_protobuf//types/descriptorpb", ], ) + +alias( + name = "go_default_library", + actual = ":gengateway", + visibility = ["//protoc-gen-grpc-gateway:__subpackages__"], +) diff --git a/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator.go b/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator.go index 9e9e682..42f26d3 100644 --- a/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator.go +++ b/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator.go @@ -3,15 +3,16 @@ package gengateway import ( "errors" "fmt" + "go/format" + "path" + "github.com/golang/glog" // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor" "github.com/binchencoder/ease-gateway/gateway/internal/descriptor" // gen "github.com/grpc-ecosystem/grpc-gateway/v2/internal/generator" gen "github.com/binchencoder/ease-gateway/gateway/internal/generator" - "go/format" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/pluginpb" - "path" ) var ( @@ -41,7 +42,7 @@ func New(reg *descriptor.Registry, useRequestContext bool, registerFuncSuffix st "unicode/utf8": "", // "github.com/grpc-ecosystem/grpc-gateway/v2/runtime", "github.com/binchencoder/ease-gateway/gateway/runtime": "", - "github.com/grpc-ecosystem/grpc-gateway/v2/utilities": "", + "github.com/grpc-ecosystem/grpc-gateway/v2/utilities": "", "google.golang.org/protobuf/proto": "", "github.com/binchencoder/gateway-proto/data": "vexpb", "github.com/binchencoder/gateway-proto/frontend": "fpb", @@ -52,10 +53,10 @@ func New(reg *descriptor.Registry, useRequestContext bool, registerFuncSuffix st "github.com/binchencoder/skylb-api/proto": "skypb", "google.golang.org/grpc": "", "google.golang.org/grpc/codes": "", - "google.golang.org/grpc/naming": "", - "google.golang.org/grpc/grpclog": "", - "google.golang.org/grpc/metadata": "", - "google.golang.org/grpc/status": "", + // "google.golang.org/grpc/naming": "", + "google.golang.org/grpc/grpclog": "", + "google.golang.org/grpc/metadata": "", + "google.golang.org/grpc/status": "", } { pkg := descriptor.GoPackage{ Path: pkgpath, diff --git a/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator_test.go b/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator_test.go index 9e30d4c..e2d73f3 100644 --- a/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator_test.go +++ b/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator_test.go @@ -78,6 +78,7 @@ func newExampleFileDescriptorWithGoPkg(gp *descriptor.GoPackage, filenamePrefix func TestGenerator_Generate(t *testing.T) { g := new(generator) + g.reg = descriptor.NewRegistry() result, err := g.Generate([]*descriptor.File{ crossLinkFixture(newExampleFileDescriptorWithGoPkg(&descriptor.GoPackage{ Path: "example.com/path/to/example", diff --git a/gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go b/gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go index 5cd7480..5b039c0 100644 --- a/gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go +++ b/gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go @@ -39,7 +39,7 @@ func (b binding) GetBodyFieldPath() string { return "*" } -// GetBodyFieldPath returns the binding body's struct field name. +// GetBodyFieldStructName returns the binding body's struct field name. func (b binding) GetBodyFieldStructName() (string, error) { if b.Body != nil && len(b.Body.FieldPath) != 0 { return casing.Camel(b.Body.FieldPath.String()), nil @@ -173,11 +173,6 @@ func applyTemplate(p param, reg *descriptor.Registry) (string, error) { if err := headerTemplate.Execute(w, p); err != nil { return "", err } - - if err := validatorTemplate.Execute(w, p); err != nil { - return "", err - } - var targetServices []*descriptor.Service for _, msg := range p.Messages { @@ -195,6 +190,10 @@ func applyTemplate(p param, reg *descriptor.Registry) (string, error) { methName := casing.Camel(*meth.Name) meth.Name = &methName for _, b := range meth.Bindings { + if err := reg.CheckDuplicateAnnotation(b.HTTPMethod, b.PathTmpl.Template, svc); err != nil { + return "", err + } + methodWithBindingsSeen = true if err := handlerTemplate.Execute(w, binding{ Binding: b, @@ -651,15 +650,6 @@ var ( } 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 { @@ -816,12 +806,17 @@ func Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}Server(ctx context.Context, var stream runtime.ServerTransportStream ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/{{$svc.File.GetPackage}}.{{$svc.GetName}}/{{$m.GetName}}") + var err error + {{- if $b.PathTmpl }} + ctx, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/{{$svc.File.GetPackage}}.{{$svc.GetName}}/{{$m.GetName}}", runtime.WithHTTPPathPattern("{{$b.PathTmpl.Template}}")) + {{- else -}} + ctx, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/{{$svc.File.GetPackage}}.{{$svc.GetName}}/{{$m.GetName}}") + {{- end }} 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) + resp, md, err := local_request_{{$svc.GetName}}_{{$m.GetName}}_{{$b.Index}}(ctx, inboundMarshaler, server, req, pathParams) md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { @@ -872,7 +867,7 @@ func init() { {{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(mux *runtime.ServeMux) (err error) { +func Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}FromEndpoint(ctx context.Context, mux *runtime.ServeMux) (err error) { // conn, err := grpc.Dial(endpoint, opts...) // if err != nil { // return err @@ -892,8 +887,8 @@ func Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}FromEndpoint(mux *runtime.S // }() // }() - // return Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}(ctx, mux, conn) - return Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}(nil, mux, nil) + return Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}(ctx, mux, conn) + // return Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}(nil, mux, nil) } // Register{{$svc.GetName}}{{$.RegisterFuncSuffix}} registers the http handlers for service {{$svc.GetName}} to "mux". @@ -939,12 +934,17 @@ func Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}Client(ctx context.Context, {{- end }} defer cancel() // inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req, "/{{$svc.File.GetPackage}}.{{$svc.GetName}}/{{$m.GetName}}") + var err error + {{- if $b.PathTmpl }} + ctx, err = runtime.AnnotateContext(ctx, mux, req, "/{{$svc.File.GetPackage}}.{{$svc.GetName}}/{{$m.GetName}}", runtime.WithHTTPPathPattern("{{$b.PathTmpl.Template}}")) + {{- else -}} + ctx, err = runtime.AnnotateContext(ctx, mux, req, "/{{$svc.File.GetPackage}}.{{$svc.GetName}}/{{$m.GetName}}") + {{- end }} 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) + resp, md, err := request_{{$svc.GetName}}_{{$m.GetName}}_{{$b.Index}}(ctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) diff --git a/gateway/protoc-gen-grpc-gateway/internal/gengateway/template_test.go b/gateway/protoc-gen-grpc-gateway/internal/gengateway/template_test.go index 28db071..b9730a6 100644 --- a/gateway/protoc-gen-grpc-gateway/internal/gengateway/template_test.go +++ b/gateway/protoc-gen-grpc-gateway/internal/gengateway/template_test.go @@ -30,6 +30,14 @@ func crossLinkFixture(f *descriptor.File) *descriptor.File { return f } +func compilePath(t *testing.T, path string) httprule.Template { + parsed, err := httprule.Parse(path) + if err != nil { + t.Fatalf("httprule.Parse(%q) failed with %v; want success", path, err) + } + return parsed.Compile() +} + func TestApplyTemplateHeader(t *testing.T) { msgdesc := &descriptorpb.DescriptorProto{ Name: proto.String("ExampleMessage"), @@ -186,8 +194,9 @@ func TestApplyTemplateRequestWithoutClientStreaming(t *testing.T) { { HTTPMethod: "POST", PathTmpl: httprule.Template{ - Version: 1, - OpCodes: []int{0, 0}, + Version: 1, + OpCodes: []int{0, 0}, + Template: "/v1", }, PathParams: []descriptor.Parameter{ { @@ -246,7 +255,7 @@ func TestApplyTemplateRequestWithoutClientStreaming(t *testing.T) { if want := `pattern_ExampleService_Echo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{0, 0}, []string(nil), ""))`; !strings.Contains(got, want) { t.Errorf("applyTemplate(%#v) = %s; want to contain %s", file, got, want) } - if want := `rctx, err := runtime.AnnotateContext(ctx, mux, req, "/example.ExampleService/Echo")`; !strings.Contains(got, want) { + if want := `ctx, err = runtime.AnnotateContext(ctx, mux, req, "/example.ExampleService/Echo", runtime.WithHTTPPathPattern("/v1"))`; !strings.Contains(got, want) { t.Errorf("applyTemplate(%#v) = %s; want to contain %s", file, got, want) } } @@ -454,7 +463,7 @@ func TestApplyTemplateInProcess(t *testing.T) { serverStreaming: false, sigWant: []string{ `func local_request_ExampleService_Echo_0(ctx context.Context, marshaler runtime.Marshaler, server ExampleServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {`, - `resp, md, err := local_request_ExampleService_Echo_0(rctx, inboundMarshaler, server, req, pathParams)`, + `resp, md, err := local_request_ExampleService_Echo_0(ctx, inboundMarshaler, server, req, pathParams)`, }, }, { @@ -675,7 +684,7 @@ func TestIdentifierCapitalization(t *testing.T) { OutputType: proto.String("example_response"), } meth2 := &descriptorpb.MethodDescriptorProto{ - Name: proto.String("Exampl_eGet"), + Name: proto.String("Exampl_ePost"), InputType: proto.String("Exam_pleRequest"), OutputType: proto.String("example_response"), } @@ -728,7 +737,7 @@ func TestIdentifierCapitalization(t *testing.T) { ResponseType: msg2, Bindings: []*descriptor.Binding{ { - HTTPMethod: "GET", + HTTPMethod: "POST", Body: &descriptor.Body{FieldPath: nil}, }, }, @@ -746,7 +755,7 @@ func TestIdentifierCapitalization(t *testing.T) { if want := `msg, err := client.ExampleGe2T(ctx, &protoReq, grpc.Header(&metadata.HeaderMD)`; !strings.Contains(got, want) { t.Errorf("applyTemplate(%#v) = %s; want to contain %s", file, got, want) } - if want := `msg, err := client.ExamplEGet(ctx, &protoReq, grpc.Header(&metadata.HeaderMD)`; !strings.Contains(got, want) { + if want := `msg, err := client.ExamplEPost(ctx, &protoReq, grpc.Header(&metadata.HeaderMD)`; !strings.Contains(got, want) { t.Errorf("applyTemplate(%#v) = %s; want to contain %s", file, got, want) } if want := `var protoReq ExamPleRequest`; !strings.Contains(got, want) { @@ -756,3 +765,164 @@ func TestIdentifierCapitalization(t *testing.T) { t.Errorf("applyTemplate(%#v) = %s; want to contain %s", file, got, want) } } + +func TestDuplicatePathsInSameService(t *testing.T) { + msgdesc := &descriptorpb.DescriptorProto{ + Name: proto.String("ExampleMessage"), + Field: []*descriptorpb.FieldDescriptorProto{ + { + Name: proto.String("nested"), + Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), + TypeName: proto.String(".google.protobuf.StringValue"), + Number: proto.Int32(1), + }, + }, + } + meth1 := &descriptorpb.MethodDescriptorProto{ + Name: proto.String("Echo"), + InputType: proto.String("ExampleMessage"), + OutputType: proto.String("ExampleMessage"), + } + meth2 := &descriptorpb.MethodDescriptorProto{ + Name: proto.String("Echo2"), + InputType: proto.String("ExampleMessage"), + OutputType: proto.String("ExampleMessage"), + } + svc := &descriptorpb.ServiceDescriptorProto{ + Name: proto.String("ExampleService"), + Method: []*descriptorpb.MethodDescriptorProto{meth1, meth2}, + } + msg := &descriptor.Message{ + DescriptorProto: msgdesc, + } + binding := &descriptor.Binding{ + Index: 1, + PathTmpl: compilePath(t, "/v1/example/echo"), + HTTPMethod: "GET", + PathParams: nil, + Body: nil, + } + file := descriptor.File{ + FileDescriptorProto: &descriptorpb.FileDescriptorProto{ + Name: proto.String("example.proto"), + Package: proto.String("example"), + MessageType: []*descriptorpb.DescriptorProto{msgdesc}, + Service: []*descriptorpb.ServiceDescriptorProto{svc}, + }, + GoPkg: descriptor.GoPackage{ + Path: "example.com/path/to/example/example.pb", + Name: "example_pb", + }, + Messages: []*descriptor.Message{msg}, + Services: []*descriptor.Service{ + { + ServiceDescriptorProto: svc, + Methods: []*descriptor.Method{ + { + MethodDescriptorProto: meth1, + RequestType: msg, + ResponseType: msg, + Bindings: []*descriptor.Binding{binding}, + }, + { + MethodDescriptorProto: meth2, + RequestType: msg, + ResponseType: msg, + Bindings: []*descriptor.Binding{binding}, + }, + }, + }, + }, + } + _, err := applyTemplate(param{File: crossLinkFixture(&file), RegisterFuncSuffix: "Handler", AllowPatchFeature: true}, descriptor.NewRegistry()) + if err == nil { + t.Errorf("applyTemplate(%#v) succeeded; want an error", file) + return + } +} + +func TestDuplicatePathsInDifferentService(t *testing.T) { + msgdesc := &descriptorpb.DescriptorProto{ + Name: proto.String("ExampleMessage"), + Field: []*descriptorpb.FieldDescriptorProto{ + { + Name: proto.String("nested"), + Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), + TypeName: proto.String(".google.protobuf.StringValue"), + Number: proto.Int32(1), + }, + }, + } + meth1 := &descriptorpb.MethodDescriptorProto{ + Name: proto.String("Echo"), + InputType: proto.String("ExampleMessage"), + OutputType: proto.String("ExampleMessage"), + } + meth2 := &descriptorpb.MethodDescriptorProto{ + Name: proto.String("Echo2"), + InputType: proto.String("ExampleMessage"), + OutputType: proto.String("ExampleMessage"), + } + svc1 := &descriptorpb.ServiceDescriptorProto{ + Name: proto.String("ExampleServiceNumberOne"), + Method: []*descriptorpb.MethodDescriptorProto{meth1, meth2}, + } + svc2 := &descriptorpb.ServiceDescriptorProto{ + Name: proto.String("ExampleServiceNumberTwo"), + Method: []*descriptorpb.MethodDescriptorProto{meth1, meth2}, + } + msg := &descriptor.Message{ + DescriptorProto: msgdesc, + } + binding := &descriptor.Binding{ + Index: 1, + PathTmpl: compilePath(t, "/v1/example/echo"), + HTTPMethod: "GET", + PathParams: nil, + Body: nil, + } + file := descriptor.File{ + FileDescriptorProto: &descriptorpb.FileDescriptorProto{ + Name: proto.String("example.proto"), + Package: proto.String("example"), + MessageType: []*descriptorpb.DescriptorProto{msgdesc}, + Service: []*descriptorpb.ServiceDescriptorProto{svc1, svc2}, + }, + GoPkg: descriptor.GoPackage{ + Path: "example.com/path/to/example/example.pb", + Name: "example_pb", + }, + Messages: []*descriptor.Message{msg}, + Services: []*descriptor.Service{ + { + ServiceDescriptorProto: svc1, + Methods: []*descriptor.Method{ + { + MethodDescriptorProto: meth1, + RequestType: msg, + ResponseType: msg, + Bindings: []*descriptor.Binding{binding}, + }, + }, + }, + { + ServiceDescriptorProto: svc2, + Methods: []*descriptor.Method{ + { + MethodDescriptorProto: meth2, + RequestType: msg, + ResponseType: msg, + Bindings: []*descriptor.Binding{binding}, + }, + }, + }, + }, + } + _, err := applyTemplate(param{File: crossLinkFixture(&file), RegisterFuncSuffix: "Handler", AllowPatchFeature: true}, descriptor.NewRegistry()) + if err != nil { + t.Errorf("applyTemplate(%#v) failed; want success", file) + return + } +} diff --git a/gateway/protoc-gen-grpc-gateway/main.go b/gateway/protoc-gen-grpc-gateway/main.go index f79141b..5a2c1cb 100644 --- a/gateway/protoc-gen-grpc-gateway/main.go +++ b/gateway/protoc-gen-grpc-gateway/main.go @@ -15,6 +15,8 @@ import ( "strings" "github.com/golang/glog" + "github.com/grpc-ecosystem/grpc-gateway/v2/internal/codegenerator" + // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor" "github.com/binchencoder/ease-gateway/gateway/internal/descriptor" // "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway/internal/gengateway" @@ -64,6 +66,8 @@ func main() { return err } + codegenerator.SetSupportedFeaturesOnPluginGen(gen) + generator := gengateway.New(reg, *useRequestContext, *registerFuncSuffix, *allowPatchFeature, *standalone) glog.V(1).Infof("Parsing code generator request") diff --git a/gateway/protoc-gen-openapiv2/BUILD.bazel b/gateway/protoc-gen-openapiv2/BUILD.bazel index 5daacad..dda91e1 100644 --- a/gateway/protoc-gen-openapiv2/BUILD.bazel +++ b/gateway/protoc-gen-openapiv2/BUILD.bazel @@ -3,28 +3,29 @@ load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test") package(default_visibility = ["//visibility:private"]) go_library( - name = "go_default_library", + name = "protoc-gen-openapiv2_lib", srcs = ["main.go"], importpath = "github.com/binchencoder/ease-gateway/gateway/protoc-gen-openapiv2", deps = [ - "@com_github_grpc_ecosystem_grpc_gateway//internal/codegenerator:go_default_library", - "//gateway/internal/descriptor:go_default_library", - "//gateway/protoc-gen-openapiv2/internal/genopenapi:go_default_library", - "@com_github_golang_glog//:go_default_library", - "@org_golang_google_protobuf//proto:go_default_library", - "@org_golang_google_protobuf//types/pluginpb:go_default_library", + "@com_github_grpc_ecosystem_grpc_gateway//internal/codegenerator", + "//gateway/internal/descriptor", + "//gateway/protoc-gen-openapiv2/internal/genopenapi", + "@com_github_grpc_ecosystem_grpc_gateway//utilities", + "@com_github_golang_glog//:glog", + "@org_golang_google_protobuf//proto", + "@org_golang_google_protobuf//types/pluginpb", ], ) go_binary( name = "protoc-gen-openapiv2", - embed = [":go_default_library"], + embed = [":protoc-gen-openapiv2_lib"], visibility = ["//visibility:public"], ) go_test( - name = "go_default_test", + name = "protoc-gen-openapiv2_test", size = "small", srcs = ["main_test.go"], - embed = [":go_default_library"], + embed = [":protoc-gen-openapiv2_lib"], ) diff --git a/gateway/protoc-gen-openapiv2/defs.bzl b/gateway/protoc-gen-openapiv2/defs.bzl index 146bc1e..1dbdfc4 100644 --- a/gateway/protoc-gen-openapiv2/defs.bzl +++ b/gateway/protoc-gen-openapiv2/defs.bzl @@ -27,12 +27,12 @@ def _direct_source_infos(proto_info, provided_sources = []): source_root = proto_info.proto_source_root if "." == source_root: - return [struct(file = src, import_path = src.path) for src in proto_info.direct_sources] + return [struct(file = src, import_path = src.path) for src in proto_info.check_deps_sources.to_list()] offset = len(source_root) + 1 # + '/'. infos = [] - for src in proto_info.direct_sources: + for src in proto_info.check_deps_sources.to_list(): # TODO(yannic): Remove this hack when we drop support for Bazel < 1.0. local_offset = offset if src.root.path and not source_root.startswith(src.root.path): @@ -51,10 +51,24 @@ def _run_proto_gen_openapi( transitive_proto_srcs, protoc, protoc_gen_openapiv2, - grpc_api_configuration, single_output, + allow_delete_body, + grpc_api_configuration, json_names_for_fields, - fqn_for_openapi_name): + repeated_path_param_separator, + include_package_in_tags, + fqn_for_openapi_name, + openapi_naming_strategy, + use_go_templates, + disable_default_errors, + enums_as_ints, + omit_enum_default_value, + output_format, + simple_operation_ids, + proto3_optional_nullable, + openapi_configuration, + generate_unbound_methods, + visibility_restriction_selectors): args = actions.args() args.add("--plugin", "protoc-gen-openapiv2=%s" % protoc_gen_openapiv2.path) @@ -67,11 +81,53 @@ def _run_proto_gen_openapi( extra_inputs.append(grpc_api_configuration) args.add("--openapiv2_opt", "grpc_api_configuration=%s" % grpc_api_configuration.path) + if openapi_configuration: + extra_inputs.append(openapi_configuration) + args.add("--openapiv2_opt", "openapi_configuration=%s" % openapi_configuration.path) + if not json_names_for_fields: args.add("--openapiv2_opt", "json_names_for_fields=false") if fqn_for_openapi_name: - args.add("--openapi_opt", "fqn_for_openapi_name=true") + args.add("--openapiv2_opt", "fqn_for_openapi_name=true") + + if openapi_naming_strategy: + args.add("--openapiv2_opt", "openapi_naming_strategy=%s" % openapi_naming_strategy) + + if generate_unbound_methods: + args.add("--openapiv2_opt", "generate_unbound_methods=true") + + if simple_operation_ids: + args.add("--openapiv2_opt", "simple_operation_ids=true") + + if allow_delete_body: + args.add("--openapiv2_opt", "allow_delete_body=true") + + if include_package_in_tags: + args.add("--openapiv2_opt", "include_package_in_tags=true") + + if use_go_templates: + args.add("--openapiv2_opt", "use_go_templates=true") + + if disable_default_errors: + args.add("--openapiv2_opt", "disable_default_errors=true") + + if enums_as_ints: + args.add("--openapiv2_opt", "enums_as_ints=true") + + if omit_enum_default_value: + args.add("--openapiv2_opt", "omit_enum_default_value=true") + + if output_format: + args.add("--openapiv2_opt", "output_format=%s" % output_format) + + if proto3_optional_nullable: + args.add("--openapiv2_opt", "proto3_optional_nullable=true") + + for visibility_restriction_selector in visibility_restriction_selectors: + args.add("--openapiv2_opt", "visibility_restriction_selectors=%s" % visibility_restriction_selector) + + args.add("--openapiv2_opt", "repeated_path_param_separator=%s" % repeated_path_param_separator) proto_file_infos = _direct_source_infos(proto_info) @@ -154,10 +210,24 @@ def _proto_gen_openapi_impl(ctx): ), protoc = ctx.executable._protoc, protoc_gen_openapiv2 = ctx.executable._protoc_gen_openapi, - grpc_api_configuration = ctx.file.grpc_api_configuration, single_output = ctx.attr.single_output, + allow_delete_body = ctx.attr.allow_delete_body, + grpc_api_configuration = ctx.file.grpc_api_configuration, json_names_for_fields = ctx.attr.json_names_for_fields, + repeated_path_param_separator = ctx.attr.repeated_path_param_separator, + include_package_in_tags = ctx.attr.include_package_in_tags, fqn_for_openapi_name = ctx.attr.fqn_for_openapi_name, + openapi_naming_strategy = ctx.attr.openapi_naming_strategy, + use_go_templates = ctx.attr.use_go_templates, + disable_default_errors = ctx.attr.disable_default_errors, + enums_as_ints = ctx.attr.enums_as_ints, + omit_enum_default_value = ctx.attr.omit_enum_default_value, + output_format = ctx.attr.output_format, + simple_operation_ids = ctx.attr.simple_operation_ids, + proto3_optional_nullable = ctx.attr.proto3_optional_nullable, + openapi_configuration = ctx.file.openapi_configuration, + generate_unbound_methods = ctx.attr.generate_unbound_methods, + visibility_restriction_selectors = ctx.attr.visibility_restriction_selectors, ), ), ), @@ -169,21 +239,112 @@ protoc_gen_openapiv2 = rule( mandatory = True, providers = [ProtoInfo], ), - "grpc_api_configuration": attr.label( - allow_single_file = True, + "single_output": attr.bool( + default = False, mandatory = False, + doc = "if set, the rule will generate a single OpenAPI file", ), - "single_output": attr.bool( + "allow_delete_body": attr.bool( default = False, mandatory = False, + doc = "unless set, HTTP DELETE methods may not have a body", + ), + "grpc_api_configuration": attr.label( + allow_single_file = True, + mandatory = False, + doc = "path to file which describes the gRPC API Configuration in YAML format", ), "json_names_for_fields": attr.bool( default = True, mandatory = False, + doc = "if disabled, the original proto name will be used for generating OpenAPI definitions", + ), + "repeated_path_param_separator": attr.string( + default = "csv", + mandatory = False, + values = ["csv", "pipes", "ssv", "tsv"], + doc = "configures how repeated fields should be split." + + " Allowed values are `csv`, `pipes`, `ssv` and `tsv`", + ), + "include_package_in_tags": attr.bool( + default = False, + mandatory = False, + doc = "if unset, the gRPC service name is added to the `Tags`" + + " field of each operation. If set and the `package` directive" + + " is shown in the proto file, the package name will be " + + " prepended to the service name", ), "fqn_for_openapi_name": attr.bool( default = False, mandatory = False, + doc = "if set, the object's OpenAPI names will use the fully" + + " qualified names from the proto definition" + + " (ie my.package.MyMessage.MyInnerMessage", + ), + "openapi_naming_strategy": attr.string( + default = "", + mandatory = False, + values = ["", "simple", "legacy", "fqn"], + doc = "configures how OpenAPI names are determined." + + " Allowed values are `` (empty), `simple`, `legacy` and `fqn`." + + " If unset, either `legacy` or `fqn` are selected, depending" + + " on the value of the `fqn_for_openapi_name` setting", + ), + "use_go_templates": attr.bool( + default = False, + mandatory = False, + doc = "if set, you can use Go templates in protofile comments", + ), + "disable_default_errors": attr.bool( + default = False, + mandatory = False, + doc = "if set, disables generation of default errors." + + " This is useful if you have defined custom error handling", + ), + "enums_as_ints": attr.bool( + default = False, + mandatory = False, + doc = "whether to render enum values as integers, as opposed to string values", + ), + "omit_enum_default_value": attr.bool( + default = False, + mandatory = False, + doc = "if set, omit default enum value", + ), + "output_format": attr.string( + default = "json", + mandatory = False, + values = ["json", "yaml"], + doc = "output content format. Allowed values are: `json`, `yaml`", + ), + "simple_operation_ids": attr.bool( + default = False, + mandatory = False, + doc = "whether to remove the service prefix in the operationID" + + " generation. Can introduce duplicate operationIDs, use with caution.", + ), + "proto3_optional_nullable": attr.bool( + default = False, + mandatory = False, + doc = "whether Proto3 Optional fields should be marked as x-nullable", + ), + "openapi_configuration": attr.label( + allow_single_file = True, + mandatory = False, + doc = "path to file which describes the OpenAPI Configuration in YAML format", + ), + "generate_unbound_methods": attr.bool( + default = False, + mandatory = False, + doc = "generate swagger metadata even for RPC methods that have" + + " no HttpRule annotation", + ), + "visibility_restriction_selectors": attr.string_list( + mandatory = False, + doc = "list of `google.api.VisibilityRule` visibility labels to include" + + " in the generated output when a visibility annotation is defined." + + " Repeat this option to supply multiple values. Elements without" + + " visibility annotations are unaffected by this setting.", ), "_protoc": attr.label( default = "@com_google_protobuf//:protoc", diff --git a/gateway/protoc-gen-openapiv2/internal/genopenapi/BUILD.bazel b/gateway/protoc-gen-openapiv2/internal/genopenapi/BUILD.bazel index 67c49ae..90b780b 100644 --- a/gateway/protoc-gen-openapiv2/internal/genopenapi/BUILD.bazel +++ b/gateway/protoc-gen-openapiv2/internal/genopenapi/BUILD.bazel @@ -3,54 +3,71 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") package(default_visibility = ["//visibility:public"]) go_library( - name = "go_default_library", + name = "genopenapi", srcs = [ "doc.go", + "format.go", "generator.go", "helpers.go", "helpers_go111_old.go", + "naming.go", "template.go", "types.go", ], importpath = "github.com/binchencoder/ease-gateway/gateway/protoc-gen-openapiv2/internal/genopenapi", deps = [ - "//gateway/internal/casing:go_default_library", - "//gateway/internal/descriptor:go_default_library", - "//gateway/internal/generator:go_default_library", - "//gateway/protoc-gen-openapiv2/options:go_default_library", - "//httpoptions:go_default_library", - "@com_github_golang_glog//:go_default_library", + "//gateway/internal/casing", + "//gateway/internal/descriptor", + "//gateway/internal/generator", + "//gateway/protoc-gen-openapiv2/options", + "//httpoptions", + "@com_github_golang_glog//:glog", "@com_github_golang_protobuf//descriptor:go_default_library_gen", + "@go_googleapis//google/api:annotations_go_proto", + "@go_googleapis//google/api:visibility_go_proto", "@go_googleapis//google/rpc:status_go_proto", + "@in_gopkg_yaml_v2//:yaml_v2", "@io_bazel_rules_go//proto/wkt:any_go_proto", - "@io_bazel_rules_go//proto/wkt:struct_go_proto", - "@org_golang_google_protobuf//encoding/protojson:go_default_library", - "@org_golang_google_protobuf//proto:go_default_library", - "@org_golang_google_protobuf//types/descriptorpb:go_default_library", - "@org_golang_google_protobuf//types/pluginpb:go_default_library", + "@org_golang_google_protobuf//encoding/protojson", + "@org_golang_google_protobuf//proto", + "@org_golang_google_protobuf//types/descriptorpb", + "@org_golang_google_protobuf//types/known/structpb", + "@org_golang_google_protobuf//types/pluginpb", ], ) go_test( - name = "go_default_test", + name = "genopenapi_test", size = "small", - srcs = ["template_test.go"], - embed = [":go_default_library"], + srcs = [ + "cycle_test.go", + ], + embed = [":genopenapi"], deps = [ - "//gateway/internal/descriptor:go_default_library", - "//gateway/internal/descriptor/openapiconfig:go_default_library", - "@com_github_grpc_ecosystem_grpc_gateway//internal/httprule:go_default_library", - "//gateway/protoc-gen-openapiv2/options:go_default_library", - "//gateway/runtime:go_default_library", - "@com_github_google_go_cmp//cmp:go_default_library", + "//gateway/internal/descriptor", + "//gateway/internal/descriptor/openapiconfig", + "@com_github_grpc_ecosystem_grpc_gateway//internal/httprule", + "//gateway/protoc-gen-openapiv2/options", + "//gateway/runtime", + "@com_github_google_go_cmp//cmp", + "@go_googleapis//google/api:annotations_go_proto", + "@go_googleapis//google/api:visibility_go_proto", + "@in_gopkg_yaml_v2//:yaml_v2", "@io_bazel_rules_go//proto/wkt:field_mask_go_proto", - "@org_golang_google_protobuf//proto:go_default_library", - "@org_golang_google_protobuf//reflect/protodesc:go_default_library", - "@org_golang_google_protobuf//types/descriptorpb:go_default_library", - "@org_golang_google_protobuf//types/known/durationpb:go_default_library", - "@org_golang_google_protobuf//types/known/structpb:go_default_library", - "@org_golang_google_protobuf//types/known/timestamppb:go_default_library", - "@org_golang_google_protobuf//types/known/wrapperspb:go_default_library", - "@org_golang_google_protobuf//types/pluginpb:go_default_library", + "@org_golang_google_protobuf//proto", + "@org_golang_google_protobuf//reflect/protodesc", + "@org_golang_google_protobuf//types/descriptorpb", + "@org_golang_google_protobuf//types/known/anypb", + "@org_golang_google_protobuf//types/known/durationpb", + "@org_golang_google_protobuf//types/known/structpb", + "@org_golang_google_protobuf//types/known/timestamppb", + "@org_golang_google_protobuf//types/known/wrapperspb", + "@org_golang_google_protobuf//types/pluginpb", ], ) + +alias( + name = "go_default_library", + actual = ":genopenapi", + visibility = ["//protoc-gen-openapiv2:__subpackages__"], +) diff --git a/gateway/protoc-gen-openapiv2/internal/genopenapi/cycle_test.go b/gateway/protoc-gen-openapiv2/internal/genopenapi/cycle_test.go new file mode 100644 index 0000000..8861315 --- /dev/null +++ b/gateway/protoc-gen-openapiv2/internal/genopenapi/cycle_test.go @@ -0,0 +1,41 @@ +package genopenapi + +import ( + "testing" +) + +func TestCycle(t *testing.T) { + for _, tt := range []struct { + max int + attempt int + e bool + }{ + { + max: 3, + attempt: 3, + e: true, + }, + { + max: 5, + attempt: 6, + }, + { + max: 1000, + attempt: 1001, + }, + } { + + c := newCycleChecker(tt.max) + var final bool + for i := 0; i < tt.attempt; i++ { + final = c.Check("a") + if !final { + break + } + } + + if final != tt.e { + t.Errorf("got: %t wanted: %t", final, tt.e) + } + } +} diff --git a/gateway/protoc-gen-openapiv2/internal/genopenapi/format.go b/gateway/protoc-gen-openapiv2/internal/genopenapi/format.go new file mode 100644 index 0000000..e957acc --- /dev/null +++ b/gateway/protoc-gen-openapiv2/internal/genopenapi/format.go @@ -0,0 +1,43 @@ +package genopenapi + +import ( + "encoding/json" + "errors" + "io" + + "gopkg.in/yaml.v2" +) + +type Format string + +const ( + FormatJSON Format = "json" + FormatYAML Format = "yaml" +) + +type ContentEncoder interface { + Encode(v interface{}) (err error) +} + +func (f Format) Validate() error { + switch f { + case FormatJSON, FormatYAML: + return nil + default: + return errors.New("unknown format: " + string(f)) + } +} + +func (f Format) NewEncoder(w io.Writer) (ContentEncoder, error) { + switch f { + case FormatYAML: + return yaml.NewEncoder(w), nil + case FormatJSON: + enc := json.NewEncoder(w) + enc.SetIndent("", " ") + + return enc, nil + default: + return nil, errors.New("unknown format: " + string(f)) + } +} diff --git a/gateway/protoc-gen-openapiv2/internal/genopenapi/generator.go b/gateway/protoc-gen-openapiv2/internal/genopenapi/generator.go index f3b7a7b..ab67212 100644 --- a/gateway/protoc-gen-openapiv2/internal/genopenapi/generator.go +++ b/gateway/protoc-gen-openapiv2/internal/genopenapi/generator.go @@ -22,7 +22,7 @@ import ( "google.golang.org/protobuf/types/descriptorpb" "google.golang.org/protobuf/types/pluginpb" - //lint:ignore SA1019 known issue, will be replaced when possible + //nolint:staticcheck // Known issue, will be replaced when possible legacydescriptor "github.com/golang/protobuf/descriptor" ) @@ -31,7 +31,8 @@ var ( ) type generator struct { - reg *descriptor.Registry + reg *descriptor.Registry + format Format } type wrapper struct { @@ -39,9 +40,17 @@ type wrapper struct { swagger *openapiSwaggerObject } +type GeneratorOptions struct { + Registry *descriptor.Registry + RecursiveDepth int +} + // New returns a new generator which generates grpc gateway files. -func New(reg *descriptor.Registry) gen.Generator { - return &generator{reg: reg} +func New(reg *descriptor.Registry, format Format) gen.Generator { + return &generator{ + reg: reg, + format: format, + } } // Merge a lot of OpenAPI file (wrapper) to single one OpenAPI file @@ -141,21 +150,25 @@ func extensionMarshalJSON(so interface{}, extensions []extension) ([]byte, error } // encodeOpenAPI converts OpenAPI file obj to pluginpb.CodeGeneratorResponse_File -func encodeOpenAPI(file *wrapper) (*descriptor.ResponseFile, error) { - var formatted bytes.Buffer - enc := json.NewEncoder(&formatted) - enc.SetIndent("", " ") +func encodeOpenAPI(file *wrapper, format Format) (*descriptor.ResponseFile, error) { + var contentBuf bytes.Buffer + enc, err := format.NewEncoder(&contentBuf) + if err != nil { + return nil, err + } + if err := enc.Encode(*file.swagger); err != nil { return nil, err } + name := file.fileName ext := filepath.Ext(name) base := strings.TrimSuffix(name, ext) - output := fmt.Sprintf("%s.swagger.json", base) + output := fmt.Sprintf("%s.swagger."+string(format), base) return &descriptor.ResponseFile{ CodeGeneratorResponse_File: &pluginpb.CodeGeneratorResponse_File{ Name: proto.String(output), - Content: proto.String(formatted.String()), + Content: proto.String(contentBuf.String()), }, }, nil } @@ -205,7 +218,7 @@ func (g *generator) Generate(targets []*descriptor.File) ([]*descriptor.Response if g.reg.IsAllowMerge() { targetOpenAPI := mergeTargetFile(openapis, g.reg.GetMergeFileName()) - f, err := encodeOpenAPI(targetOpenAPI) + f, err := encodeOpenAPI(targetOpenAPI, g.format) if err != nil { return nil, fmt.Errorf("failed to encode OpenAPI for %s: %s", g.reg.GetMergeFileName(), err) } @@ -213,7 +226,7 @@ func (g *generator) Generate(targets []*descriptor.File) ([]*descriptor.Response glog.V(1).Infof("New OpenAPI file will emit") } else { for _, file := range openapis { - f, err := encodeOpenAPI(file) + f, err := encodeOpenAPI(file, g.format) if err != nil { return nil, fmt.Errorf("failed to encode OpenAPI for %s: %s", file.fileName, err) } diff --git a/gateway/protoc-gen-openapiv2/internal/genopenapi/naming.go b/gateway/protoc-gen-openapiv2/internal/genopenapi/naming.go new file mode 100644 index 0000000..338ea2d --- /dev/null +++ b/gateway/protoc-gen-openapiv2/internal/genopenapi/naming.go @@ -0,0 +1,110 @@ +package genopenapi + +import ( + "reflect" + "strings" +) + +// LookupNamingStrategy looks up the given naming strategy and returns the naming +// strategy function for it. The naming strategy function takes in the list of all +// fully-qualified proto message names, and returns a mapping from fully-qualified +// name to OpenAPI name. +func LookupNamingStrategy(strategyName string) func([]string) map[string]string { + switch strings.ToLower(strategyName) { + case "fqn": + return resolveNamesFQN + case "legacy": + return resolveNamesLegacy + case "simple": + return resolveNamesSimple + } + return nil +} + +// resolveNamesFQN uses the fully-qualified proto message name as the +// OpenAPI name, stripping the leading dot. +func resolveNamesFQN(messages []string) map[string]string { + uniqueNames := make(map[string]string, len(messages)) + for _, p := range messages { + // strip leading dot from proto fqn + uniqueNames[p] = p[1:] + } + return uniqueNames +} + +// resolveNamesLegacy takes the names of all proto messages and generates unique references by +// applying the legacy heuristics for deriving unique names: starting from the bottom of the name hierarchy, it +// determines the minimum number of components necessary to yield a unique name, adds one +// to that number, and then concatenates those last components with no separator in between +// to form a unique name. +// +// E.g., if the fully qualified name is `.a.b.C.D`, and there are other messages with fully +// qualified names ending in `.D` but not in `.C.D`, it assigns the unique name `bCD`. +func resolveNamesLegacy(messages []string) map[string]string { + return resolveNamesUniqueWithContext(messages, 1, "") +} + +// resolveNamesSimple takes the names of all proto messages and generates unique references by using a simple +// heuristic: starting from the bottom of the name hierarchy, it determines the minimum +// number of components necessary to yield a unique name, and then concatenates those last +// components with a "." separator in between to form a unique name. +// +// E.g., if the fully qualified name is `.a.b.C.D`, and there are other messages with +// fully qualified names ending in `.D` but not in `.C.D`, it assigns the unique name `C.D`. +func resolveNamesSimple(messages []string) map[string]string { + return resolveNamesUniqueWithContext(messages, 0, ".") +} + +// Take the names of every proto message and generates a unique reference by: +// first, separating each message name into its components by splitting at dots. Then, +// take the shortest suffix slice from each components slice that is unique among all +// messages, and convert it into a component name by taking extraContext additional +// components into consideration and joining all components with componentSeparator. +func resolveNamesUniqueWithContext(messages []string, extraContext int, componentSeparator string) map[string]string { + packagesByDepth := make(map[int][][]string) + uniqueNames := make(map[string]string) + + hierarchy := func(pkg string) []string { + return strings.Split(pkg, ".") + } + + for _, p := range messages { + h := hierarchy(p) + for depth := range h { + if _, ok := packagesByDepth[depth]; !ok { + packagesByDepth[depth] = make([][]string, 0) + } + packagesByDepth[depth] = append(packagesByDepth[depth], h[len(h)-depth:]) + } + } + + count := func(list [][]string, item []string) int { + i := 0 + for _, element := range list { + if reflect.DeepEqual(element, item) { + i++ + } + } + return i + } + + for _, p := range messages { + h := hierarchy(p) + depth := 0 + for ; depth < len(h); depth++ { + // depth + extraContext > 0 ensures that we only break for values of depth when the + // resulting slice of name components is non-empty. Otherwise, we would return the + // empty string as the concise unique name is len(messages) == 1 (which is + // technically correct). + if depth+extraContext > 0 && count(packagesByDepth[depth], h[len(h)-depth:]) == 1 { + break + } + } + start := len(h) - depth - extraContext + if start < 0 { + start = 0 + } + uniqueNames[p] = strings.Join(h[start:], componentSeparator) + } + return uniqueNames +} diff --git a/gateway/protoc-gen-openapiv2/internal/genopenapi/template.go b/gateway/protoc-gen-openapiv2/internal/genopenapi/template.go index 4defa99..5fccfa2 100644 --- a/gateway/protoc-gen-openapiv2/internal/genopenapi/template.go +++ b/gateway/protoc-gen-openapiv2/internal/genopenapi/template.go @@ -5,6 +5,8 @@ import ( "encoding/json" "fmt" "io/ioutil" + "math" + "net/textproto" "os" "reflect" "regexp" @@ -13,9 +15,9 @@ import ( "strings" "sync" "text/template" + "time" "github.com/golang/glog" - structpb "github.com/golang/protobuf/ptypes/struct" // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/casing" "github.com/binchencoder/ease-gateway/gateway/internal/casing" @@ -23,22 +25,34 @@ import ( "github.com/binchencoder/ease-gateway/gateway/internal/descriptor" // openapi_options "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options" openapi_options "github.com/binchencoder/ease-gateway/gateway/protoc-gen-openapiv2/options" + "google.golang.org/genproto/googleapis/api/annotations" + "google.golang.org/genproto/googleapis/api/visibility" "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/descriptorpb" + "google.golang.org/protobuf/types/known/structpb" + options "github.com/binchencoder/ease-gateway/httpoptions" ) +// The OpenAPI specification does not allow for more than one endpoint with the same HTTP method and path. +// This prevents multiple gRPC service methods from sharing the same stripped version of the path and method. +// For example: `GET /v1/{name=organizations/*}/roles` and `GET /v1/{name=users/*}/roles` both get stripped to `GET /v1/{name}/roles`. +// We must make the URL unique by adding a suffix and an incrementing index to each path parameter +// to differentiate the endpoints. +// Since path parameter names do not affect the request contents (i.e. they're replaced in the path) +// this will be hidden from the real grpc gateway consumer. +const pathParamUniqueSuffixDeliminator = "_" + +const paragraphDeliminator = "\n\n" + // wktSchemas are the schemas of well-known-types. // The schemas must match with the behavior of the JSON unmarshaler in // https://github.com/protocolbuffers/protobuf-go/blob/v1.25.0/encoding/protojson/well_known_types.go var wktSchemas = map[string]schemaCore{ ".google.protobuf.FieldMask": { - Type: "array", - Items: (*openapiItemsObject)(&schemaCore{ - Type: "string", - }), + Type: "string", }, ".google.protobuf.Timestamp": { Type: "string", @@ -99,24 +113,38 @@ var wktSchemas = map[string]schemaCore{ }, } -func listEnumNames(enum *descriptor.Enum) (names []string) { +func listEnumNames(reg *descriptor.Registry, enum *descriptor.Enum) (names []string) { for _, value := range enum.GetValue() { + if !isVisible(getEnumValueVisibilityOption(value), reg) { + continue + } + if reg.GetOmitEnumDefaultValue() && value.GetNumber() == 0 { + continue + } names = append(names, value.GetName()) } return names } -func listEnumNumbers(enum *descriptor.Enum) (numbers []string) { +func listEnumNumbers(reg *descriptor.Registry, enum *descriptor.Enum) (numbers []string) { for _, value := range enum.GetValue() { + if reg.GetOmitEnumDefaultValue() && value.GetNumber() == 0 { + continue + } + if !isVisible(getEnumValueVisibilityOption(value), reg) { + continue + } numbers = append(numbers, strconv.Itoa(int(value.GetNumber()))) } return } -func getEnumDefault(enum *descriptor.Enum) string { - for _, value := range enum.GetValue() { - if value.GetNumber() == 0 { - return value.GetName() +func getEnumDefault(reg *descriptor.Registry, enum *descriptor.Enum) string { + if !reg.GetOmitEnumDefaultValue() { + for _, value := range enum.GetValue() { + if value.GetNumber() == 0 { + return value.GetName() + } } } return "" @@ -125,7 +153,11 @@ func getEnumDefault(enum *descriptor.Enum) string { // messageToQueryParameters converts a message to a list of OpenAPI query parameters. func messageToQueryParameters(message *descriptor.Message, reg *descriptor.Registry, pathParams []descriptor.Parameter, body *descriptor.Body) (params []openapiParameterObject, err error) { for _, field := range message.Fields { - p, err := queryParams(message, field, "", reg, pathParams, body) + if !isVisible(getFieldVisibilityOption(field), reg) { + continue + } + + p, err := queryParams(message, field, "", reg, pathParams, body, reg.GetRecursiveDepth()) if err != nil { return nil, err } @@ -135,17 +167,64 @@ func messageToQueryParameters(message *descriptor.Message, reg *descriptor.Regis } // queryParams converts a field to a list of OpenAPI query parameters recursively through the use of nestedQueryParams. -func queryParams(message *descriptor.Message, field *descriptor.Field, prefix string, reg *descriptor.Registry, pathParams []descriptor.Parameter, body *descriptor.Body) (params []openapiParameterObject, err error) { - return nestedQueryParams(message, field, prefix, reg, pathParams, body, map[string]bool{}) +func queryParams(message *descriptor.Message, field *descriptor.Field, prefix string, reg *descriptor.Registry, pathParams []descriptor.Parameter, body *descriptor.Body, recursiveCount int) (params []openapiParameterObject, err error) { + return nestedQueryParams(message, field, prefix, reg, pathParams, body, newCycleChecker(recursiveCount)) +} + +type cycleChecker struct { + m map[string]int + count int +} + +func newCycleChecker(recursive int) *cycleChecker { + return &cycleChecker{ + m: make(map[string]int), + count: recursive, + } +} + +// Check returns whether name is still within recursion +// toleration +func (c *cycleChecker) Check(name string) bool { + count, ok := c.m[name] + count = count + 1 + isCycle := count > c.count + + if isCycle { + return false + } + + // provision map entry if not available + if !ok { + c.m[name] = 1 + return true + } + + c.m[name] = count + + return true +} + +func (c *cycleChecker) Branch() *cycleChecker { + copy := &cycleChecker{ + count: c.count, + m: map[string]int{}, + } + + for k, v := range c.m { + copy.m[k] = v + } + + return copy } // nestedQueryParams converts a field to a list of OpenAPI query parameters recursively. // This function is a helper function for queryParams, that keeps track of cyclical message references // through the use of -// touched map[string]bool -// If a cycle is discovered, an error is returned, as cyclical data structures aren't allowed +// touched map[string]int +// If a cycle is discovered, an error is returned, as cyclical data structures are dangerous // in query parameters. -func nestedQueryParams(message *descriptor.Message, field *descriptor.Field, prefix string, reg *descriptor.Registry, pathParams []descriptor.Parameter, body *descriptor.Body, touchedIn map[string]bool) (params []openapiParameterObject, err error) { +func nestedQueryParams(message *descriptor.Message, field *descriptor.Field, prefix string, reg *descriptor.Registry, pathParams []descriptor.Parameter, body *descriptor.Body, cycle *cycleChecker) (params []openapiParameterObject, err error) { // make sure the parameter is not already listed as a path parameter for _, pathParam := range pathParams { if pathParam.Target == field { @@ -181,15 +260,12 @@ func nestedQueryParams(message *descriptor.Message, field *descriptor.Field, pre if items != nil && (items.Type == "" || items.Type == "object") && !isEnum { return nil, nil // TODO: currently, mapping object in query parameter is not supported } - desc := schema.Description - if schema.Title != "" { // merge title because title of parameter object will be ignored - desc = strings.TrimSpace(schema.Title + ". " + schema.Description) - } + desc := mergeDescription(schema) // verify if the field is required required := false for _, fieldName := range schema.Required { - if fieldName == field.GetName() { + if fieldName == reg.FieldName(field) { required = true break } @@ -202,17 +278,14 @@ func nestedQueryParams(message *descriptor.Message, field *descriptor.Field, pre Type: schema.Type, Items: schema.Items, Format: schema.Format, + Pattern: schema.Pattern, Required: required, } if param.Type == "array" { param.CollectionFormat = "multi" } - if reg.GetUseJSONNamesForFields() { - param.Name = prefix + field.GetJsonName() - } else { - param.Name = prefix + field.GetName() - } + param.Name = prefix + reg.FieldName(field) if isEnum { enum, err := reg.LookupEnum("", fieldType) @@ -222,20 +295,22 @@ func nestedQueryParams(message *descriptor.Message, field *descriptor.Field, pre if items != nil { // array param.Items = &openapiItemsObject{ Type: "string", - Enum: listEnumNames(enum), + Enum: listEnumNames(reg, enum), } if reg.GetEnumsAsInts() { param.Items.Type = "integer" - param.Items.Enum = listEnumNumbers(enum) + param.Items.Enum = listEnumNumbers(reg, enum) } } else { param.Type = "string" - param.Enum = listEnumNames(enum) - param.Default = getEnumDefault(enum) + param.Enum = listEnumNames(reg, enum) + param.Default = getEnumDefault(reg, enum) if reg.GetEnumsAsInts() { param.Type = "integer" - param.Enum = listEnumNumbers(enum) - param.Default = "0" + param.Enum = listEnumNumbers(reg, enum) + if !reg.GetOmitEnumDefaultValue() { + param.Default = "0" + } } } valueComments := enumValueProtoComments(reg, enum) @@ -253,27 +328,22 @@ func nestedQueryParams(message *descriptor.Message, field *descriptor.Field, pre } // Check for cyclical message reference: - isCycle := touchedIn[*msg.Name] - if isCycle { - return nil, fmt.Errorf("recursive types are not allowed for query parameters, cycle found on %q", fieldType) + isOK := cycle.Check(*msg.Name) + if !isOK { + return nil, fmt.Errorf("exceeded recursive count (%d) for query parameter %q", cycle.count, fieldType) } // Construct a new map with the message name so a cycle further down the recursive path can be detected. // Do not keep anything in the original touched reference and do not pass that reference along. This will // prevent clobbering adjacent records while recursing. - touchedOut := make(map[string]bool) - for k, v := range touchedIn { - touchedOut[k] = v - } - touchedOut[*msg.Name] = true + touchedOut := cycle.Branch() for _, nestedField := range msg.Fields { - var fieldName string - if reg.GetUseJSONNamesForFields() { - fieldName = field.GetJsonName() - } else { - fieldName = field.GetName() + if !isVisible(getFieldVisibilityOption(nestedField), reg) { + continue } + + fieldName := reg.FieldName(field) p, err := nestedQueryParams(msg, nestedField, prefix+fieldName+".", reg, pathParams, body, touchedOut) if err != nil { return nil, err @@ -321,6 +391,10 @@ func findServicesMessagesAndEnumerations(s []*descriptor.Service, reg *descripto func findNestedMessagesAndEnumerations(message *descriptor.Message, reg *descriptor.Registry, m messageMap, e enumMap) { // Iterate over all the fields that for _, t := range message.Fields { + if !isVisible(getFieldVisibilityOption(t), reg) { + continue + } + fieldType := t.GetTypeName() // If the type is an empty string then it is a proto primitive if fieldType != "" { @@ -346,11 +420,153 @@ func skipRenderingRef(refName string) bool { return ok } -func renderMessagesAsDefinition(messages messageMap, d openapiDefinitionsObject, reg *descriptor.Registry, customRefs refMap) { +func renderMessageAsDefinition(msg *descriptor.Message, reg *descriptor.Registry, customRefs refMap, pathParams []descriptor.Parameter) (openapiSchemaObject, error) { + schema := openapiSchemaObject{ + schemaCore: schemaCore{ + Type: "object", + }, + } + msgComments := protoComments(reg, msg.File, msg.Outers, "MessageType", int32(msg.Index)) + if err := updateOpenAPIDataFromComments(reg, &schema, msg, msgComments, false); err != nil { + return openapiSchemaObject{}, err + } + opts, err := getMessageOpenAPIOption(reg, msg) + if err != nil { + return openapiSchemaObject{}, err + } + if opts != nil { + protoSchema := openapiSchemaFromProtoSchema(opts, reg, customRefs, msg) + + // Warning: Make sure not to overwrite any fields already set on the schema type. + schema.ExternalDocs = protoSchema.ExternalDocs + schema.ReadOnly = protoSchema.ReadOnly + schema.MultipleOf = protoSchema.MultipleOf + schema.Maximum = protoSchema.Maximum + schema.ExclusiveMaximum = protoSchema.ExclusiveMaximum + schema.Minimum = protoSchema.Minimum + schema.ExclusiveMinimum = protoSchema.ExclusiveMinimum + schema.MaxLength = protoSchema.MaxLength + schema.MinLength = protoSchema.MinLength + schema.Pattern = protoSchema.Pattern + schema.Default = protoSchema.Default + schema.MaxItems = protoSchema.MaxItems + schema.MinItems = protoSchema.MinItems + schema.UniqueItems = protoSchema.UniqueItems + schema.MaxProperties = protoSchema.MaxProperties + schema.MinProperties = protoSchema.MinProperties + schema.Required = protoSchema.Required + schema.XNullable = protoSchema.XNullable + if protoSchema.schemaCore.Type != "" || protoSchema.schemaCore.Ref != "" { + schema.schemaCore = protoSchema.schemaCore + } + if protoSchema.Title != "" { + schema.Title = protoSchema.Title + } + if protoSchema.Description != "" { + schema.Description = protoSchema.Description + } + if protoSchema.Example != nil { + schema.Example = protoSchema.Example + } + } + + schema.Required = filterOutExcludedFields(schema.Required, pathParams) + + for _, f := range msg.Fields { + if !isVisible(getFieldVisibilityOption(f), reg) { + continue + } + + if shouldExcludeField(f.GetName(), pathParams) { + continue + } + subPathParams := subPathParams(f.GetName(), pathParams) + fieldSchema, err := renderFieldAsDefinition(f, reg, customRefs, subPathParams) + if err != nil { + return openapiSchemaObject{}, err + } + comments := fieldProtoComments(reg, msg, f) + if err := updateOpenAPIDataFromComments(reg, &fieldSchema, f, comments, false); err != nil { + return openapiSchemaObject{}, err + } + + if requiredIdx := find(schema.Required, *f.Name); requiredIdx != -1 && reg.GetUseJSONNamesForFields() { + schema.Required[requiredIdx] = f.GetJsonName() + } + + if fieldSchema.Required != nil { + schema.Required = append(schema.Required, fieldSchema.Required...) + } + + kv := keyVal{Value: fieldSchema} + kv.Key = reg.FieldName(f) + if schema.Properties == nil { + schema.Properties = &openapiSchemaObjectProperties{} + } + *schema.Properties = append(*schema.Properties, kv) + } + + if msg.FQMN() == ".google.protobuf.Any" { + transformAnyForJSON(&schema, reg.GetUseJSONNamesForFields()) + } + + return schema, nil +} + +func renderFieldAsDefinition(f *descriptor.Field, reg *descriptor.Registry, refs refMap, pathParams []descriptor.Parameter) (openapiSchemaObject, error) { + if len(pathParams) == 0 { + return schemaOfField(f, reg, refs), nil + } + location := "" + if ix := strings.LastIndex(f.Message.FQMN(), "."); ix > 0 { + location = f.Message.FQMN()[0:ix] + } + msg, err := reg.LookupMsg(location, f.GetTypeName()) + if err != nil { + return openapiSchemaObject{}, err + } + schema, err := renderMessageAsDefinition(msg, reg, refs, pathParams) + if err != nil { + return openapiSchemaObject{}, err + } + comments := fieldProtoComments(reg, f.Message, f) + if len(comments) > 0 { + // Use title and description from field instead of nested message if present. + paragraphs := strings.Split(comments, paragraphDeliminator) + schema.Title = strings.TrimSpace(paragraphs[0]) + schema.Description = strings.TrimSpace(strings.Join(paragraphs[1:], paragraphDeliminator)) + } + return schema, nil +} + +// transformAnyForJSON should be called when the schema object represents a google.protobuf.Any, and will replace the +// Properties slice with a single value for '@type'. We mutate the incorrectly named field so that we inherit the same +// documentation as specified on the original field in the protobuf descriptors. +func transformAnyForJSON(schema *openapiSchemaObject, useJSONNames bool) { + var typeFieldName string + if useJSONNames { + typeFieldName = "typeUrl" + } else { + typeFieldName = "type_url" + } + + for _, property := range *schema.Properties { + if property.Key == typeFieldName { + schema.AdditionalProperties = &openapiSchemaObject{} + schema.Properties = &openapiSchemaObjectProperties{keyVal{ + Key: "@type", + Value: property.Value, + }} + break + } + } +} + +func renderMessagesAsDefinition(messages messageMap, d openapiDefinitionsObject, reg *descriptor.Registry, customRefs refMap, pathParams []descriptor.Parameter) error { for name, msg := range messages { swgName, ok := fullyQualifiedNameToOpenAPIName(msg.FQMN(), reg) if !ok { - panic(fmt.Sprintf("can't resolve OpenAPI name from '%v'", msg.FQMN())) + return fmt.Errorf("can't resolve OpenAPI name from '%v'", msg.FQMN()) } if skipRenderingRef(name) { continue @@ -359,74 +575,55 @@ func renderMessagesAsDefinition(messages messageMap, d openapiDefinitionsObject, if opt := msg.GetOptions(); opt != nil && opt.MapEntry != nil && *opt.MapEntry { continue } - schema := openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "object", - }, - } - msgComments := protoComments(reg, msg.File, msg.Outers, "MessageType", int32(msg.Index)) - if err := updateOpenAPIDataFromComments(reg, &schema, msg, msgComments, false); err != nil { - panic(err) - } - opts, err := getMessageOpenAPIOption(reg, msg) + var err error + d[swgName], err = renderMessageAsDefinition(msg, reg, customRefs, pathParams) if err != nil { - panic(err) + return err } - if opts != nil { - protoSchema := openapiSchemaFromProtoSchema(opts, reg, customRefs, msg) - - // Warning: Make sure not to overwrite any fields already set on the schema type. - schema.ExternalDocs = protoSchema.ExternalDocs - schema.ReadOnly = protoSchema.ReadOnly - schema.MultipleOf = protoSchema.MultipleOf - schema.Maximum = protoSchema.Maximum - schema.ExclusiveMaximum = protoSchema.ExclusiveMaximum - schema.Minimum = protoSchema.Minimum - schema.ExclusiveMinimum = protoSchema.ExclusiveMinimum - schema.MaxLength = protoSchema.MaxLength - schema.MinLength = protoSchema.MinLength - schema.Pattern = protoSchema.Pattern - schema.Default = protoSchema.Default - schema.MaxItems = protoSchema.MaxItems - schema.MinItems = protoSchema.MinItems - schema.UniqueItems = protoSchema.UniqueItems - schema.MaxProperties = protoSchema.MaxProperties - schema.MinProperties = protoSchema.MinProperties - schema.Required = protoSchema.Required - if protoSchema.schemaCore.Type != "" || protoSchema.schemaCore.Ref != "" { - schema.schemaCore = protoSchema.schemaCore - } - if protoSchema.Title != "" { - schema.Title = protoSchema.Title - } - if protoSchema.Description != "" { - schema.Description = protoSchema.Description - } - if protoSchema.Example != nil { - schema.Example = protoSchema.Example - } + } + return nil +} + +// isVisible checks if a field/RPC is visible based on the visibility restriction +// combined with the `visibility_restriction_selectors`. +// Elements with an overlap on `visibility_restriction_selectors` are visible, those without are not visible. +// Elements without `google.api.VisibilityRule` annotations entirely are always visible. +func isVisible(r *visibility.VisibilityRule, reg *descriptor.Registry) bool { + if r == nil { + return true + } + + restrictions := strings.Split(strings.TrimSpace(r.Restriction), ",") + // No restrictions results in the element always being visible + if len(restrictions) == 0 { + return true + } + + for _, restriction := range restrictions { + if reg.GetVisibilityRestrictionSelectors()[strings.TrimSpace(restriction)] { + return true } + } - for _, f := range msg.Fields { - fieldValue := schemaOfField(f, reg, customRefs) - comments := fieldProtoComments(reg, msg, f) - if err := updateOpenAPIDataFromComments(reg, &fieldValue, f, comments, false); err != nil { - panic(err) - } + return false +} - kv := keyVal{Value: fieldValue} - if reg.GetUseJSONNamesForFields() { - kv.Key = f.GetJsonName() - } else { - kv.Key = f.GetName() - } - if schema.Properties == nil { - schema.Properties = &openapiSchemaObjectProperties{} - } - *schema.Properties = append(*schema.Properties, kv) +func shouldExcludeField(name string, excluded []descriptor.Parameter) bool { + for _, p := range excluded { + if len(p.FieldPath) == 1 && name == p.FieldPath[0].Name { + return true + } + } + return false +} +func filterOutExcludedFields(fields []string, excluded []descriptor.Parameter) []string { + var filtered []string + for _, f := range fields { + if !shouldExcludeField(f, excluded) { + filtered = append(filtered, f) } - d[swgName] = schema } + return filtered } // schemaOfField returns a OpenAPI Schema Object for a protobuf field. @@ -442,7 +639,11 @@ func schemaOfField(f *descriptor.Field, reg *descriptor.Registry, refs refMap) o ) fd := f.FieldDescriptorProto - if m, err := reg.LookupMsg("", f.GetTypeName()); err == nil { + location := "" + if ix := strings.LastIndex(f.Message.FQMN(), "."); ix > 0 { + location = f.Message.FQMN()[0:ix] + } + if m, err := reg.LookupMsg(location, f.GetTypeName()); err == nil { if opt := m.GetOptions(); opt != nil && opt.MapEntry != nil && *opt.MapEntry { fd = m.GetField()[1] aggregate = object @@ -515,6 +716,14 @@ func schemaOfField(f *descriptor.Field, reg *descriptor.Registry, refs refMap) o updateswaggerObjectFromJSONSchema(&ret, j, reg, f) } + if j, err := getFieldBehaviorOption(reg, f); err == nil { + updateSwaggerObjectFromFieldBehavior(&ret, j, reg, f) + } + + if reg.GetProto3OptionalNullable() && f.GetProto3Optional() { + ret.XNullable = true + } + return ret } @@ -587,8 +796,8 @@ func renderEnumerationsAsDefinition(enums enumMap, d openapiDefinitionsObject, r enumComments := protoComments(reg, enum.File, enum.Outers, "EnumType", int32(enum.Index)) // it may be necessary to sort the result of the GetValue function. - enumNames := listEnumNames(enum) - defaultValue := getEnumDefault(enum) + enumNames := listEnumNames(reg, enum) + defaultValue := getEnumDefault(reg, enum) valueComments := enumValueProtoComments(reg, enum) if valueComments != "" { enumComments = strings.TrimLeft(enumComments+"\n\n "+valueComments, "\n") @@ -604,7 +813,7 @@ func renderEnumerationsAsDefinition(enums enumMap, d openapiDefinitionsObject, r enumSchemaObject.Type = "integer" enumSchemaObject.Format = "int32" enumSchemaObject.Default = "0" - enumSchemaObject.Enum = listEnumNumbers(enum) + enumSchemaObject.Enum = listEnumNumbers(reg, enum) } if err := updateOpenAPIDataFromComments(reg, &enumSchemaObject, enum, enumComments, false); err != nil { panic(err) @@ -623,7 +832,7 @@ func fullyQualifiedNameToOpenAPIName(fqn string, reg *descriptor.Registry) (stri ret, ok := mapping[fqn] return ret, ok } - mapping := resolveFullyQualifiedNameToOpenAPINames(append(reg.GetAllFQMNs(), reg.GetAllFQENs()...), reg.GetUseFQNForOpenAPIName()) + mapping := resolveFullyQualifiedNameToOpenAPINames(append(reg.GetAllFQMNs(), reg.GetAllFQENs()...), reg.GetOpenAPINamingStrategy()) registriesSeen[reg] = mapping ret, ok := mapping[fqn] return ret, ok @@ -648,65 +857,20 @@ func lookupMsgAndOpenAPIName(location, name string, reg *descriptor.Registry) (* var registriesSeen = map[*descriptor.Registry]map[string]string{} var registriesSeenMutex sync.Mutex -// Take the names of every proto and "uniq-ify" them. The idea is to produce a -// set of names that meet a couple of conditions. They must be stable, they -// must be unique, and they must be shorter than the FQN. -// -// This likely could be made better. This will always generate the same names -// but may not always produce optimal names. This is a reasonably close -// approximation of what they should look like in most cases. -func resolveFullyQualifiedNameToOpenAPINames(messages []string, useFQNForOpenAPIName bool) map[string]string { - packagesByDepth := make(map[int][][]string) - uniqueNames := make(map[string]string) - - hierarchy := func(pkg string) []string { - return strings.Split(pkg, ".") - } - - for _, p := range messages { - h := hierarchy(p) - for depth := range h { - if _, ok := packagesByDepth[depth]; !ok { - packagesByDepth[depth] = make([][]string, 0) - } - packagesByDepth[depth] = append(packagesByDepth[depth], h[len(h)-depth:]) - } - } - - count := func(list [][]string, item []string) int { - i := 0 - for _, element := range list { - if reflect.DeepEqual(element, item) { - i++ - } - } - return i - } - - for _, p := range messages { - if useFQNForOpenAPIName { - // strip leading dot from proto fqn - uniqueNames[p] = p[1:] - } else { - h := hierarchy(p) - for depth := 0; depth < len(h); depth++ { - if count(packagesByDepth[depth], h[len(h)-depth:]) == 1 { - uniqueNames[p] = strings.Join(h[len(h)-depth-1:], "") - break - } - if depth == len(h)-1 { - uniqueNames[p] = strings.Join(h, "") - } - } - } +// Take the names of every proto message and generate a unique reference for each, according to the given strategy. +func resolveFullyQualifiedNameToOpenAPINames(messages []string, namingStrategy string) map[string]string { + strategyFn := LookupNamingStrategy(namingStrategy) + if strategyFn == nil { + return nil } - return uniqueNames + return strategyFn(messages) } -var canRegexp = regexp.MustCompile("{([a-zA-Z][a-zA-Z0-9_.]*).*}") +var canRegexp = regexp.MustCompile("{([a-zA-Z][a-zA-Z0-9_.]*)([^}]*)}") -// OpenAPI expects paths of the form /path/{string_value} but grpc-gateway paths are expected to be of the form /path/{string_value=strprefix/*}. This should reformat it correctly. -func templateToOpenAPIPath(path string, reg *descriptor.Registry, fields []*descriptor.Field, msgs []*descriptor.Message) string { +// templateToParts will split a URL template as defined by https://github.com/googleapis/googleapis/blob/master/google/api/http.proto +// into a string slice with each part as an element of the slice for use by `partsToOpenAPIPath` and `partsToRegexpMap`. +func templateToParts(path string, reg *descriptor.Registry, fields []*descriptor.Field, msgs []*descriptor.Message) []string { // It seems like the right thing to do here is to just use // strings.Split(path, "/") but that breaks badly when you hit a url like // /{my_field=prefix/*}/ and end up with 2 sections representing my_field. @@ -758,28 +922,86 @@ func templateToOpenAPIPath(path string, reg *descriptor.Registry, fields []*desc // Now append the last element to parts parts = append(parts, buffer) - // Parts is now an array of segments of the path. Interestingly, since the - // syntax for this subsection CAN be handled by a regexp since it has no - // memory. + return parts +} + +// partsToOpenAPIPath converts each path part of the form /path/{string_value=strprefix/*} which is defined in +// https://github.com/googleapis/googleapis/blob/master/google/api/http.proto to the OpenAPI expected form /path/{string_value}. +// For example this would replace the path segment of "{foo=bar/*}" with "{foo}" or "prefix{bang=bash/**}" with "prefix{bang}". +// OpenAPI 2 only allows simple path parameters with the constraints on that parameter specified in the OpenAPI +// schema's "pattern" instead of in the path parameter itself. +func partsToOpenAPIPath(parts []string) string { for index, part := range parts { - // If part is a resource name such as "parent", "name", "user.name", the format info must be retained. - prefix := canRegexp.ReplaceAllString(part, "$1") - if isResourceName(prefix) { - continue - } parts[index] = canRegexp.ReplaceAllString(part, "{$1}") } - return strings.Join(parts, "/") } -func isResourceName(prefix string) bool { - words := strings.Split(prefix, ".") - l := len(words) - field := words[l-1] - words = strings.Split(field, ":") - field = words[0] - return field == "parent" || field == "name" +// partsToRegexpMap returns a map of parameter name to ECMA 262 patterns +// which is what the "pattern" field on an OpenAPI parameter expects. +// See https://swagger.io/specification/v2/ (Parameter Object) and +// https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.2.3. +// The expression is generated based on expressions defined by https://github.com/googleapis/googleapis/blob/master/google/api/http.proto +// "Path Template Syntax" section which allow for a "param_name=foobar/*/bang/**" style expressions inside +// the path parameter placeholders that indicate constraints on the values of those parameters. +// This function will scan the split parts of a path template for parameters and +// outputs a map of the name of the parameter to a ECMA regular expression. See the http.proto file for descriptions +// of the supported syntax. This function will ignore any path parameters that don't contain a "=" after the +// parameter name. For supported parameters, we assume "*" represent all characters except "/" as it's +// intended to match a single path element and we assume "**" matches any character as it's intended to match multiple +// path elements. +// For example "{name=organizations/*/roles/*}" would produce the regular expression for the "name" parameter of +// "organizations/[^/]+/roles/[^/]+" or "{bar=bing/*/bang/**}" would produce the regular expression for the "bar" +// parameter of "bing/[^/]+/bang/.+". +func partsToRegexpMap(parts []string) map[string]string { + regExps := make(map[string]string) + for _, part := range parts { + if submatch := canRegexp.FindStringSubmatch(part); len(submatch) > 2 { + if strings.HasPrefix(submatch[2], "=") { // this part matches the standard and should be made into a regular expression + // assume the string's characters other than "**" and "*" are literals (not necessarily a good assumption 100% of the times, but it will support most use cases) + regex := submatch[2][1:] + regex = strings.ReplaceAll(regex, "**", ".+") // ** implies any character including "/" + regex = strings.ReplaceAll(regex, "*", "[^/]+") // * implies any character except "/" + regExps[submatch[1]] = regex + } + } + } + return regExps +} + +func renderServiceTags(services []*descriptor.Service, reg *descriptor.Registry) []openapiTagObject { + var tags []openapiTagObject + for _, svc := range services { + if !isVisible(getServiceVisibilityOption(svc), reg) { + continue + } + tagName := svc.GetName() + if pkg := svc.File.GetPackage(); pkg != "" && reg.IsIncludePackageInTags() { + tagName = pkg + "." + tagName + } + + tag := openapiTagObject{ + Name: tagName, + } + if proto.HasExtension(svc.Options, openapi_options.E_Openapiv2Tag) { + ext := proto.GetExtension(svc.Options, openapi_options.E_Openapiv2Tag) + opts, ok := ext.(*openapi_options.Tag) + if !ok { + glog.Errorf("extension is %T; want an OpenAPI Tag object", ext) + return nil + } + + tag.Description = opts.Description + if opts.ExternalDocs != nil { + tag.ExternalDocs = &openapiExternalDocumentationObject{ + Description: opts.ExternalDocs.Description, + URL: opts.ExternalDocs.Url, + } + } + } + tags = append(tags, tag) + } + return tags } func renderServices(services []*descriptor.Service, paths openapiPathsObject, reg *descriptor.Registry, requestResponseRefs, customRefs refMap, msgs []*descriptor.Message) error { @@ -791,10 +1013,24 @@ func renderServices(services []*descriptor.Service, paths openapiPathsObject, re lastFile = svc.File svcBaseIdx = svcIdx } + + if !isVisible(getServiceVisibilityOption(svc), reg) { + continue + } + for methIdx, meth := range svc.Methods { + if !isVisible(getMethodVisibilityOption(meth), reg) { + continue + } + for bIdx, b := range meth.Bindings { + operationFunc := operationForMethod(b.HTTPMethod) // Iterate over all the OpenAPI parameters parameters := openapiParametersObject{} + // split the path template into its parts + parts := templateToParts(b.PathTmpl.Template, reg, meth.RequestType.Fields, msgs) + // extract any constraints specified in the path placeholders into ECMA regular expressions + pathParamRegexpMap := partsToRegexpMap(parts) for _, parameter := range b.PathParams { var paramType, paramFormat, desc, collectionFormat, defaultValue string @@ -822,11 +1058,11 @@ func renderServices(services []*descriptor.Service, paths openapiPathsObject, re } paramType = "string" paramFormat = "" - enumNames = listEnumNames(enum) + enumNames = listEnumNames(reg, enum) if reg.GetEnumsAsInts() { paramType = "integer" paramFormat = "" - enumNames = listEnumNumbers(enum) + enumNames = listEnumNumbers(reg, enum) } schema := schemaOfField(parameter.Target, reg, customRefs) desc = schema.Description @@ -865,6 +1101,10 @@ func renderServices(services []*descriptor.Service, paths openapiPathsObject, re if reg.GetUseJSONNamesForFields() { parameterString = lowerCamelCase(parameterString, meth.RequestType.Fields, msgs) } + var pattern string + if regExp, ok := pathParamRegexpMap[parameterString]; ok { + pattern = regExp + } parameters = append(parameters, openapiParameterObject{ Name: parameterString, Description: desc, @@ -878,39 +1118,70 @@ func renderServices(services []*descriptor.Service, paths openapiPathsObject, re Items: items, CollectionFormat: collectionFormat, MinItems: minItems, + Pattern: pattern, }) } // Now check if there is a body parameter if b.Body != nil { + // Recursively render fields as definitions as long as they contain path parameters. + // Special case for top level body if we don't have a body field. var schema openapiSchemaObject desc := "" - + var bodyFieldName string + schema = openapiSchemaObject{ + schemaCore: schemaCore{}, + } if len(b.Body.FieldPath) == 0 { - schema = openapiSchemaObject{ - schemaCore: schemaCore{}, - } - + // No field for body, use type. + bodyFieldName = "body" wknSchemaCore, isWkn := wktSchemas[meth.RequestType.FQMN()] - if !isWkn { - err := schema.setRefFromFQN(meth.RequestType.FQMN(), reg) - if err != nil { - return err - } - } else { + if isWkn { schema.schemaCore = wknSchemaCore - // Special workaround for Empty: it's well-known type but wknSchemas only returns schema.schemaCore; but we need to set schema.Properties which is a level higher. if meth.RequestType.FQMN() == ".google.protobuf.Empty" { schema.Properties = &openapiSchemaObjectProperties{} } + } else { + if len(b.PathParams) == 0 { + err := schema.setRefFromFQN(meth.RequestType.FQMN(), reg) + if err != nil { + return err + } + } else { + var err error + schema, err = renderMessageAsDefinition(meth.RequestType, reg, customRefs, b.PathParams) + if err != nil { + return err + } + if schema.Properties == nil || len(*schema.Properties) == 0 { + glog.Warningf("created a body with 0 properties in the message, this might be unintended: %s", *meth.RequestType) + } + } } } else { - lastField := b.Body.FieldPath[len(b.Body.FieldPath)-1] - schema = schemaOfField(lastField.Target, reg, customRefs) - if schema.Description != "" { - desc = schema.Description + // Body field path is limited to one path component. From google.api.HttpRule.body: + // "NOTE: the referred field must be present at the top-level of the request message type." + // Ref: https://github.com/googleapis/googleapis/blob/b3397f5febbf21dfc69b875ddabaf76bee765058/google/api/http.proto#L350-L352 + if len(b.Body.FieldPath) > 1 { + return fmt.Errorf("Body of request '%s' is not a top level field: '%v'.", meth.Service.GetName(), b.Body.FieldPath) + } + bodyField := b.Body.FieldPath[0] + if reg.GetUseJSONNamesForFields() { + bodyFieldName = lowerCamelCase(bodyField.Name, meth.RequestType.Fields, msgs) + } else { + bodyFieldName = bodyField.Name + } + // Align pathParams with body field path. + pathParams := subPathParams(bodyFieldName, b.PathParams) + var err error + schema, err = renderFieldAsDefinition(bodyField.Target, reg, customRefs, pathParams) + if err != nil { + return err + } + if schema.Title != "" { + desc = mergeDescription(schema) } else { - desc = fieldProtoComments(reg, lastField.Target.Message, lastField.Target) + desc = fieldProtoComments(reg, bodyField.Target.Message, bodyField.Target) } } @@ -918,30 +1189,67 @@ func renderServices(services []*descriptor.Service, paths openapiPathsObject, re desc += " (streaming inputs)" } parameters = append(parameters, openapiParameterObject{ - Name: "body", + Name: bodyFieldName, Description: desc, In: "body", Required: true, Schema: &schema, }) - // add the parameters to the query string - queryParams, err := messageToQueryParameters(meth.RequestType, reg, b.PathParams, b.Body) - if err != nil { - return err - } - parameters = append(parameters, queryParams...) - } else if b.HTTPMethod == "GET" || b.HTTPMethod == "DELETE" { - // add the parameters to the query string - queryParams, err := messageToQueryParameters(meth.RequestType, reg, b.PathParams, b.Body) - if err != nil { - return err - } - parameters = append(parameters, queryParams...) } - pathItemObject, ok := paths[templateToOpenAPIPath(b.PathTmpl.Template, reg, meth.RequestType.Fields, msgs)] + // add the parameters to the query string + queryParams, err := messageToQueryParameters(meth.RequestType, reg, b.PathParams, b.Body) + if err != nil { + return err + } + parameters = append(parameters, queryParams...) + + path := partsToOpenAPIPath(parts) + pathItemObject, ok := paths[path] if !ok { pathItemObject = openapiPathItemObject{} + } else { + // handle case where we have an existing mapping for the same path and method + existingOperationObject := operationFunc(&pathItemObject) + if existingOperationObject != nil { + var firstPathParameter *openapiParameterObject + var firstParamIndex int + for index, param := range parameters { + if param.In == "path" { + firstPathParameter = ¶m + firstParamIndex = index + break + } + } + if firstPathParameter == nil { + // Without a path parameter, there is nothing to vary to support multiple mappings of the same path/method. + // Previously this did not log an error and only overwrote the mapping, we now log the error but + // still overwrite the mapping + glog.Errorf("Duplicate mapping for path %s %s", b.HTTPMethod, path) + } else { + newPathCount := 0 + var newPath string + var newPathElement string + // Iterate until there is not an existing operation that matches the same escaped path. + // Most of the time this will only be a single iteration, but a large API could technically have + // a pretty large amount of these if it used similar patterns for all its functions. + for existingOperationObject != nil { + newPathCount += 1 + newPathElement = firstPathParameter.Name + pathParamUniqueSuffixDeliminator + strconv.Itoa(newPathCount) + newPath = strings.ReplaceAll(path, "{"+firstPathParameter.Name+"}", "{"+newPathElement+"}") + if newPathItemObject, ok := paths[newPath]; ok { + existingOperationObject = operationFunc(&newPathItemObject) + } else { + existingOperationObject = nil + } + } + // update the pathItemObject we are adding to with the new path + pathItemObject = paths[newPath] + firstPathParameter.Name = newPathElement + path = newPath + parameters[firstParamIndex] = *firstPathParameter + } + } } methProtoPath := protoPathIndex(reflect.TypeOf((*descriptorpb.ServiceDescriptorProto)(nil)), "Method") @@ -1023,6 +1331,7 @@ func renderServices(services []*descriptor.Service, paths openapiPathsObject, re "200": openapiResponseObject{ Description: desc, Schema: responseSchema, + Headers: openapiHeadersObject{}, }, }, } @@ -1119,6 +1428,13 @@ func renderServices(services []*descriptor.Service, paths openapiPathsObject, re if resp.Examples != nil { respObj.Examples = openapiExamplesFromProtoExamples(resp.Examples) } + if resp.Headers != nil { + hdrs, err := processHeaders(resp.Headers) + if err != nil { + return err + } + respObj.Headers = hdrs + } if resp.Extensions != nil { exts, err := processExtensions(resp.Extensions) if err != nil { @@ -1158,7 +1474,7 @@ func renderServices(services []*descriptor.Service, paths openapiPathsObject, re case "PATCH": pathItemObject.Patch = operationObject } - paths[templateToOpenAPIPath(b.PathTmpl.Template, reg, meth.RequestType.Fields, msgs)] = pathItemObject + paths[path] = pathItemObject } } } @@ -1167,6 +1483,31 @@ func renderServices(services []*descriptor.Service, paths openapiPathsObject, re return nil } +func mergeDescription(schema openapiSchemaObject) string { + desc := schema.Description + if schema.Title != "" { // join title because title of parameter object will be ignored + desc = strings.TrimSpace(schema.Title + paragraphDeliminator + schema.Description) + } + return desc +} + +func operationForMethod(httpMethod string) func(*openapiPathItemObject) *openapiOperationObject { + switch httpMethod { + case "GET": + return func(obj *openapiPathItemObject) *openapiOperationObject { return obj.Get } + case "POST": + return func(obj *openapiPathItemObject) *openapiOperationObject { return obj.Post } + case "PUT": + return func(obj *openapiPathItemObject) *openapiOperationObject { return obj.Put } + case "DELETE": + return func(obj *openapiPathItemObject) *openapiOperationObject { return obj.Delete } + case "PATCH": + return func(obj *openapiPathItemObject) *openapiOperationObject { return obj.Patch } + default: + return nil + } +} + // This function is called with a param which contains the entire definition of a method. func applyTemplate(p param) (*openapiSwaggerObject, error) { // Create the basic template object. This is the object that everything is @@ -1191,6 +1532,7 @@ func applyTemplate(p param) (*openapiSwaggerObject, error) { if err := renderServices(p.Services, s.Paths, p.reg, requestResponseRefs, customRefs, p.Messages); err != nil { panic(err) } + s.Tags = append(s.Tags, renderServiceTags(p.Services, p.reg)...) messages := messageMap{} streamingMessages := messageMap{} @@ -1210,20 +1552,22 @@ func applyTemplate(p param) (*openapiSwaggerObject, error) { // Find all the service's messages and enumerations that are defined (recursively) // and write request, response and other custom (but referenced) types out as definition objects. findServicesMessagesAndEnumerations(p.Services, p.reg, messages, streamingMessages, enums, requestResponseRefs) - renderMessagesAsDefinition(messages, s.Definitions, p.reg, customRefs) + if err := renderMessagesAsDefinition(messages, s.Definitions, p.reg, customRefs, nil); err != nil { + return nil, err + } renderEnumerationsAsDefinition(enums, s.Definitions, p.reg) // File itself might have some comments and metadata. packageProtoPath := protoPathIndex(reflect.TypeOf((*descriptorpb.FileDescriptorProto)(nil)), "Package") packageComments := protoComments(p.reg, p.File, nil, "Package", packageProtoPath) if err := updateOpenAPIDataFromComments(p.reg, &s, p, packageComments, true); err != nil { - panic(err) + return nil, err } // There may be additional options in the OpenAPI option in the proto. spb, err := getFileOpenAPIOption(p.reg, p.File) if err != nil { - panic(err) + return nil, err } if spb != nil { if spb.Swagger != "" { @@ -1374,6 +1718,9 @@ func applyTemplate(p param) (*openapiSwaggerObject, error) { for _, secReq := range spb.Security { newSecReq := openapiSecurityRequirementObject{} for secReqKey, secReqValue := range secReq.SecurityRequirement { + if secReqValue == nil { + return nil, fmt.Errorf("malformed security requirement spec for key %q; value is required", secReqKey) + } newSecReqValue := make([]string, len(secReqValue.Scope)) copy(newSecReqValue, secReqValue.Scope) newSecReq[secReqKey] = newSecReqValue @@ -1434,7 +1781,9 @@ func applyTemplate(p param) (*openapiSwaggerObject, error) { // Finally add any references added by users that aren't // otherwise rendered. - addCustomRefs(s.Definitions, p.reg, customRefs) + if err := addCustomRefs(s.Definitions, p.reg, customRefs); err != nil { + return nil, err + } return &s, nil } @@ -1455,6 +1804,180 @@ func processExtensions(inputExts map[string]*structpb.Value) ([]extension, error return exts, nil } +func validateHeaderTypeAndFormat(headerType string, format string) error { + // The type of the object. The value MUST be one of "string", "number", "integer", "boolean", or "array" + // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#headerObject + // Note: currently not implementing array as we are only implementing this in the operation response context + switch headerType { + // the format property is an open string-valued property, and can have any value to support documentation needs + // primary check for format is to ensure that the number/integer formats are extensions of the specified type + // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#dataTypeFormat + case "string": + return nil + case "number": + switch format { + case "uint", + "uint8", + "uint16", + "uint32", + "uint64", + "int", + "int8", + "int16", + "int32", + "int64", + "float", + "float32", + "float64", + "complex64", + "complex128", + "double", + "byte", + "rune", + "uintptr", + "": + return nil + default: + return fmt.Errorf("the provided format %q is not a valid extension of the type %q", format, headerType) + } + case "integer": + switch format { + case "uint", + "uint8", + "uint16", + "uint32", + "uint64", + "int", + "int8", + "int16", + "int32", + "int64", + "": + return nil + default: + return fmt.Errorf("the provided format %q is not a valid extension of the type %q", format, headerType) + } + case "boolean": + return nil + } + return fmt.Errorf("the provided header type %q is not supported", headerType) +} + +func validateDefaultValueTypeAndFormat(headerType string, defaultValue string, format string) error { + switch headerType { + case "string": + if !isQuotedString(defaultValue) { + return fmt.Errorf("the provided default value %q does not match provider type %q, or is not properly quoted with escaped quotations", defaultValue, headerType) + } + switch format { + case "date-time": + unquoteTime := strings.Trim(defaultValue, `"`) + _, err := time.Parse(time.RFC3339, unquoteTime) + if err != nil { + return fmt.Errorf("the provided default value %q is not a valid RFC3339 date-time string", defaultValue) + } + case "date": + const ( + layoutRFC3339Date = "2006-01-02" + ) + unquoteDate := strings.Trim(defaultValue, `"`) + _, err := time.Parse(layoutRFC3339Date, unquoteDate) + if err != nil { + return fmt.Errorf("the provided default value %q is not a valid RFC3339 date-time string", defaultValue) + } + } + case "number": + err := isJSONNumber(defaultValue, headerType) + if err != nil { + return err + } + case "integer": + switch format { + case "int32": + _, err := strconv.ParseInt(defaultValue, 0, 32) + if err != nil { + return fmt.Errorf("the provided default value %q does not match provided format %q", defaultValue, format) + } + case "uint32": + _, err := strconv.ParseUint(defaultValue, 0, 32) + if err != nil { + return fmt.Errorf("the provided default value %q does not match provided format %q", defaultValue, format) + } + case "int64": + _, err := strconv.ParseInt(defaultValue, 0, 64) + if err != nil { + return fmt.Errorf("the provided default value %q does not match provided format %q", defaultValue, format) + } + case "uint64": + _, err := strconv.ParseUint(defaultValue, 0, 64) + if err != nil { + return fmt.Errorf("the provided default value %q does not match provided format %q", defaultValue, format) + } + default: + _, err := strconv.ParseInt(defaultValue, 0, 64) + if err != nil { + return fmt.Errorf("the provided default value %q does not match provided type %q", defaultValue, headerType) + } + } + case "boolean": + if !isBool(defaultValue) { + return fmt.Errorf("the provided default value %q does not match provider type %q", defaultValue, headerType) + } + } + return nil +} + +func isQuotedString(s string) bool { + return len(s) >= 2 && s[0] == '"' && s[len(s)-1] == '"' +} + +func isJSONNumber(s string, t string) error { + val, err := strconv.ParseFloat(s, 64) + if err != nil { + return fmt.Errorf("the provided default value %q does not match provider type %q", s, t) + } + // Floating point values that cannot be represented as sequences of digits (such as Infinity and NaN) are not permitted. + // See: https://tools.ietf.org/html/rfc4627#section-2.4 + if math.IsInf(val, 0) || math.IsNaN(val) { + return fmt.Errorf("the provided number %q is not a valid JSON number", s) + } + + return nil +} + +func isBool(s string) bool { + // Unable to use strconv.ParseBool because it returns truthy values https://golang.org/pkg/strconv/#example_ParseBool + // per https://swagger.io/specification/v2/#data-types + // type: boolean represents two values: true and false. Note that truthy and falsy values such as "true", "", 0 or null are not considered boolean values. + return s == "true" || s == "false" +} + +func processHeaders(inputHdrs map[string]*openapi_options.Header) (openapiHeadersObject, error) { + hdrs := map[string]openapiHeaderObject{} + for k, v := range inputHdrs { + header := textproto.CanonicalMIMEHeaderKey(k) + ret := openapiHeaderObject{ + Description: v.Description, + Format: v.Format, + Pattern: v.Pattern, + } + err := validateHeaderTypeAndFormat(v.Type, v.Format) + if err != nil { + return nil, err + } + ret.Type = v.Type + if v.Default != "" { + err := validateDefaultValueTypeAndFormat(v.Type, v.Default, v.Format) + if err != nil { + return nil, err + } + ret.Default = RawExample(v.Default) + } + hdrs[header] = ret + } + return hdrs, nil +} + // updateOpenAPIDataFromComments updates a OpenAPI object based on a comment // from the proto file. // @@ -1501,13 +2024,13 @@ func updateOpenAPIDataFromComments(reg *descriptor.Registry, swaggerObject inter usingTitle = true } - paragraphs := strings.Split(comment, "\n\n") + paragraphs := strings.Split(comment, paragraphDeliminator) // If there is a summary (or summary-equivalent) and it's empty, use the first // paragraph as summary, and the rest as description. if summaryValue.CanSet() { summary := strings.TrimSpace(paragraphs[0]) - description := strings.TrimSpace(strings.Join(paragraphs[1:], "\n\n")) + description := strings.TrimSpace(strings.Join(paragraphs[1:], paragraphDeliminator)) if !usingTitle || (len(summary) > 0 && summary[len(summary)-1] != '.') { // overrides the schema value only if it's empty // keep the comment precedence when updating the package definition @@ -1532,7 +2055,7 @@ func updateOpenAPIDataFromComments(reg *descriptor.Registry, swaggerObject inter // whole comment into description if the OpenAPI object description is empty. if descriptionValue.CanSet() { if descriptionValue.Len() == 0 || isPackageObject { - descriptionValue.Set(reflect.ValueOf(strings.Join(paragraphs, "\n\n"))) + descriptionValue.Set(reflect.ValueOf(strings.Join(paragraphs, paragraphDeliminator))) } return nil } @@ -1554,6 +2077,9 @@ func enumValueProtoComments(reg *descriptor.Registry, enum *descriptor.Enum) str protoPath := protoPathIndex(reflect.TypeOf((*descriptorpb.EnumDescriptorProto)(nil)), "Value") var comments []string for idx, value := range enum.GetValue() { + if !isVisible(getEnumValueVisibilityOption(value), reg) { + continue + } name := value.GetName() if reg.GetEnumsAsInts() { name = strconv.Itoa(int(value.GetNumber())) @@ -1810,6 +2336,81 @@ func extractJSONSchemaFromFieldDescriptor(fd *descriptorpb.FieldDescriptorProto) return opts, nil } +func extractFieldBehaviorFromFieldDescriptor(fd *descriptorpb.FieldDescriptorProto) ([]annotations.FieldBehavior, error) { + if fd.Options == nil { + return nil, nil + } + if !proto.HasExtension(fd.Options, annotations.E_FieldBehavior) { + return nil, nil + } + ext := proto.GetExtension(fd.Options, annotations.E_FieldBehavior) + opts, ok := ext.([]annotations.FieldBehavior) + if !ok { + return nil, fmt.Errorf("extension is %T; want a []FieldBehavior object", ext) + } + return opts, nil +} + +func getFieldVisibilityOption(fd *descriptor.Field) *visibility.VisibilityRule { + if fd.Options == nil { + return nil + } + if !proto.HasExtension(fd.Options, visibility.E_FieldVisibility) { + return nil + } + ext := proto.GetExtension(fd.Options, visibility.E_FieldVisibility) + opts, ok := ext.(*visibility.VisibilityRule) + if !ok { + return nil + } + return opts +} + +func getServiceVisibilityOption(fd *descriptor.Service) *visibility.VisibilityRule { + if fd.Options == nil { + return nil + } + if !proto.HasExtension(fd.Options, visibility.E_ApiVisibility) { + return nil + } + ext := proto.GetExtension(fd.Options, visibility.E_ApiVisibility) + opts, ok := ext.(*visibility.VisibilityRule) + if !ok { + return nil + } + return opts +} + +func getMethodVisibilityOption(fd *descriptor.Method) *visibility.VisibilityRule { + if fd.Options == nil { + return nil + } + if !proto.HasExtension(fd.Options, visibility.E_MethodVisibility) { + return nil + } + ext := proto.GetExtension(fd.Options, visibility.E_MethodVisibility) + opts, ok := ext.(*visibility.VisibilityRule) + if !ok { + return nil + } + return opts +} + +func getEnumValueVisibilityOption(fd *descriptorpb.EnumValueDescriptorProto) *visibility.VisibilityRule { + if fd.Options == nil { + return nil + } + if !proto.HasExtension(fd.Options, visibility.E_ValueVisibility) { + return nil + } + ext := proto.GetExtension(fd.Options, visibility.E_ValueVisibility) + opts, ok := ext.(*visibility.VisibilityRule) + if !ok { + return nil + } + return opts +} + func getMethodOpenAPIOption(reg *descriptor.Registry, meth *descriptor.Method) (*openapi_options.Operation, error) { opts, err := extractOperationOptionFromMethodDescriptor(meth.MethodDescriptorProto) if err != nil { @@ -1870,6 +2471,17 @@ func getFieldOpenAPIOption(reg *descriptor.Registry, fd *descriptor.Field) (*ope return opts, nil } +func getFieldBehaviorOption(reg *descriptor.Registry, fd *descriptor.Field) ([]annotations.FieldBehavior, error) { + opts, err := extractFieldBehaviorFromFieldDescriptor(fd.FieldDescriptorProto) + if err != nil { + return nil, err + } + if opts != nil { + return opts, nil + } + return opts, nil +} + func protoJSONSchemaToOpenAPISchemaCore(j *openapi_options.JSONSchema, reg *descriptor.Registry, refs refMap) schemaCore { ret := schemaCore{} @@ -1916,9 +2528,48 @@ func updateswaggerObjectFromJSONSchema(s *openapiSchemaObject, j *openapi_option s.MaxProperties = j.GetMaxProperties() s.MinProperties = j.GetMinProperties() s.Required = j.GetRequired() + if reg.GetUseJSONNamesForFields() { + for i, r := range s.Required { + // TODO(oyvindwe): Look up field and use field.GetJsonName()? + s.Required[i] = doCamelCase(r) + } + } + s.Enum = j.GetEnum() if overrideType := j.GetType(); len(overrideType) > 0 { s.Type = strings.ToLower(overrideType[0].String()) } + if j != nil && j.GetExample() != "" { + s.Example = RawExample(j.GetExample()) + } + if j != nil && j.GetFormat() != "" { + s.Format = j.GetFormat() + } +} + +func updateSwaggerObjectFromFieldBehavior(s *openapiSchemaObject, j []annotations.FieldBehavior, reg *descriptor.Registry, field *descriptor.Field) { + // Per the JSON Reference syntax: Any members other than "$ref" in a JSON Reference object SHALL be ignored. + // https://tools.ietf.org/html/draft-pbryan-zyp-json-ref-03#section-3 + if s.Ref != "" { + return + } + + for _, fb := range j { + switch fb { + case annotations.FieldBehavior_REQUIRED: + if reg.GetUseJSONNamesForFields() { + s.Required = append(s.Required, *field.JsonName) + } else { + s.Required = append(s.Required, *field.Name) + } + case annotations.FieldBehavior_OUTPUT_ONLY: + s.ReadOnly = true + case annotations.FieldBehavior_FIELD_BEHAVIOR_UNSPECIFIED: + case annotations.FieldBehavior_OPTIONAL: + case annotations.FieldBehavior_INPUT_ONLY: + // OpenAPI v3 supports a writeOnly property, but this is not supported in Open API v2 + case annotations.FieldBehavior_IMMUTABLE: + } + } } func openapiSchemaFromProtoSchema(s *openapi_options.Schema, reg *descriptor.Registry, refs refMap, data interface{}) openapiSchemaObject { @@ -1930,7 +2581,7 @@ func openapiSchemaFromProtoSchema(s *openapi_options.Schema, reg *descriptor.Reg updateswaggerObjectFromJSONSchema(&ret, s.GetJsonSchema(), reg, data) if s != nil && s.Example != "" { - ret.Example = json.RawMessage(s.Example) + ret.Example = RawExample(s.Example) } return ret @@ -2005,9 +2656,9 @@ func protoExternalDocumentationToOpenAPIExternalDocumentation(in *openapi_option } } -func addCustomRefs(d openapiDefinitionsObject, reg *descriptor.Registry, refs refMap) { +func addCustomRefs(d openapiDefinitionsObject, reg *descriptor.Registry, refs refMap) error { if len(refs) == 0 { - return + return nil } msgMap := make(messageMap) enumMap := make(enumMap) @@ -2035,11 +2686,13 @@ func addCustomRefs(d openapiDefinitionsObject, reg *descriptor.Registry, refs re // ?? Should be either enum or msg } - renderMessagesAsDefinition(msgMap, d, reg, refs) + if err := renderMessagesAsDefinition(msgMap, d, reg, refs, nil); err != nil { + return err + } renderEnumerationsAsDefinition(enumMap, d, reg) // Run again in case any new refs were added - addCustomRefs(d, reg, refs) + return addCustomRefs(d, reg, refs) } func lowerCamelCase(fieldName string, fields []*descriptor.Field, msgs []*descriptor.Message) string { @@ -2093,3 +2746,30 @@ func getReservedJSONName(fieldName string, messageNameToFieldsToJSONName map[str fieldNames := strings.Split(fieldName, ".") return getReservedJSONName(strings.Join(fieldNames[1:], "."), messageNameToFieldsToJSONName, fieldNameToType) } + +func find(a []string, x string) int { + // This is a linear search but we are dealing with a small number of fields + for i, n := range a { + if x == n { + return i + } + } + return -1 +} + +// Make a deep copy of the outer parameters that has paramName as the first component, +// but remove the first component of the field path. +func subPathParams(paramName string, outerParams []descriptor.Parameter) []descriptor.Parameter { + var innerParams []descriptor.Parameter + for _, p := range outerParams { + if len(p.FieldPath) > 1 && p.FieldPath[0].Name == paramName { + subParam := descriptor.Parameter{ + FieldPath: p.FieldPath[1:], + Target: p.Target, + Method: p.Method, + } + innerParams = append(innerParams, subParam) + } + } + return innerParams +} diff --git a/gateway/protoc-gen-openapiv2/internal/genopenapi/template_test.go b/gateway/protoc-gen-openapiv2/internal/genopenapi/template_test.go deleted file mode 100644 index 2b55842..0000000 --- a/gateway/protoc-gen-openapiv2/internal/genopenapi/template_test.go +++ /dev/null @@ -1,3702 +0,0 @@ -package genopenapi - -import ( - "encoding/json" - "errors" - "fmt" - "reflect" - "strings" - "testing" - - "github.com/google/go-cmp/cmp" - // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor" - "github.com/binchencoder/ease-gateway/gateway/internal/descriptor" - // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor/openapiconfig" - "github.com/binchencoder/ease-gateway/gateway/internal/descriptor/openapiconfig" - "github.com/grpc-ecosystem/grpc-gateway/v2/internal/httprule" - // openapi_options "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options" - openapi_options "github.com/binchencoder/ease-gateway/gateway/protoc-gen-openapiv2/options" - // "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" - "github.com/binchencoder/ease-gateway/gateway/runtime" - "google.golang.org/genproto/protobuf/field_mask" - "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/reflect/protodesc" - "google.golang.org/protobuf/types/descriptorpb" - "google.golang.org/protobuf/types/known/durationpb" - "google.golang.org/protobuf/types/known/structpb" - "google.golang.org/protobuf/types/known/timestamppb" - "google.golang.org/protobuf/types/known/wrapperspb" - "google.golang.org/protobuf/types/pluginpb" -) - -var marshaler = &runtime.JSONPb{} - -func crossLinkFixture(f *descriptor.File) *descriptor.File { - for _, m := range f.Messages { - m.File = f - } - for _, svc := range f.Services { - svc.File = f - for _, m := range svc.Methods { - m.Service = svc - for _, b := range m.Bindings { - b.Method = m - for _, param := range b.PathParams { - param.Method = m - } - } - } - } - return f -} - -func reqFromFile(f *descriptor.File) *pluginpb.CodeGeneratorRequest { - return &pluginpb.CodeGeneratorRequest{ - ProtoFile: []*descriptorpb.FileDescriptorProto{ - f.FileDescriptorProto, - }, - FileToGenerate: []string{f.GetName()}, - } -} - -func TestMessageToQueryParametersWithEnumAsInt(t *testing.T) { - type test struct { - MsgDescs []*descriptorpb.DescriptorProto - Message string - Params []openapiParameterObject - } - - tests := []test{ - { - MsgDescs: []*descriptorpb.DescriptorProto{ - { - Name: proto.String("ExampleMessage"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("a"), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - Number: proto.Int32(1), - }, - { - Name: proto.String("b"), - Type: descriptorpb.FieldDescriptorProto_TYPE_DOUBLE.Enum(), - Number: proto.Int32(2), - }, - { - Name: proto.String("c"), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - Label: descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(), - Number: proto.Int32(3), - }, - }, - }, - }, - Message: "ExampleMessage", - Params: []openapiParameterObject{ - { - Name: "a", - In: "query", - Required: false, - Type: "string", - }, - { - Name: "b", - In: "query", - Required: false, - Type: "number", - Format: "double", - }, - { - Name: "c", - In: "query", - Required: false, - Type: "array", - CollectionFormat: "multi", - }, - }, - }, - { - MsgDescs: []*descriptorpb.DescriptorProto{ - { - Name: proto.String("ExampleMessage"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("nested"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - TypeName: proto.String(".example.Nested"), - Number: proto.Int32(1), - }, - }, - }, - { - Name: proto.String("Nested"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("a"), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - Number: proto.Int32(1), - }, - { - Name: proto.String("deep"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - TypeName: proto.String(".example.Nested.DeepNested"), - Number: proto.Int32(2), - }, - }, - NestedType: []*descriptorpb.DescriptorProto{{ - Name: proto.String("DeepNested"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("b"), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - Number: proto.Int32(1), - }, - { - Name: proto.String("c"), - Type: descriptorpb.FieldDescriptorProto_TYPE_ENUM.Enum(), - TypeName: proto.String(".example.Nested.DeepNested.DeepEnum"), - Number: proto.Int32(2), - }, - }, - EnumType: []*descriptorpb.EnumDescriptorProto{ - { - Name: proto.String("DeepEnum"), - Value: []*descriptorpb.EnumValueDescriptorProto{ - {Name: proto.String("FALSE"), Number: proto.Int32(0)}, - {Name: proto.String("TRUE"), Number: proto.Int32(1)}, - }, - }, - }, - }}, - }, - }, - Message: "ExampleMessage", - Params: []openapiParameterObject{ - { - Name: "nested.a", - In: "query", - Required: false, - Type: "string", - }, - { - Name: "nested.deep.b", - In: "query", - Required: false, - Type: "string", - }, - { - Name: "nested.deep.c", - In: "query", - Required: false, - Type: "integer", - Enum: []string{"0", "1"}, - Default: "0", - }, - }, - }, - } - - for _, test := range tests { - reg := descriptor.NewRegistry() - reg.SetEnumsAsInts(true) - msgs := []*descriptor.Message{} - for _, msgdesc := range test.MsgDescs { - msgs = append(msgs, &descriptor.Message{DescriptorProto: msgdesc}) - } - file := descriptor.File{ - FileDescriptorProto: &descriptorpb.FileDescriptorProto{ - SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, - Name: proto.String("example.proto"), - Package: proto.String("example"), - Dependency: []string{}, - MessageType: test.MsgDescs, - Service: []*descriptorpb.ServiceDescriptorProto{}, - }, - GoPkg: descriptor.GoPackage{ - Path: "example.com/path/to/example/example.pb", - Name: "example_pb", - }, - Messages: msgs, - } - reg.Load(&pluginpb.CodeGeneratorRequest{ - ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto}, - }) - - message, err := reg.LookupMsg("", ".example."+test.Message) - if err != nil { - t.Fatalf("failed to lookup message: %s", err) - } - params, err := messageToQueryParameters(message, reg, []descriptor.Parameter{}, nil) - if err != nil { - t.Fatalf("failed to convert message to query parameters: %s", err) - } - // avoid checking Items for array types - for i := range params { - params[i].Items = nil - } - if !reflect.DeepEqual(params, test.Params) { - t.Errorf("expected %v, got %v", test.Params, params) - } - } -} - -func TestMessageToQueryParameters(t *testing.T) { - type test struct { - MsgDescs []*descriptorpb.DescriptorProto - Message string - Params []openapiParameterObject - } - - tests := []test{ - { - MsgDescs: []*descriptorpb.DescriptorProto{ - { - Name: proto.String("ExampleMessage"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("a"), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - Number: proto.Int32(1), - }, - { - Name: proto.String("b"), - Type: descriptorpb.FieldDescriptorProto_TYPE_DOUBLE.Enum(), - Number: proto.Int32(2), - }, - { - Name: proto.String("c"), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - Label: descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(), - Number: proto.Int32(3), - }, - }, - }, - }, - Message: "ExampleMessage", - Params: []openapiParameterObject{ - { - Name: "a", - In: "query", - Required: false, - Type: "string", - }, - { - Name: "b", - In: "query", - Required: false, - Type: "number", - Format: "double", - }, - { - Name: "c", - In: "query", - Required: false, - Type: "array", - CollectionFormat: "multi", - }, - }, - }, - { - MsgDescs: []*descriptorpb.DescriptorProto{ - { - Name: proto.String("ExampleMessage"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("nested"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - TypeName: proto.String(".example.Nested"), - Number: proto.Int32(1), - }, - }, - }, - { - Name: proto.String("Nested"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("a"), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - Number: proto.Int32(1), - }, - { - Name: proto.String("deep"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - TypeName: proto.String(".example.Nested.DeepNested"), - Number: proto.Int32(2), - }, - }, - NestedType: []*descriptorpb.DescriptorProto{{ - Name: proto.String("DeepNested"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("b"), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - Number: proto.Int32(1), - }, - { - Name: proto.String("c"), - Type: descriptorpb.FieldDescriptorProto_TYPE_ENUM.Enum(), - TypeName: proto.String(".example.Nested.DeepNested.DeepEnum"), - Number: proto.Int32(2), - }, - }, - EnumType: []*descriptorpb.EnumDescriptorProto{ - { - Name: proto.String("DeepEnum"), - Value: []*descriptorpb.EnumValueDescriptorProto{ - {Name: proto.String("FALSE"), Number: proto.Int32(0)}, - {Name: proto.String("TRUE"), Number: proto.Int32(1)}, - }, - }, - }, - }}, - }, - }, - Message: "ExampleMessage", - Params: []openapiParameterObject{ - { - Name: "nested.a", - In: "query", - Required: false, - Type: "string", - }, - { - Name: "nested.deep.b", - In: "query", - Required: false, - Type: "string", - }, - { - Name: "nested.deep.c", - In: "query", - Required: false, - Type: "string", - Enum: []string{"FALSE", "TRUE"}, - Default: "FALSE", - }, - }, - }, - } - - for _, test := range tests { - reg := descriptor.NewRegistry() - msgs := []*descriptor.Message{} - for _, msgdesc := range test.MsgDescs { - msgs = append(msgs, &descriptor.Message{DescriptorProto: msgdesc}) - } - file := descriptor.File{ - FileDescriptorProto: &descriptorpb.FileDescriptorProto{ - SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, - Name: proto.String("example.proto"), - Package: proto.String("example"), - Dependency: []string{}, - MessageType: test.MsgDescs, - Service: []*descriptorpb.ServiceDescriptorProto{}, - }, - GoPkg: descriptor.GoPackage{ - Path: "example.com/path/to/example/example.pb", - Name: "example_pb", - }, - Messages: msgs, - } - reg.Load(&pluginpb.CodeGeneratorRequest{ - ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto}, - }) - - message, err := reg.LookupMsg("", ".example."+test.Message) - if err != nil { - t.Fatalf("failed to lookup message: %s", err) - } - params, err := messageToQueryParameters(message, reg, []descriptor.Parameter{}, nil) - if err != nil { - t.Fatalf("failed to convert message to query parameters: %s", err) - } - // avoid checking Items for array types - for i := range params { - params[i].Items = nil - } - if !reflect.DeepEqual(params, test.Params) { - t.Errorf("expected %v, got %v", test.Params, params) - } - } -} - -// TestMessagetoQueryParametersNoRecursive, is a check that cyclical references between messages -// are not falsely detected given previous known edge-cases. -func TestMessageToQueryParametersNoRecursive(t *testing.T) { - type test struct { - MsgDescs []*descriptorpb.DescriptorProto - Message string - } - - tests := []test{ - // First test: - // Here is a message that has two of another message adjacent to one another in a nested message. - // There is no loop but this was previouly falsely flagged as a cycle. - // Example proto: - // message NonRecursiveMessage { - // string field = 1; - // } - // message BaseMessage { - // NonRecursiveMessage first = 1; - // NonRecursiveMessage second = 2; - // } - // message QueryMessage { - // BaseMessage first = 1; - // string second = 2; - // } - { - MsgDescs: []*descriptorpb.DescriptorProto{ - &descriptorpb.DescriptorProto{ - Name: proto.String("QueryMessage"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("first"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - TypeName: proto.String(".example.BaseMessage"), - Number: proto.Int32(1), - }, - { - Name: proto.String("second"), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - Number: proto.Int32(2), - }, - }, - }, - &descriptorpb.DescriptorProto{ - Name: proto.String("BaseMessage"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("first"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - TypeName: proto.String(".example.NonRecursiveMessage"), - Number: proto.Int32(1), - }, - { - Name: proto.String("second"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - TypeName: proto.String(".example.NonRecursiveMessage"), - Number: proto.Int32(2), - }, - }, - }, - // Note there is no recursive nature to this message - &descriptorpb.DescriptorProto{ - Name: proto.String("NonRecursiveMessage"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("field"), - //Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - Number: proto.Int32(1), - }, - }, - }, - }, - Message: "QueryMessage", - }, - } - - for _, test := range tests { - reg := descriptor.NewRegistry() - msgs := []*descriptor.Message{} - for _, msgdesc := range test.MsgDescs { - msgs = append(msgs, &descriptor.Message{DescriptorProto: msgdesc}) - } - file := descriptor.File{ - FileDescriptorProto: &descriptorpb.FileDescriptorProto{ - SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, - Name: proto.String("example.proto"), - Package: proto.String("example"), - Dependency: []string{}, - MessageType: test.MsgDescs, - Service: []*descriptorpb.ServiceDescriptorProto{}, - }, - GoPkg: descriptor.GoPackage{ - Path: "example.com/path/to/example/example.pb", - Name: "example_pb", - }, - Messages: msgs, - } - reg.Load(&pluginpb.CodeGeneratorRequest{ - ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto}, - }) - - message, err := reg.LookupMsg("", ".example."+test.Message) - if err != nil { - t.Fatalf("failed to lookup message: %s", err) - } - - _, err = messageToQueryParameters(message, reg, []descriptor.Parameter{}, nil) - if err != nil { - t.Fatalf("No recursion error should be thrown: %s", err) - } - } -} - -// TestMessagetoQueryParametersRecursive, is a check that cyclical references between messages -// are handled gracefully. The goal is to insure that attempts to add messages with cyclical -// references to query-parameters returns an error message. -func TestMessageToQueryParametersRecursive(t *testing.T) { - type test struct { - MsgDescs []*descriptorpb.DescriptorProto - Message string - } - - tests := []test{ - // First test: - // Here we test that a message that references it self through a field will return an error. - // Example proto: - // message DirectRecursiveMessage { - // DirectRecursiveMessage nested = 1; - // } - { - MsgDescs: []*descriptorpb.DescriptorProto{ - { - Name: proto.String("DirectRecursiveMessage"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("nested"), - Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - TypeName: proto.String(".example.DirectRecursiveMessage"), - Number: proto.Int32(1), - }, - }, - }, - }, - Message: "DirectRecursiveMessage", - }, - // Second test: - // Here we test that a cycle through multiple messages is detected and that an error is returned. - // Sample: - // message Root { NodeMessage nested = 1; } - // message NodeMessage { CycleMessage nested = 1; } - // message CycleMessage { Root nested = 1; } - { - MsgDescs: []*descriptorpb.DescriptorProto{ - { - Name: proto.String("RootMessage"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("nested"), - Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - TypeName: proto.String(".example.NodeMessage"), - Number: proto.Int32(1), - }, - }, - }, - { - Name: proto.String("NodeMessage"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("nested"), - Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - TypeName: proto.String(".example.CycleMessage"), - Number: proto.Int32(1), - }, - }, - }, - { - Name: proto.String("CycleMessage"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("nested"), - Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - TypeName: proto.String(".example.RootMessage"), - Number: proto.Int32(1), - }, - }, - }, - }, - Message: "RootMessage", - }, - } - - for _, test := range tests { - reg := descriptor.NewRegistry() - msgs := []*descriptor.Message{} - for _, msgdesc := range test.MsgDescs { - msgs = append(msgs, &descriptor.Message{DescriptorProto: msgdesc}) - } - file := descriptor.File{ - FileDescriptorProto: &descriptorpb.FileDescriptorProto{ - SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, - Name: proto.String("example.proto"), - Package: proto.String("example"), - Dependency: []string{}, - MessageType: test.MsgDescs, - Service: []*descriptorpb.ServiceDescriptorProto{}, - }, - GoPkg: descriptor.GoPackage{ - Path: "example.com/path/to/example/example.pb", - Name: "example_pb", - }, - Messages: msgs, - } - reg.Load(&pluginpb.CodeGeneratorRequest{ - ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto}, - }) - - message, err := reg.LookupMsg("", ".example."+test.Message) - if err != nil { - t.Fatalf("failed to lookup message: %s", err) - } - _, err = messageToQueryParameters(message, reg, []descriptor.Parameter{}, nil) - if err == nil { - t.Fatalf("It should not be allowed to have recursive query parameters") - } - } -} - -func TestMessageToQueryParametersWithJsonName(t *testing.T) { - type test struct { - MsgDescs []*descriptorpb.DescriptorProto - Message string - Params []openapiParameterObject - } - - tests := []test{ - { - MsgDescs: []*descriptorpb.DescriptorProto{ - { - Name: proto.String("ExampleMessage"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("test_field_a"), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - Number: proto.Int32(1), - JsonName: proto.String("testFieldA"), - }, - }, - }, - }, - Message: "ExampleMessage", - Params: []openapiParameterObject{ - { - Name: "testFieldA", - In: "query", - Required: false, - Type: "string", - }, - }, - }, - { - MsgDescs: []*descriptorpb.DescriptorProto{ - { - Name: proto.String("SubMessage"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("test_field_a"), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - Number: proto.Int32(1), - JsonName: proto.String("testFieldA"), - }, - }, - }, - { - Name: proto.String("ExampleMessage"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("sub_message"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - TypeName: proto.String(".example.SubMessage"), - Number: proto.Int32(1), - JsonName: proto.String("subMessage"), - }, - }, - }, - }, - Message: "ExampleMessage", - Params: []openapiParameterObject{ - { - Name: "subMessage.testFieldA", - In: "query", - Required: false, - Type: "string", - }, - }, - }, - } - - for _, test := range tests { - reg := descriptor.NewRegistry() - reg.SetUseJSONNamesForFields(true) - msgs := []*descriptor.Message{} - for _, msgdesc := range test.MsgDescs { - msgs = append(msgs, &descriptor.Message{DescriptorProto: msgdesc}) - } - file := descriptor.File{ - FileDescriptorProto: &descriptorpb.FileDescriptorProto{ - SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, - Name: proto.String("example.proto"), - Package: proto.String("example"), - Dependency: []string{}, - MessageType: test.MsgDescs, - Service: []*descriptorpb.ServiceDescriptorProto{}, - }, - GoPkg: descriptor.GoPackage{ - Path: "example.com/path/to/example/example.pb", - Name: "example_pb", - }, - Messages: msgs, - } - reg.Load(&pluginpb.CodeGeneratorRequest{ - ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto}, - }) - - message, err := reg.LookupMsg("", ".example."+test.Message) - if err != nil { - t.Fatalf("failed to lookup message: %s", err) - } - params, err := messageToQueryParameters(message, reg, []descriptor.Parameter{}, nil) - if err != nil { - t.Fatalf("failed to convert message to query parameters: %s", err) - } - if !reflect.DeepEqual(params, test.Params) { - t.Errorf("expected %v, got %v", test.Params, params) - } - } -} - -func TestMessageToQueryParametersWellKnownTypes(t *testing.T) { - type test struct { - MsgDescs []*descriptorpb.DescriptorProto - WellKnownMsgDescs []*descriptorpb.DescriptorProto - Message string - Params []openapiParameterObject - } - - tests := []test{ - { - MsgDescs: []*descriptorpb.DescriptorProto{ - { - Name: proto.String("ExampleMessage"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("a_field_mask"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - TypeName: proto.String(".google.protobuf.FieldMask"), - Number: proto.Int32(1), - }, - { - Name: proto.String("a_timestamp"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - TypeName: proto.String(".google.protobuf.Timestamp"), - Number: proto.Int32(2), - }, - }, - }, - }, - WellKnownMsgDescs: []*descriptorpb.DescriptorProto{ - { - Name: proto.String("FieldMask"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("paths"), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - Label: descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(), - Number: proto.Int32(1), - }, - }, - }, - { - Name: proto.String("Timestamp"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("seconds"), - Type: descriptorpb.FieldDescriptorProto_TYPE_INT64.Enum(), - Number: proto.Int32(1), - }, - { - Name: proto.String("nanos"), - Type: descriptorpb.FieldDescriptorProto_TYPE_INT32.Enum(), - Number: proto.Int32(2), - }, - }, - }, - }, - Message: "ExampleMessage", - Params: []openapiParameterObject{ - { - Name: "a_field_mask", - In: "query", - Required: false, - Type: "array", - Items: &openapiItemsObject{ - Type: "string", - }, - CollectionFormat: "multi", - }, - { - Name: "a_timestamp", - In: "query", - Required: false, - Type: "string", - Format: "date-time", - }, - }, - }, - } - - for _, test := range tests { - reg := descriptor.NewRegistry() - reg.SetEnumsAsInts(true) - err := reg.Load(&pluginpb.CodeGeneratorRequest{ - ProtoFile: []*descriptorpb.FileDescriptorProto{ - { - SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, - Name: proto.String("google/well_known.proto"), - Package: proto.String("google.protobuf"), - Dependency: []string{}, - MessageType: test.WellKnownMsgDescs, - Service: []*descriptorpb.ServiceDescriptorProto{}, - }, - { - SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, - Name: proto.String("acme/example.proto"), - Package: proto.String("example"), - Dependency: []string{"google/well_known.proto"}, - MessageType: test.MsgDescs, - Service: []*descriptorpb.ServiceDescriptorProto{}, - }, - }, - }) - if err != nil { - t.Fatalf("failed to load CodeGeneratorRequest: %v", err) - } - - message, err := reg.LookupMsg("", ".example."+test.Message) - if err != nil { - t.Fatalf("failed to lookup message: %s", err) - } - params, err := messageToQueryParameters(message, reg, []descriptor.Parameter{}, nil) - if err != nil { - t.Fatalf("failed to convert message to query parameters: %s", err) - } - if !reflect.DeepEqual(params, test.Params) { - t.Errorf("expected %v, got %v", test.Params, params) - } - } -} - -func TestApplyTemplateSimple(t *testing.T) { - msgdesc := &descriptorpb.DescriptorProto{ - Name: proto.String("ExampleMessage"), - } - meth := &descriptorpb.MethodDescriptorProto{ - Name: proto.String("Example"), - InputType: proto.String("ExampleMessage"), - OutputType: proto.String("ExampleMessage"), - } - svc := &descriptorpb.ServiceDescriptorProto{ - Name: proto.String("ExampleService"), - Method: []*descriptorpb.MethodDescriptorProto{meth}, - } - msg := &descriptor.Message{ - DescriptorProto: msgdesc, - } - file := descriptor.File{ - FileDescriptorProto: &descriptorpb.FileDescriptorProto{ - SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, - Name: proto.String("example.proto"), - Package: proto.String("example"), - MessageType: []*descriptorpb.DescriptorProto{msgdesc}, - Service: []*descriptorpb.ServiceDescriptorProto{svc}, - }, - GoPkg: descriptor.GoPackage{ - Path: "example.com/path/to/example/example.pb", - Name: "example_pb", - }, - Messages: []*descriptor.Message{msg}, - Services: []*descriptor.Service{ - { - ServiceDescriptorProto: svc, - Methods: []*descriptor.Method{ - { - MethodDescriptorProto: meth, - RequestType: msg, - ResponseType: msg, - Bindings: []*descriptor.Binding{ - { - HTTPMethod: "GET", - Body: &descriptor.Body{FieldPath: nil}, - PathTmpl: httprule.Template{ - Version: 1, - OpCodes: []int{0, 0}, - Template: "/v1/echo", // TODO(achew22): Figure out what this should really be - }, - }, - }, - }, - }, - }, - }, - } - reg := descriptor.NewRegistry() - if err := AddErrorDefs(reg); err != nil { - t.Errorf("AddErrorDefs(%#v) failed with %v; want success", reg, err) - return - } - fileCL := crossLinkFixture(&file) - err := reg.Load(reqFromFile(fileCL)) - if err != nil { - t.Errorf("reg.Load(%#v) failed with %v; want success", file, err) - return - } - result, err := applyTemplate(param{File: fileCL, reg: reg}) - if err != nil { - t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err) - return - } - if want, is, name := "2.0", result.Swagger, "Swagger"; !reflect.DeepEqual(is, want) { - t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want) - } - if want, is, name := "", result.BasePath, "BasePath"; !reflect.DeepEqual(is, want) { - t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want) - } - if want, is, name := ([]string)(nil), result.Schemes, "Schemes"; !reflect.DeepEqual(is, want) { - t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want) - } - if want, is, name := []string{"application/json"}, result.Consumes, "Consumes"; !reflect.DeepEqual(is, want) { - t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want) - } - if want, is, name := []string{"application/json"}, result.Produces, "Produces"; !reflect.DeepEqual(is, want) { - t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want) - } - - // If there was a failure, print out the input and the json result for debugging. - if t.Failed() { - t.Errorf("had: %s", file) - t.Errorf("got: %s", fmt.Sprint(result)) - } -} - -func TestApplyTemplateMultiService(t *testing.T) { - msgdesc := &descriptorpb.DescriptorProto{ - Name: proto.String("ExampleMessage"), - } - meth := &descriptorpb.MethodDescriptorProto{ - Name: proto.String("Example"), - InputType: proto.String("ExampleMessage"), - OutputType: proto.String("ExampleMessage"), - } - - // Create two services that have the same method name. We will test that the - // operation IDs are different - svc := &descriptorpb.ServiceDescriptorProto{ - Name: proto.String("ExampleService"), - Method: []*descriptorpb.MethodDescriptorProto{meth}, - } - svc2 := &descriptorpb.ServiceDescriptorProto{ - Name: proto.String("OtherService"), - Method: []*descriptorpb.MethodDescriptorProto{meth}, - } - - msg := &descriptor.Message{ - DescriptorProto: msgdesc, - } - file := descriptor.File{ - FileDescriptorProto: &descriptorpb.FileDescriptorProto{ - SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, - Name: proto.String("example.proto"), - Package: proto.String("example"), - MessageType: []*descriptorpb.DescriptorProto{msgdesc}, - Service: []*descriptorpb.ServiceDescriptorProto{svc}, - }, - GoPkg: descriptor.GoPackage{ - Path: "example.com/path/to/example/example.pb", - Name: "example_pb", - }, - Messages: []*descriptor.Message{msg}, - Services: []*descriptor.Service{ - { - ServiceDescriptorProto: svc, - Methods: []*descriptor.Method{ - { - MethodDescriptorProto: meth, - RequestType: msg, - ResponseType: msg, - Bindings: []*descriptor.Binding{ - { - HTTPMethod: "GET", - Body: &descriptor.Body{FieldPath: nil}, - PathTmpl: httprule.Template{ - Version: 1, - OpCodes: []int{0, 0}, - Template: "/v1/echo", - }, - }, - }, - }, - }, - }, - { - ServiceDescriptorProto: svc2, - Methods: []*descriptor.Method{ - { - MethodDescriptorProto: meth, - RequestType: msg, - ResponseType: msg, - Bindings: []*descriptor.Binding{ - { - HTTPMethod: "GET", - Body: &descriptor.Body{FieldPath: nil}, - PathTmpl: httprule.Template{ - Version: 1, - OpCodes: []int{0, 0}, - Template: "/v1/ping", - }, - }, - }, - }, - }, - }, - }, - } - reg := descriptor.NewRegistry() - if err := AddErrorDefs(reg); err != nil { - t.Errorf("AddErrorDefs(%#v) failed with %v; want success", reg, err) - return - } - fileCL := crossLinkFixture(&file) - err := reg.Load(reqFromFile(fileCL)) - if err != nil { - t.Errorf("reg.Load(%#v) failed with %v; want success", file, err) - return - } - result, err := applyTemplate(param{File: fileCL, reg: reg}) - if err != nil { - t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err) - return - } - - // Check that the two services have unique operation IDs even though they - // have the same method name. - if want, is := "ExampleService_Example", result.Paths["/v1/echo"].Get.OperationID; !reflect.DeepEqual(is, want) { - t.Errorf("applyTemplate(%#v).Paths[0].Get.OperationID = %s want to be %s", file, is, want) - } - if want, is := "OtherService_Example", result.Paths["/v1/ping"].Get.OperationID; !reflect.DeepEqual(is, want) { - t.Errorf("applyTemplate(%#v).Paths[0].Get.OperationID = %s want to be %s", file, is, want) - } - - // If there was a failure, print out the input and the json result for debugging. - if t.Failed() { - t.Errorf("had: %s", file) - t.Errorf("got: %s", fmt.Sprint(result)) - } -} - -func TestApplyTemplateOverrideOperationID(t *testing.T) { - newFile := func() *descriptor.File { - msgdesc := &descriptorpb.DescriptorProto{ - Name: proto.String("ExampleMessage"), - } - meth := &descriptorpb.MethodDescriptorProto{ - Name: proto.String("Example"), - InputType: proto.String("ExampleMessage"), - OutputType: proto.String("ExampleMessage"), - Options: &descriptorpb.MethodOptions{}, - } - svc := &descriptorpb.ServiceDescriptorProto{ - Name: proto.String("ExampleService"), - Method: []*descriptorpb.MethodDescriptorProto{meth}, - } - msg := &descriptor.Message{ - DescriptorProto: msgdesc, - } - return &descriptor.File{ - FileDescriptorProto: &descriptorpb.FileDescriptorProto{ - SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, - Name: proto.String("example.proto"), - Package: proto.String("example"), - MessageType: []*descriptorpb.DescriptorProto{msgdesc}, - Service: []*descriptorpb.ServiceDescriptorProto{svc}, - }, - GoPkg: descriptor.GoPackage{ - Path: "example.com/path/to/example/example.pb", - Name: "example_pb", - }, - Messages: []*descriptor.Message{msg}, - Services: []*descriptor.Service{ - { - ServiceDescriptorProto: svc, - Methods: []*descriptor.Method{ - { - MethodDescriptorProto: meth, - RequestType: msg, - ResponseType: msg, - Bindings: []*descriptor.Binding{ - { - HTTPMethod: "GET", - Body: &descriptor.Body{FieldPath: nil}, - PathTmpl: httprule.Template{ - Version: 1, - OpCodes: []int{0, 0}, - Template: "/v1/echo", // TODO(achew22): Figure out what this should really be - }, - }, - }, - }, - }, - }, - }, - } - } - - verifyTemplateFromReq := func(t *testing.T, reg *descriptor.Registry, file *descriptor.File, opts *openapiconfig.OpenAPIOptions) { - if err := AddErrorDefs(reg); err != nil { - t.Errorf("AddErrorDefs(%#v) failed with %v; want success", reg, err) - return - } - fileCL := crossLinkFixture(file) - err := reg.Load(reqFromFile(fileCL)) - if err != nil { - t.Errorf("reg.Load(%#v) failed with %v; want success", *file, err) - return - } - if opts != nil { - if err := reg.RegisterOpenAPIOptions(opts); err != nil { - t.Fatalf("failed to register OpenAPI options: %s", err) - } - } - result, err := applyTemplate(param{File: fileCL, reg: reg}) - if err != nil { - t.Errorf("applyTemplate(%#v) failed with %v; want success", *file, err) - return - } - if want, is := "MyExample", result.Paths["/v1/echo"].Get.OperationID; !reflect.DeepEqual(is, want) { - t.Errorf("applyTemplate(%#v).Paths[0].Get.OperationID = %s want to be %s", *file, is, want) - } - - // If there was a failure, print out the input and the json result for debugging. - if t.Failed() { - t.Errorf("had: %s", *file) - t.Errorf("got: %s", fmt.Sprint(result)) - } - } - - openapiOperation := openapi_options.Operation{ - OperationId: "MyExample", - } - - t.Run("verify override via method option", func(t *testing.T) { - file := newFile() - proto.SetExtension(proto.Message(file.Services[0].Methods[0].MethodDescriptorProto.Options), - openapi_options.E_Openapiv2Operation, &openapiOperation) - - reg := descriptor.NewRegistry() - verifyTemplateFromReq(t, reg, file, nil) - }) - - t.Run("verify override options annotations", func(t *testing.T) { - file := newFile() - reg := descriptor.NewRegistry() - opts := &openapiconfig.OpenAPIOptions{ - Method: []*openapiconfig.OpenAPIMethodOption{ - { - Method: "example.ExampleService.Example", - Option: &openapiOperation, - }, - }, - } - verifyTemplateFromReq(t, reg, file, opts) - }) -} - -func TestApplyTemplateExtensions(t *testing.T) { - newFile := func() *descriptor.File { - msgdesc := &descriptorpb.DescriptorProto{ - Name: proto.String("ExampleMessage"), - } - meth := &descriptorpb.MethodDescriptorProto{ - Name: proto.String("Example"), - InputType: proto.String("ExampleMessage"), - OutputType: proto.String("ExampleMessage"), - Options: &descriptorpb.MethodOptions{}, - } - svc := &descriptorpb.ServiceDescriptorProto{ - Name: proto.String("ExampleService"), - Method: []*descriptorpb.MethodDescriptorProto{meth}, - } - msg := &descriptor.Message{ - DescriptorProto: msgdesc, - } - return &descriptor.File{ - FileDescriptorProto: &descriptorpb.FileDescriptorProto{ - SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, - Name: proto.String("example.proto"), - Package: proto.String("example"), - MessageType: []*descriptorpb.DescriptorProto{msgdesc}, - Service: []*descriptorpb.ServiceDescriptorProto{svc}, - Options: &descriptorpb.FileOptions{}, - }, - GoPkg: descriptor.GoPackage{ - Path: "example.com/path/to/example/example.pb", - Name: "example_pb", - }, - Messages: []*descriptor.Message{msg}, - Services: []*descriptor.Service{ - { - ServiceDescriptorProto: svc, - Methods: []*descriptor.Method{ - { - MethodDescriptorProto: meth, - RequestType: msg, - ResponseType: msg, - Bindings: []*descriptor.Binding{ - { - HTTPMethod: "GET", - Body: &descriptor.Body{FieldPath: nil}, - PathTmpl: httprule.Template{ - Version: 1, - OpCodes: []int{0, 0}, - Template: "/v1/echo", // TODO(achew22): Figure out what this should really be - }, - }, - }, - }, - }, - }, - }, - } - } - swagger := openapi_options.Swagger{ - Info: &openapi_options.Info{ - Title: "test", - Extensions: map[string]*structpb.Value{ - "x-info-extension": {Kind: &structpb.Value_StringValue{StringValue: "bar"}}, - }, - }, - Extensions: map[string]*structpb.Value{ - "x-foo": {Kind: &structpb.Value_StringValue{StringValue: "bar"}}, - "x-bar": {Kind: &structpb.Value_ListValue{ListValue: &structpb.ListValue{ - Values: []*structpb.Value{{Kind: &structpb.Value_StringValue{StringValue: "baz"}}}, - }}}, - }, - SecurityDefinitions: &openapi_options.SecurityDefinitions{ - Security: map[string]*openapi_options.SecurityScheme{ - "somescheme": { - Extensions: map[string]*structpb.Value{ - "x-security-baz": {Kind: &structpb.Value_BoolValue{BoolValue: true}}, - }, - }, - }, - }, - } - openapiOperation := openapi_options.Operation{ - Responses: map[string]*openapi_options.Response{ - "200": { - Extensions: map[string]*structpb.Value{ - "x-resp-id": {Kind: &structpb.Value_StringValue{StringValue: "resp1000"}}, - }, - }, - }, - Extensions: map[string]*structpb.Value{ - "x-op-foo": {Kind: &structpb.Value_StringValue{StringValue: "baz"}}, - }, - } - verifyTemplateExtensions := func(t *testing.T, reg *descriptor.Registry, file *descriptor.File, - opts *openapiconfig.OpenAPIOptions) { - if err := AddErrorDefs(reg); err != nil { - t.Errorf("AddErrorDefs(%#v) failed with %v; want success", reg, err) - return - } - fileCL := crossLinkFixture(file) - err := reg.Load(reqFromFile(fileCL)) - if err != nil { - t.Errorf("reg.Load(%#v) failed with %v; want success", file, err) - return - } - if opts != nil { - if err := reg.RegisterOpenAPIOptions(opts); err != nil { - t.Fatalf("failed to register OpenAPI annotations: %s", err) - } - } - result, err := applyTemplate(param{File: fileCL, reg: reg}) - if err != nil { - t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err) - return - } - if want, is, name := "2.0", result.Swagger, "Swagger"; !reflect.DeepEqual(is, want) { - t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want) - } - if got, want := len(result.extensions), 2; got != want { - t.Fatalf("len(applyTemplate(%#v).Extensions) = %d want to be %d", file, got, want) - } - if got, want := result.extensions[0].key, "x-bar"; got != want { - t.Errorf("applyTemplate(%#v).Extensions[0].key = %s want to be %s", file, got, want) - } - if got, want := result.extensions[1].key, "x-foo"; got != want { - t.Errorf("applyTemplate(%#v).Extensions[1].key = %s want to be %s", file, got, want) - } - { - var got []string - err = marshaler.Unmarshal(result.extensions[0].value, &got) - if err != nil { - t.Fatalf("marshaler.Unmarshal failed: %v", err) - } - want := []string{"baz"} - if diff := cmp.Diff(got, want); diff != "" { - t.Errorf(diff) - } - } - { - var got string - err = marshaler.Unmarshal(result.extensions[1].value, &got) - if err != nil { - t.Fatalf("marshaler.Unmarshal failed: %v", err) - } - want := "bar" - if diff := cmp.Diff(got, want); diff != "" { - t.Errorf(diff) - } - } - - var scheme openapiSecuritySchemeObject - for _, v := range result.SecurityDefinitions { - scheme = v - } - if want, is, name := []extension{ - {key: "x-security-baz", value: json.RawMessage("true")}, - }, scheme.extensions, "SecurityScheme.Extensions"; !reflect.DeepEqual(is, want) { - t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want) - } - - if want, is, name := []extension{ - {key: "x-info-extension", value: json.RawMessage("\"bar\"")}, - }, result.Info.extensions, "Info.Extensions"; !reflect.DeepEqual(is, want) { - t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want) - } - - var operation *openapiOperationObject - var response openapiResponseObject - for _, v := range result.Paths { - operation = v.Get - response = v.Get.Responses["200"] - } - if want, is, name := []extension{ - {key: "x-op-foo", value: json.RawMessage("\"baz\"")}, - }, operation.extensions, "operation.Extensions"; !reflect.DeepEqual(is, want) { - t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want) - } - if want, is, name := []extension{ - {key: "x-resp-id", value: json.RawMessage("\"resp1000\"")}, - }, response.extensions, "response.Extensions"; !reflect.DeepEqual(is, want) { - t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want) - } - } - t.Run("verify template options set via proto options", func(t *testing.T) { - file := newFile() - proto.SetExtension(proto.Message(file.FileDescriptorProto.Options), openapi_options.E_Openapiv2Swagger, &swagger) - proto.SetExtension(proto.Message(file.Services[0].Methods[0].Options), openapi_options.E_Openapiv2Operation, &openapiOperation) - reg := descriptor.NewRegistry() - verifyTemplateExtensions(t, reg, file, nil) - }) - t.Run("verify template options set via annotations", func(t *testing.T) { - file := newFile() - opts := &openapiconfig.OpenAPIOptions{ - File: []*openapiconfig.OpenAPIFileOption{ - { - File: "example.proto", - Option: &swagger, - }, - }, - Method: []*openapiconfig.OpenAPIMethodOption{ - { - Method: "example.ExampleService.Example", - Option: &openapiOperation, - }, - }, - } - reg := descriptor.NewRegistry() - verifyTemplateExtensions(t, reg, file, opts) - }) -} - -func TestApplyTemplateRequestWithoutClientStreaming(t *testing.T) { - msgdesc := &descriptorpb.DescriptorProto{ - Name: proto.String("ExampleMessage"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("nested"), - Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - TypeName: proto.String("NestedMessage"), - Number: proto.Int32(1), - }, - }, - } - nesteddesc := &descriptorpb.DescriptorProto{ - Name: proto.String("NestedMessage"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("int32"), - Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_INT32.Enum(), - Number: proto.Int32(1), - }, - { - Name: proto.String("bool"), - Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_BOOL.Enum(), - Number: proto.Int32(2), - }, - }, - } - meth := &descriptorpb.MethodDescriptorProto{ - Name: proto.String("Echo"), - InputType: proto.String("ExampleMessage"), - OutputType: proto.String("ExampleMessage"), - ClientStreaming: proto.Bool(false), - } - svc := &descriptorpb.ServiceDescriptorProto{ - Name: proto.String("ExampleService"), - Method: []*descriptorpb.MethodDescriptorProto{meth}, - } - - meth.ServerStreaming = proto.Bool(false) - - msg := &descriptor.Message{ - DescriptorProto: msgdesc, - } - nested := &descriptor.Message{ - DescriptorProto: nesteddesc, - } - - nestedField := &descriptor.Field{ - Message: msg, - FieldDescriptorProto: msg.GetField()[0], - } - intField := &descriptor.Field{ - Message: nested, - FieldDescriptorProto: nested.GetField()[0], - } - boolField := &descriptor.Field{ - Message: nested, - FieldDescriptorProto: nested.GetField()[1], - } - file := descriptor.File{ - FileDescriptorProto: &descriptorpb.FileDescriptorProto{ - SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, - Name: proto.String("example.proto"), - Package: proto.String("example"), - MessageType: []*descriptorpb.DescriptorProto{msgdesc, nesteddesc}, - Service: []*descriptorpb.ServiceDescriptorProto{svc}, - }, - GoPkg: descriptor.GoPackage{ - Path: "example.com/path/to/example/example.pb", - Name: "example_pb", - }, - Messages: []*descriptor.Message{msg, nested}, - Services: []*descriptor.Service{ - { - ServiceDescriptorProto: svc, - Methods: []*descriptor.Method{ - { - MethodDescriptorProto: meth, - RequestType: msg, - ResponseType: msg, - Bindings: []*descriptor.Binding{ - { - HTTPMethod: "POST", - PathTmpl: httprule.Template{ - Version: 1, - OpCodes: []int{0, 0}, - Template: "/v1/echo", // TODO(achew): Figure out what this hsould really be - }, - PathParams: []descriptor.Parameter{ - { - FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{ - { - Name: "nested", - Target: nestedField, - }, - { - Name: "int32", - Target: intField, - }, - }), - Target: intField, - }, - }, - Body: &descriptor.Body{ - FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{ - { - Name: "nested", - Target: nestedField, - }, - { - Name: "bool", - Target: boolField, - }, - }), - }, - }, - }, - }, - }, - }, - }, - } - reg := descriptor.NewRegistry() - if err := AddErrorDefs(reg); err != nil { - t.Errorf("AddErrorDefs(%#v) failed with %v; want success", reg, err) - return - } - reg.Load(&pluginpb.CodeGeneratorRequest{ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto}}) - result, err := applyTemplate(param{File: crossLinkFixture(&file), reg: reg}) - if err != nil { - t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err) - return - } - if want, got := "2.0", result.Swagger; !reflect.DeepEqual(got, want) { - t.Errorf("applyTemplate(%#v).Swagger = %s want to be %s", file, got, want) - } - if want, got := "", result.BasePath; !reflect.DeepEqual(got, want) { - t.Errorf("applyTemplate(%#v).BasePath = %s want to be %s", file, got, want) - } - if want, got := ([]string)(nil), result.Schemes; !reflect.DeepEqual(got, want) { - t.Errorf("applyTemplate(%#v).Schemes = %s want to be %s", file, got, want) - } - if want, got := []string{"application/json"}, result.Consumes; !reflect.DeepEqual(got, want) { - t.Errorf("applyTemplate(%#v).Consumes = %s want to be %s", file, got, want) - } - if want, got := []string{"application/json"}, result.Produces; !reflect.DeepEqual(got, want) { - t.Errorf("applyTemplate(%#v).Produces = %s want to be %s", file, got, want) - } - - // If there was a failure, print out the input and the json result for debugging. - if t.Failed() { - t.Errorf("had: %s", file) - t.Errorf("got: %s", fmt.Sprint(result)) - } -} - -func TestApplyTemplateRequestWithClientStreaming(t *testing.T) { - msgdesc := &descriptorpb.DescriptorProto{ - Name: proto.String("ExampleMessage"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("nested"), - Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - TypeName: proto.String("NestedMessage"), - Number: proto.Int32(1), - }, - }, - } - nesteddesc := &descriptorpb.DescriptorProto{ - Name: proto.String("NestedMessage"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("int32"), - Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_INT32.Enum(), - Number: proto.Int32(1), - }, - { - Name: proto.String("bool"), - Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_BOOL.Enum(), - Number: proto.Int32(2), - }, - }, - } - meth := &descriptorpb.MethodDescriptorProto{ - Name: proto.String("Echo"), - InputType: proto.String("ExampleMessage"), - OutputType: proto.String("ExampleMessage"), - ClientStreaming: proto.Bool(true), - ServerStreaming: proto.Bool(true), - } - svc := &descriptorpb.ServiceDescriptorProto{ - Name: proto.String("ExampleService"), - Method: []*descriptorpb.MethodDescriptorProto{meth}, - } - - msg := &descriptor.Message{ - DescriptorProto: msgdesc, - } - nested := &descriptor.Message{ - DescriptorProto: nesteddesc, - } - - nestedField := &descriptor.Field{ - Message: msg, - FieldDescriptorProto: msg.GetField()[0], - } - intField := &descriptor.Field{ - Message: nested, - FieldDescriptorProto: nested.GetField()[0], - } - boolField := &descriptor.Field{ - Message: nested, - FieldDescriptorProto: nested.GetField()[1], - } - file := descriptor.File{ - FileDescriptorProto: &descriptorpb.FileDescriptorProto{ - SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, - Name: proto.String("example.proto"), - Package: proto.String("example"), - MessageType: []*descriptorpb.DescriptorProto{msgdesc, nesteddesc}, - Service: []*descriptorpb.ServiceDescriptorProto{svc}, - }, - GoPkg: descriptor.GoPackage{ - Path: "example.com/path/to/example/example.pb", - Name: "example_pb", - }, - Messages: []*descriptor.Message{msg, nested}, - Services: []*descriptor.Service{ - { - ServiceDescriptorProto: svc, - Methods: []*descriptor.Method{ - { - MethodDescriptorProto: meth, - RequestType: msg, - ResponseType: msg, - Bindings: []*descriptor.Binding{ - { - HTTPMethod: "POST", - PathTmpl: httprule.Template{ - Version: 1, - OpCodes: []int{0, 0}, - Template: "/v1/echo", // TODO(achew): Figure out what this hsould really be - }, - PathParams: []descriptor.Parameter{ - { - FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{ - { - Name: "nested", - Target: nestedField, - }, - { - Name: "int32", - Target: intField, - }, - }), - Target: intField, - }, - }, - Body: &descriptor.Body{ - FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{ - { - Name: "nested", - Target: nestedField, - }, - { - Name: "bool", - Target: boolField, - }, - }), - }, - }, - }, - }, - }, - }, - }, - } - reg := descriptor.NewRegistry() - if err := AddErrorDefs(reg); err != nil { - t.Errorf("AddErrorDefs(%#v) failed with %v; want success", reg, err) - return - } - reg.Load(&pluginpb.CodeGeneratorRequest{ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto}}) - result, err := applyTemplate(param{File: crossLinkFixture(&file), reg: reg}) - if err != nil { - t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err) - return - } - - // Only ExampleMessage must be present, not NestedMessage - if want, got, name := 3, len(result.Definitions), "len(Definitions)"; !reflect.DeepEqual(got, want) { - t.Errorf("applyTemplate(%#v).%s = %d want to be %d", file, name, got, want) - } - if _, ok := result.Paths["/v1/echo"].Post.Responses["200"]; !ok { - t.Errorf("applyTemplate(%#v).%s = expected 200 response to be defined", file, `result.Paths["/v1/echo"].Post.Responses["200"]`) - } else { - if want, got, name := "A successful response.(streaming responses)", result.Paths["/v1/echo"].Post.Responses["200"].Description, `result.Paths["/v1/echo"].Post.Responses["200"].Description`; !reflect.DeepEqual(got, want) { - t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, got, want) - } - streamExampleExampleMessage := result.Paths["/v1/echo"].Post.Responses["200"].Schema - if want, got, name := "object", streamExampleExampleMessage.Type, `result.Paths["/v1/echo"].Post.Responses["200"].Schema.Type`; !reflect.DeepEqual(got, want) { - t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, got, want) - } - if want, got, name := "Stream result of exampleExampleMessage", streamExampleExampleMessage.Title, `result.Paths["/v1/echo"].Post.Responses["200"].Schema.Title`; !reflect.DeepEqual(got, want) { - t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, got, want) - } - streamExampleExampleMessageProperties := *(streamExampleExampleMessage.Properties) - if want, got, name := 2, len(streamExampleExampleMessageProperties), `len(StreamDefinitions["exampleExampleMessage"].Properties)`; !reflect.DeepEqual(got, want) { - t.Errorf("applyTemplate(%#v).%s = %d want to be %d", file, name, got, want) - } else { - resultProperty := streamExampleExampleMessageProperties[0] - if want, got, name := "result", resultProperty.Key, `(*(StreamDefinitions["exampleExampleMessage"].Properties))[0].Key`; !reflect.DeepEqual(got, want) { - t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, got, want) - } - result := resultProperty.Value.(openapiSchemaObject) - if want, got, name := "#/definitions/exampleExampleMessage", result.Ref, `((*(StreamDefinitions["exampleExampleMessage"].Properties))[0].Value.(openapiSchemaObject)).Ref`; !reflect.DeepEqual(got, want) { - t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, got, want) - } - errorProperty := streamExampleExampleMessageProperties[1] - if want, got, name := "error", errorProperty.Key, `(*(StreamDefinitions["exampleExampleMessage"].Properties))[0].Key`; !reflect.DeepEqual(got, want) { - t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, got, want) - } - err := errorProperty.Value.(openapiSchemaObject) - if want, got, name := "#/definitions/rpcStatus", err.Ref, `((*(StreamDefinitions["exampleExampleMessage"].Properties))[0].Value.(openapiSchemaObject)).Ref`; !reflect.DeepEqual(got, want) { - t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, got, want) - } - } - } - - // If there was a failure, print out the input and the json result for debugging. - if t.Failed() { - t.Errorf("had: %s", file) - t.Errorf("got: %s", fmt.Sprint(result)) - } -} - -func TestApplyTemplateRequestWithUnusedReferences(t *testing.T) { - reqdesc := &descriptorpb.DescriptorProto{ - Name: proto.String("ExampleMessage"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("string"), - Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - Number: proto.Int32(1), - }, - }, - } - respdesc := &descriptorpb.DescriptorProto{ - Name: proto.String("EmptyMessage"), - } - meth := &descriptorpb.MethodDescriptorProto{ - Name: proto.String("Example"), - InputType: proto.String("ExampleMessage"), - OutputType: proto.String("EmptyMessage"), - ClientStreaming: proto.Bool(false), - ServerStreaming: proto.Bool(false), - } - svc := &descriptorpb.ServiceDescriptorProto{ - Name: proto.String("ExampleService"), - Method: []*descriptorpb.MethodDescriptorProto{meth}, - } - - req := &descriptor.Message{ - DescriptorProto: reqdesc, - } - resp := &descriptor.Message{ - DescriptorProto: respdesc, - } - stringField := &descriptor.Field{ - Message: req, - FieldDescriptorProto: req.GetField()[0], - } - file := descriptor.File{ - FileDescriptorProto: &descriptorpb.FileDescriptorProto{ - SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, - Name: proto.String("example.proto"), - Package: proto.String("example"), - MessageType: []*descriptorpb.DescriptorProto{reqdesc, respdesc}, - Service: []*descriptorpb.ServiceDescriptorProto{svc}, - }, - GoPkg: descriptor.GoPackage{ - Path: "example.com/path/to/example/example.pb", - Name: "example_pb", - }, - Messages: []*descriptor.Message{req, resp}, - Services: []*descriptor.Service{ - { - ServiceDescriptorProto: svc, - Methods: []*descriptor.Method{ - { - MethodDescriptorProto: meth, - RequestType: req, - ResponseType: resp, - Bindings: []*descriptor.Binding{ - { - HTTPMethod: "GET", - PathTmpl: httprule.Template{ - Version: 1, - OpCodes: []int{0, 0}, - Template: "/v1/example", - }, - }, - { - HTTPMethod: "POST", - PathTmpl: httprule.Template{ - Version: 1, - OpCodes: []int{0, 0}, - Template: "/v1/example/{string}", - }, - PathParams: []descriptor.Parameter{ - { - FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{ - { - Name: "string", - Target: stringField, - }, - }), - Target: stringField, - }, - }, - Body: &descriptor.Body{ - FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{ - { - Name: "string", - Target: stringField, - }, - }), - }, - }, - }, - }, - }, - }, - }, - } - - reg := descriptor.NewRegistry() - if err := AddErrorDefs(reg); err != nil { - t.Errorf("AddErrorDefs(%#v) failed with %v; want success", reg, err) - return - } - reg.Load(&pluginpb.CodeGeneratorRequest{ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto}}) - result, err := applyTemplate(param{File: crossLinkFixture(&file), reg: reg}) - if err != nil { - t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err) - return - } - - // Only EmptyMessage must be present, not ExampleMessage (plus error status) - if want, got, name := 3, len(result.Definitions), "len(Definitions)"; !reflect.DeepEqual(got, want) { - t.Errorf("applyTemplate(%#v).%s = %d want to be %d", file, name, got, want) - } - - // If there was a failure, print out the input and the json result for debugging. - if t.Failed() { - t.Errorf("had: %s", file) - t.Errorf("got: %s", fmt.Sprint(result)) - } -} - -func TestApplyTemplateRequestWithBodyQueryParameters(t *testing.T) { - bookDesc := &descriptorpb.DescriptorProto{ - Name: proto.String("Book"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("name"), - Label: descriptorpb.FieldDescriptorProto_LABEL_REQUIRED.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - Number: proto.Int32(1), - }, - { - Name: proto.String("id"), - Label: descriptorpb.FieldDescriptorProto_LABEL_REQUIRED.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - Number: proto.Int32(2), - }, - }, - } - createDesc := &descriptorpb.DescriptorProto{ - Name: proto.String("CreateBookRequest"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("parent"), - Label: descriptorpb.FieldDescriptorProto_LABEL_REQUIRED.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - Number: proto.Int32(1), - }, - { - Name: proto.String("book"), - Label: descriptorpb.FieldDescriptorProto_LABEL_REQUIRED.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - Number: proto.Int32(2), - }, - { - Name: proto.String("book_id"), - Label: descriptorpb.FieldDescriptorProto_LABEL_REQUIRED.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - Number: proto.Int32(3), - }, - }, - } - meth := &descriptorpb.MethodDescriptorProto{ - Name: proto.String("CreateBook"), - InputType: proto.String("CreateBookRequest"), - OutputType: proto.String("Book"), - } - svc := &descriptorpb.ServiceDescriptorProto{ - Name: proto.String("BookService"), - Method: []*descriptorpb.MethodDescriptorProto{meth}, - } - - bookMsg := &descriptor.Message{ - DescriptorProto: bookDesc, - } - createMsg := &descriptor.Message{ - DescriptorProto: createDesc, - } - - parentField := &descriptor.Field{ - Message: createMsg, - FieldDescriptorProto: createMsg.GetField()[0], - } - bookField := &descriptor.Field{ - Message: createMsg, - FieldMessage: bookMsg, - FieldDescriptorProto: createMsg.GetField()[1], - } - bookIDField := &descriptor.Field{ - Message: createMsg, - FieldDescriptorProto: createMsg.GetField()[2], - } - - createMsg.Fields = []*descriptor.Field{parentField, bookField, bookIDField} - - file := descriptor.File{ - FileDescriptorProto: &descriptorpb.FileDescriptorProto{ - SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, - Name: proto.String("book.proto"), - MessageType: []*descriptorpb.DescriptorProto{bookDesc, createDesc}, - Service: []*descriptorpb.ServiceDescriptorProto{svc}, - }, - GoPkg: descriptor.GoPackage{ - Path: "example.com/path/to/book.pb", - Name: "book_pb", - }, - Messages: []*descriptor.Message{bookMsg, createMsg}, - Services: []*descriptor.Service{ - { - ServiceDescriptorProto: svc, - Methods: []*descriptor.Method{ - { - MethodDescriptorProto: meth, - RequestType: createMsg, - ResponseType: bookMsg, - Bindings: []*descriptor.Binding{ - { - HTTPMethod: "POST", - PathTmpl: httprule.Template{ - Version: 1, - OpCodes: []int{0, 0}, - Template: "/v1/{parent=publishers/*}/books", - }, - PathParams: []descriptor.Parameter{ - { - FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{ - { - Name: "parent", - Target: parentField, - }, - }), - Target: parentField, - }, - }, - Body: &descriptor.Body{ - FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{ - { - Name: "book", - Target: bookField, - }, - }), - }, - }, - }, - }, - }, - }, - }, - } - reg := descriptor.NewRegistry() - if err := AddErrorDefs(reg); err != nil { - t.Errorf("AddErrorDefs(%#v) failed with %v; want success", reg, err) - return - } - err := reg.Load(&pluginpb.CodeGeneratorRequest{ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto}}) - if err != nil { - t.Errorf("Registry.Load() failed with %v; want success", err) - return - } - result, err := applyTemplate(param{File: crossLinkFixture(&file), reg: reg}) - if err != nil { - t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err) - return - } - - if _, ok := result.Paths["/v1/{parent=publishers/*}/books"].Post.Responses["200"]; !ok { - t.Errorf("applyTemplate(%#v).%s = expected 200 response to be defined", file, `result.Paths["/v1/{parent=publishers/*}/books"].Post.Responses["200"]`) - } else { - if want, got, name := 3, len(result.Paths["/v1/{parent=publishers/*}/books"].Post.Parameters), `len(result.Paths["/v1/{parent=publishers/*}/books"].Post.Parameters)`; !reflect.DeepEqual(got, want) { - t.Errorf("applyTemplate(%#v).%s = %d want to be %d", file, name, got, want) - } - - type param struct { - Name string - In string - Required bool - } - - p0 := result.Paths["/v1/{parent=publishers/*}/books"].Post.Parameters[0] - if want, got, name := (param{"parent", "path", true}), (param{p0.Name, p0.In, p0.Required}), `result.Paths["/v1/{parent=publishers/*}/books"].Post.Parameters[0]`; !reflect.DeepEqual(got, want) { - t.Errorf("applyTemplate(%#v).%s = %v want to be %v", file, name, got, want) - } - p1 := result.Paths["/v1/{parent=publishers/*}/books"].Post.Parameters[1] - if want, got, name := (param{"body", "body", true}), (param{p1.Name, p1.In, p1.Required}), `result.Paths["/v1/{parent=publishers/*}/books"].Post.Parameters[1]`; !reflect.DeepEqual(got, want) { - t.Errorf("applyTemplate(%#v).%s = %v want to be %v", file, name, got, want) - } - p2 := result.Paths["/v1/{parent=publishers/*}/books"].Post.Parameters[2] - if want, got, name := (param{"book_id", "query", false}), (param{p2.Name, p2.In, p2.Required}), `result.Paths["/v1/{parent=publishers/*}/books"].Post.Parameters[1]`; !reflect.DeepEqual(got, want) { - t.Errorf("applyTemplate(%#v).%s = %v want to be %v", file, name, got, want) - } - } - - // If there was a failure, print out the input and the json result for debugging. - if t.Failed() { - t.Errorf("had: %s", file) - t.Errorf("got: %s", fmt.Sprint(result)) - } -} - -func generateFieldsForJSONReservedName() []*descriptor.Field { - fields := make([]*descriptor.Field, 0) - fieldName := string("json_name") - fieldJSONName := string("jsonNAME") - fieldDescriptor := descriptorpb.FieldDescriptorProto{Name: &fieldName, JsonName: &fieldJSONName} - field := &descriptor.Field{FieldDescriptorProto: &fieldDescriptor} - return append(fields, field) -} - -func generateMsgsForJSONReservedName() []*descriptor.Message { - result := make([]*descriptor.Message, 0) - // The first message, its field is field_abc and its type is NewType - // NewType field_abc - fieldName := "field_abc" - fieldJSONName := "fieldAbc" - messageName1 := "message1" - messageType := "pkg.a.NewType" - pfd := descriptorpb.FieldDescriptorProto{Name: &fieldName, JsonName: &fieldJSONName, TypeName: &messageType} - result = append(result, - &descriptor.Message{ - DescriptorProto: &descriptorpb.DescriptorProto{ - Name: &messageName1, Field: []*descriptorpb.FieldDescriptorProto{&pfd}, - }, - }) - // The second message, its name is NewName, its type is string - // message NewType { - // string field_newName [json_name = RESERVEDJSONNAME] - // } - messageName := "NewType" - field := "field_newName" - fieldJSONName2 := "RESERVEDJSONNAME" - pfd2 := descriptorpb.FieldDescriptorProto{Name: &field, JsonName: &fieldJSONName2} - result = append(result, &descriptor.Message{ - DescriptorProto: &descriptorpb.DescriptorProto{ - Name: &messageName, Field: []*descriptorpb.FieldDescriptorProto{&pfd2}, - }, - }) - return result -} - -func TestTemplateWithJsonCamelCase(t *testing.T) { - var tests = []struct { - input string - expected string - }{ - {"/test/{test_id}", "/test/{testId}"}, - {"/test1/{test1_id}/test2/{test2_id}", "/test1/{test1Id}/test2/{test2Id}"}, - {"/test1/{test1_id}/{test2_id}", "/test1/{test1Id}/{test2Id}"}, - {"/test1/test2/{test1_id}/{test2_id}", "/test1/test2/{test1Id}/{test2Id}"}, - {"/test1/{test1_id1_id2}", "/test1/{test1Id1Id2}"}, - {"/test1/{test1_id1_id2}/test2/{test2_id3_id4}", "/test1/{test1Id1Id2}/test2/{test2Id3Id4}"}, - {"/test1/test2/{test1_id1_id2}/{test2_id3_id4}", "/test1/test2/{test1Id1Id2}/{test2Id3Id4}"}, - {"test/{a}", "test/{a}"}, - {"test/{ab}", "test/{ab}"}, - {"test/{a_a}", "test/{aA}"}, - {"test/{ab_c}", "test/{abC}"}, - {"test/{json_name}", "test/{jsonNAME}"}, - {"test/{field_abc.field_newName}", "test/{fieldAbc.RESERVEDJSONNAME}"}, - } - reg := descriptor.NewRegistry() - reg.SetUseJSONNamesForFields(true) - for _, data := range tests { - actual := templateToOpenAPIPath(data.input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName()) - if data.expected != actual { - t.Errorf("Expected templateToOpenAPIPath(%v) = %v, actual: %v", data.input, data.expected, actual) - } - } -} - -func TestTemplateWithoutJsonCamelCase(t *testing.T) { - var tests = []struct { - input string - expected string - }{ - {"/test/{test_id}", "/test/{test_id}"}, - {"/test1/{test1_id}/test2/{test2_id}", "/test1/{test1_id}/test2/{test2_id}"}, - {"/test1/{test1_id}/{test2_id}", "/test1/{test1_id}/{test2_id}"}, - {"/test1/test2/{test1_id}/{test2_id}", "/test1/test2/{test1_id}/{test2_id}"}, - {"/test1/{test1_id1_id2}", "/test1/{test1_id1_id2}"}, - {"/test1/{test1_id1_id2}/test2/{test2_id3_id4}", "/test1/{test1_id1_id2}/test2/{test2_id3_id4}"}, - {"/test1/test2/{test1_id1_id2}/{test2_id3_id4}", "/test1/test2/{test1_id1_id2}/{test2_id3_id4}"}, - {"test/{a}", "test/{a}"}, - {"test/{ab}", "test/{ab}"}, - {"test/{a_a}", "test/{a_a}"}, - {"test/{json_name}", "test/{json_name}"}, - {"test/{field_abc.field_newName}", "test/{field_abc.field_newName}"}, - } - reg := descriptor.NewRegistry() - reg.SetUseJSONNamesForFields(false) - for _, data := range tests { - actual := templateToOpenAPIPath(data.input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName()) - if data.expected != actual { - t.Errorf("Expected templateToOpenAPIPath(%v) = %v, actual: %v", data.input, data.expected, actual) - } - } -} - -func TestTemplateToOpenAPIPath(t *testing.T) { - var tests = []struct { - input string - expected string - }{ - {"/test", "/test"}, - {"/{test}", "/{test}"}, - {"/{test=prefix/*}", "/{test}"}, - {"/{test=prefix/that/has/multiple/parts/to/it/*}", "/{test}"}, - {"/{test1}/{test2}", "/{test1}/{test2}"}, - {"/{test1}/{test2}/", "/{test1}/{test2}/"}, - {"/{name=prefix/*}", "/{name=prefix/*}"}, - {"/{name=prefix1/*/prefix2/*}", "/{name=prefix1/*/prefix2/*}"}, - {"/{user.name=prefix/*}", "/{user.name=prefix/*}"}, - {"/{user.name=prefix1/*/prefix2/*}", "/{user.name=prefix1/*/prefix2/*}"}, - {"/{parent=prefix/*}/children", "/{parent=prefix/*}/children"}, - {"/{name=prefix/*}:customMethod", "/{name=prefix/*}:customMethod"}, - {"/{name=prefix1/*/prefix2/*}:customMethod", "/{name=prefix1/*/prefix2/*}:customMethod"}, - {"/{user.name=prefix/*}:customMethod", "/{user.name=prefix/*}:customMethod"}, - {"/{user.name=prefix1/*/prefix2/*}:customMethod", "/{user.name=prefix1/*/prefix2/*}:customMethod"}, - {"/{parent=prefix/*}/children:customMethod", "/{parent=prefix/*}/children:customMethod"}, - } - reg := descriptor.NewRegistry() - reg.SetUseJSONNamesForFields(false) - for _, data := range tests { - actual := templateToOpenAPIPath(data.input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName()) - if data.expected != actual { - t.Errorf("Expected templateToOpenAPIPath(%v) = %v, actual: %v", data.input, data.expected, actual) - } - } - reg.SetUseJSONNamesForFields(true) - for _, data := range tests { - actual := templateToOpenAPIPath(data.input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName()) - if data.expected != actual { - t.Errorf("Expected templateToOpenAPIPath(%v) = %v, actual: %v", data.input, data.expected, actual) - } - } -} - -func BenchmarkTemplateToOpenAPIPath(b *testing.B) { - const input = "/{user.name=prefix1/*/prefix2/*}:customMethod" - - b.Run("with JSON names", func(b *testing.B) { - reg := descriptor.NewRegistry() - reg.SetUseJSONNamesForFields(false) - - for i := 0; i < b.N; i++ { - _ = templateToOpenAPIPath(input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName()) - } - }) - - b.Run("without JSON names", func(b *testing.B) { - reg := descriptor.NewRegistry() - reg.SetUseJSONNamesForFields(true) - - for i := 0; i < b.N; i++ { - _ = templateToOpenAPIPath(input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName()) - } - }) -} - -func TestResolveFullyQualifiedNameToOpenAPIName(t *testing.T) { - var tests = []struct { - input string - output string - listOfFQMNs []string - useFQNForOpenAPIName bool - }{ - { - ".a.b.C", - "C", - []string{ - ".a.b.C", - }, - false, - }, - { - ".a.b.C", - "abC", - []string{ - ".a.C", - ".a.b.C", - }, - false, - }, - { - ".a.b.C", - "abC", - []string{ - ".C", - ".a.C", - ".a.b.C", - }, - false, - }, - { - ".a.b.C", - "a.b.C", - []string{ - ".C", - ".a.C", - ".a.b.C", - }, - true, - }, - } - - for _, data := range tests { - names := resolveFullyQualifiedNameToOpenAPINames(data.listOfFQMNs, data.useFQNForOpenAPIName) - output := names[data.input] - if output != data.output { - t.Errorf("Expected fullyQualifiedNameToOpenAPIName(%v) to be %s but got %s", - data.input, data.output, output) - } - } -} - -func TestFQMNtoOpenAPIName(t *testing.T) { - var tests = []struct { - input string - expected string - }{ - {"/test", "/test"}, - {"/{test}", "/{test}"}, - {"/{test=prefix/*}", "/{test}"}, - {"/{test=prefix/that/has/multiple/parts/to/it/*}", "/{test}"}, - {"/{test1}/{test2}", "/{test1}/{test2}"}, - {"/{test1}/{test2}/", "/{test1}/{test2}/"}, - } - reg := descriptor.NewRegistry() - reg.SetUseJSONNamesForFields(false) - for _, data := range tests { - actual := templateToOpenAPIPath(data.input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName()) - if data.expected != actual { - t.Errorf("Expected templateToOpenAPIPath(%v) = %v, actual: %v", data.input, data.expected, actual) - } - } - reg.SetUseJSONNamesForFields(true) - for _, data := range tests { - actual := templateToOpenAPIPath(data.input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName()) - if data.expected != actual { - t.Errorf("Expected templateToOpenAPIPath(%v) = %v, actual: %v", data.input, data.expected, actual) - } - } -} - -func TestSchemaOfField(t *testing.T) { - type test struct { - field *descriptor.Field - refs refMap - expected openapiSchemaObject - openAPIOptions *openapiconfig.OpenAPIOptions - } - - jsonSchema := &openapi_options.JSONSchema{ - Title: "field title", - Description: "field description", - } - - var fieldOptions = new(descriptorpb.FieldOptions) - proto.SetExtension(fieldOptions, openapi_options.E_Openapiv2Field, jsonSchema) - - tests := []test{ - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("primitive_field"), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "string", - }, - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("repeated_primitive_field"), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - Label: descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(), - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "array", - Items: &openapiItemsObject{ - Type: "string", - }, - }, - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("wrapped_field"), - TypeName: proto.String(".google.protobuf.FieldMask"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "array", - Items: &openapiItemsObject{ - Type: "string", - }, - }, - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("wrapped_field"), - TypeName: proto.String(".google.protobuf.Timestamp"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "string", - Format: "date-time", - }, - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("wrapped_field"), - TypeName: proto.String(".google.protobuf.Duration"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "string", - }, - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("wrapped_field"), - TypeName: proto.String(".google.protobuf.StringValue"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "string", - }, - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("repeated_wrapped_field"), - TypeName: proto.String(".google.protobuf.StringValue"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - Label: descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(), - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "array", - Items: &openapiItemsObject{ - Type: "string", - }, - }, - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("wrapped_field"), - TypeName: proto.String(".google.protobuf.BytesValue"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "string", - Format: "byte", - }, - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("wrapped_field"), - TypeName: proto.String(".google.protobuf.Int32Value"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "integer", - Format: "int32", - }, - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("wrapped_field"), - TypeName: proto.String(".google.protobuf.UInt32Value"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "integer", - Format: "int64", - }, - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("wrapped_field"), - TypeName: proto.String(".google.protobuf.Int64Value"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "string", - Format: "int64", - }, - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("wrapped_field"), - TypeName: proto.String(".google.protobuf.UInt64Value"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "string", - Format: "uint64", - }, - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("wrapped_field"), - TypeName: proto.String(".google.protobuf.FloatValue"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "number", - Format: "float", - }, - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("wrapped_field"), - TypeName: proto.String(".google.protobuf.DoubleValue"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "number", - Format: "double", - }, - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("wrapped_field"), - TypeName: proto.String(".google.protobuf.BoolValue"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "boolean", - }, - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("wrapped_field"), - TypeName: proto.String(".google.protobuf.Struct"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "object", - }, - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("wrapped_field"), - TypeName: proto.String(".google.protobuf.Value"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "object", - }, - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("wrapped_field"), - TypeName: proto.String(".google.protobuf.ListValue"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "array", - Items: (*openapiItemsObject)(&schemaCore{ - Type: "object", - }), - }, - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("wrapped_field"), - TypeName: proto.String(".google.protobuf.NullValue"), - Type: descriptorpb.FieldDescriptorProto_TYPE_ENUM.Enum(), - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "string", - }, - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("message_field"), - TypeName: proto.String(".example.Message"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - }, - }, - refs: refMap{".example.Message": struct{}{}}, - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Ref: "#/definitions/exampleMessage", - }, - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("map_field"), - Label: descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - TypeName: proto.String(".example.Message.MapFieldEntry"), - Options: fieldOptions, - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "object", - }, - AdditionalProperties: &openapiSchemaObject{ - schemaCore: schemaCore{Type: "string"}, - }, - Title: "field title", - Description: "field description", - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("array_field"), - Label: descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - Options: fieldOptions, - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "array", - Items: (*openapiItemsObject)(&schemaCore{Type: "string"}), - }, - Title: "field title", - Description: "field description", - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("primitive_field"), - Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_INT32.Enum(), - Options: fieldOptions, - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "integer", - Format: "int32", - }, - Title: "field title", - Description: "field description", - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("message_field"), - Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - TypeName: proto.String(".example.Empty"), - Options: fieldOptions, - }, - }, - refs: refMap{".example.Empty": struct{}{}}, - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Ref: "#/definitions/exampleEmpty", - }, - Title: "field title", - Description: "field description", - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("map_field"), // should be called map_field_option but it's not valid map field name - Label: descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - TypeName: proto.String(".example.Message.MapFieldEntry"), - }, - }, - openAPIOptions: &openapiconfig.OpenAPIOptions{ - Field: []*openapiconfig.OpenAPIFieldOption{ - { - Field: "example.Message.map_field", - Option: jsonSchema, - }, - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "object", - }, - AdditionalProperties: &openapiSchemaObject{ - schemaCore: schemaCore{Type: "string"}, - }, - Title: "field title", - Description: "field description", - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("array_field_option"), - Label: descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - }, - }, - openAPIOptions: &openapiconfig.OpenAPIOptions{ - Field: []*openapiconfig.OpenAPIFieldOption{ - { - Field: "example.Message.array_field_option", - Option: jsonSchema, - }, - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "array", - Items: (*openapiItemsObject)(&schemaCore{Type: "string"}), - }, - Title: "field title", - Description: "field description", - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("primitive_field_option"), - Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_INT32.Enum(), - }, - }, - openAPIOptions: &openapiconfig.OpenAPIOptions{ - Field: []*openapiconfig.OpenAPIFieldOption{ - { - Field: "example.Message.primitive_field_option", - Option: jsonSchema, - }, - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "integer", - Format: "int32", - }, - Title: "field title", - Description: "field description", - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("message_field_option"), - Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - TypeName: proto.String(".example.Empty"), - }, - }, - openAPIOptions: &openapiconfig.OpenAPIOptions{ - Field: []*openapiconfig.OpenAPIFieldOption{ - { - Field: "example.Message.message_field_option", - Option: jsonSchema, - }, - }, - }, - refs: refMap{".example.Empty": struct{}{}}, - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Ref: "#/definitions/exampleEmpty", - }, - Title: "field title", - Description: "field description", - }, - }, - } - for _, test := range tests { - reg := descriptor.NewRegistry() - req := &pluginpb.CodeGeneratorRequest{ - ProtoFile: []*descriptorpb.FileDescriptorProto{ - { - Name: proto.String("third_party/google.proto"), - Package: proto.String("google.protobuf"), - MessageType: []*descriptorpb.DescriptorProto{ - protodesc.ToDescriptorProto((&structpb.Struct{}).ProtoReflect().Descriptor()), - protodesc.ToDescriptorProto((&structpb.Value{}).ProtoReflect().Descriptor()), - protodesc.ToDescriptorProto((&structpb.ListValue{}).ProtoReflect().Descriptor()), - protodesc.ToDescriptorProto((&field_mask.FieldMask{}).ProtoReflect().Descriptor()), - protodesc.ToDescriptorProto((×tamppb.Timestamp{}).ProtoReflect().Descriptor()), - protodesc.ToDescriptorProto((&durationpb.Duration{}).ProtoReflect().Descriptor()), - protodesc.ToDescriptorProto((&wrapperspb.StringValue{}).ProtoReflect().Descriptor()), - protodesc.ToDescriptorProto((&wrapperspb.BytesValue{}).ProtoReflect().Descriptor()), - protodesc.ToDescriptorProto((&wrapperspb.Int32Value{}).ProtoReflect().Descriptor()), - protodesc.ToDescriptorProto((&wrapperspb.UInt32Value{}).ProtoReflect().Descriptor()), - protodesc.ToDescriptorProto((&wrapperspb.Int64Value{}).ProtoReflect().Descriptor()), - protodesc.ToDescriptorProto((&wrapperspb.UInt64Value{}).ProtoReflect().Descriptor()), - protodesc.ToDescriptorProto((&wrapperspb.FloatValue{}).ProtoReflect().Descriptor()), - protodesc.ToDescriptorProto((&wrapperspb.DoubleValue{}).ProtoReflect().Descriptor()), - protodesc.ToDescriptorProto((&wrapperspb.BoolValue{}).ProtoReflect().Descriptor()), - }, - EnumType: []*descriptorpb.EnumDescriptorProto{ - protodesc.ToEnumDescriptorProto(structpb.NullValue(0).Descriptor()), - }, - }, - { - SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, - Name: proto.String("example.proto"), - Package: proto.String("example"), - Dependency: []string{"third_party/google.proto"}, - MessageType: []*descriptorpb.DescriptorProto{ - { - Name: proto.String("Message"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("value"), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - Number: proto.Int32(1), - }, - func() *descriptorpb.FieldDescriptorProto { - fd := test.field.FieldDescriptorProto - fd.Number = proto.Int32(2) - return fd - }(), - }, - NestedType: []*descriptorpb.DescriptorProto{ - { - Name: proto.String("MapFieldEntry"), - Options: &descriptorpb.MessageOptions{MapEntry: proto.Bool(true)}, - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("key"), - Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - Number: proto.Int32(1), - }, - { - Name: proto.String("value"), - Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - Number: proto.Int32(2), - }, - }, - }, - }, - }, - { - Name: proto.String("Empty"), - }, - }, - EnumType: []*descriptorpb.EnumDescriptorProto{ - { - Name: proto.String("MessageType"), - Value: []*descriptorpb.EnumValueDescriptorProto{ - { - Name: proto.String("MESSAGE_TYPE_1"), - Number: proto.Int32(0), - }, - }, - }, - }, - Service: []*descriptorpb.ServiceDescriptorProto{}, - }, - }, - } - err := reg.Load(req) - if err != nil { - t.Errorf("failed to reg.Load(req): %v", err) - } - - // set field's parent message pointer to message so field can resolve its FQFN - test.field.Message = &descriptor.Message{ - DescriptorProto: req.ProtoFile[1].MessageType[0], - File: &descriptor.File{ - FileDescriptorProto: req.ProtoFile[1], - }, - } - - if test.openAPIOptions != nil { - if err := reg.RegisterOpenAPIOptions(test.openAPIOptions); err != nil { - t.Fatalf("failed to register OpenAPI options: %s", err) - } - } - - refs := make(refMap) - actual := schemaOfField(test.field, reg, refs) - expectedSchemaObject := test.expected - if e, a := expectedSchemaObject, actual; !reflect.DeepEqual(a, e) { - t.Errorf("Expected schemaOfField(%v) = \n%#+v, actual: \n%#+v", test.field, e, a) - } - if !reflect.DeepEqual(refs, test.refs) { - t.Errorf("Expected schemaOfField(%v) to add refs %v, not %v", test.field, test.refs, refs) - } - } -} - -func TestRenderMessagesAsDefinition(t *testing.T) { - - tests := []struct { - descr string - msgDescs []*descriptorpb.DescriptorProto - schema map[string]openapi_options.Schema // per-message schema to add - defs openapiDefinitionsObject - openAPIOptions *openapiconfig.OpenAPIOptions - }{ - { - descr: "no OpenAPI options", - msgDescs: []*descriptorpb.DescriptorProto{ - {Name: proto.String("Message")}, - }, - schema: map[string]openapi_options.Schema{}, - defs: map[string]openapiSchemaObject{ - "Message": {schemaCore: schemaCore{Type: "object"}}, - }, - }, - { - descr: "example option", - msgDescs: []*descriptorpb.DescriptorProto{ - {Name: proto.String("Message")}, - }, - schema: map[string]openapi_options.Schema{ - "Message": { - Example: `{"foo":"bar"}`, - }, - }, - defs: map[string]openapiSchemaObject{ - "Message": {schemaCore: schemaCore{ - Type: "object", - Example: json.RawMessage(`{"foo":"bar"}`), - }}, - }, - }, - { - descr: "example option with something non-json", - msgDescs: []*descriptorpb.DescriptorProto{ - {Name: proto.String("Message")}, - }, - schema: map[string]openapi_options.Schema{ - "Message": { - Example: `XXXX anything goes XXXX`, - }, - }, - defs: map[string]openapiSchemaObject{ - "Message": {schemaCore: schemaCore{ - Type: "object", - Example: json.RawMessage(`XXXX anything goes XXXX`), - }}, - }, - }, - { - descr: "external docs option", - msgDescs: []*descriptorpb.DescriptorProto{ - {Name: proto.String("Message")}, - }, - schema: map[string]openapi_options.Schema{ - "Message": { - ExternalDocs: &openapi_options.ExternalDocumentation{ - Description: "glorious docs", - Url: "https://nada", - }, - }, - }, - defs: map[string]openapiSchemaObject{ - "Message": { - schemaCore: schemaCore{ - Type: "object", - }, - ExternalDocs: &openapiExternalDocumentationObject{ - Description: "glorious docs", - URL: "https://nada", - }, - }, - }, - }, - { - descr: "JSONSchema options", - msgDescs: []*descriptorpb.DescriptorProto{ - {Name: proto.String("Message")}, - }, - schema: map[string]openapi_options.Schema{ - "Message": { - JsonSchema: &openapi_options.JSONSchema{ - Title: "title", - Description: "desc", - MultipleOf: 100, - Maximum: 101, - ExclusiveMaximum: true, - Minimum: 1, - ExclusiveMinimum: true, - MaxLength: 10, - MinLength: 3, - Pattern: "[a-z]+", - MaxItems: 20, - MinItems: 2, - UniqueItems: true, - MaxProperties: 33, - MinProperties: 22, - Required: []string{"req"}, - ReadOnly: true, - }, - }, - }, - defs: map[string]openapiSchemaObject{ - "Message": { - schemaCore: schemaCore{ - Type: "object", - }, - Title: "title", - Description: "desc", - MultipleOf: 100, - Maximum: 101, - ExclusiveMaximum: true, - Minimum: 1, - ExclusiveMinimum: true, - MaxLength: 10, - MinLength: 3, - Pattern: "[a-z]+", - MaxItems: 20, - MinItems: 2, - UniqueItems: true, - MaxProperties: 33, - MinProperties: 22, - Required: []string{"req"}, - ReadOnly: true, - }, - }, - }, - { - descr: "JSONSchema options from registry", - msgDescs: []*descriptorpb.DescriptorProto{ - {Name: proto.String("Message")}, - }, - openAPIOptions: &openapiconfig.OpenAPIOptions{ - Message: []*openapiconfig.OpenAPIMessageOption{ - { - Message: "example.Message", - Option: &openapi_options.Schema{ - JsonSchema: &openapi_options.JSONSchema{ - Title: "title", - Description: "desc", - MultipleOf: 100, - Maximum: 101, - ExclusiveMaximum: true, - Minimum: 1, - ExclusiveMinimum: true, - MaxLength: 10, - MinLength: 3, - Pattern: "[a-z]+", - MaxItems: 20, - MinItems: 2, - UniqueItems: true, - MaxProperties: 33, - MinProperties: 22, - Required: []string{"req"}, - ReadOnly: true, - }, - }, - }, - }, - }, - defs: map[string]openapiSchemaObject{ - "Message": { - schemaCore: schemaCore{ - Type: "object", - }, - Title: "title", - Description: "desc", - MultipleOf: 100, - Maximum: 101, - ExclusiveMaximum: true, - Minimum: 1, - ExclusiveMinimum: true, - MaxLength: 10, - MinLength: 3, - Pattern: "[a-z]+", - MaxItems: 20, - MinItems: 2, - UniqueItems: true, - MaxProperties: 33, - MinProperties: 22, - Required: []string{"req"}, - ReadOnly: true, - }, - }, - }, - } - - for _, test := range tests { - t.Run(test.descr, func(t *testing.T) { - - msgs := []*descriptor.Message{} - for _, msgdesc := range test.msgDescs { - msgdesc.Options = &descriptorpb.MessageOptions{} - msgs = append(msgs, &descriptor.Message{DescriptorProto: msgdesc}) - } - - reg := descriptor.NewRegistry() - file := descriptor.File{ - FileDescriptorProto: &descriptorpb.FileDescriptorProto{ - SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, - Name: proto.String("example.proto"), - Package: proto.String("example"), - Dependency: []string{}, - MessageType: test.msgDescs, - EnumType: []*descriptorpb.EnumDescriptorProto{}, - Service: []*descriptorpb.ServiceDescriptorProto{}, - }, - Messages: msgs, - } - reg.Load(&pluginpb.CodeGeneratorRequest{ - ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto}, - }) - - msgMap := map[string]*descriptor.Message{} - for _, d := range test.msgDescs { - name := d.GetName() - msg, err := reg.LookupMsg("example", name) - if err != nil { - t.Fatalf("lookup message %v: %v", name, err) - } - msgMap[msg.FQMN()] = msg - - if schema, ok := test.schema[name]; ok { - proto.SetExtension(d.Options, openapi_options.E_Openapiv2Schema, &schema) - } - } - - if test.openAPIOptions != nil { - if err := reg.RegisterOpenAPIOptions(test.openAPIOptions); err != nil { - t.Fatalf("failed to register OpenAPI options: %s", err) - } - } - - refs := make(refMap) - actual := make(openapiDefinitionsObject) - renderMessagesAsDefinition(msgMap, actual, reg, refs) - - if !reflect.DeepEqual(actual, test.defs) { - t.Errorf("Expected renderMessagesAsDefinition() to add defs %+v, not %+v", test.defs, actual) - } - }) - } -} - -func TestUpdateOpenAPIDataFromComments(t *testing.T) { - - tests := []struct { - descr string - openapiSwaggerObject interface{} - comments string - expectedError error - expectedOpenAPIObject interface{} - useGoTemplate bool - }{ - { - descr: "empty comments", - openapiSwaggerObject: nil, - expectedOpenAPIObject: nil, - comments: "", - expectedError: nil, - }, - { - descr: "set field to read only", - openapiSwaggerObject: &openapiSchemaObject{}, - expectedOpenAPIObject: &openapiSchemaObject{ - ReadOnly: true, - Description: "... Output only. ...", - }, - comments: "... Output only. ...", - expectedError: nil, - }, - { - descr: "set title", - openapiSwaggerObject: &openapiSchemaObject{}, - expectedOpenAPIObject: &openapiSchemaObject{ - Title: "Comment with no trailing dot", - }, - comments: "Comment with no trailing dot", - expectedError: nil, - }, - { - descr: "set description", - openapiSwaggerObject: &openapiSchemaObject{}, - expectedOpenAPIObject: &openapiSchemaObject{ - Description: "Comment with trailing dot.", - }, - comments: "Comment with trailing dot.", - expectedError: nil, - }, - { - descr: "use info object", - openapiSwaggerObject: &openapiSwaggerObject{ - Info: openapiInfoObject{}, - }, - expectedOpenAPIObject: &openapiSwaggerObject{ - Info: openapiInfoObject{ - Description: "Comment with trailing dot.", - }, - }, - comments: "Comment with trailing dot.", - expectedError: nil, - }, - { - descr: "multi line comment with title", - openapiSwaggerObject: &openapiSchemaObject{}, - expectedOpenAPIObject: &openapiSchemaObject{ - Title: "First line", - Description: "Second line", - }, - comments: "First line\n\nSecond line", - expectedError: nil, - }, - { - descr: "multi line comment no title", - openapiSwaggerObject: &openapiSchemaObject{}, - expectedOpenAPIObject: &openapiSchemaObject{ - Description: "First line.\n\nSecond line", - }, - comments: "First line.\n\nSecond line", - expectedError: nil, - }, - { - descr: "multi line comment with summary with dot", - openapiSwaggerObject: &openapiOperationObject{}, - expectedOpenAPIObject: &openapiOperationObject{ - Summary: "First line.", - Description: "Second line", - }, - comments: "First line.\n\nSecond line", - expectedError: nil, - }, - { - descr: "multi line comment with summary no dot", - openapiSwaggerObject: &openapiOperationObject{}, - expectedOpenAPIObject: &openapiOperationObject{ - Summary: "First line", - Description: "Second line", - }, - comments: "First line\n\nSecond line", - expectedError: nil, - }, - { - descr: "multi line comment with summary no dot", - openapiSwaggerObject: &schemaCore{}, - expectedOpenAPIObject: &schemaCore{}, - comments: "Any comment", - expectedError: errors.New("no description nor summary property"), - }, - { - descr: "without use_go_template", - openapiSwaggerObject: &openapiSchemaObject{}, - expectedOpenAPIObject: &openapiSchemaObject{ - Title: "First line", - Description: "{{import \"documentation.md\"}}", - }, - comments: "First line\n\n{{import \"documentation.md\"}}", - expectedError: nil, - }, - { - descr: "error with use_go_template", - openapiSwaggerObject: &openapiSchemaObject{}, - expectedOpenAPIObject: &openapiSchemaObject{ - Title: "First line", - Description: "open noneexistingfile.txt: no such file or directory", - }, - comments: "First line\n\n{{import \"noneexistingfile.txt\"}}", - expectedError: nil, - useGoTemplate: true, - }, - { - descr: "template with use_go_template", - openapiSwaggerObject: &openapiSchemaObject{}, - expectedOpenAPIObject: &openapiSchemaObject{ - Title: "Template", - Description: `Description "which means nothing"`, - }, - comments: "Template\n\nDescription {{with \"which means nothing\"}}{{printf \"%q\" .}}{{end}}", - expectedError: nil, - useGoTemplate: true, - }, - } - - for _, test := range tests { - t.Run(test.descr, func(t *testing.T) { - reg := descriptor.NewRegistry() - if test.useGoTemplate { - reg.SetUseGoTemplate(true) - } - err := updateOpenAPIDataFromComments(reg, test.openapiSwaggerObject, nil, test.comments, false) - if test.expectedError == nil { - if err != nil { - t.Errorf("unexpected error '%v'", err) - } - if !reflect.DeepEqual(test.openapiSwaggerObject, test.expectedOpenAPIObject) { - t.Errorf("openapiSwaggerObject was not updated correctly, expected '%+v', got '%+v'", test.expectedOpenAPIObject, test.openapiSwaggerObject) - } - } else { - if err == nil { - t.Error("expected update error not returned") - } - if !reflect.DeepEqual(test.openapiSwaggerObject, test.expectedOpenAPIObject) { - t.Errorf("openapiSwaggerObject was not updated correctly, expected '%+v', got '%+v'", test.expectedOpenAPIObject, test.openapiSwaggerObject) - } - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error malformed, expected %q, got %q", test.expectedError.Error(), err.Error()) - } - } - }) - } -} - -func TestMessageOptionsWithGoTemplate(t *testing.T) { - tests := []struct { - descr string - msgDescs []*descriptorpb.DescriptorProto - schema map[string]openapi_options.Schema // per-message schema to add - defs openapiDefinitionsObject - openAPIOptions *openapiconfig.OpenAPIOptions - useGoTemplate bool - }{ - { - descr: "external docs option", - msgDescs: []*descriptorpb.DescriptorProto{ - {Name: proto.String("Message")}, - }, - schema: map[string]openapi_options.Schema{ - "Message": { - JsonSchema: &openapi_options.JSONSchema{ - Title: "{{.Name}}", - Description: "Description {{with \"which means nothing\"}}{{printf \"%q\" .}}{{end}}", - }, - ExternalDocs: &openapi_options.ExternalDocumentation{ - Description: "Description {{with \"which means nothing\"}}{{printf \"%q\" .}}{{end}}", - }, - }, - }, - defs: map[string]openapiSchemaObject{ - "Message": { - schemaCore: schemaCore{ - Type: "object", - }, - Title: "Message", - Description: `Description "which means nothing"`, - ExternalDocs: &openapiExternalDocumentationObject{ - Description: `Description "which means nothing"`, - }, - }, - }, - useGoTemplate: true, - }, - { - descr: "external docs option", - msgDescs: []*descriptorpb.DescriptorProto{ - {Name: proto.String("Message")}, - }, - schema: map[string]openapi_options.Schema{ - "Message": { - JsonSchema: &openapi_options.JSONSchema{ - Title: "{{.Name}}", - Description: "Description {{with \"which means nothing\"}}{{printf \"%q\" .}}{{end}}", - }, - ExternalDocs: &openapi_options.ExternalDocumentation{ - Description: "Description {{with \"which means nothing\"}}{{printf \"%q\" .}}{{end}}", - }, - }, - }, - defs: map[string]openapiSchemaObject{ - "Message": { - schemaCore: schemaCore{ - Type: "object", - }, - Title: "{{.Name}}", - Description: "Description {{with \"which means nothing\"}}{{printf \"%q\" .}}{{end}}", - ExternalDocs: &openapiExternalDocumentationObject{ - Description: "Description {{with \"which means nothing\"}}{{printf \"%q\" .}}{{end}}", - }, - }, - }, - useGoTemplate: false, - }, - { - descr: "registered OpenAPIOption", - msgDescs: []*descriptorpb.DescriptorProto{ - {Name: proto.String("Message")}, - }, - openAPIOptions: &openapiconfig.OpenAPIOptions{ - Message: []*openapiconfig.OpenAPIMessageOption{ - { - Message: "example.Message", - Option: &openapi_options.Schema{ - JsonSchema: &openapi_options.JSONSchema{ - Title: "{{.Name}}", - Description: "Description {{with \"which means nothing\"}}{{printf \"%q\" .}}{{end}}", - }, - ExternalDocs: &openapi_options.ExternalDocumentation{ - Description: "Description {{with \"which means nothing\"}}{{printf \"%q\" .}}{{end}}", - }, - }, - }, - }, - }, - defs: map[string]openapiSchemaObject{ - "Message": { - schemaCore: schemaCore{ - Type: "object", - }, - Title: "Message", - Description: `Description "which means nothing"`, - ExternalDocs: &openapiExternalDocumentationObject{ - Description: `Description "which means nothing"`, - }, - }, - }, - useGoTemplate: true, - }, - } - - for _, test := range tests { - t.Run(test.descr, func(t *testing.T) { - - msgs := []*descriptor.Message{} - for _, msgdesc := range test.msgDescs { - msgdesc.Options = &descriptorpb.MessageOptions{} - msgs = append(msgs, &descriptor.Message{DescriptorProto: msgdesc}) - } - - reg := descriptor.NewRegistry() - reg.SetUseGoTemplate(test.useGoTemplate) - file := descriptor.File{ - FileDescriptorProto: &descriptorpb.FileDescriptorProto{ - SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, - Name: proto.String("example.proto"), - Package: proto.String("example"), - Dependency: []string{}, - MessageType: test.msgDescs, - EnumType: []*descriptorpb.EnumDescriptorProto{}, - Service: []*descriptorpb.ServiceDescriptorProto{}, - }, - Messages: msgs, - } - reg.Load(&pluginpb.CodeGeneratorRequest{ - ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto}, - }) - - msgMap := map[string]*descriptor.Message{} - for _, d := range test.msgDescs { - name := d.GetName() - msg, err := reg.LookupMsg("example", name) - if err != nil { - t.Fatalf("lookup message %v: %v", name, err) - } - msgMap[msg.FQMN()] = msg - - if schema, ok := test.schema[name]; ok { - proto.SetExtension(d.Options, openapi_options.E_Openapiv2Schema, &schema) - } - } - - if test.openAPIOptions != nil { - if err := reg.RegisterOpenAPIOptions(test.openAPIOptions); err != nil { - t.Fatalf("failed to register OpenAPI options: %s", err) - } - } - - refs := make(refMap) - actual := make(openapiDefinitionsObject) - renderMessagesAsDefinition(msgMap, actual, reg, refs) - - if !reflect.DeepEqual(actual, test.defs) { - t.Errorf("Expected renderMessagesAsDefinition() to add defs %+v, not %+v", test.defs, actual) - } - }) - } -} - -func TestTemplateWithoutErrorDefinition(t *testing.T) { - msgdesc := &descriptorpb.DescriptorProto{ - Name: proto.String("ExampleMessage"), - Field: []*descriptorpb.FieldDescriptorProto{}, - } - meth := &descriptorpb.MethodDescriptorProto{ - Name: proto.String("Echo"), - InputType: proto.String("ExampleMessage"), - OutputType: proto.String("ExampleMessage"), - } - svc := &descriptorpb.ServiceDescriptorProto{ - Name: proto.String("ExampleService"), - Method: []*descriptorpb.MethodDescriptorProto{meth}, - } - - msg := &descriptor.Message{ - DescriptorProto: msgdesc, - } - - file := descriptor.File{ - FileDescriptorProto: &descriptorpb.FileDescriptorProto{ - SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, - Name: proto.String("example.proto"), - Package: proto.String("example"), - MessageType: []*descriptorpb.DescriptorProto{msgdesc}, - Service: []*descriptorpb.ServiceDescriptorProto{svc}, - }, - GoPkg: descriptor.GoPackage{ - Path: "example.com/path/to/example/example.pb", - Name: "example_pb", - }, - Messages: []*descriptor.Message{msg}, - Services: []*descriptor.Service{ - { - ServiceDescriptorProto: svc, - Methods: []*descriptor.Method{ - { - MethodDescriptorProto: meth, - RequestType: msg, - ResponseType: msg, - Bindings: []*descriptor.Binding{ - { - HTTPMethod: "POST", - PathTmpl: httprule.Template{ - Version: 1, - OpCodes: []int{0, 0}, - Template: "/v1/echo", - }, - Body: &descriptor.Body{ - FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{}), - }, - }, - }, - }, - }, - }, - }, - } - reg := descriptor.NewRegistry() - err := reg.Load(&pluginpb.CodeGeneratorRequest{ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto}}) - if err != nil { - t.Errorf("failed to reg.Load(): %v", err) - return - } - result, err := applyTemplate(param{File: crossLinkFixture(&file), reg: reg}) - if err != nil { - t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err) - return - } - - defRsp, ok := result.Paths["/v1/echo"].Post.Responses["default"] - if !ok { - return - } - - ref := defRsp.Schema.schemaCore.Ref - refName := strings.TrimPrefix(ref, "#/definitions/") - if refName == "" { - t.Fatal("created default Error response with empty reflink") - } - - if _, ok := result.Definitions[refName]; !ok { - t.Errorf("default Error response with reflink '%v', but its definition was not found", refName) - } -} - -func Test_getReservedJsonName(t *testing.T) { - type args struct { - fieldName string - messageNameToFieldsToJSONName map[string]map[string]string - fieldNameToType map[string]string - } - tests := []struct { - name string - args args - want string - }{ - { - "test case 1: single dot use case", - args{ - fieldName: "abc.a_1", - messageNameToFieldsToJSONName: map[string]map[string]string{ - "Msg": { - "a_1": "a1JSONNAME", - "b_1": "b1JSONNAME", - }, - }, - fieldNameToType: map[string]string{ - "abc": "pkg1.test.Msg", - "bcd": "pkg1.test.Msg", - }, - }, - "a1JSONNAME", - }, - { - "test case 2: single dot use case with no existing field", - args{ - fieldName: "abc.d_1", - messageNameToFieldsToJSONName: map[string]map[string]string{ - "Msg": { - "a_1": "a1JSONNAME", - "b_1": "b1JSONNAME", - }, - }, - fieldNameToType: map[string]string{ - "abc": "pkg1.test.Msg", - "bcd": "pkg1.test.Msg", - }, - }, - "", - }, - { - "test case 3: double dot use case", - args{ - fieldName: "pkg.abc.a_1", - messageNameToFieldsToJSONName: map[string]map[string]string{ - "Msg": { - "a_1": "a1JSONNAME", - "b_1": "b1JSONNAME", - }, - }, - fieldNameToType: map[string]string{ - "abc": "pkg1.test.Msg", - "bcd": "pkg1.test.Msg", - }, - }, - "a1JSONNAME", - }, - { - "test case 4: double dot use case with a not existed field", - args{ - fieldName: "pkg.abc.c_1", - messageNameToFieldsToJSONName: map[string]map[string]string{ - "Msg": { - "a_1": "a1JSONNAME", - "b_1": "b1JSONNAME", - }, - }, - fieldNameToType: map[string]string{ - "abc": "pkg1.test.Msg", - "bcd": "pkg1.test.Msg", - }, - }, - "", - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := getReservedJSONName(tt.args.fieldName, tt.args.messageNameToFieldsToJSONName, tt.args.fieldNameToType); got != tt.want { - t.Errorf("getReservedJSONName() = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/gateway/protoc-gen-openapiv2/internal/genopenapi/types.go b/gateway/protoc-gen-openapiv2/internal/genopenapi/types.go index 40e7d0f..1155b78 100644 --- a/gateway/protoc-gen-openapiv2/internal/genopenapi/types.go +++ b/gateway/protoc-gen-openapiv2/internal/genopenapi/types.go @@ -8,6 +8,7 @@ import ( // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor" "github.com/binchencoder/ease-gateway/gateway/internal/descriptor" options "github.com/binchencoder/ease-gateway/httpoptions" + "gopkg.in/yaml.v2" ) type param struct { @@ -17,57 +18,65 @@ type param struct { // http://swagger.io/specification/#infoObject type openapiInfoObject struct { - Title string `json:"title"` - Description string `json:"description,omitempty"` - TermsOfService string `json:"termsOfService,omitempty"` - Version string `json:"version"` + Title string `json:"title" yaml:"title"` + Description string `json:"description,omitempty" yaml:"description,omitempty"` + TermsOfService string `json:"termsOfService,omitempty" yaml:"termsOfService,omitempty"` + Version string `json:"version" yaml:"version"` - Contact *openapiContactObject `json:"contact,omitempty"` - License *openapiLicenseObject `json:"license,omitempty"` + Contact *openapiContactObject `json:"contact,omitempty" yaml:"contact,omitempty"` + License *openapiLicenseObject `json:"license,omitempty" yaml:"license,omitempty"` - extensions []extension + extensions []extension `json:"-" yaml:"-"` +} + +// https://swagger.io/specification/#tagObject +type openapiTagObject struct { + Name string `json:"name" yaml:"name"` + Description string `json:"description,omitempty" yaml:"description,omitempty"` + ExternalDocs *openapiExternalDocumentationObject `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"` } // http://swagger.io/specification/#contactObject type openapiContactObject struct { - Name string `json:"name,omitempty"` - URL string `json:"url,omitempty"` - Email string `json:"email,omitempty"` + Name string `json:"name,omitempty" yaml:"name,omitempty"` + URL string `json:"url,omitempty" yaml:"url,omitempty"` + Email string `json:"email,omitempty" yaml:"email,omitempty"` } // http://swagger.io/specification/#licenseObject type openapiLicenseObject struct { - Name string `json:"name,omitempty"` - URL string `json:"url,omitempty"` + Name string `json:"name,omitempty" yaml:"name,omitempty"` + URL string `json:"url,omitempty" yaml:"url,omitempty"` } // http://swagger.io/specification/#externalDocumentationObject type openapiExternalDocumentationObject struct { - Description string `json:"description,omitempty"` - URL string `json:"url,omitempty"` + Description string `json:"description,omitempty" yaml:"description,omitempty"` + URL string `json:"url,omitempty" yaml:"url,omitempty"` } type extension struct { - key string - value json.RawMessage + key string `json:"-" yaml:"-"` + value json.RawMessage `json:"-" yaml:"-"` } // http://swagger.io/specification/#swaggerObject type openapiSwaggerObject struct { - Swagger string `json:"swagger"` - Info openapiInfoObject `json:"info"` - Host string `json:"host,omitempty"` - BasePath string `json:"basePath,omitempty"` - Schemes []string `json:"schemes,omitempty"` - Consumes []string `json:"consumes"` - Produces []string `json:"produces"` - Paths openapiPathsObject `json:"paths"` - Definitions openapiDefinitionsObject `json:"definitions"` - SecurityDefinitions openapiSecurityDefinitionsObject `json:"securityDefinitions,omitempty"` - Security []openapiSecurityRequirementObject `json:"security,omitempty"` - ExternalDocs *openapiExternalDocumentationObject `json:"externalDocs,omitempty"` - - extensions []extension + Swagger string `json:"swagger" yaml:"swagger"` + Info openapiInfoObject `json:"info" yaml:"info"` + Tags []openapiTagObject `json:"tags,omitempty" yaml:"tags,omitempty"` + Host string `json:"host,omitempty" yaml:"host,omitempty"` + BasePath string `json:"basePath,omitempty" yaml:"basePath,omitempty"` + Schemes []string `json:"schemes,omitempty" yaml:"schemes,omitempty"` + Consumes []string `json:"consumes" yaml:"consumes"` + Produces []string `json:"produces" yaml:"produces"` + Paths openapiPathsObject `json:"paths" yaml:"paths"` + Definitions openapiDefinitionsObject `json:"definitions" yaml:"definitions"` + SecurityDefinitions openapiSecurityDefinitionsObject `json:"securityDefinitions,omitempty" yaml:"securityDefinitions,omitempty"` + Security []openapiSecurityRequirementObject `json:"security,omitempty" yaml:"security,omitempty"` + ExternalDocs *openapiExternalDocumentationObject `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"` + + extensions []extension `json:"-" yaml:"-"` } // http://swagger.io/specification/#securityDefinitionsObject @@ -75,16 +84,16 @@ type openapiSecurityDefinitionsObject map[string]openapiSecuritySchemeObject // http://swagger.io/specification/#securitySchemeObject type openapiSecuritySchemeObject struct { - Type string `json:"type"` - Description string `json:"description,omitempty"` - Name string `json:"name,omitempty"` - In string `json:"in,omitempty"` - Flow string `json:"flow,omitempty"` - AuthorizationURL string `json:"authorizationUrl,omitempty"` - TokenURL string `json:"tokenUrl,omitempty"` - Scopes openapiScopesObject `json:"scopes,omitempty"` - - extensions []extension + Type string `json:"type" yaml:"type"` + Description string `json:"description,omitempty" yaml:"description,omitempty"` + Name string `json:"name,omitempty" yaml:"name,omitempty"` + In string `json:"in,omitempty" yaml:"in,omitempty"` + Flow string `json:"flow,omitempty" yaml:"flow,omitempty"` + AuthorizationURL string `json:"authorizationUrl,omitempty" yaml:"authorizationUrl,omitempty"` + TokenURL string `json:"tokenUrl,omitempty" yaml:"tokenUrl,omitempty"` + Scopes openapiScopesObject `json:"scopes,omitempty" yaml:"scopes,omitempty"` + + extensions []extension `json:"-" yaml:"-"` } // http://swagger.io/specification/#scopesObject @@ -98,69 +107,110 @@ type openapiPathsObject map[string]openapiPathItemObject // http://swagger.io/specification/#pathItemObject type openapiPathItemObject struct { - Get *openapiOperationObject `json:"get,omitempty"` - Delete *openapiOperationObject `json:"delete,omitempty"` - Post *openapiOperationObject `json:"post,omitempty"` - Put *openapiOperationObject `json:"put,omitempty"` - Patch *openapiOperationObject `json:"patch,omitempty"` + Get *openapiOperationObject `json:"get,omitempty" yaml:"get,omitempty"` + Delete *openapiOperationObject `json:"delete,omitempty" yaml:"delete,omitempty"` + Post *openapiOperationObject `json:"post,omitempty" yaml:"post,omitempty"` + Put *openapiOperationObject `json:"put,omitempty" yaml:"put,omitempty"` + Patch *openapiOperationObject `json:"patch,omitempty" yaml:"patch,omitempty"` } // http://swagger.io/specification/#operationObject type openapiOperationObject struct { - Summary string `json:"summary,omitempty"` - Description string `json:"description,omitempty"` - OperationID string `json:"operationId"` - Responses openapiResponsesObject `json:"responses"` - Parameters openapiParametersObject `json:"parameters,omitempty"` - Tags []string `json:"tags,omitempty"` - Deprecated bool `json:"deprecated,omitempty"` - Produces []string `json:"produces,omitempty"` - - Security *[]openapiSecurityRequirementObject `json:"security,omitempty"` - ExternalDocs *openapiExternalDocumentationObject `json:"externalDocs,omitempty"` - - extensions []extension + Summary string `json:"summary,omitempty" yaml:"summary,omitempty"` + Description string `json:"description,omitempty" yaml:"description,omitempty"` + OperationID string `json:"operationId" yaml:"operationId"` + Responses openapiResponsesObject `json:"responses" yaml:"responses"` + Parameters openapiParametersObject `json:"parameters,omitempty" yaml:"parameters,omitempty"` + Tags []string `json:"tags,omitempty" yaml:"tags,omitempty"` + Deprecated bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"` + Produces []string `json:"produces,omitempty" yaml:"produces,omitempty"` + + Security *[]openapiSecurityRequirementObject `json:"security,omitempty" yaml:"security,omitempty"` + ExternalDocs *openapiExternalDocumentationObject `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"` + + extensions []extension `json:"-" yaml:"-"` } type openapiParametersObject []openapiParameterObject // http://swagger.io/specification/#parameterObject type openapiParameterObject struct { - Name string `json:"name"` - Description string `json:"description,omitempty"` - In string `json:"in,omitempty"` - Required bool `json:"required"` - Type string `json:"type,omitempty"` - Format string `json:"format,omitempty"` - Items *openapiItemsObject `json:"items,omitempty"` - Enum []string `json:"enum,omitempty"` - CollectionFormat string `json:"collectionFormat,omitempty"` - Default string `json:"default,omitempty"` - MinItems *int `json:"minItems,omitempty"` + Name string `json:"name" yaml:"name"` + Description string `json:"description,omitempty" yaml:"description,omitempty"` + In string `json:"in,omitempty" yaml:"in,omitempty"` + Required bool `json:"required" yaml:"required"` + Type string `json:"type,omitempty" yaml:"type,omitempty"` + Format string `json:"format,omitempty" yaml:"format,omitempty"` + Items *openapiItemsObject `json:"items,omitempty" yaml:"items,omitempty"` + Enum []string `json:"enum,omitempty" yaml:"enum,omitempty"` + CollectionFormat string `json:"collectionFormat,omitempty" yaml:"collectionFormat,omitempty"` + Default string `json:"default,omitempty" yaml:"default,omitempty"` + MinItems *int `json:"minItems,omitempty" yaml:"minItems,omitempty"` + Pattern string `json:"pattern,omitempty" yaml:"pattern,omitempty"` // Or you can explicitly refer to another type. If this is defined all // other fields should be empty - Schema *openapiSchemaObject `json:"schema,omitempty"` + Schema *openapiSchemaObject `json:"schema,omitempty" yaml:"schema,omitempty"` } // core part of schema, which is common to itemsObject and schemaObject. -// http://swagger.io/specification/#itemsObject +// http://swagger.io/specification/v2/#itemsObject +// The OAS3 spec (https://swagger.io/specification/#schemaObject) defines the +// `nullable` field as part of a Schema Object. This behavior has been +// "back-ported" to OAS2 as the Specification Extension `x-nullable`, and is +// supported by generation tools such as swagger-codegen and go-swagger. +// For protoc-gen-openapiv3, we'd want to add `nullable` instead. type schemaCore struct { - Type string `json:"type,omitempty"` - Format string `json:"format,omitempty"` - Ref string `json:"$ref,omitempty"` - Example json.RawMessage `json:"example,omitempty"` + Type string `json:"type,omitempty" yaml:"type,omitempty"` + Format string `json:"format,omitempty" yaml:"format,omitempty"` + Ref string `json:"$ref,omitempty" yaml:"$ref,omitempty"` + XNullable bool `json:"x-nullable,omitempty" yaml:"x-nullable,omitempty"` + Example RawExample `json:"example,omitempty" yaml:"example,omitempty"` - Items *openapiItemsObject `json:"items,omitempty"` + Items *openapiItemsObject `json:"items,omitempty" yaml:"items,omitempty"` // If the item is an enumeration include a list of all the *NAMES* of the // enum values. I'm not sure how well this will work but assuming all enums // start from 0 index it will be great. I don't think that is a good assumption. - Enum []string `json:"enum,omitempty"` - Default string `json:"default,omitempty"` + Enum []string `json:"enum,omitempty" yaml:"enum,omitempty"` + Default string `json:"default,omitempty" yaml:"default,omitempty"` Rules []options.ValidationRule `json:"rules,omitempty"` } +type RawExample json.RawMessage + +func (m RawExample) MarshalJSON() ([]byte, error) { + return (json.RawMessage)(m).MarshalJSON() +} + +func (m *RawExample) UnmarshalJSON(data []byte) error { + return (*json.RawMessage)(m).UnmarshalJSON(data) +} + +// MarshalYAML implements yaml.Marshaler interface. +// +// It converts RawExample to one of yaml-supported types and returns it. +// +// From yaml.Marshaler docs: The Marshaler interface may be implemented +// by types to customize their behavior when being marshaled into a YAML +// document. The returned value is marshaled in place of the original +// value implementing Marshaler. +func (e RawExample) MarshalYAML() (interface{}, error) { + // From docs, json.Unmarshal will store one of next types to data: + // - bool, for JSON booleans; + // - float64, for JSON numbers; + // - string, for JSON strings; + // - []interface{}, for JSON arrays; + // - map[string]interface{}, for JSON objects; + // - nil for JSON null. + var data interface{} + if err := json.Unmarshal(e, &data); err != nil { + return nil, err + } + + return data, nil +} + func (s *schemaCore) setRefFromFQN(ref string, reg *descriptor.Registry) error { name, ok := fullyQualifiedNameToOpenAPIName(ref, reg) if !ok { @@ -177,11 +227,23 @@ type openapiResponsesObject map[string]openapiResponseObject // http://swagger.io/specification/#responseObject type openapiResponseObject struct { - Description string `json:"description"` - Schema openapiSchemaObject `json:"schema"` - Examples map[string]interface{} `json:"examples,omitempty"` + Description string `json:"description" yaml:"description"` + Schema openapiSchemaObject `json:"schema" yaml:"schema"` + Examples map[string]interface{} `json:"examples,omitempty" yaml:"examples,omitempty"` + Headers openapiHeadersObject `json:"headers,omitempty" yaml:"headers,omitempty"` - extensions []extension + extensions []extension `json:"-" yaml:"-"` +} + +type openapiHeadersObject map[string]openapiHeaderObject + +// http://swagger.io/specification/#headerObject +type openapiHeaderObject struct { + Description string `json:"description,omitempty" yaml:"description,omitempty"` + Type string `json:"type,omitempty" yaml:"type,omitempty"` + Format string `json:"format,omitempty" yaml:"format,omitempty"` + Default RawExample `json:"default,omitempty" yaml:"default,omitempty"` + Pattern string `json:"pattern,omitempty" yaml:"pattern,omitempty"` } type keyVal struct { @@ -191,6 +253,19 @@ type keyVal struct { type openapiSchemaObjectProperties []keyVal +func (p openapiSchemaObjectProperties) MarshalYAML() (interface{}, error) { + ms := make(yaml.MapSlice, len(p)) + + for i, v := range p { + ms[i] = yaml.MapItem{ + Key: v.Key, + Value: v.Value, + } + } + + return ms, nil +} + func (op openapiSchemaObjectProperties) MarshalJSON() ([]byte, error) { var buf bytes.Buffer buf.WriteString("{") @@ -217,31 +292,31 @@ func (op openapiSchemaObjectProperties) MarshalJSON() ([]byte, error) { // http://swagger.io/specification/#schemaObject type openapiSchemaObject struct { - schemaCore + schemaCore `yaml:",inline"` // Properties can be recursively defined - Properties *openapiSchemaObjectProperties `json:"properties,omitempty"` - AdditionalProperties *openapiSchemaObject `json:"additionalProperties,omitempty"` - - Description string `json:"description,omitempty"` - Title string `json:"title,omitempty"` - - ExternalDocs *openapiExternalDocumentationObject `json:"externalDocs,omitempty"` - - ReadOnly bool `json:"readOnly,omitempty"` - MultipleOf float64 `json:"multipleOf,omitempty"` - Maximum float64 `json:"maximum,omitempty"` - ExclusiveMaximum bool `json:"exclusiveMaximum,omitempty"` - Minimum float64 `json:"minimum,omitempty"` - ExclusiveMinimum bool `json:"exclusiveMinimum,omitempty"` - MaxLength uint64 `json:"maxLength,omitempty"` - MinLength uint64 `json:"minLength,omitempty"` - Pattern string `json:"pattern,omitempty"` - MaxItems uint64 `json:"maxItems,omitempty"` - MinItems uint64 `json:"minItems,omitempty"` - UniqueItems bool `json:"uniqueItems,omitempty"` - MaxProperties uint64 `json:"maxProperties,omitempty"` - MinProperties uint64 `json:"minProperties,omitempty"` - Required []string `json:"required,omitempty"` + Properties *openapiSchemaObjectProperties `json:"properties,omitempty" yaml:"properties,omitempty"` + AdditionalProperties *openapiSchemaObject `json:"additionalProperties,omitempty" yaml:"additionalProperties,omitempty"` + + Description string `json:"description,omitempty" yaml:"description,omitempty"` + Title string `json:"title,omitempty" yaml:"title,omitempty"` + + ExternalDocs *openapiExternalDocumentationObject `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"` + + ReadOnly bool `json:"readOnly,omitempty" yaml:"readOnly,omitempty"` + MultipleOf float64 `json:"multipleOf,omitempty" yaml:"multipleOf,omitempty"` + Maximum float64 `json:"maximum,omitempty" yaml:"maximum,omitempty"` + ExclusiveMaximum bool `json:"exclusiveMaximum,omitempty" yaml:"exclusiveMaximum,omitempty"` + Minimum float64 `json:"minimum,omitempty" yaml:"minimum,omitempty"` + ExclusiveMinimum bool `json:"exclusiveMinimum,omitempty" yaml:"exclusiveMinimum,omitempty"` + MaxLength uint64 `json:"maxLength,omitempty" yaml:"maxLength,omitempty"` + MinLength uint64 `json:"minLength,omitempty" yaml:"minLength,omitempty"` + Pattern string `json:"pattern,omitempty" yaml:"pattern,omitempty"` + MaxItems uint64 `json:"maxItems,omitempty" yaml:"maxItems,omitempty"` + MinItems uint64 `json:"minItems,omitempty" yaml:"minItems,omitempty"` + UniqueItems bool `json:"uniqueItems,omitempty" yaml:"uniqueItems,omitempty"` + MaxProperties uint64 `json:"maxProperties,omitempty" yaml:"maxProperties,omitempty"` + MinProperties uint64 `json:"minProperties,omitempty" yaml:"minProperties,omitempty"` + Required []string `json:"required,omitempty" yaml:"required,omitempty"` } // http://swagger.io/specification/#definitionsObject diff --git a/gateway/protoc-gen-openapiv2/main.go b/gateway/protoc-gen-openapiv2/main.go index e180b06..3e48a20 100644 --- a/gateway/protoc-gen-openapiv2/main.go +++ b/gateway/protoc-gen-openapiv2/main.go @@ -11,31 +11,38 @@ import ( // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor" "github.com/binchencoder/ease-gateway/gateway/internal/descriptor" - // genopenapi "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/internal/genopenapi" + // "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/internal/genopenapi" genopenapi "github.com/binchencoder/ease-gateway/gateway/protoc-gen-openapiv2/internal/genopenapi" + "github.com/grpc-ecosystem/grpc-gateway/v2/utilities" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/pluginpb" ) var ( - importPrefix = flag.String("import_prefix", "", "prefix to be added to go package paths for imported proto files") - file = flag.String("file", "-", "where to load data from") - allowDeleteBody = flag.Bool("allow_delete_body", false, "unless set, HTTP DELETE methods may not have a body") - grpcAPIConfiguration = flag.String("grpc_api_configuration", "", "path to gRPC API Configuration in YAML format") - allowMerge = flag.Bool("allow_merge", false, "if set, generation one OpenAPI file out of multiple protos") - mergeFileName = flag.String("merge_file_name", "apidocs", "target OpenAPI file name prefix after merge") - useJSONNamesForFields = flag.Bool("json_names_for_fields", true, "if disabled, the original proto name will be used for generating OpenAPI definitions") - repeatedPathParamSeparator = flag.String("repeated_path_param_separator", "csv", "configures how repeated fields should be split. Allowed values are `csv`, `pipes`, `ssv` and `tsv`.") - versionFlag = flag.Bool("version", false, "print the current version") - allowRepeatedFieldsInBody = flag.Bool("allow_repeated_fields_in_body", false, "allows to use repeated field in `body` and `response_body` field of `google.api.http` annotation option") - includePackageInTags = flag.Bool("include_package_in_tags", false, "if unset, the gRPC service name is added to the `Tags` field of each operation. if set and the `package` directive is shown in the proto file, the package name will be prepended to the service name") - useFQNForOpenAPIName = flag.Bool("fqn_for_openapi_name", false, "if set, the object's OpenAPI names will use the fully qualify name from the proto definition (ie my.package.MyMessage.MyInnerMessage") - useGoTemplate = flag.Bool("use_go_templates", false, "if set, you can use Go templates in protofile comments") - disableDefaultErrors = flag.Bool("disable_default_errors", false, "if set, disables generation of default errors. This is useful if you have defined custom error handling") - enumsAsInts = flag.Bool("enums_as_ints", false, "whether to render enum values as integers, as opposed to string values") - simpleOperationIDs = flag.Bool("simple_operation_ids", false, "whether to remove the service prefix in the operationID generation. Can introduce duplicate operationIDs, use with caution.") - openAPIConfiguration = flag.String("openapi_configuration", "", "path to OpenAPI Configuration in YAML format") - generateUnboundMethods = flag.Bool("generate_unbound_methods", false, "generate swagger metadata even for RPC methods that have no HttpRule annotation") + importPrefix = flag.String("import_prefix", "", "prefix to be added to go package paths for imported proto files") + file = flag.String("file", "-", "where to load data from") + allowDeleteBody = flag.Bool("allow_delete_body", false, "unless set, HTTP DELETE methods may not have a body") + grpcAPIConfiguration = flag.String("grpc_api_configuration", "", "path to file which describes the gRPC API Configuration in YAML format") + allowMerge = flag.Bool("allow_merge", false, "if set, generation one OpenAPI file out of multiple protos") + mergeFileName = flag.String("merge_file_name", "apidocs", "target OpenAPI file name prefix after merge") + useJSONNamesForFields = flag.Bool("json_names_for_fields", true, "if disabled, the original proto name will be used for generating OpenAPI definitions") + repeatedPathParamSeparator = flag.String("repeated_path_param_separator", "csv", "configures how repeated fields should be split. Allowed values are `csv`, `pipes`, `ssv` and `tsv`") + versionFlag = flag.Bool("version", false, "print the current version") + allowRepeatedFieldsInBody = flag.Bool("allow_repeated_fields_in_body", false, "allows to use repeated field in `body` and `response_body` field of `google.api.http` annotation option") + includePackageInTags = flag.Bool("include_package_in_tags", false, "if unset, the gRPC service name is added to the `Tags` field of each operation. If set and the `package` directive is shown in the proto file, the package name will be prepended to the service name") + useFQNForOpenAPIName = flag.Bool("fqn_for_openapi_name", false, "if set, the object's OpenAPI names will use the fully qualified names from the proto definition (ie my.package.MyMessage.MyInnerMessage). DEPRECATED: prefer `openapi_naming_strategy=fqn`") + openAPINamingStrategy = flag.String("openapi_naming_strategy", "", "use the given OpenAPI naming strategy. Allowed values are `legacy`, `fqn`, `simple`. If unset, either `legacy` or `fqn` are selected, depending on the value of the `fqn_for_openapi_name` flag") + useGoTemplate = flag.Bool("use_go_templates", false, "if set, you can use Go templates in protofile comments") + disableDefaultErrors = flag.Bool("disable_default_errors", false, "if set, disables generation of default errors. This is useful if you have defined custom error handling") + enumsAsInts = flag.Bool("enums_as_ints", false, "whether to render enum values as integers, as opposed to string values") + simpleOperationIDs = flag.Bool("simple_operation_ids", false, "whether to remove the service prefix in the operationID generation. Can introduce duplicate operationIDs, use with caution.") + proto3OptionalNullable = flag.Bool("proto3_optional_nullable", false, "whether Proto3 Optional fields should be marked as x-nullable") + openAPIConfiguration = flag.String("openapi_configuration", "", "path to file which describes the OpenAPI Configuration in YAML format") + generateUnboundMethods = flag.Bool("generate_unbound_methods", false, "generate swagger metadata even for RPC methods that have no HttpRule annotation") + recursiveDepth = flag.Int("recursive-depth", 1000, "maximum recursion count allowed for a field type") + omitEnumDefaultValue = flag.Bool("omit_enum_default_value", false, "if set, omit default enum value") + outputFormat = flag.String("output_format", string(genopenapi.FormatJSON), fmt.Sprintf("output content format. Allowed values are: `%s`, `%s`", genopenapi.FormatJSON, genopenapi.FormatYAML)) + visibilityRestrictionSelectors = utilities.StringArrayFlag(flag.CommandLine, "visibility_restriction_selectors", "list of `google.api.VisibilityRule` visibility labels to include in the generated output when a visibility annotation is defined. Repeat this option to supply multiple values. Elements without visibility annotations are unaffected by this setting.") ) // Variables set by goreleaser at build time @@ -86,12 +93,34 @@ func main() { reg.SetUseJSONNamesForFields(*useJSONNamesForFields) reg.SetAllowRepeatedFieldsInBody(*allowRepeatedFieldsInBody) reg.SetIncludePackageInTags(*includePackageInTags) + reg.SetUseFQNForOpenAPIName(*useFQNForOpenAPIName) + // Set the naming strategy either directly from the flag, or via the value of the legacy fqn_for_openapi_name + // flag. + namingStrategy := *openAPINamingStrategy + if *useFQNForOpenAPIName { + if namingStrategy != "" { + glog.Fatal("The deprecated `fqn_for_openapi_name` flag must remain unset if `openapi_naming_strategy` is set.") + } + glog.Warning("The `fqn_for_openapi_name` flag is deprecated. Please use `openapi_naming_strategy=fqn` instead.") + namingStrategy = "fqn" + } else if namingStrategy == "" { + namingStrategy = "legacy" + } + if strategyFn := genopenapi.LookupNamingStrategy(namingStrategy); strategyFn == nil { + emitError(fmt.Errorf("invalid naming strategy %q", namingStrategy)) + return + } + reg.SetOpenAPINamingStrategy(namingStrategy) reg.SetUseGoTemplate(*useGoTemplate) reg.SetEnumsAsInts(*enumsAsInts) reg.SetDisableDefaultErrors(*disableDefaultErrors) reg.SetSimpleOperationIDs(*simpleOperationIDs) + reg.SetProto3OptionalNullable(*proto3OptionalNullable) reg.SetGenerateUnboundMethods(*generateUnboundMethods) + reg.SetRecursiveDepth(*recursiveDepth) + reg.SetOmitEnumDefaultValue(*omitEnumDefaultValue) + reg.SetVisibilityRestrictionSelectors(*visibilityRestrictionSelectors) if err := reg.SetRepeatedPathParamSeparator(*repeatedPathParamSeparator); err != nil { emitError(err) return @@ -107,7 +136,13 @@ func main() { } } - g := genopenapi.New(reg) + format := genopenapi.Format(*outputFormat) + if err := format.Validate(); err != nil { + emitError(err) + return + } + + g := genopenapi.New(reg, format) if err := genopenapi.AddErrorDefs(reg); err != nil { emitError(err) @@ -149,7 +184,9 @@ func emitFiles(out []*descriptor.ResponseFile) { for idx, item := range out { files[idx] = item.CodeGeneratorResponse_File } - emitResp(&pluginpb.CodeGeneratorResponse{File: files}) + resp := &pluginpb.CodeGeneratorResponse{File: files} + codegenerator.SetSupportedFeaturesOnCodeGeneratorResponse(resp) + emitResp(resp) } func emitError(err error) { diff --git a/gateway/protoc-gen-openapiv2/main_test.go b/gateway/protoc-gen-openapiv2/main_test.go index 514840a..e1b9a1f 100644 --- a/gateway/protoc-gen-openapiv2/main_test.go +++ b/gateway/protoc-gen-openapiv2/main_test.go @@ -22,98 +22,175 @@ func TestParseReqParam(t *testing.T) { importPathV string mergeFileNameV string useFQNForOpenAPINameV bool + openAPINamingStrategyV string }{ { // this one must be first - with no leading clearFlags call it // verifies our expectation of default values as we reset by // clearFlags - name: "Test 0", - expected: map[string]string{}, - request: "", - allowDeleteBodyV: false, allowMergeV: false, allowRepeatedFieldsInBodyV: false, includePackageInTagsV: false, - fileV: "-", importPathV: "", mergeFileNameV: "apidocs", + name: "Test 0", + expected: map[string]string{}, + request: "", + allowDeleteBodyV: false, + allowMergeV: false, + allowRepeatedFieldsInBodyV: false, + includePackageInTagsV: false, + fileV: "-", + importPathV: "", + mergeFileNameV: "apidocs", }, { - name: "Test 1", - expected: map[string]string{"google/api/annotations.proto": "github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis/google/api"}, - request: "allow_delete_body,allow_merge,allow_repeated_fields_in_body,include_package_in_tags,file=./foo.pb,import_prefix=/bar/baz,Mgoogle/api/annotations.proto=github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis/google/api", - allowDeleteBodyV: true, allowMergeV: true, allowRepeatedFieldsInBodyV: true, includePackageInTagsV: true, - fileV: "./foo.pb", importPathV: "/bar/baz", mergeFileNameV: "apidocs", + name: "Test 1", + expected: map[string]string{"google/api/annotations.proto": "github.com/googleapis/googleapis/google/api"}, + request: "allow_delete_body,allow_merge,allow_repeated_fields_in_body,include_package_in_tags,file=./foo.pb,import_prefix=/bar/baz,Mgoogle/api/annotations.proto=github.com/googleapis/googleapis/google/api", + allowDeleteBodyV: true, + allowMergeV: true, + allowRepeatedFieldsInBodyV: true, + includePackageInTagsV: true, + fileV: "./foo.pb", + importPathV: "/bar/baz", + mergeFileNameV: "apidocs", }, { - name: "Test 2", - expected: map[string]string{"google/api/annotations.proto": "github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis/google/api"}, - request: "allow_delete_body=true,allow_merge=true,allow_repeated_fields_in_body=true,include_package_in_tags=true,merge_file_name=test_name,file=./foo.pb,import_prefix=/bar/baz,Mgoogle/api/annotations.proto=github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis/google/api", - allowDeleteBodyV: true, allowMergeV: true, allowRepeatedFieldsInBodyV: true, includePackageInTagsV: true, - fileV: "./foo.pb", importPathV: "/bar/baz", mergeFileNameV: "test_name", + name: "Test 2", + expected: map[string]string{"google/api/annotations.proto": "github.com/googleapis/googleapis/google/api"}, + request: "allow_delete_body=true,allow_merge=true,allow_repeated_fields_in_body=true,include_package_in_tags=true,merge_file_name=test_name,file=./foo.pb,import_prefix=/bar/baz,Mgoogle/api/annotations.proto=github.com/googleapis/googleapis/google/api", + allowDeleteBodyV: true, + allowMergeV: true, + allowRepeatedFieldsInBodyV: true, + includePackageInTagsV: true, + fileV: "./foo.pb", + importPathV: "/bar/baz", + mergeFileNameV: "test_name", }, { - name: "Test 3", - expected: map[string]string{"a/b/c.proto": "github.com/x/y/z", "f/g/h.proto": "github.com/1/2/3/"}, - request: "allow_delete_body=false,allow_merge=false,Ma/b/c.proto=github.com/x/y/z,Mf/g/h.proto=github.com/1/2/3/", - allowDeleteBodyV: false, allowMergeV: false, allowRepeatedFieldsInBodyV: false, includePackageInTagsV: false, - fileV: "stdin", importPathV: "", mergeFileNameV: "apidocs", + name: "Test 3", + expected: map[string]string{"a/b/c.proto": "github.com/x/y/z", "f/g/h.proto": "github.com/1/2/3/"}, + request: "allow_delete_body=false,allow_merge=false,Ma/b/c.proto=github.com/x/y/z,Mf/g/h.proto=github.com/1/2/3/", + allowDeleteBodyV: false, + allowMergeV: false, + allowRepeatedFieldsInBodyV: false, + includePackageInTagsV: false, + fileV: "stdin", + importPathV: "", + mergeFileNameV: "apidocs", }, { - name: "Test 4", - expected: map[string]string{}, - request: "", - allowDeleteBodyV: false, allowMergeV: false, allowRepeatedFieldsInBodyV: false, includePackageInTagsV: false, - fileV: "stdin", importPathV: "", mergeFileNameV: "apidocs", + name: "Test 4", + expected: map[string]string{}, + request: "", + allowDeleteBodyV: false, + allowMergeV: false, + allowRepeatedFieldsInBodyV: false, + includePackageInTagsV: false, + fileV: "stdin", + importPathV: "", + mergeFileNameV: "apidocs", }, { - name: "Test 5", - expected: map[string]string{}, - request: "unknown_param=17", - expectedError: errors.New("cannot set flag unknown_param=17: no such flag -unknown_param"), - allowDeleteBodyV: false, allowMergeV: false, allowRepeatedFieldsInBodyV: false, includePackageInTagsV: false, - fileV: "stdin", importPathV: "", mergeFileNameV: "apidocs", + name: "Test 5", + expected: map[string]string{}, + request: "unknown_param=17", + expectedError: errors.New("cannot set flag unknown_param=17: no such flag -unknown_param"), + allowDeleteBodyV: false, + allowMergeV: false, + allowRepeatedFieldsInBodyV: false, + includePackageInTagsV: false, + fileV: "stdin", + importPathV: "", + mergeFileNameV: "apidocs", }, { - name: "Test 6", - expected: map[string]string{}, - request: "Mfoo", - expectedError: errors.New("cannot set flag Mfoo: no such flag -Mfoo"), - allowDeleteBodyV: false, allowMergeV: false, allowRepeatedFieldsInBodyV: false, includePackageInTagsV: false, - fileV: "stdin", importPathV: "", mergeFileNameV: "apidocs", + name: "Test 6", + expected: map[string]string{}, + request: "Mfoo", + expectedError: errors.New("cannot set flag Mfoo: no such flag -Mfoo"), + allowDeleteBodyV: false, + allowMergeV: false, + allowRepeatedFieldsInBodyV: false, + includePackageInTagsV: false, + fileV: "stdin", + importPathV: "", + mergeFileNameV: "apidocs", }, { - name: "Test 7", - expected: map[string]string{}, - request: "allow_delete_body,file,import_prefix,allow_merge,allow_repeated_fields_in_body,include_package_in_tags,merge_file_name", - allowDeleteBodyV: true, allowMergeV: true, allowRepeatedFieldsInBodyV: true, includePackageInTagsV: true, - fileV: "", importPathV: "", mergeFileNameV: "", + name: "Test 7", + expected: map[string]string{}, + request: "allow_delete_body,file,import_prefix,allow_merge,allow_repeated_fields_in_body,include_package_in_tags,merge_file_name", + allowDeleteBodyV: true, + allowMergeV: true, + allowRepeatedFieldsInBodyV: true, + includePackageInTagsV: true, + fileV: "", + importPathV: "", + mergeFileNameV: "", }, { - name: "Test 8", - expected: map[string]string{}, - request: "allow_delete_body,file,import_prefix,allow_merge,allow_repeated_fields_in_body=3,merge_file_name", - expectedError: errors.New(`cannot set flag allow_repeated_fields_in_body=3: parse error`), - allowDeleteBodyV: true, allowMergeV: true, allowRepeatedFieldsInBodyV: false, includePackageInTagsV: false, - fileV: "", importPathV: "", mergeFileNameV: "apidocs", + name: "Test 8", + expected: map[string]string{}, + request: "allow_delete_body,file,import_prefix,allow_merge,allow_repeated_fields_in_body=3,merge_file_name", + expectedError: errors.New(`cannot set flag allow_repeated_fields_in_body=3: parse error`), + allowDeleteBodyV: true, + allowMergeV: true, + allowRepeatedFieldsInBodyV: false, + includePackageInTagsV: false, + fileV: "", + importPathV: "", + mergeFileNameV: "apidocs", }, { - name: "Test 9", - expected: map[string]string{}, - request: "include_package_in_tags=3", - expectedError: errors.New(`cannot set flag include_package_in_tags=3: parse error`), - allowDeleteBodyV: false, allowMergeV: false, allowRepeatedFieldsInBodyV: false, includePackageInTagsV: false, - fileV: "stdin", importPathV: "", mergeFileNameV: "apidocs", + name: "Test 9", + expected: map[string]string{}, + request: "include_package_in_tags=3", + expectedError: errors.New(`cannot set flag include_package_in_tags=3: parse error`), + allowDeleteBodyV: false, + allowMergeV: false, + allowRepeatedFieldsInBodyV: false, + includePackageInTagsV: false, + fileV: "stdin", + importPathV: "", + mergeFileNameV: "apidocs", }, { - name: "Test 10", - expected: map[string]string{}, - request: "fqn_for_openapi_name=3", - expectedError: errors.New(`cannot set flag fqn_for_openapi_name=3: parse error`), - allowDeleteBodyV: false, allowMergeV: false, allowRepeatedFieldsInBodyV: false, includePackageInTagsV: false, useFQNForOpenAPINameV: false, - fileV: "stdin", importPathV: "", mergeFileNameV: "apidocs", + name: "Test 10", + expected: map[string]string{}, + request: "fqn_for_openapi_name=3", + expectedError: errors.New(`cannot set flag fqn_for_openapi_name=3: parse error`), + allowDeleteBodyV: false, + allowMergeV: false, + allowRepeatedFieldsInBodyV: false, + includePackageInTagsV: false, + useFQNForOpenAPINameV: false, + fileV: "stdin", + importPathV: "", + mergeFileNameV: "apidocs", }, { - name: "Test 11", - expected: map[string]string{}, - request: "fqn_for_openapi_name=true", - allowDeleteBodyV: false, allowMergeV: false, allowRepeatedFieldsInBodyV: false, includePackageInTagsV: false, useFQNForOpenAPINameV: true, - fileV: "stdin", importPathV: "", mergeFileNameV: "apidocs", + name: "Test 11", + expected: map[string]string{}, + request: "fqn_for_openapi_name=true", + allowDeleteBodyV: false, + allowMergeV: false, + allowRepeatedFieldsInBodyV: false, + includePackageInTagsV: false, + useFQNForOpenAPINameV: true, + fileV: "stdin", + importPathV: "", + mergeFileNameV: "apidocs", + }, + { + name: "Test 12", + expected: map[string]string{}, + request: "openapi_naming_strategy=simple", + allowDeleteBodyV: false, + allowMergeV: false, + allowRepeatedFieldsInBodyV: false, + includePackageInTagsV: false, + useFQNForOpenAPINameV: false, + openAPINamingStrategyV: "simple", + fileV: "stdin", + importPathV: "", + mergeFileNameV: "apidocs", }, } @@ -140,15 +217,26 @@ func TestParseReqParam(t *testing.T) { tt.Errorf("expected error malformed, expected %q, got %q", tc.expectedError.Error(), err.Error()) } } - checkFlags(tc.allowDeleteBodyV, tc.allowMergeV, tc.allowRepeatedFieldsInBodyV, tc.includePackageInTagsV, tc.useFQNForOpenAPINameV, tc.fileV, tc.importPathV, tc.mergeFileNameV, tt, i) + checkFlags(tc.allowDeleteBodyV, tc.allowMergeV, tc.allowRepeatedFieldsInBodyV, tc.includePackageInTagsV, tc.useFQNForOpenAPINameV, tc.openAPINamingStrategyV, tc.fileV, tc.importPathV, tc.mergeFileNameV, tt, i) clearFlags() }) } - } -func checkFlags(allowDeleteV, allowMergeV, allowRepeatedFieldsInBodyV, includePackageInTagsV bool, useFQNForOpenAPINameV bool, fileV, importPathV, mergeFileNameV string, t *testing.T, tid int) { +func checkFlags( + allowDeleteV, + allowMergeV, + allowRepeatedFieldsInBodyV, + includePackageInTagsV bool, + useFQNForOpenAPINameV bool, + openAPINamingStrategyV, + fileV, + importPathV, + mergeFileNameV string, + t *testing.T, + tid int, +) { if *importPrefix != importPathV { t.Errorf("Test %v: import_prefix misparsed, expected '%v', got '%v'", tid, importPathV, *importPrefix) } @@ -173,6 +261,9 @@ func checkFlags(allowDeleteV, allowMergeV, allowRepeatedFieldsInBodyV, includePa if *useFQNForOpenAPIName != useFQNForOpenAPINameV { t.Errorf("Test %v: fqn_for_openapi_name misparsed, expected '%v', got '%v'", tid, useFQNForOpenAPINameV, *useFQNForOpenAPIName) } + if *openAPINamingStrategy != openAPINamingStrategyV { + t.Errorf("Test %v: openapi_naming_strategy misparsed, expected '%v', got '%v'", tid, openAPINamingStrategyV, *openAPINamingStrategy) + } } func clearFlags() { @@ -183,4 +274,6 @@ func clearFlags() { *allowRepeatedFieldsInBody = false *includePackageInTags = false *mergeFileName = "apidocs" + *useFQNForOpenAPIName = false + *openAPINamingStrategy = "" } diff --git a/gateway/protoc-gen-openapiv2/options/BUILD.bazel b/gateway/protoc-gen-openapiv2/options/BUILD.bazel index 21e9273..ecbca2b 100644 --- a/gateway/protoc-gen-openapiv2/options/BUILD.bazel +++ b/gateway/protoc-gen-openapiv2/options/BUILD.bazel @@ -13,7 +13,7 @@ filegroup( ) go_library( - name = "go_default_library", + name = "options", embed = [":options_go_proto"], importpath = "github.com/binchencoder/ease-gateway/gateway/protoc-gen-openapiv2/options", ) @@ -36,3 +36,9 @@ go_proto_library( importpath = "github.com/binchencoder/ease-gateway/gateway/protoc-gen-openapiv2/options", proto = ":options_proto", ) + +alias( + name = "go_default_library", + actual = ":options", + visibility = ["//visibility:public"], +) diff --git a/gateway/protoc-gen-openapiv2/options/annotations.pb.go b/gateway/protoc-gen-openapiv2/options/annotations.pb.go old mode 100644 new mode 100755 index b8af0e1..7a0c232 --- a/gateway/protoc-gen-openapiv2/options/annotations.pb.go +++ b/gateway/protoc-gen-openapiv2/options/annotations.pb.go @@ -1,16 +1,15 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.23.0 -// protoc v3.12.3 +// protoc-gen-go v1.27.1 +// protoc v3.19.4 // source: gateway/protoc-gen-openapiv2/options/annotations.proto package options import ( - proto "github.com/golang/protobuf/proto" - descriptor "github.com/golang/protobuf/protoc-gen-go/descriptor" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + descriptorpb "google.golang.org/protobuf/types/descriptorpb" reflect "reflect" ) @@ -21,13 +20,9 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - var file_gateway_protoc_gen_openapiv2_options_annotations_proto_extTypes = []protoimpl.ExtensionInfo{ { - ExtendedType: (*descriptor.FileOptions)(nil), + ExtendedType: (*descriptorpb.FileOptions)(nil), ExtensionType: (*Swagger)(nil), Field: 1042, Name: "grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger", @@ -35,7 +30,7 @@ var file_gateway_protoc_gen_openapiv2_options_annotations_proto_extTypes = []pro Filename: "gateway/protoc-gen-openapiv2/options/annotations.proto", }, { - ExtendedType: (*descriptor.MethodOptions)(nil), + ExtendedType: (*descriptorpb.MethodOptions)(nil), ExtensionType: (*Operation)(nil), Field: 1042, Name: "grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation", @@ -43,7 +38,7 @@ var file_gateway_protoc_gen_openapiv2_options_annotations_proto_extTypes = []pro Filename: "gateway/protoc-gen-openapiv2/options/annotations.proto", }, { - ExtendedType: (*descriptor.MessageOptions)(nil), + ExtendedType: (*descriptorpb.MessageOptions)(nil), ExtensionType: (*Schema)(nil), Field: 1042, Name: "grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema", @@ -51,7 +46,7 @@ var file_gateway_protoc_gen_openapiv2_options_annotations_proto_extTypes = []pro Filename: "gateway/protoc-gen-openapiv2/options/annotations.proto", }, { - ExtendedType: (*descriptor.ServiceOptions)(nil), + ExtendedType: (*descriptorpb.ServiceOptions)(nil), ExtensionType: (*Tag)(nil), Field: 1042, Name: "grpc.gateway.protoc_gen_openapiv2.options.openapiv2_tag", @@ -59,7 +54,7 @@ var file_gateway_protoc_gen_openapiv2_options_annotations_proto_extTypes = []pro Filename: "gateway/protoc-gen-openapiv2/options/annotations.proto", }, { - ExtendedType: (*descriptor.FieldOptions)(nil), + ExtendedType: (*descriptorpb.FieldOptions)(nil), ExtensionType: (*JSONSchema)(nil), Field: 1042, Name: "grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field", @@ -68,57 +63,32 @@ var file_gateway_protoc_gen_openapiv2_options_annotations_proto_extTypes = []pro }, } -// Extension fields to descriptor.FileOptions. +// Extension fields to descriptorpb.FileOptions. var ( - // ID assigned by protobuf-global-extension-registry@google.com for grpc-gateway project. - // - // All IDs are the same, as assigned. It is okay that they are the same, as they extend - // different descriptor messages. - // // optional grpc.gateway.protoc_gen_openapiv2.options.Swagger openapiv2_swagger = 1042; E_Openapiv2Swagger = &file_gateway_protoc_gen_openapiv2_options_annotations_proto_extTypes[0] ) -// Extension fields to descriptor.MethodOptions. +// Extension fields to descriptorpb.MethodOptions. var ( - // ID assigned by protobuf-global-extension-registry@google.com for grpc-gateway project. - // - // All IDs are the same, as assigned. It is okay that they are the same, as they extend - // different descriptor messages. - // // optional grpc.gateway.protoc_gen_openapiv2.options.Operation openapiv2_operation = 1042; E_Openapiv2Operation = &file_gateway_protoc_gen_openapiv2_options_annotations_proto_extTypes[1] ) -// Extension fields to descriptor.MessageOptions. +// Extension fields to descriptorpb.MessageOptions. var ( - // ID assigned by protobuf-global-extension-registry@google.com for grpc-gateway project. - // - // All IDs are the same, as assigned. It is okay that they are the same, as they extend - // different descriptor messages. - // // optional grpc.gateway.protoc_gen_openapiv2.options.Schema openapiv2_schema = 1042; E_Openapiv2Schema = &file_gateway_protoc_gen_openapiv2_options_annotations_proto_extTypes[2] ) -// Extension fields to descriptor.ServiceOptions. +// Extension fields to descriptorpb.ServiceOptions. var ( - // ID assigned by protobuf-global-extension-registry@google.com for grpc-gateway project. - // - // All IDs are the same, as assigned. It is okay that they are the same, as they extend - // different descriptor messages. - // // optional grpc.gateway.protoc_gen_openapiv2.options.Tag openapiv2_tag = 1042; E_Openapiv2Tag = &file_gateway_protoc_gen_openapiv2_options_annotations_proto_extTypes[3] ) -// Extension fields to descriptor.FieldOptions. +// Extension fields to descriptorpb.FieldOptions. var ( - // ID assigned by protobuf-global-extension-registry@google.com for grpc-gateway project. - // - // All IDs are the same, as assigned. It is okay that they are the same, as they extend - // different descriptor messages. - // // optional grpc.gateway.protoc_gen_openapiv2.options.JSONSchema openapiv2_field = 1042; E_Openapiv2Field = &file_gateway_protoc_gen_openapiv2_options_annotations_proto_extTypes[4] ) @@ -186,16 +156,16 @@ var file_gateway_protoc_gen_openapiv2_options_annotations_proto_rawDesc = []byte } var file_gateway_protoc_gen_openapiv2_options_annotations_proto_goTypes = []interface{}{ - (*descriptor.FileOptions)(nil), // 0: google.protobuf.FileOptions - (*descriptor.MethodOptions)(nil), // 1: google.protobuf.MethodOptions - (*descriptor.MessageOptions)(nil), // 2: google.protobuf.MessageOptions - (*descriptor.ServiceOptions)(nil), // 3: google.protobuf.ServiceOptions - (*descriptor.FieldOptions)(nil), // 4: google.protobuf.FieldOptions - (*Swagger)(nil), // 5: grpc.gateway.protoc_gen_openapiv2.options.Swagger - (*Operation)(nil), // 6: grpc.gateway.protoc_gen_openapiv2.options.Operation - (*Schema)(nil), // 7: grpc.gateway.protoc_gen_openapiv2.options.Schema - (*Tag)(nil), // 8: grpc.gateway.protoc_gen_openapiv2.options.Tag - (*JSONSchema)(nil), // 9: grpc.gateway.protoc_gen_openapiv2.options.JSONSchema + (*descriptorpb.FileOptions)(nil), // 0: google.protobuf.FileOptions + (*descriptorpb.MethodOptions)(nil), // 1: google.protobuf.MethodOptions + (*descriptorpb.MessageOptions)(nil), // 2: google.protobuf.MessageOptions + (*descriptorpb.ServiceOptions)(nil), // 3: google.protobuf.ServiceOptions + (*descriptorpb.FieldOptions)(nil), // 4: google.protobuf.FieldOptions + (*Swagger)(nil), // 5: grpc.gateway.protoc_gen_openapiv2.options.Swagger + (*Operation)(nil), // 6: grpc.gateway.protoc_gen_openapiv2.options.Operation + (*Schema)(nil), // 7: grpc.gateway.protoc_gen_openapiv2.options.Schema + (*Tag)(nil), // 8: grpc.gateway.protoc_gen_openapiv2.options.Tag + (*JSONSchema)(nil), // 9: grpc.gateway.protoc_gen_openapiv2.options.JSONSchema } var file_gateway_protoc_gen_openapiv2_options_annotations_proto_depIdxs = []int32{ 0, // 0: grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger:extendee -> google.protobuf.FileOptions diff --git a/gateway/protoc-gen-openapiv2/options/annotations.proto b/gateway/protoc-gen-openapiv2/options/annotations.proto index ad054db..63dc872 100644 --- a/gateway/protoc-gen-openapiv2/options/annotations.proto +++ b/gateway/protoc-gen-openapiv2/options/annotations.proto @@ -8,35 +8,35 @@ import "google/protobuf/descriptor.proto"; import "gateway/protoc-gen-openapiv2/options/openapiv2.proto"; extend google.protobuf.FileOptions { - // ID assigned by protobuf-global-extension-registry@google.com for grpc-gateway project. + // ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project. // // All IDs are the same, as assigned. It is okay that they are the same, as they extend // different descriptor messages. Swagger openapiv2_swagger = 1042; } extend google.protobuf.MethodOptions { - // ID assigned by protobuf-global-extension-registry@google.com for grpc-gateway project. + // ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project. // // All IDs are the same, as assigned. It is okay that they are the same, as they extend // different descriptor messages. Operation openapiv2_operation = 1042; } extend google.protobuf.MessageOptions { - // ID assigned by protobuf-global-extension-registry@google.com for grpc-gateway project. + // ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project. // // All IDs are the same, as assigned. It is okay that they are the same, as they extend // different descriptor messages. Schema openapiv2_schema = 1042; } extend google.protobuf.ServiceOptions { - // ID assigned by protobuf-global-extension-registry@google.com for grpc-gateway project. + // ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project. // // All IDs are the same, as assigned. It is okay that they are the same, as they extend // different descriptor messages. Tag openapiv2_tag = 1042; } extend google.protobuf.FieldOptions { - // ID assigned by protobuf-global-extension-registry@google.com for grpc-gateway project. + // ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project. // // All IDs are the same, as assigned. It is okay that they are the same, as they extend // different descriptor messages. diff --git a/gateway/protoc-gen-openapiv2/options/openapiv2.pb.go b/gateway/protoc-gen-openapiv2/options/openapiv2.pb.go old mode 100644 new mode 100755 index b8e1322..fceae2e --- a/gateway/protoc-gen-openapiv2/options/openapiv2.pb.go +++ b/gateway/protoc-gen-openapiv2/options/openapiv2.pb.go @@ -1,16 +1,15 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.23.0 -// protoc v3.12.3 +// protoc-gen-go v1.27.1 +// protoc v3.19.4 // source: gateway/protoc-gen-openapiv2/options/openapiv2.proto package options import ( - proto "github.com/golang/protobuf/proto" - _struct "github.com/golang/protobuf/ptypes/struct" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + structpb "google.golang.org/protobuf/types/known/structpb" reflect "reflect" sync "sync" ) @@ -22,12 +21,6 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - -// Scheme describes the schemes supported by the OpenAPI Swagger -// and Operation objects. type Scheme int32 const ( @@ -144,11 +137,9 @@ func (x JSONSchema_JSONSchemaSimpleTypes) Number() protoreflect.EnumNumber { // Deprecated: Use JSONSchema_JSONSchemaSimpleTypes.Descriptor instead. func (JSONSchema_JSONSchemaSimpleTypes) EnumDescriptor() ([]byte, []int) { - return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{8, 0} + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{9, 0} } -// The type of the security scheme. Valid values are "basic", -// "apiKey" or "oauth2". type SecurityScheme_Type int32 const ( @@ -198,10 +189,9 @@ func (x SecurityScheme_Type) Number() protoreflect.EnumNumber { // Deprecated: Use SecurityScheme_Type.Descriptor instead. func (SecurityScheme_Type) EnumDescriptor() ([]byte, []int) { - return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{11, 0} + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{12, 0} } -// The location of the API key. Valid values are "query" or "header". type SecurityScheme_In int32 const ( @@ -248,11 +238,9 @@ func (x SecurityScheme_In) Number() protoreflect.EnumNumber { // Deprecated: Use SecurityScheme_In.Descriptor instead. func (SecurityScheme_In) EnumDescriptor() ([]byte, []int) { - return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{11, 1} + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{12, 1} } -// The flow used by the OAuth2 security scheme. Valid values are -// "implicit", "password", "application" or "accessCode". type SecurityScheme_Flow int32 const ( @@ -305,87 +293,26 @@ func (x SecurityScheme_Flow) Number() protoreflect.EnumNumber { // Deprecated: Use SecurityScheme_Flow.Descriptor instead. func (SecurityScheme_Flow) EnumDescriptor() ([]byte, []int) { - return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{11, 2} -} - -// `Swagger` is a representation of OpenAPI v2 specification's Swagger object. -// -// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#swaggerObject -// -// Example: -// -// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { -// info: { -// title: "Echo API"; -// version: "1.0"; -// description: "; -// contact: { -// name: "gRPC-Gateway project"; -// url: "https://github.com/grpc-ecosystem/grpc-gateway"; -// email: "none@example.com"; -// }; -// license: { -// name: "BSD 3-Clause License"; -// url: "https://github.com/grpc-ecosystem/grpc-gateway/blob/master/LICENSE.txt"; -// }; -// }; -// schemes: HTTPS; -// consumes: "application/json"; -// produces: "application/json"; -// }; -// + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{12, 2} +} + type Swagger struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // Specifies the OpenAPI Specification version being used. It can be - // used by the OpenAPI UI and other clients to interpret the API listing. The - // value MUST be "2.0". - Swagger string `protobuf:"bytes,1,opt,name=swagger,proto3" json:"swagger,omitempty"` - // Provides metadata about the API. The metadata can be used by the - // clients if needed. - Info *Info `protobuf:"bytes,2,opt,name=info,proto3" json:"info,omitempty"` - // The host (name or ip) serving the API. This MUST be the host only and does - // not include the scheme nor sub-paths. It MAY include a port. If the host is - // not included, the host serving the documentation is to be used (including - // the port). The host does not support path templating. - Host string `protobuf:"bytes,3,opt,name=host,proto3" json:"host,omitempty"` - // The base path on which the API is served, which is relative to the host. If - // it is not included, the API is served directly under the host. The value - // MUST start with a leading slash (/). The basePath does not support path - // templating. - // Note that using `base_path` does not change the endpoint paths that are - // generated in the resulting OpenAPI file. If you wish to use `base_path` - // with relatively generated OpenAPI paths, the `base_path` prefix must be - // manually removed from your `google.api.http` paths and your code changed to - // serve the API from the `base_path`. - BasePath string `protobuf:"bytes,4,opt,name=base_path,json=basePath,proto3" json:"base_path,omitempty"` - // The transfer protocol of the API. Values MUST be from the list: "http", - // "https", "ws", "wss". If the schemes is not included, the default scheme to - // be used is the one used to access the OpenAPI definition itself. - Schemes []Scheme `protobuf:"varint,5,rep,packed,name=schemes,proto3,enum=grpc.gateway.protoc_gen_openapiv2.options.Scheme" json:"schemes,omitempty"` - // A list of MIME types the APIs can consume. This is global to all APIs but - // can be overridden on specific API calls. Value MUST be as described under - // Mime Types. - Consumes []string `protobuf:"bytes,6,rep,name=consumes,proto3" json:"consumes,omitempty"` - // A list of MIME types the APIs can produce. This is global to all APIs but - // can be overridden on specific API calls. Value MUST be as described under - // Mime Types. - Produces []string `protobuf:"bytes,7,rep,name=produces,proto3" json:"produces,omitempty"` - // An object to hold responses that can be used across operations. This - // property does not define global responses for all operations. - Responses map[string]*Response `protobuf:"bytes,10,rep,name=responses,proto3" json:"responses,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - // Security scheme definitions that can be used across the specification. - SecurityDefinitions *SecurityDefinitions `protobuf:"bytes,11,opt,name=security_definitions,json=securityDefinitions,proto3" json:"security_definitions,omitempty"` - // A declaration of which security schemes are applied for the API as a whole. - // The list of values describes alternative security schemes that can be used - // (that is, there is a logical OR between the security requirements). - // Individual operations can override this definition. - Security []*SecurityRequirement `protobuf:"bytes,12,rep,name=security,proto3" json:"security,omitempty"` - // Additional external documentation. - ExternalDocs *ExternalDocumentation `protobuf:"bytes,14,opt,name=external_docs,json=externalDocs,proto3" json:"external_docs,omitempty"` - Extensions map[string]*_struct.Value `protobuf:"bytes,15,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Swagger string `protobuf:"bytes,1,opt,name=swagger,proto3" json:"swagger,omitempty"` + Info *Info `protobuf:"bytes,2,opt,name=info,proto3" json:"info,omitempty"` + Host string `protobuf:"bytes,3,opt,name=host,proto3" json:"host,omitempty"` + BasePath string `protobuf:"bytes,4,opt,name=base_path,json=basePath,proto3" json:"base_path,omitempty"` + Schemes []Scheme `protobuf:"varint,5,rep,packed,name=schemes,proto3,enum=grpc.gateway.protoc_gen_openapiv2.options.Scheme" json:"schemes,omitempty"` + Consumes []string `protobuf:"bytes,6,rep,name=consumes,proto3" json:"consumes,omitempty"` + Produces []string `protobuf:"bytes,7,rep,name=produces,proto3" json:"produces,omitempty"` + Responses map[string]*Response `protobuf:"bytes,10,rep,name=responses,proto3" json:"responses,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + SecurityDefinitions *SecurityDefinitions `protobuf:"bytes,11,opt,name=security_definitions,json=securityDefinitions,proto3" json:"security_definitions,omitempty"` + Security []*SecurityRequirement `protobuf:"bytes,12,rep,name=security,proto3" json:"security,omitempty"` + ExternalDocs *ExternalDocumentation `protobuf:"bytes,14,opt,name=external_docs,json=externalDocs,proto3" json:"external_docs,omitempty"` + Extensions map[string]*structpb.Value `protobuf:"bytes,15,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } func (x *Swagger) Reset() { @@ -497,84 +424,30 @@ func (x *Swagger) GetExternalDocs() *ExternalDocumentation { return nil } -func (x *Swagger) GetExtensions() map[string]*_struct.Value { +func (x *Swagger) GetExtensions() map[string]*structpb.Value { if x != nil { return x.Extensions } return nil } -// `Operation` is a representation of OpenAPI v2 specification's Operation object. -// -// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#operationObject -// -// Example: -// -// service EchoService { -// rpc Echo(SimpleMessage) returns (SimpleMessage) { -// option (google.api.http) = { -// get: "/v1/example/echo/{id}" -// }; -// -// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { -// summary: "Get a message."; -// operation_id: "getMessage"; -// tags: "echo"; -// responses: { -// key: "200" -// value: { -// description: "OK"; -// } -// } -// }; -// } -// } type Operation struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // A list of tags for API documentation control. Tags can be used for logical - // grouping of operations by resources or any other qualifier. - Tags []string `protobuf:"bytes,1,rep,name=tags,proto3" json:"tags,omitempty"` - // A short summary of what the operation does. For maximum readability in the - // swagger-ui, this field SHOULD be less than 120 characters. - Summary string `protobuf:"bytes,2,opt,name=summary,proto3" json:"summary,omitempty"` - // A verbose explanation of the operation behavior. GFM syntax can be used for - // rich text representation. - Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"` - // Additional external documentation for this operation. - ExternalDocs *ExternalDocumentation `protobuf:"bytes,4,opt,name=external_docs,json=externalDocs,proto3" json:"external_docs,omitempty"` - // Unique string used to identify the operation. The id MUST be unique among - // all operations described in the API. Tools and libraries MAY use the - // operationId to uniquely identify an operation, therefore, it is recommended - // to follow common programming naming conventions. - OperationId string `protobuf:"bytes,5,opt,name=operation_id,json=operationId,proto3" json:"operation_id,omitempty"` - // A list of MIME types the operation can consume. This overrides the consumes - // definition at the OpenAPI Object. An empty value MAY be used to clear the - // global definition. Value MUST be as described under Mime Types. - Consumes []string `protobuf:"bytes,6,rep,name=consumes,proto3" json:"consumes,omitempty"` - // A list of MIME types the operation can produce. This overrides the produces - // definition at the OpenAPI Object. An empty value MAY be used to clear the - // global definition. Value MUST be as described under Mime Types. - Produces []string `protobuf:"bytes,7,rep,name=produces,proto3" json:"produces,omitempty"` - // The list of possible responses as they are returned from executing this - // operation. - Responses map[string]*Response `protobuf:"bytes,9,rep,name=responses,proto3" json:"responses,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - // The transfer protocol for the operation. Values MUST be from the list: - // "http", "https", "ws", "wss". The value overrides the OpenAPI Object - // schemes definition. - Schemes []Scheme `protobuf:"varint,10,rep,packed,name=schemes,proto3,enum=grpc.gateway.protoc_gen_openapiv2.options.Scheme" json:"schemes,omitempty"` - // Declares this operation to be deprecated. Usage of the declared operation - // should be refrained. Default value is false. - Deprecated bool `protobuf:"varint,11,opt,name=deprecated,proto3" json:"deprecated,omitempty"` - // A declaration of which security schemes are applied for this operation. The - // list of values describes alternative security schemes that can be used - // (that is, there is a logical OR between the security requirements). This - // definition overrides any declared top-level security. To remove a top-level - // security declaration, an empty array can be used. - Security []*SecurityRequirement `protobuf:"bytes,12,rep,name=security,proto3" json:"security,omitempty"` - Extensions map[string]*_struct.Value `protobuf:"bytes,13,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Tags []string `protobuf:"bytes,1,rep,name=tags,proto3" json:"tags,omitempty"` + Summary string `protobuf:"bytes,2,opt,name=summary,proto3" json:"summary,omitempty"` + Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"` + ExternalDocs *ExternalDocumentation `protobuf:"bytes,4,opt,name=external_docs,json=externalDocs,proto3" json:"external_docs,omitempty"` + OperationId string `protobuf:"bytes,5,opt,name=operation_id,json=operationId,proto3" json:"operation_id,omitempty"` + Consumes []string `protobuf:"bytes,6,rep,name=consumes,proto3" json:"consumes,omitempty"` + Produces []string `protobuf:"bytes,7,rep,name=produces,proto3" json:"produces,omitempty"` + Responses map[string]*Response `protobuf:"bytes,9,rep,name=responses,proto3" json:"responses,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Schemes []Scheme `protobuf:"varint,10,rep,packed,name=schemes,proto3,enum=grpc.gateway.protoc_gen_openapiv2.options.Scheme" json:"schemes,omitempty"` + Deprecated bool `protobuf:"varint,11,opt,name=deprecated,proto3" json:"deprecated,omitempty"` + Security []*SecurityRequirement `protobuf:"bytes,12,rep,name=security,proto3" json:"security,omitempty"` + Extensions map[string]*structpb.Value `protobuf:"bytes,13,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } func (x *Operation) Reset() { @@ -686,38 +559,108 @@ func (x *Operation) GetSecurity() []*SecurityRequirement { return nil } -func (x *Operation) GetExtensions() map[string]*_struct.Value { +func (x *Operation) GetExtensions() map[string]*structpb.Value { if x != nil { return x.Extensions } return nil } -// `Response` is a representation of OpenAPI v2 specification's Response object. -// -// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#responseObject -// -type Response struct { +type Header struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // `Description` is a short description of the response. - // GFM syntax can be used for rich text representation. Description string `protobuf:"bytes,1,opt,name=description,proto3" json:"description,omitempty"` - // `Schema` optionally defines the structure of the response. - // If `Schema` is not provided, it means there is no content to the response. - Schema *Schema `protobuf:"bytes,2,opt,name=schema,proto3" json:"schema,omitempty"` - // `Examples` gives per-mimetype response examples. - // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#example-object - Examples map[string]string `protobuf:"bytes,4,rep,name=examples,proto3" json:"examples,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - Extensions map[string]*_struct.Value `protobuf:"bytes,5,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"` + Format string `protobuf:"bytes,3,opt,name=format,proto3" json:"format,omitempty"` + Default string `protobuf:"bytes,6,opt,name=default,proto3" json:"default,omitempty"` + Pattern string `protobuf:"bytes,13,opt,name=pattern,proto3" json:"pattern,omitempty"` +} + +func (x *Header) Reset() { + *x = Header{} + if protoimpl.UnsafeEnabled { + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Header) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Header) ProtoMessage() {} + +func (x *Header) ProtoReflect() protoreflect.Message { + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Header.ProtoReflect.Descriptor instead. +func (*Header) Descriptor() ([]byte, []int) { + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{2} +} + +func (x *Header) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *Header) GetType() string { + if x != nil { + return x.Type + } + return "" +} + +func (x *Header) GetFormat() string { + if x != nil { + return x.Format + } + return "" +} + +func (x *Header) GetDefault() string { + if x != nil { + return x.Default + } + return "" +} + +func (x *Header) GetPattern() string { + if x != nil { + return x.Pattern + } + return "" +} + +type Response struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Description string `protobuf:"bytes,1,opt,name=description,proto3" json:"description,omitempty"` + Schema *Schema `protobuf:"bytes,2,opt,name=schema,proto3" json:"schema,omitempty"` + Headers map[string]*Header `protobuf:"bytes,3,rep,name=headers,proto3" json:"headers,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Examples map[string]string `protobuf:"bytes,4,rep,name=examples,proto3" json:"examples,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Extensions map[string]*structpb.Value `protobuf:"bytes,5,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } func (x *Response) Reset() { *x = Response{} if protoimpl.UnsafeEnabled { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[2] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -730,7 +673,7 @@ func (x *Response) String() string { func (*Response) ProtoMessage() {} func (x *Response) ProtoReflect() protoreflect.Message { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[2] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[3] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -743,7 +686,7 @@ func (x *Response) ProtoReflect() protoreflect.Message { // Deprecated: Use Response.ProtoReflect.Descriptor instead. func (*Response) Descriptor() ([]byte, []int) { - return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{2} + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{3} } func (x *Response) GetDescription() string { @@ -760,6 +703,13 @@ func (x *Response) GetSchema() *Schema { return nil } +func (x *Response) GetHeaders() map[string]*Header { + if x != nil { + return x.Headers + } + return nil +} + func (x *Response) GetExamples() map[string]string { if x != nil { return x.Examples @@ -767,63 +717,31 @@ func (x *Response) GetExamples() map[string]string { return nil } -func (x *Response) GetExtensions() map[string]*_struct.Value { +func (x *Response) GetExtensions() map[string]*structpb.Value { if x != nil { return x.Extensions } return nil } -// `Info` is a representation of OpenAPI v2 specification's Info object. -// -// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#infoObject -// -// Example: -// -// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { -// info: { -// title: "Echo API"; -// version: "1.0"; -// description: "; -// contact: { -// name: "gRPC-Gateway project"; -// url: "https://github.com/grpc-ecosystem/grpc-gateway"; -// email: "none@example.com"; -// }; -// license: { -// name: "BSD 3-Clause License"; -// url: "https://github.com/grpc-ecosystem/grpc-gateway/blob/master/LICENSE.txt"; -// }; -// }; -// ... -// }; -// type Info struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // The title of the application. - Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` - // A short description of the application. GFM syntax can be used for rich - // text representation. - Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` - // The Terms of Service for the API. - TermsOfService string `protobuf:"bytes,3,opt,name=terms_of_service,json=termsOfService,proto3" json:"terms_of_service,omitempty"` - // The contact information for the exposed API. - Contact *Contact `protobuf:"bytes,4,opt,name=contact,proto3" json:"contact,omitempty"` - // The license information for the exposed API. - License *License `protobuf:"bytes,5,opt,name=license,proto3" json:"license,omitempty"` - // Provides the version of the application API (not to be confused - // with the specification version). - Version string `protobuf:"bytes,6,opt,name=version,proto3" json:"version,omitempty"` - Extensions map[string]*_struct.Value `protobuf:"bytes,7,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` + TermsOfService string `protobuf:"bytes,3,opt,name=terms_of_service,json=termsOfService,proto3" json:"terms_of_service,omitempty"` + Contact *Contact `protobuf:"bytes,4,opt,name=contact,proto3" json:"contact,omitempty"` + License *License `protobuf:"bytes,5,opt,name=license,proto3" json:"license,omitempty"` + Version string `protobuf:"bytes,6,opt,name=version,proto3" json:"version,omitempty"` + Extensions map[string]*structpb.Value `protobuf:"bytes,7,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } func (x *Info) Reset() { *x = Info{} if protoimpl.UnsafeEnabled { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[3] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -836,7 +754,7 @@ func (x *Info) String() string { func (*Info) ProtoMessage() {} func (x *Info) ProtoReflect() protoreflect.Message { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[3] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -849,7 +767,7 @@ func (x *Info) ProtoReflect() protoreflect.Message { // Deprecated: Use Info.ProtoReflect.Descriptor instead. func (*Info) Descriptor() ([]byte, []int) { - return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{3} + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{4} } func (x *Info) GetTitle() string { @@ -894,51 +812,27 @@ func (x *Info) GetVersion() string { return "" } -func (x *Info) GetExtensions() map[string]*_struct.Value { +func (x *Info) GetExtensions() map[string]*structpb.Value { if x != nil { return x.Extensions } return nil } -// `Contact` is a representation of OpenAPI v2 specification's Contact object. -// -// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#contactObject -// -// Example: -// -// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { -// info: { -// ... -// contact: { -// name: "gRPC-Gateway project"; -// url: "https://github.com/grpc-ecosystem/grpc-gateway"; -// email: "none@example.com"; -// }; -// ... -// }; -// ... -// }; -// type Contact struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // The identifying name of the contact person/organization. - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - // The URL pointing to the contact information. MUST be in the format of a - // URL. - Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"` - // The email address of the contact person/organization. MUST be in the format - // of an email address. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"` Email string `protobuf:"bytes,3,opt,name=email,proto3" json:"email,omitempty"` } func (x *Contact) Reset() { *x = Contact{} if protoimpl.UnsafeEnabled { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[4] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -951,7 +845,7 @@ func (x *Contact) String() string { func (*Contact) ProtoMessage() {} func (x *Contact) ProtoReflect() protoreflect.Message { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[4] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -964,7 +858,7 @@ func (x *Contact) ProtoReflect() protoreflect.Message { // Deprecated: Use Contact.ProtoReflect.Descriptor instead. func (*Contact) Descriptor() ([]byte, []int) { - return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{4} + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{5} } func (x *Contact) GetName() string { @@ -988,39 +882,19 @@ func (x *Contact) GetEmail() string { return "" } -// `License` is a representation of OpenAPI v2 specification's License object. -// -// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#licenseObject -// -// Example: -// -// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { -// info: { -// ... -// license: { -// name: "BSD 3-Clause License"; -// url: "https://github.com/grpc-ecosystem/grpc-gateway/blob/master/LICENSE.txt"; -// }; -// ... -// }; -// ... -// }; -// type License struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // The license name used for the API. Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - // A URL to the license used for the API. MUST be in the format of a URL. - Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"` + Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"` } func (x *License) Reset() { *x = License{} if protoimpl.UnsafeEnabled { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[5] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1033,7 +907,7 @@ func (x *License) String() string { func (*License) ProtoMessage() {} func (x *License) ProtoReflect() protoreflect.Message { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[5] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1046,7 +920,7 @@ func (x *License) ProtoReflect() protoreflect.Message { // Deprecated: Use License.ProtoReflect.Descriptor instead. func (*License) Descriptor() ([]byte, []int) { - return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{5} + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{6} } func (x *License) GetName() string { @@ -1063,39 +937,19 @@ func (x *License) GetUrl() string { return "" } -// `ExternalDocumentation` is a representation of OpenAPI v2 specification's -// ExternalDocumentation object. -// -// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#externalDocumentationObject -// -// Example: -// -// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { -// ... -// external_docs: { -// description: "More about gRPC-Gateway"; -// url: "https://github.com/grpc-ecosystem/grpc-gateway"; -// } -// ... -// }; -// type ExternalDocumentation struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // A short description of the target documentation. GFM syntax can be used for - // rich text representation. Description string `protobuf:"bytes,1,opt,name=description,proto3" json:"description,omitempty"` - // The URL for the target documentation. Value MUST be in the format - // of a URL. - Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"` + Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"` } func (x *ExternalDocumentation) Reset() { *x = ExternalDocumentation{} if protoimpl.UnsafeEnabled { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[6] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1108,7 +962,7 @@ func (x *ExternalDocumentation) String() string { func (*ExternalDocumentation) ProtoMessage() {} func (x *ExternalDocumentation) ProtoReflect() protoreflect.Message { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[6] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1121,7 +975,7 @@ func (x *ExternalDocumentation) ProtoReflect() protoreflect.Message { // Deprecated: Use ExternalDocumentation.ProtoReflect.Descriptor instead. func (*ExternalDocumentation) Descriptor() ([]byte, []int) { - return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{6} + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{7} } func (x *ExternalDocumentation) GetDescription() string { @@ -1138,39 +992,22 @@ func (x *ExternalDocumentation) GetUrl() string { return "" } -// `Schema` is a representation of OpenAPI v2 specification's Schema object. -// -// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#schemaObject -// type Schema struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - JsonSchema *JSONSchema `protobuf:"bytes,1,opt,name=json_schema,json=jsonSchema,proto3" json:"json_schema,omitempty"` - // Adds support for polymorphism. The discriminator is the schema property - // name that is used to differentiate between other schema that inherit this - // schema. The property name used MUST be defined at this schema and it MUST - // be in the required property list. When used, the value MUST be the name of - // this schema or any schema that inherits it. - Discriminator string `protobuf:"bytes,2,opt,name=discriminator,proto3" json:"discriminator,omitempty"` - // Relevant only for Schema "properties" definitions. Declares the property as - // "read only". This means that it MAY be sent as part of a response but MUST - // NOT be sent as part of the request. Properties marked as readOnly being - // true SHOULD NOT be in the required list of the defined schema. Default - // value is false. - ReadOnly bool `protobuf:"varint,3,opt,name=read_only,json=readOnly,proto3" json:"read_only,omitempty"` - // Additional external documentation for this schema. - ExternalDocs *ExternalDocumentation `protobuf:"bytes,5,opt,name=external_docs,json=externalDocs,proto3" json:"external_docs,omitempty"` - // A free-form property to include an example of an instance for this schema in JSON. - // This is copied verbatim to the output. - Example string `protobuf:"bytes,6,opt,name=example,proto3" json:"example,omitempty"` + JsonSchema *JSONSchema `protobuf:"bytes,1,opt,name=json_schema,json=jsonSchema,proto3" json:"json_schema,omitempty"` + Discriminator string `protobuf:"bytes,2,opt,name=discriminator,proto3" json:"discriminator,omitempty"` + ReadOnly bool `protobuf:"varint,3,opt,name=read_only,json=readOnly,proto3" json:"read_only,omitempty"` + ExternalDocs *ExternalDocumentation `protobuf:"bytes,5,opt,name=external_docs,json=externalDocs,proto3" json:"external_docs,omitempty"` + Example string `protobuf:"bytes,6,opt,name=example,proto3" json:"example,omitempty"` } func (x *Schema) Reset() { *x = Schema{} if protoimpl.UnsafeEnabled { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[7] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1183,7 +1020,7 @@ func (x *Schema) String() string { func (*Schema) ProtoMessage() {} func (x *Schema) ProtoReflect() protoreflect.Message { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[7] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1196,7 +1033,7 @@ func (x *Schema) ProtoReflect() protoreflect.Message { // Deprecated: Use Schema.ProtoReflect.Descriptor instead. func (*Schema) Descriptor() ([]byte, []int) { - return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{7} + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{8} } func (x *Schema) GetJsonSchema() *JSONSchema { @@ -1234,79 +1071,41 @@ func (x *Schema) GetExample() string { return "" } -// `JSONSchema` represents properties from JSON Schema taken, and as used, in -// the OpenAPI v2 spec. -// -// This includes changes made by OpenAPI v2. -// -// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#schemaObject -// -// See also: https://cswr.github.io/JsonSchema/spec/basic_types/, -// https://github.com/json-schema-org/json-schema-spec/blob/master/schema.json -// -// Example: -// -// message SimpleMessage { -// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema) = { -// json_schema: { -// title: "SimpleMessage" -// description: "A simple message." -// required: ["id"] -// } -// }; -// -// // Id represents the message identifier. -// string id = 1; [ -// (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { -// {description: "The unique identifier of the simple message." -// }]; -// } -// type JSONSchema struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // Ref is used to define an external reference to include in the message. - // This could be a fully qualified proto message reference, and that type must - // be imported into the protofile. If no message is identified, the Ref will - // be used verbatim in the output. - // For example: - // `ref: ".google.protobuf.Timestamp"`. - Ref string `protobuf:"bytes,3,opt,name=ref,proto3" json:"ref,omitempty"` - // The title of the schema. - Title string `protobuf:"bytes,5,opt,name=title,proto3" json:"title,omitempty"` - // A short description of the schema. - Description string `protobuf:"bytes,6,opt,name=description,proto3" json:"description,omitempty"` - Default string `protobuf:"bytes,7,opt,name=default,proto3" json:"default,omitempty"` - ReadOnly bool `protobuf:"varint,8,opt,name=read_only,json=readOnly,proto3" json:"read_only,omitempty"` - MultipleOf float64 `protobuf:"fixed64,10,opt,name=multiple_of,json=multipleOf,proto3" json:"multiple_of,omitempty"` - // Maximum represents an inclusive upper limit for a numeric instance. The - // value of MUST be a number, - Maximum float64 `protobuf:"fixed64,11,opt,name=maximum,proto3" json:"maximum,omitempty"` - ExclusiveMaximum bool `protobuf:"varint,12,opt,name=exclusive_maximum,json=exclusiveMaximum,proto3" json:"exclusive_maximum,omitempty"` - // minimum represents an inclusive lower limit for a numeric instance. The - // value of MUST be a number, - Minimum float64 `protobuf:"fixed64,13,opt,name=minimum,proto3" json:"minimum,omitempty"` - ExclusiveMinimum bool `protobuf:"varint,14,opt,name=exclusive_minimum,json=exclusiveMinimum,proto3" json:"exclusive_minimum,omitempty"` - MaxLength uint64 `protobuf:"varint,15,opt,name=max_length,json=maxLength,proto3" json:"max_length,omitempty"` - MinLength uint64 `protobuf:"varint,16,opt,name=min_length,json=minLength,proto3" json:"min_length,omitempty"` - Pattern string `protobuf:"bytes,17,opt,name=pattern,proto3" json:"pattern,omitempty"` - MaxItems uint64 `protobuf:"varint,20,opt,name=max_items,json=maxItems,proto3" json:"max_items,omitempty"` - MinItems uint64 `protobuf:"varint,21,opt,name=min_items,json=minItems,proto3" json:"min_items,omitempty"` - UniqueItems bool `protobuf:"varint,22,opt,name=unique_items,json=uniqueItems,proto3" json:"unique_items,omitempty"` - MaxProperties uint64 `protobuf:"varint,24,opt,name=max_properties,json=maxProperties,proto3" json:"max_properties,omitempty"` - MinProperties uint64 `protobuf:"varint,25,opt,name=min_properties,json=minProperties,proto3" json:"min_properties,omitempty"` - Required []string `protobuf:"bytes,26,rep,name=required,proto3" json:"required,omitempty"` - // Items in 'array' must be unique. - Array []string `protobuf:"bytes,34,rep,name=array,proto3" json:"array,omitempty"` - Type []JSONSchema_JSONSchemaSimpleTypes `protobuf:"varint,35,rep,packed,name=type,proto3,enum=grpc.gateway.protoc_gen_openapiv2.options.JSONSchema_JSONSchemaSimpleTypes" json:"type,omitempty"` + Ref string `protobuf:"bytes,3,opt,name=ref,proto3" json:"ref,omitempty"` + Title string `protobuf:"bytes,5,opt,name=title,proto3" json:"title,omitempty"` + Description string `protobuf:"bytes,6,opt,name=description,proto3" json:"description,omitempty"` + Default string `protobuf:"bytes,7,opt,name=default,proto3" json:"default,omitempty"` + ReadOnly bool `protobuf:"varint,8,opt,name=read_only,json=readOnly,proto3" json:"read_only,omitempty"` + Example string `protobuf:"bytes,9,opt,name=example,proto3" json:"example,omitempty"` + MultipleOf float64 `protobuf:"fixed64,10,opt,name=multiple_of,json=multipleOf,proto3" json:"multiple_of,omitempty"` + Maximum float64 `protobuf:"fixed64,11,opt,name=maximum,proto3" json:"maximum,omitempty"` + ExclusiveMaximum bool `protobuf:"varint,12,opt,name=exclusive_maximum,json=exclusiveMaximum,proto3" json:"exclusive_maximum,omitempty"` + Minimum float64 `protobuf:"fixed64,13,opt,name=minimum,proto3" json:"minimum,omitempty"` + ExclusiveMinimum bool `protobuf:"varint,14,opt,name=exclusive_minimum,json=exclusiveMinimum,proto3" json:"exclusive_minimum,omitempty"` + MaxLength uint64 `protobuf:"varint,15,opt,name=max_length,json=maxLength,proto3" json:"max_length,omitempty"` + MinLength uint64 `protobuf:"varint,16,opt,name=min_length,json=minLength,proto3" json:"min_length,omitempty"` + Pattern string `protobuf:"bytes,17,opt,name=pattern,proto3" json:"pattern,omitempty"` + MaxItems uint64 `protobuf:"varint,20,opt,name=max_items,json=maxItems,proto3" json:"max_items,omitempty"` + MinItems uint64 `protobuf:"varint,21,opt,name=min_items,json=minItems,proto3" json:"min_items,omitempty"` + UniqueItems bool `protobuf:"varint,22,opt,name=unique_items,json=uniqueItems,proto3" json:"unique_items,omitempty"` + MaxProperties uint64 `protobuf:"varint,24,opt,name=max_properties,json=maxProperties,proto3" json:"max_properties,omitempty"` + MinProperties uint64 `protobuf:"varint,25,opt,name=min_properties,json=minProperties,proto3" json:"min_properties,omitempty"` + Required []string `protobuf:"bytes,26,rep,name=required,proto3" json:"required,omitempty"` + Array []string `protobuf:"bytes,34,rep,name=array,proto3" json:"array,omitempty"` + Type []JSONSchema_JSONSchemaSimpleTypes `protobuf:"varint,35,rep,packed,name=type,proto3,enum=grpc.gateway.protoc_gen_openapiv2.options.JSONSchema_JSONSchemaSimpleTypes" json:"type,omitempty"` + Format string `protobuf:"bytes,36,opt,name=format,proto3" json:"format,omitempty"` + Enum []string `protobuf:"bytes,46,rep,name=enum,proto3" json:"enum,omitempty"` } func (x *JSONSchema) Reset() { *x = JSONSchema{} if protoimpl.UnsafeEnabled { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[8] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1319,7 +1118,7 @@ func (x *JSONSchema) String() string { func (*JSONSchema) ProtoMessage() {} func (x *JSONSchema) ProtoReflect() protoreflect.Message { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[8] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1332,7 +1131,7 @@ func (x *JSONSchema) ProtoReflect() protoreflect.Message { // Deprecated: Use JSONSchema.ProtoReflect.Descriptor instead. func (*JSONSchema) Descriptor() ([]byte, []int) { - return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{8} + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{9} } func (x *JSONSchema) GetRef() string { @@ -1370,6 +1169,13 @@ func (x *JSONSchema) GetReadOnly() bool { return false } +func (x *JSONSchema) GetExample() string { + if x != nil { + return x.Example + } + return "" +} + func (x *JSONSchema) GetMultipleOf() float64 { if x != nil { return x.MultipleOf @@ -1482,26 +1288,33 @@ func (x *JSONSchema) GetType() []JSONSchema_JSONSchemaSimpleTypes { return nil } -// `Tag` is a representation of OpenAPI v2 specification's Tag object. -// -// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#tagObject -// +func (x *JSONSchema) GetFormat() string { + if x != nil { + return x.Format + } + return "" +} + +func (x *JSONSchema) GetEnum() []string { + if x != nil { + return x.Enum + } + return nil +} + type Tag struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // A short description for the tag. GFM syntax can be used for rich text - // representation. - Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` - // Additional external documentation for this tag. + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` ExternalDocs *ExternalDocumentation `protobuf:"bytes,3,opt,name=external_docs,json=externalDocs,proto3" json:"external_docs,omitempty"` } func (x *Tag) Reset() { *x = Tag{} if protoimpl.UnsafeEnabled { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[9] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1514,7 +1327,7 @@ func (x *Tag) String() string { func (*Tag) ProtoMessage() {} func (x *Tag) ProtoReflect() protoreflect.Message { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[9] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1527,7 +1340,7 @@ func (x *Tag) ProtoReflect() protoreflect.Message { // Deprecated: Use Tag.ProtoReflect.Descriptor instead. func (*Tag) Descriptor() ([]byte, []int) { - return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{9} + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{10} } func (x *Tag) GetDescription() string { @@ -1544,28 +1357,18 @@ func (x *Tag) GetExternalDocs() *ExternalDocumentation { return nil } -// `SecurityDefinitions` is a representation of OpenAPI v2 specification's -// Security Definitions object. -// -// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#securityDefinitionsObject -// -// A declaration of the security schemes available to be used in the -// specification. This does not enforce the security schemes on the operations -// and only serves to provide the relevant details for each scheme. type SecurityDefinitions struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // A single security scheme definition, mapping a "name" to the scheme it - // defines. Security map[string]*SecurityScheme `protobuf:"bytes,1,rep,name=security,proto3" json:"security,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } func (x *SecurityDefinitions) Reset() { *x = SecurityDefinitions{} if protoimpl.UnsafeEnabled { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[10] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1578,7 +1381,7 @@ func (x *SecurityDefinitions) String() string { func (*SecurityDefinitions) ProtoMessage() {} func (x *SecurityDefinitions) ProtoReflect() protoreflect.Message { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[10] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1591,7 +1394,7 @@ func (x *SecurityDefinitions) ProtoReflect() protoreflect.Message { // Deprecated: Use SecurityDefinitions.ProtoReflect.Descriptor instead. func (*SecurityDefinitions) Descriptor() ([]byte, []int) { - return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{10} + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{11} } func (x *SecurityDefinitions) GetSecurity() map[string]*SecurityScheme { @@ -1601,54 +1404,26 @@ func (x *SecurityDefinitions) GetSecurity() map[string]*SecurityScheme { return nil } -// `SecurityScheme` is a representation of OpenAPI v2 specification's -// Security Scheme object. -// -// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#securitySchemeObject -// -// Allows the definition of a security scheme that can be used by the -// operations. Supported schemes are basic authentication, an API key (either as -// a header or as a query parameter) and OAuth2's common flows (implicit, -// password, application and access code). type SecurityScheme struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // The type of the security scheme. Valid values are "basic", - // "apiKey" or "oauth2". - Type SecurityScheme_Type `protobuf:"varint,1,opt,name=type,proto3,enum=grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme_Type" json:"type,omitempty"` - // A short description for security scheme. - Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` - // The name of the header or query parameter to be used. - // Valid for apiKey. - Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` - // The location of the API key. Valid values are "query" or - // "header". - // Valid for apiKey. - In SecurityScheme_In `protobuf:"varint,4,opt,name=in,proto3,enum=grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme_In" json:"in,omitempty"` - // The flow used by the OAuth2 security scheme. Valid values are - // "implicit", "password", "application" or "accessCode". - // Valid for oauth2. - Flow SecurityScheme_Flow `protobuf:"varint,5,opt,name=flow,proto3,enum=grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme_Flow" json:"flow,omitempty"` - // The authorization URL to be used for this flow. This SHOULD be in - // the form of a URL. - // Valid for oauth2/implicit and oauth2/accessCode. - AuthorizationUrl string `protobuf:"bytes,6,opt,name=authorization_url,json=authorizationUrl,proto3" json:"authorization_url,omitempty"` - // The token URL to be used for this flow. This SHOULD be in the - // form of a URL. - // Valid for oauth2/password, oauth2/application and oauth2/accessCode. - TokenUrl string `protobuf:"bytes,7,opt,name=token_url,json=tokenUrl,proto3" json:"token_url,omitempty"` - // The available scopes for the OAuth2 security scheme. - // Valid for oauth2. - Scopes *Scopes `protobuf:"bytes,8,opt,name=scopes,proto3" json:"scopes,omitempty"` - Extensions map[string]*_struct.Value `protobuf:"bytes,9,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Type SecurityScheme_Type `protobuf:"varint,1,opt,name=type,proto3,enum=grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme_Type" json:"type,omitempty"` + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` + Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` + In SecurityScheme_In `protobuf:"varint,4,opt,name=in,proto3,enum=grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme_In" json:"in,omitempty"` + Flow SecurityScheme_Flow `protobuf:"varint,5,opt,name=flow,proto3,enum=grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme_Flow" json:"flow,omitempty"` + AuthorizationUrl string `protobuf:"bytes,6,opt,name=authorization_url,json=authorizationUrl,proto3" json:"authorization_url,omitempty"` + TokenUrl string `protobuf:"bytes,7,opt,name=token_url,json=tokenUrl,proto3" json:"token_url,omitempty"` + Scopes *Scopes `protobuf:"bytes,8,opt,name=scopes,proto3" json:"scopes,omitempty"` + Extensions map[string]*structpb.Value `protobuf:"bytes,9,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } func (x *SecurityScheme) Reset() { *x = SecurityScheme{} if protoimpl.UnsafeEnabled { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[11] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1661,7 +1436,7 @@ func (x *SecurityScheme) String() string { func (*SecurityScheme) ProtoMessage() {} func (x *SecurityScheme) ProtoReflect() protoreflect.Message { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[11] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1674,7 +1449,7 @@ func (x *SecurityScheme) ProtoReflect() protoreflect.Message { // Deprecated: Use SecurityScheme.ProtoReflect.Descriptor instead. func (*SecurityScheme) Descriptor() ([]byte, []int) { - return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{11} + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{12} } func (x *SecurityScheme) GetType() SecurityScheme_Type { @@ -1733,40 +1508,25 @@ func (x *SecurityScheme) GetScopes() *Scopes { return nil } -func (x *SecurityScheme) GetExtensions() map[string]*_struct.Value { +func (x *SecurityScheme) GetExtensions() map[string]*structpb.Value { if x != nil { return x.Extensions } return nil } -// `SecurityRequirement` is a representation of OpenAPI v2 specification's -// Security Requirement object. -// -// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#securityRequirementObject -// -// Lists the required security schemes to execute this operation. The object can -// have multiple security schemes declared in it which are all required (that -// is, there is a logical AND between the schemes). -// -// The name used for each property MUST correspond to a security scheme -// declared in the Security Definitions. type SecurityRequirement struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // Each name must correspond to a security scheme which is declared in - // the Security Definitions. If the security scheme is of type "oauth2", - // then the value is a list of scope names required for the execution. - // For other security scheme types, the array MUST be empty. SecurityRequirement map[string]*SecurityRequirement_SecurityRequirementValue `protobuf:"bytes,1,rep,name=security_requirement,json=securityRequirement,proto3" json:"security_requirement,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } func (x *SecurityRequirement) Reset() { *x = SecurityRequirement{} if protoimpl.UnsafeEnabled { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[12] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1779,7 +1539,7 @@ func (x *SecurityRequirement) String() string { func (*SecurityRequirement) ProtoMessage() {} func (x *SecurityRequirement) ProtoReflect() protoreflect.Message { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[12] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1792,7 +1552,7 @@ func (x *SecurityRequirement) ProtoReflect() protoreflect.Message { // Deprecated: Use SecurityRequirement.ProtoReflect.Descriptor instead. func (*SecurityRequirement) Descriptor() ([]byte, []int) { - return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{12} + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{13} } func (x *SecurityRequirement) GetSecurityRequirement() map[string]*SecurityRequirement_SecurityRequirementValue { @@ -1802,25 +1562,18 @@ func (x *SecurityRequirement) GetSecurityRequirement() map[string]*SecurityRequi return nil } -// `Scopes` is a representation of OpenAPI v2 specification's Scopes object. -// -// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#scopesObject -// -// Lists the available scopes for an OAuth2 security scheme. type Scopes struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // Maps between a name of a scope to a short description of it (as the value - // of the property). Scope map[string]string `protobuf:"bytes,1,rep,name=scope,proto3" json:"scope,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } func (x *Scopes) Reset() { *x = Scopes{} if protoimpl.UnsafeEnabled { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[13] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1833,7 +1586,7 @@ func (x *Scopes) String() string { func (*Scopes) ProtoMessage() {} func (x *Scopes) ProtoReflect() protoreflect.Message { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[13] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1846,7 +1599,7 @@ func (x *Scopes) ProtoReflect() protoreflect.Message { // Deprecated: Use Scopes.ProtoReflect.Descriptor instead. func (*Scopes) Descriptor() ([]byte, []int) { - return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{13} + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{14} } func (x *Scopes) GetScope() map[string]string { @@ -1856,9 +1609,6 @@ func (x *Scopes) GetScope() map[string]string { return nil } -// If the security scheme is of type "oauth2", then the value is a list of -// scope names required for the execution. For other security scheme types, -// the array MUST be empty. type SecurityRequirement_SecurityRequirementValue struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1870,7 +1620,7 @@ type SecurityRequirement_SecurityRequirementValue struct { func (x *SecurityRequirement_SecurityRequirementValue) Reset() { *x = SecurityRequirement_SecurityRequirementValue{} if protoimpl.UnsafeEnabled { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[23] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1883,7 +1633,7 @@ func (x *SecurityRequirement_SecurityRequirementValue) String() string { func (*SecurityRequirement_SecurityRequirementValue) ProtoMessage() {} func (x *SecurityRequirement_SecurityRequirementValue) ProtoReflect() protoreflect.Message { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[23] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[25] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1896,7 +1646,7 @@ func (x *SecurityRequirement_SecurityRequirementValue) ProtoReflect() protorefle // Deprecated: Use SecurityRequirement_SecurityRequirementValue.ProtoReflect.Descriptor instead. func (*SecurityRequirement_SecurityRequirementValue) Descriptor() ([]byte, []int) { - return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{12, 0} + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{13, 0} } func (x *SecurityRequirement_SecurityRequirementValue) GetScope() []string { @@ -2036,37 +1786,63 @@ var file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDesc = []byte{ 0x79, 0x12, 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, - 0x02, 0x38, 0x01, 0x4a, 0x04, 0x08, 0x08, 0x10, 0x09, 0x22, 0xd5, 0x03, 0x0a, 0x08, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x49, 0x0a, 0x06, 0x73, 0x63, 0x68, 0x65, - 0x6d, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, - 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, - 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x06, 0x73, 0x63, 0x68, - 0x65, 0x6d, 0x61, 0x12, 0x5d, 0x0a, 0x08, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x18, - 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x41, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, - 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, - 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x45, 0x78, 0x61, 0x6d, 0x70, - 0x6c, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, - 0x65, 0x73, 0x12, 0x63, 0x0a, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, - 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x43, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, - 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, - 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x45, 0x78, 0x74, 0x65, - 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x65, 0x78, 0x74, - 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x3b, 0x0a, 0x0d, 0x45, 0x78, 0x61, 0x6d, 0x70, - 0x6c, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x55, 0x0a, 0x0f, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, - 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, - 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x4a, 0x04, 0x08, 0x03, 0x10, - 0x04, 0x22, 0xd6, 0x03, 0x0a, 0x04, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, + 0x02, 0x38, 0x01, 0x4a, 0x04, 0x08, 0x08, 0x10, 0x09, 0x22, 0xd8, 0x01, 0x0a, 0x06, 0x48, 0x65, + 0x61, 0x64, 0x65, 0x72, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x6f, + 0x72, 0x6d, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x6f, 0x72, 0x6d, + 0x61, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x12, 0x18, 0x0a, 0x07, + 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, + 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x4a, 0x04, 0x08, 0x05, + 0x10, 0x06, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08, 0x4a, 0x04, 0x08, 0x08, 0x10, 0x09, 0x4a, 0x04, + 0x08, 0x09, 0x10, 0x0a, 0x4a, 0x04, 0x08, 0x0a, 0x10, 0x0b, 0x4a, 0x04, 0x08, 0x0b, 0x10, 0x0c, + 0x4a, 0x04, 0x08, 0x0c, 0x10, 0x0d, 0x4a, 0x04, 0x08, 0x0e, 0x10, 0x0f, 0x4a, 0x04, 0x08, 0x0f, + 0x10, 0x10, 0x4a, 0x04, 0x08, 0x10, 0x10, 0x11, 0x4a, 0x04, 0x08, 0x11, 0x10, 0x12, 0x4a, 0x04, + 0x08, 0x12, 0x10, 0x13, 0x22, 0x9a, 0x05, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x49, 0x0a, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, + 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, + 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, + 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x5a, + 0x0a, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x40, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, + 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x52, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x5d, 0x0a, 0x08, 0x65, 0x78, + 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x41, 0x2e, 0x67, + 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, + 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x2e, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, + 0x08, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x12, 0x63, 0x0a, 0x0a, 0x65, 0x78, 0x74, + 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x43, 0x2e, + 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, + 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x6d, + 0x0a, 0x0c, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, + 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, + 0x12, 0x47, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x31, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, + 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x48, 0x65, 0x61, 0x64, + 0x65, 0x72, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3b, 0x0a, + 0x0d, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, + 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, + 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x55, 0x0a, 0x0f, 0x45, 0x78, + 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, + 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, + 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, + 0x01, 0x22, 0xd6, 0x03, 0x0a, 0x04, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, @@ -2126,7 +1902,7 @@ var file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDesc = []byte{ 0x6c, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x44, 0x6f, 0x63, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x65, - 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x22, 0x9f, 0x07, 0x0a, + 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x22, 0xdf, 0x07, 0x0a, 0x0a, 0x4a, 0x53, 0x4f, 0x4e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x10, 0x0a, 0x03, 0x72, 0x65, 0x66, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x72, 0x65, 0x66, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, @@ -2135,55 +1911,59 @@ var file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDesc = []byte{ 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x08, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x61, 0x64, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x1f, 0x0a, 0x0b, - 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x5f, 0x6f, 0x66, 0x18, 0x0a, 0x20, 0x01, 0x28, - 0x01, 0x52, 0x0a, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x4f, 0x66, 0x12, 0x18, 0x0a, - 0x07, 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x01, 0x52, 0x07, - 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x12, 0x2b, 0x0a, 0x11, 0x65, 0x78, 0x63, 0x6c, 0x75, - 0x73, 0x69, 0x76, 0x65, 0x5f, 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x18, 0x0c, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x10, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x76, 0x65, 0x4d, 0x61, 0x78, - 0x69, 0x6d, 0x75, 0x6d, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x18, - 0x0d, 0x20, 0x01, 0x28, 0x01, 0x52, 0x07, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x12, 0x2b, - 0x0a, 0x11, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x76, 0x65, 0x5f, 0x6d, 0x69, 0x6e, 0x69, - 0x6d, 0x75, 0x6d, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x65, 0x78, 0x63, 0x6c, 0x75, - 0x73, 0x69, 0x76, 0x65, 0x4d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, - 0x61, 0x78, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x09, 0x6d, 0x61, 0x78, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x69, - 0x6e, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x10, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, - 0x6d, 0x69, 0x6e, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x74, - 0x74, 0x65, 0x72, 0x6e, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x74, 0x74, - 0x65, 0x72, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x61, 0x78, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x73, - 0x18, 0x14, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x49, 0x74, 0x65, 0x6d, 0x73, - 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x69, 0x6e, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x15, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x08, 0x6d, 0x69, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x21, 0x0a, - 0x0c, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x16, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x0b, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x73, - 0x12, 0x25, 0x0a, 0x0e, 0x6d, 0x61, 0x78, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, - 0x65, 0x73, 0x18, 0x18, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x6d, 0x61, 0x78, 0x50, 0x72, 0x6f, - 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x6d, 0x69, 0x6e, 0x5f, 0x70, - 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x19, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x0d, 0x6d, 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x12, 0x1a, - 0x0a, 0x08, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x18, 0x1a, 0x20, 0x03, 0x28, 0x09, - 0x52, 0x08, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x72, - 0x72, 0x61, 0x79, 0x18, 0x22, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x61, 0x72, 0x72, 0x61, 0x79, - 0x12, 0x5f, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x23, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x4b, - 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, - 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4a, 0x53, 0x4f, 0x4e, 0x53, - 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x4a, 0x53, 0x4f, 0x4e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, - 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x52, 0x04, 0x74, 0x79, 0x70, - 0x65, 0x22, 0x77, 0x0a, 0x15, 0x4a, 0x53, 0x4f, 0x4e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x53, - 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, - 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x52, 0x52, 0x41, 0x59, - 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x42, 0x4f, 0x4f, 0x4c, 0x45, 0x41, 0x4e, 0x10, 0x02, 0x12, - 0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x10, 0x03, 0x12, 0x08, 0x0a, 0x04, - 0x4e, 0x55, 0x4c, 0x4c, 0x10, 0x04, 0x12, 0x0a, 0x0a, 0x06, 0x4e, 0x55, 0x4d, 0x42, 0x45, 0x52, - 0x10, 0x05, 0x12, 0x0a, 0x0a, 0x06, 0x4f, 0x42, 0x4a, 0x45, 0x43, 0x54, 0x10, 0x06, 0x12, 0x0a, - 0x0a, 0x06, 0x53, 0x54, 0x52, 0x49, 0x4e, 0x47, 0x10, 0x07, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, - 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x4a, 0x04, 0x08, 0x09, - 0x10, 0x0a, 0x4a, 0x04, 0x08, 0x12, 0x10, 0x13, 0x4a, 0x04, 0x08, 0x13, 0x10, 0x14, 0x4a, 0x04, + 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x61, 0x64, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x18, 0x0a, 0x07, + 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x65, + 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, + 0x6c, 0x65, 0x5f, 0x6f, 0x66, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0a, 0x6d, 0x75, 0x6c, + 0x74, 0x69, 0x70, 0x6c, 0x65, 0x4f, 0x66, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x61, 0x78, 0x69, 0x6d, + 0x75, 0x6d, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x01, 0x52, 0x07, 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, + 0x6d, 0x12, 0x2b, 0x0a, 0x11, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x76, 0x65, 0x5f, 0x6d, + 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x65, 0x78, + 0x63, 0x6c, 0x75, 0x73, 0x69, 0x76, 0x65, 0x4d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x12, 0x18, + 0x0a, 0x07, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x01, 0x52, + 0x07, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x12, 0x2b, 0x0a, 0x11, 0x65, 0x78, 0x63, 0x6c, + 0x75, 0x73, 0x69, 0x76, 0x65, 0x5f, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x18, 0x0e, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x10, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x76, 0x65, 0x4d, 0x69, + 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x61, 0x78, 0x5f, 0x6c, 0x65, 0x6e, + 0x67, 0x74, 0x68, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x6d, 0x61, 0x78, 0x4c, 0x65, + 0x6e, 0x67, 0x74, 0x68, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x69, 0x6e, 0x5f, 0x6c, 0x65, 0x6e, 0x67, + 0x74, 0x68, 0x18, 0x10, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x6d, 0x69, 0x6e, 0x4c, 0x65, 0x6e, + 0x67, 0x74, 0x68, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x18, 0x11, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x12, 0x1b, 0x0a, + 0x09, 0x6d, 0x61, 0x78, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x14, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x08, 0x6d, 0x61, 0x78, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x69, + 0x6e, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x15, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x6d, + 0x69, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x75, 0x6e, 0x69, 0x71, 0x75, + 0x65, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x16, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x75, + 0x6e, 0x69, 0x71, 0x75, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x6d, 0x61, + 0x78, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x18, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x0d, 0x6d, 0x61, 0x78, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, + 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x6d, 0x69, 0x6e, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, + 0x69, 0x65, 0x73, 0x18, 0x19, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x6d, 0x69, 0x6e, 0x50, 0x72, + 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x71, 0x75, + 0x69, 0x72, 0x65, 0x64, 0x18, 0x1a, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x71, 0x75, + 0x69, 0x72, 0x65, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x72, 0x72, 0x61, 0x79, 0x18, 0x22, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x05, 0x61, 0x72, 0x72, 0x61, 0x79, 0x12, 0x5f, 0x0a, 0x04, 0x74, 0x79, + 0x70, 0x65, 0x18, 0x23, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x4b, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, + 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, + 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4a, 0x53, 0x4f, 0x4e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, + 0x4a, 0x53, 0x4f, 0x4e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x73, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x66, + 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x18, 0x24, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x6f, 0x72, + 0x6d, 0x61, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x6e, 0x75, 0x6d, 0x18, 0x2e, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x04, 0x65, 0x6e, 0x75, 0x6d, 0x22, 0x77, 0x0a, 0x15, 0x4a, 0x53, 0x4f, 0x4e, 0x53, + 0x63, 0x68, 0x65, 0x6d, 0x61, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, + 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x09, 0x0a, + 0x05, 0x41, 0x52, 0x52, 0x41, 0x59, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x42, 0x4f, 0x4f, 0x4c, + 0x45, 0x41, 0x4e, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, + 0x10, 0x03, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x55, 0x4c, 0x4c, 0x10, 0x04, 0x12, 0x0a, 0x0a, 0x06, + 0x4e, 0x55, 0x4d, 0x42, 0x45, 0x52, 0x10, 0x05, 0x12, 0x0a, 0x0a, 0x06, 0x4f, 0x42, 0x4a, 0x45, + 0x43, 0x54, 0x10, 0x06, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x54, 0x52, 0x49, 0x4e, 0x47, 0x10, 0x07, + 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x4a, 0x04, 0x08, 0x04, + 0x10, 0x05, 0x4a, 0x04, 0x08, 0x12, 0x10, 0x13, 0x4a, 0x04, 0x08, 0x13, 0x10, 0x14, 0x4a, 0x04, 0x08, 0x17, 0x10, 0x18, 0x4a, 0x04, 0x08, 0x1b, 0x10, 0x1c, 0x4a, 0x04, 0x08, 0x1c, 0x10, 0x1d, - 0x4a, 0x04, 0x08, 0x1d, 0x10, 0x1e, 0x4a, 0x04, 0x08, 0x1e, 0x10, 0x22, 0x4a, 0x04, 0x08, 0x24, + 0x4a, 0x04, 0x08, 0x1d, 0x10, 0x1e, 0x4a, 0x04, 0x08, 0x1e, 0x10, 0x22, 0x4a, 0x04, 0x08, 0x25, 0x10, 0x2a, 0x4a, 0x04, 0x08, 0x2a, 0x10, 0x2b, 0x4a, 0x04, 0x08, 0x2b, 0x10, 0x2e, 0x22, 0x94, 0x01, 0x0a, 0x03, 0x54, 0x61, 0x67, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, @@ -2324,7 +2104,7 @@ func file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP() []b } var file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_enumTypes = make([]protoimpl.EnumInfo, 5) -var file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes = make([]protoimpl.MessageInfo, 26) +var file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes = make([]protoimpl.MessageInfo, 28) var file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_goTypes = []interface{}{ (Scheme)(0), // 0: grpc.gateway.protoc_gen_openapiv2.options.Scheme (JSONSchema_JSONSchemaSimpleTypes)(0), // 1: grpc.gateway.protoc_gen_openapiv2.options.JSONSchema.JSONSchemaSimpleTypes @@ -2333,77 +2113,81 @@ var file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_goTypes = []interf (SecurityScheme_Flow)(0), // 4: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.Flow (*Swagger)(nil), // 5: grpc.gateway.protoc_gen_openapiv2.options.Swagger (*Operation)(nil), // 6: grpc.gateway.protoc_gen_openapiv2.options.Operation - (*Response)(nil), // 7: grpc.gateway.protoc_gen_openapiv2.options.Response - (*Info)(nil), // 8: grpc.gateway.protoc_gen_openapiv2.options.Info - (*Contact)(nil), // 9: grpc.gateway.protoc_gen_openapiv2.options.Contact - (*License)(nil), // 10: grpc.gateway.protoc_gen_openapiv2.options.License - (*ExternalDocumentation)(nil), // 11: grpc.gateway.protoc_gen_openapiv2.options.ExternalDocumentation - (*Schema)(nil), // 12: grpc.gateway.protoc_gen_openapiv2.options.Schema - (*JSONSchema)(nil), // 13: grpc.gateway.protoc_gen_openapiv2.options.JSONSchema - (*Tag)(nil), // 14: grpc.gateway.protoc_gen_openapiv2.options.Tag - (*SecurityDefinitions)(nil), // 15: grpc.gateway.protoc_gen_openapiv2.options.SecurityDefinitions - (*SecurityScheme)(nil), // 16: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme - (*SecurityRequirement)(nil), // 17: grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement - (*Scopes)(nil), // 18: grpc.gateway.protoc_gen_openapiv2.options.Scopes - nil, // 19: grpc.gateway.protoc_gen_openapiv2.options.Swagger.ResponsesEntry - nil, // 20: grpc.gateway.protoc_gen_openapiv2.options.Swagger.ExtensionsEntry - nil, // 21: grpc.gateway.protoc_gen_openapiv2.options.Operation.ResponsesEntry - nil, // 22: grpc.gateway.protoc_gen_openapiv2.options.Operation.ExtensionsEntry - nil, // 23: grpc.gateway.protoc_gen_openapiv2.options.Response.ExamplesEntry - nil, // 24: grpc.gateway.protoc_gen_openapiv2.options.Response.ExtensionsEntry - nil, // 25: grpc.gateway.protoc_gen_openapiv2.options.Info.ExtensionsEntry - nil, // 26: grpc.gateway.protoc_gen_openapiv2.options.SecurityDefinitions.SecurityEntry - nil, // 27: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.ExtensionsEntry - (*SecurityRequirement_SecurityRequirementValue)(nil), // 28: grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement.SecurityRequirementValue - nil, // 29: grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement.SecurityRequirementEntry - nil, // 30: grpc.gateway.protoc_gen_openapiv2.options.Scopes.ScopeEntry - (*_struct.Value)(nil), // 31: google.protobuf.Value + (*Header)(nil), // 7: grpc.gateway.protoc_gen_openapiv2.options.Header + (*Response)(nil), // 8: grpc.gateway.protoc_gen_openapiv2.options.Response + (*Info)(nil), // 9: grpc.gateway.protoc_gen_openapiv2.options.Info + (*Contact)(nil), // 10: grpc.gateway.protoc_gen_openapiv2.options.Contact + (*License)(nil), // 11: grpc.gateway.protoc_gen_openapiv2.options.License + (*ExternalDocumentation)(nil), // 12: grpc.gateway.protoc_gen_openapiv2.options.ExternalDocumentation + (*Schema)(nil), // 13: grpc.gateway.protoc_gen_openapiv2.options.Schema + (*JSONSchema)(nil), // 14: grpc.gateway.protoc_gen_openapiv2.options.JSONSchema + (*Tag)(nil), // 15: grpc.gateway.protoc_gen_openapiv2.options.Tag + (*SecurityDefinitions)(nil), // 16: grpc.gateway.protoc_gen_openapiv2.options.SecurityDefinitions + (*SecurityScheme)(nil), // 17: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme + (*SecurityRequirement)(nil), // 18: grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement + (*Scopes)(nil), // 19: grpc.gateway.protoc_gen_openapiv2.options.Scopes + nil, // 20: grpc.gateway.protoc_gen_openapiv2.options.Swagger.ResponsesEntry + nil, // 21: grpc.gateway.protoc_gen_openapiv2.options.Swagger.ExtensionsEntry + nil, // 22: grpc.gateway.protoc_gen_openapiv2.options.Operation.ResponsesEntry + nil, // 23: grpc.gateway.protoc_gen_openapiv2.options.Operation.ExtensionsEntry + nil, // 24: grpc.gateway.protoc_gen_openapiv2.options.Response.HeadersEntry + nil, // 25: grpc.gateway.protoc_gen_openapiv2.options.Response.ExamplesEntry + nil, // 26: grpc.gateway.protoc_gen_openapiv2.options.Response.ExtensionsEntry + nil, // 27: grpc.gateway.protoc_gen_openapiv2.options.Info.ExtensionsEntry + nil, // 28: grpc.gateway.protoc_gen_openapiv2.options.SecurityDefinitions.SecurityEntry + nil, // 29: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.ExtensionsEntry + (*SecurityRequirement_SecurityRequirementValue)(nil), // 30: grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement.SecurityRequirementValue + nil, // 31: grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement.SecurityRequirementEntry + nil, // 32: grpc.gateway.protoc_gen_openapiv2.options.Scopes.ScopeEntry + (*structpb.Value)(nil), // 33: google.protobuf.Value } var file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_depIdxs = []int32{ - 8, // 0: grpc.gateway.protoc_gen_openapiv2.options.Swagger.info:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Info + 9, // 0: grpc.gateway.protoc_gen_openapiv2.options.Swagger.info:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Info 0, // 1: grpc.gateway.protoc_gen_openapiv2.options.Swagger.schemes:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Scheme - 19, // 2: grpc.gateway.protoc_gen_openapiv2.options.Swagger.responses:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Swagger.ResponsesEntry - 15, // 3: grpc.gateway.protoc_gen_openapiv2.options.Swagger.security_definitions:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityDefinitions - 17, // 4: grpc.gateway.protoc_gen_openapiv2.options.Swagger.security:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement - 11, // 5: grpc.gateway.protoc_gen_openapiv2.options.Swagger.external_docs:type_name -> grpc.gateway.protoc_gen_openapiv2.options.ExternalDocumentation - 20, // 6: grpc.gateway.protoc_gen_openapiv2.options.Swagger.extensions:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Swagger.ExtensionsEntry - 11, // 7: grpc.gateway.protoc_gen_openapiv2.options.Operation.external_docs:type_name -> grpc.gateway.protoc_gen_openapiv2.options.ExternalDocumentation - 21, // 8: grpc.gateway.protoc_gen_openapiv2.options.Operation.responses:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Operation.ResponsesEntry + 20, // 2: grpc.gateway.protoc_gen_openapiv2.options.Swagger.responses:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Swagger.ResponsesEntry + 16, // 3: grpc.gateway.protoc_gen_openapiv2.options.Swagger.security_definitions:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityDefinitions + 18, // 4: grpc.gateway.protoc_gen_openapiv2.options.Swagger.security:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement + 12, // 5: grpc.gateway.protoc_gen_openapiv2.options.Swagger.external_docs:type_name -> grpc.gateway.protoc_gen_openapiv2.options.ExternalDocumentation + 21, // 6: grpc.gateway.protoc_gen_openapiv2.options.Swagger.extensions:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Swagger.ExtensionsEntry + 12, // 7: grpc.gateway.protoc_gen_openapiv2.options.Operation.external_docs:type_name -> grpc.gateway.protoc_gen_openapiv2.options.ExternalDocumentation + 22, // 8: grpc.gateway.protoc_gen_openapiv2.options.Operation.responses:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Operation.ResponsesEntry 0, // 9: grpc.gateway.protoc_gen_openapiv2.options.Operation.schemes:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Scheme - 17, // 10: grpc.gateway.protoc_gen_openapiv2.options.Operation.security:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement - 22, // 11: grpc.gateway.protoc_gen_openapiv2.options.Operation.extensions:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Operation.ExtensionsEntry - 12, // 12: grpc.gateway.protoc_gen_openapiv2.options.Response.schema:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Schema - 23, // 13: grpc.gateway.protoc_gen_openapiv2.options.Response.examples:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Response.ExamplesEntry - 24, // 14: grpc.gateway.protoc_gen_openapiv2.options.Response.extensions:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Response.ExtensionsEntry - 9, // 15: grpc.gateway.protoc_gen_openapiv2.options.Info.contact:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Contact - 10, // 16: grpc.gateway.protoc_gen_openapiv2.options.Info.license:type_name -> grpc.gateway.protoc_gen_openapiv2.options.License - 25, // 17: grpc.gateway.protoc_gen_openapiv2.options.Info.extensions:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Info.ExtensionsEntry - 13, // 18: grpc.gateway.protoc_gen_openapiv2.options.Schema.json_schema:type_name -> grpc.gateway.protoc_gen_openapiv2.options.JSONSchema - 11, // 19: grpc.gateway.protoc_gen_openapiv2.options.Schema.external_docs:type_name -> grpc.gateway.protoc_gen_openapiv2.options.ExternalDocumentation - 1, // 20: grpc.gateway.protoc_gen_openapiv2.options.JSONSchema.type:type_name -> grpc.gateway.protoc_gen_openapiv2.options.JSONSchema.JSONSchemaSimpleTypes - 11, // 21: grpc.gateway.protoc_gen_openapiv2.options.Tag.external_docs:type_name -> grpc.gateway.protoc_gen_openapiv2.options.ExternalDocumentation - 26, // 22: grpc.gateway.protoc_gen_openapiv2.options.SecurityDefinitions.security:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityDefinitions.SecurityEntry - 2, // 23: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.type:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.Type - 3, // 24: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.in:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.In - 4, // 25: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.flow:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.Flow - 18, // 26: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.scopes:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Scopes - 27, // 27: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.extensions:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.ExtensionsEntry - 29, // 28: grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement.security_requirement:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement.SecurityRequirementEntry - 30, // 29: grpc.gateway.protoc_gen_openapiv2.options.Scopes.scope:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Scopes.ScopeEntry - 7, // 30: grpc.gateway.protoc_gen_openapiv2.options.Swagger.ResponsesEntry.value:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Response - 31, // 31: grpc.gateway.protoc_gen_openapiv2.options.Swagger.ExtensionsEntry.value:type_name -> google.protobuf.Value - 7, // 32: grpc.gateway.protoc_gen_openapiv2.options.Operation.ResponsesEntry.value:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Response - 31, // 33: grpc.gateway.protoc_gen_openapiv2.options.Operation.ExtensionsEntry.value:type_name -> google.protobuf.Value - 31, // 34: grpc.gateway.protoc_gen_openapiv2.options.Response.ExtensionsEntry.value:type_name -> google.protobuf.Value - 31, // 35: grpc.gateway.protoc_gen_openapiv2.options.Info.ExtensionsEntry.value:type_name -> google.protobuf.Value - 16, // 36: grpc.gateway.protoc_gen_openapiv2.options.SecurityDefinitions.SecurityEntry.value:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme - 31, // 37: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.ExtensionsEntry.value:type_name -> google.protobuf.Value - 28, // 38: grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement.SecurityRequirementEntry.value:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement.SecurityRequirementValue - 39, // [39:39] is the sub-list for method output_type - 39, // [39:39] is the sub-list for method input_type - 39, // [39:39] is the sub-list for extension type_name - 39, // [39:39] is the sub-list for extension extendee - 0, // [0:39] is the sub-list for field type_name + 18, // 10: grpc.gateway.protoc_gen_openapiv2.options.Operation.security:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement + 23, // 11: grpc.gateway.protoc_gen_openapiv2.options.Operation.extensions:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Operation.ExtensionsEntry + 13, // 12: grpc.gateway.protoc_gen_openapiv2.options.Response.schema:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Schema + 24, // 13: grpc.gateway.protoc_gen_openapiv2.options.Response.headers:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Response.HeadersEntry + 25, // 14: grpc.gateway.protoc_gen_openapiv2.options.Response.examples:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Response.ExamplesEntry + 26, // 15: grpc.gateway.protoc_gen_openapiv2.options.Response.extensions:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Response.ExtensionsEntry + 10, // 16: grpc.gateway.protoc_gen_openapiv2.options.Info.contact:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Contact + 11, // 17: grpc.gateway.protoc_gen_openapiv2.options.Info.license:type_name -> grpc.gateway.protoc_gen_openapiv2.options.License + 27, // 18: grpc.gateway.protoc_gen_openapiv2.options.Info.extensions:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Info.ExtensionsEntry + 14, // 19: grpc.gateway.protoc_gen_openapiv2.options.Schema.json_schema:type_name -> grpc.gateway.protoc_gen_openapiv2.options.JSONSchema + 12, // 20: grpc.gateway.protoc_gen_openapiv2.options.Schema.external_docs:type_name -> grpc.gateway.protoc_gen_openapiv2.options.ExternalDocumentation + 1, // 21: grpc.gateway.protoc_gen_openapiv2.options.JSONSchema.type:type_name -> grpc.gateway.protoc_gen_openapiv2.options.JSONSchema.JSONSchemaSimpleTypes + 12, // 22: grpc.gateway.protoc_gen_openapiv2.options.Tag.external_docs:type_name -> grpc.gateway.protoc_gen_openapiv2.options.ExternalDocumentation + 28, // 23: grpc.gateway.protoc_gen_openapiv2.options.SecurityDefinitions.security:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityDefinitions.SecurityEntry + 2, // 24: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.type:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.Type + 3, // 25: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.in:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.In + 4, // 26: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.flow:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.Flow + 19, // 27: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.scopes:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Scopes + 29, // 28: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.extensions:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.ExtensionsEntry + 31, // 29: grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement.security_requirement:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement.SecurityRequirementEntry + 32, // 30: grpc.gateway.protoc_gen_openapiv2.options.Scopes.scope:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Scopes.ScopeEntry + 8, // 31: grpc.gateway.protoc_gen_openapiv2.options.Swagger.ResponsesEntry.value:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Response + 33, // 32: grpc.gateway.protoc_gen_openapiv2.options.Swagger.ExtensionsEntry.value:type_name -> google.protobuf.Value + 8, // 33: grpc.gateway.protoc_gen_openapiv2.options.Operation.ResponsesEntry.value:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Response + 33, // 34: grpc.gateway.protoc_gen_openapiv2.options.Operation.ExtensionsEntry.value:type_name -> google.protobuf.Value + 7, // 35: grpc.gateway.protoc_gen_openapiv2.options.Response.HeadersEntry.value:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Header + 33, // 36: grpc.gateway.protoc_gen_openapiv2.options.Response.ExtensionsEntry.value:type_name -> google.protobuf.Value + 33, // 37: grpc.gateway.protoc_gen_openapiv2.options.Info.ExtensionsEntry.value:type_name -> google.protobuf.Value + 17, // 38: grpc.gateway.protoc_gen_openapiv2.options.SecurityDefinitions.SecurityEntry.value:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme + 33, // 39: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.ExtensionsEntry.value:type_name -> google.protobuf.Value + 30, // 40: grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement.SecurityRequirementEntry.value:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement.SecurityRequirementValue + 41, // [41:41] is the sub-list for method output_type + 41, // [41:41] is the sub-list for method input_type + 41, // [41:41] is the sub-list for extension type_name + 41, // [41:41] is the sub-list for extension extendee + 0, // [0:41] is the sub-list for field type_name } func init() { file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_init() } @@ -2437,7 +2221,7 @@ func file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_init() { } } file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Response); i { + switch v := v.(*Header); i { case 0: return &v.state case 1: @@ -2449,7 +2233,7 @@ func file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_init() { } } file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Info); i { + switch v := v.(*Response); i { case 0: return &v.state case 1: @@ -2461,7 +2245,7 @@ func file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_init() { } } file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Contact); i { + switch v := v.(*Info); i { case 0: return &v.state case 1: @@ -2473,7 +2257,7 @@ func file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_init() { } } file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*License); i { + switch v := v.(*Contact); i { case 0: return &v.state case 1: @@ -2485,7 +2269,7 @@ func file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_init() { } } file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ExternalDocumentation); i { + switch v := v.(*License); i { case 0: return &v.state case 1: @@ -2497,7 +2281,7 @@ func file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_init() { } } file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Schema); i { + switch v := v.(*ExternalDocumentation); i { case 0: return &v.state case 1: @@ -2509,7 +2293,7 @@ func file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_init() { } } file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*JSONSchema); i { + switch v := v.(*Schema); i { case 0: return &v.state case 1: @@ -2521,7 +2305,7 @@ func file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_init() { } } file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Tag); i { + switch v := v.(*JSONSchema); i { case 0: return &v.state case 1: @@ -2533,7 +2317,7 @@ func file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_init() { } } file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SecurityDefinitions); i { + switch v := v.(*Tag); i { case 0: return &v.state case 1: @@ -2545,7 +2329,7 @@ func file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_init() { } } file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SecurityScheme); i { + switch v := v.(*SecurityDefinitions); i { case 0: return &v.state case 1: @@ -2557,7 +2341,7 @@ func file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_init() { } } file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SecurityRequirement); i { + switch v := v.(*SecurityScheme); i { case 0: return &v.state case 1: @@ -2569,6 +2353,18 @@ func file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_init() { } } file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SecurityRequirement); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Scopes); i { case 0: return &v.state @@ -2580,7 +2376,7 @@ func file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_init() { return nil } } - file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { + file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*SecurityRequirement_SecurityRequirementValue); i { case 0: return &v.state @@ -2599,7 +2395,7 @@ func file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDesc, NumEnums: 5, - NumMessages: 26, + NumMessages: 28, NumExtensions: 0, NumServices: 0, }, diff --git a/gateway/protoc-gen-openapiv2/options/openapiv2.proto b/gateway/protoc-gen-openapiv2/options/openapiv2.proto index 41add95..9d078a5 100644 --- a/gateway/protoc-gen-openapiv2/options/openapiv2.proto +++ b/gateway/protoc-gen-openapiv2/options/openapiv2.proto @@ -172,6 +172,51 @@ message Operation { map extensions = 13; } +// `Header` is a representation of OpenAPI v2 specification's Header object. +// +// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#headerObject +// +message Header { + // `Description` is a short description of the header. + string description = 1; + // The type of the object. The value MUST be one of "string", "number", "integer", or "boolean". The "array" type is not supported. + string type = 2; + // `Format` The extending format for the previously mentioned type. + string format = 3; + // field 4 is reserved for 'items', but in OpenAPI-specific way. + reserved 4; + // field 5 is reserved `Collection Format` Determines the format of the array if type array is used. + reserved 5; + // `Default` Declares the value of the header that the server will use if none is provided. + // See: https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-6.2. + // Unlike JSON Schema this value MUST conform to the defined type for the header. + string default = 6; + // field 7 is reserved for 'maximum'. + reserved 7; + // field 8 is reserved for 'exclusiveMaximum'. + reserved 8; + // field 9 is reserved for 'minimum'. + reserved 9; + // field 10 is reserved for 'exclusiveMinimum'. + reserved 10; + // field 11 is reserved for 'maxLength'. + reserved 11; + // field 12 is reserved for 'minLength'. + reserved 12; + // 'Pattern' See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.2.3. + string pattern = 13; + // field 14 is reserved for 'maxItems'. + reserved 14; + // field 15 is reserved for 'minItems'. + reserved 15; + // field 16 is reserved for 'uniqueItems'. + reserved 16; + // field 17 is reserved for 'enum'. + reserved 17; + // field 18 is reserved for 'multipleOf'. + reserved 18; +} + // `Response` is a representation of OpenAPI v2 specification's Response object. // // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#responseObject @@ -183,8 +228,10 @@ message Response { // `Schema` optionally defines the structure of the response. // If `Schema` is not provided, it means there is no content to the response. Schema schema = 2; - // field 3 is reserved for 'headers'. - reserved 3; + // `Headers` A list of headers that are sent with the response. + // `Header` name is expected to be a string in the canonical format of the MIME header key + // See: https://golang.org/pkg/net/textproto/#CanonicalMIMEHeaderKey + map headers = 3; // `Examples` gives per-mimetype response examples. // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#example-object map examples = 4; @@ -364,7 +411,7 @@ message Schema { // // Id represents the message identifier. // string id = 1; [ // (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { -// {description: "The unique identifier of the simple message." +// description: "The unique identifier of the simple message." // }]; // } // @@ -388,9 +435,10 @@ message JSONSchema { string description = 6; string default = 7; bool read_only = 8; - // field 9 is reserved for 'examples', which is omitted from OpenAPI v2 in - // favor of 'example' field. - reserved 9; + // A free-form property to include a JSON example of this field. This is copied + // verbatim to the output swagger.json. Quotes must be escaped. + // This property is the same for 2.0 and 3.0.0 https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/3.0.0.md#schemaObject https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#schemaObject + string example = 9; double multiple_of = 10; // Maximum represents an inclusive upper limit for a numeric instance. The // value of MUST be a number, @@ -443,9 +491,11 @@ message JSONSchema { } repeated JSONSchemaSimpleTypes type = 35; + // `Format` + string format = 36; // following fields are reserved, as the properties have been omitted from - // OpenAPI v2: format, contentMediaType, contentEncoding, if, then, else - reserved 36 to 41; + // OpenAPI v2: contentMediaType, contentEncoding, if, then, else + reserved 37 to 41; // field 42 is reserved for 'allOf', but in OpenAPI-specific way. // TODO(ivucica): add 'allOf'? reserved 42; @@ -453,6 +503,8 @@ message JSONSchema { // OpenAPI v2: // anyOf, oneOf, not reserved 43 to 45; + // Items in `enum` must be unique https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.5.1 + repeated string enum = 46; } // `Tag` is a representation of OpenAPI v2 specification's Tag object. diff --git a/gateway/runtime/BUILD.bazel b/gateway/runtime/BUILD.bazel index e55634d..55a2770 100644 --- a/gateway/runtime/BUILD.bazel +++ b/gateway/runtime/BUILD.bazel @@ -3,45 +3,46 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") package(default_visibility = ["//visibility:public"]) go_library( - name = "go_default_library", + name = "runtime", srcs = glob( ["*.go"], exclude = ["*_test.go"], ), importpath = "github.com/binchencoder/ease-gateway/gateway/runtime", deps = [ + "@com_github_grpc_ecosystem_grpc_gateway//internal/httprule", + "@com_github_grpc_ecosystem_grpc_gateway//utilities", "//gateway/internal:go_default_library", - "//httpoptions:go_default_library", + "//httpoptions", "@com_github_binchencoder_gateway_proto//data:go_default_library", "@com_github_binchencoder_gateway_proto//frontend:go_default_library", "@com_github_binchencoder_letsgo//grpc:go_default_library", "@com_github_binchencoder_letsgo//hashring:go_default_library", "@com_github_binchencoder_skylb_api//proto:go_default_library", "@com_github_golang_protobuf//ptypes:go_default_library_gen", - "@com_github_grpc_ecosystem_grpc_gateway//utilities:go_default_library", - "@com_github_grpc_ecosystem_grpc_gateway//internal/httprule:go_default_library", "@com_github_pborman_uuid//:go_default_library", "@com_github_golang_protobuf//jsonpb:go_default_library_gen", "@go_googleapis//google/api:httpbody_go_proto", - "@io_bazel_rules_go//proto/wkt:duration_go_proto", "@io_bazel_rules_go//proto/wkt:field_mask_go_proto", - "@io_bazel_rules_go//proto/wkt:timestamp_go_proto", - "@io_bazel_rules_go//proto/wkt:wrappers_go_proto", - "@org_golang_google_grpc//codes:go_default_library", - "@org_golang_google_grpc//grpclog:go_default_library", - "@org_golang_google_grpc//metadata:go_default_library", - "@org_golang_google_grpc//status:go_default_library", - "@org_golang_google_protobuf//encoding/protojson:go_default_library", - "@org_golang_google_protobuf//proto:go_default_library", - "@org_golang_google_protobuf//reflect/protoreflect:go_default_library", - "@org_golang_google_protobuf//reflect/protoregistry:go_default_library", "@org_golang_google_grpc//:go_default_library", + "@org_golang_google_grpc//codes", + "@org_golang_google_grpc//grpclog", + "@org_golang_google_grpc//health/grpc_health_v1", + "@org_golang_google_grpc//metadata", + "@org_golang_google_grpc//status", + "@org_golang_google_protobuf//encoding/protojson", + "@org_golang_google_protobuf//proto", + "@org_golang_google_protobuf//reflect/protoreflect", + "@org_golang_google_protobuf//reflect/protoregistry", + "@org_golang_google_protobuf//types/known/durationpb", + "@org_golang_google_protobuf//types/known/timestamppb", + "@org_golang_google_protobuf//types/known/wrapperspb", "@org_golang_x_net//context:go_default_library", ], ) go_test( - name = "go_default_test", + name = "runtime_test", size = "small", srcs = [ "balancer_test.go", @@ -52,39 +53,40 @@ go_test( "marshal_httpbodyproto_test.go", "marshaler_registry_test.go", "mux_test.go", - "pattern_test.go", - "query_test.go", ], - embed = [":go_default_library"], + embed = [":runtime"], deps = [ "//examples/internal/proto/examplepb:go_default_library", "//gateway/internal:go_default_library", "//gateway/runtime/internal/examplepb:go_default_library", + "@com_github_grpc_ecosystem_grpc_gateway//utilities", "//httpoptions:go_default_library", "@com_github_binchencoder_letsgo//hashring:go_default_library", "@com_github_binchencoder_skylb_api//proto:go_default_library", - "@com_github_grpc_ecosystem_grpc_gateway//utilities:go_default_library", - "@com_github_grpc_ecosystem_grpc_gateway//runtime/internal/examplepb:go_default_library", - "@com_github_golang_protobuf//ptypes:go_default_library_gen", - "@com_github_golang_protobuf//proto:go_default_library", - "@com_github_google_go_cmp//cmp:go_default_library", - "@com_github_google_go_cmp//cmp/cmpopts:go_default_library", + "@com_github_google_go_cmp//cmp", + "@com_github_google_go_cmp//cmp/cmpopts", "@go_googleapis//google/api:httpbody_go_proto", "@go_googleapis//google/rpc:errdetails_go_proto", "@go_googleapis//google/rpc:status_go_proto", - "@io_bazel_rules_go//proto/wkt:duration_go_proto", - "@io_bazel_rules_go//proto/wkt:empty_go_proto", "@io_bazel_rules_go//proto/wkt:field_mask_go_proto", - "@io_bazel_rules_go//proto/wkt:struct_go_proto", - "@io_bazel_rules_go//proto/wkt:timestamp_go_proto", - "@io_bazel_rules_go//proto/wkt:wrappers_go_proto", - "@org_golang_google_grpc//codes:go_default_library", - "@org_golang_google_grpc//metadata:go_default_library", - "@org_golang_google_grpc//status:go_default_library", - "@org_golang_google_protobuf//encoding/protojson:go_default_library", - "@org_golang_google_protobuf//proto:go_default_library", - "@org_golang_google_protobuf//testing/protocmp:go_default_library", "@org_golang_google_grpc//:go_default_library", - "@org_golang_x_net//context:go_default_library", + "@org_golang_google_grpc//codes", + "@org_golang_google_grpc//health/grpc_health_v1", + "@org_golang_google_grpc//metadata", + "@org_golang_google_grpc//status", + "@org_golang_google_protobuf//encoding/protojson", + "@org_golang_google_protobuf//proto", + "@org_golang_google_protobuf//testing/protocmp", + "@org_golang_google_protobuf//types/known/durationpb", + "@org_golang_google_protobuf//types/known/emptypb", + "@org_golang_google_protobuf//types/known/structpb", + "@org_golang_google_protobuf//types/known/timestamppb", + "@org_golang_google_protobuf//types/known/wrapperspb", ], ) + +alias( + name = "go_default_library", + actual = ":runtime", + visibility = ["//visibility:public"], +) diff --git a/gateway/runtime/context.go b/gateway/runtime/context.go index 2c249eb..b5d1e6c 100644 --- a/gateway/runtime/context.go +++ b/gateway/runtime/context.go @@ -41,7 +41,24 @@ var ( DefaultContextTimeout = 0 * time.Second ) -type rpcMethodKey struct{} +// malformedHTTPHeaders lists the headers that the gRPC server may reject outright as malformed. +// See https://github.com/grpc/grpc-go/pull/4803#issuecomment-986093310 for more context. +var malformedHTTPHeaders = map[string]struct{}{ + "connection": {}, +} + +type ( + rpcMethodKey struct{} + httpPathPatternKey struct{} + + AnnotateContextOption func(ctx context.Context) context.Context +) + +func WithHTTPPathPattern(pattern string) AnnotateContextOption { + return func(ctx context.Context) context.Context { + return withHTTPPathPattern(ctx, pattern) + } +} func decodeBinHeader(v string) ([]byte, error) { if len(v)%4 == 0 { @@ -58,8 +75,8 @@ At a minimum, the RemoteAddr is included in the fashion of "X-Forwarded-For", except that the forwarded destination is not another HTTP service but rather a gRPC service. */ -func AnnotateContext(ctx context.Context, mux *ServeMux, req *http.Request, rpcMethodName string) (context.Context, error) { - ctx, md, err := annotateContext(ctx, mux, req, rpcMethodName) +func AnnotateContext(ctx context.Context, mux *ServeMux, req *http.Request, rpcMethodName string, options ...AnnotateContextOption) (context.Context, error) { + ctx, md, err := annotateContext(ctx, mux, req, rpcMethodName, options...) if err != nil { return nil, err } @@ -72,8 +89,8 @@ func AnnotateContext(ctx context.Context, mux *ServeMux, req *http.Request, rpcM // AnnotateIncomingContext adds context information such as metadata from the request. // Attach metadata as incoming context. -func AnnotateIncomingContext(ctx context.Context, mux *ServeMux, req *http.Request, rpcMethodName string) (context.Context, error) { - ctx, md, err := annotateContext(ctx, mux, req, rpcMethodName) +func AnnotateIncomingContext(ctx context.Context, mux *ServeMux, req *http.Request, rpcMethodName string, options ...AnnotateContextOption) (context.Context, error) { + ctx, md, err := annotateContext(ctx, mux, req, rpcMethodName, options...) if err != nil { return nil, err } @@ -84,8 +101,11 @@ func AnnotateIncomingContext(ctx context.Context, mux *ServeMux, req *http.Reque return metadata.NewIncomingContext(ctx, md), nil } -func annotateContext(ctx context.Context, mux *ServeMux, req *http.Request, rpcMethodName string) (context.Context, metadata.MD, error) { +func annotateContext(ctx context.Context, mux *ServeMux, req *http.Request, rpcMethodName string, options ...AnnotateContextOption) (context.Context, metadata.MD, error) { ctx = withRPCMethod(ctx, rpcMethodName) + for _, o := range options { + ctx = o(ctx) + } var pairs []string timeout := DefaultContextTimeout if tm := req.Header.Get(metadataGrpcTimeout); tm != "" { @@ -135,6 +155,7 @@ func annotateContext(ctx context.Context, mux *ServeMux, req *http.Request, rpcM } if timeout != 0 { + //nolint:govet // The context outlives this function ctx, _ = context.WithTimeout(ctx, timeout) } if len(pairs) == 0 { @@ -293,6 +314,13 @@ func isPermanentHTTPHeader(hdr string) bool { return false } +// isMalformedHTTPHeader checks whether header belongs to the list of +// "malformed headers" and would be rejected by the gRPC server. +func isMalformedHTTPHeader(header string) bool { + _, isMalformed := malformedHTTPHeaders[strings.ToLower(header)] + return isMalformed +} + // RPCMethod returns the method string for the server context. The returned // string is in the format of "/package.service/method". func RPCMethod(ctx context.Context) (string, bool) { @@ -310,3 +338,21 @@ func RPCMethod(ctx context.Context) (string, bool) { func withRPCMethod(ctx context.Context, rpcMethodName string) context.Context { return context.WithValue(ctx, rpcMethodKey{}, rpcMethodName) } + +// HTTPPathPattern returns the HTTP path pattern string relating to the HTTP handler, if one exists. +// The format of the returned string is defined by the google.api.http path template type. +func HTTPPathPattern(ctx context.Context) (string, bool) { + m := ctx.Value(httpPathPatternKey{}) + if m == nil { + return "", false + } + ms, ok := m.(string) + if !ok { + return "", false + } + return ms, true +} + +func withHTTPPathPattern(ctx context.Context, httpPathPattern string) context.Context { + return context.WithValue(ctx, httpPathPatternKey{}, httpPathPattern) +} diff --git a/gateway/runtime/context_test.go b/gateway/runtime/context_test.go index b618f60..76f79d8 100644 --- a/gateway/runtime/context_test.go +++ b/gateway/runtime/context_test.go @@ -20,12 +20,13 @@ const ( func TestAnnotateContext_WorksWithEmpty(t *testing.T) { ctx := context.Background() expectedRPCName := "/example.Example/Example" - request, err := http.NewRequest("GET", "http://www.example.com", nil) + expectedHTTPPathPattern := "/v1" + request, err := http.NewRequest("GET", "http://www.example.com/v1", nil) if err != nil { t.Fatalf("http.NewRequest(%q, %q, nil) failed with %v; want success", "GET", "http://www.example.com", err) } request.Header.Add("Some-Irrelevant-Header", "some value") - annotated, err := runtime.AnnotateContext(ctx, runtime.NewServeMux(), request, expectedRPCName) + annotated, err := runtime.AnnotateContext(ctx, runtime.NewServeMux(), request, expectedRPCName, runtime.WithHTTPPathPattern(expectedHTTPPathPattern)) if err != nil { t.Errorf("runtime.AnnotateContext(ctx, %#v) failed with %v; want success", request, err) return @@ -39,7 +40,8 @@ func TestAnnotateContext_WorksWithEmpty(t *testing.T) { func TestAnnotateContext_ForwardsGrpcMetadata(t *testing.T) { ctx := context.Background() expectedRPCName := "/example.Example/Example" - request, err := http.NewRequest("GET", "http://www.example.com", nil) + expectedHTTPPathPattern := "/v1" + request, err := http.NewRequest("GET", "http://www.example.com/v1", nil) if err != nil { t.Fatalf("http.NewRequest(%q, %q, nil) failed with %v; want success", "GET", "http://www.example.com", err) } @@ -48,7 +50,7 @@ func TestAnnotateContext_ForwardsGrpcMetadata(t *testing.T) { request.Header.Add("Grpc-Metadata-Foo-BAZ", "Value2") request.Header.Add("Grpc-Metadata-foo-bAz", "Value3") request.Header.Add("Authorization", "Token 1234567890") - annotated, err := runtime.AnnotateContext(ctx, runtime.NewServeMux(), request, expectedRPCName) + annotated, err := runtime.AnnotateContext(ctx, runtime.NewServeMux(), request, expectedRPCName, runtime.WithHTTPPathPattern(expectedHTTPPathPattern)) if err != nil { t.Errorf("runtime.AnnotateContext(ctx, %#v) failed with %v; want success", request, err) return @@ -74,6 +76,12 @@ func TestAnnotateContext_ForwardsGrpcMetadata(t *testing.T) { } else if m != expectedRPCName { t.Errorf("runtime.RPCMethod(annotated) failed with %s; want %s", m, expectedRPCName) } + + if m, ok := runtime.HTTPPathPattern(annotated); !ok { + t.Errorf("runtime.HTTPPathPattern(annotated) failed with no value; want %s", expectedHTTPPathPattern) + } else if m != expectedHTTPPathPattern { + t.Errorf("runtime.HTTPPathPattern(annotated) failed with %s; want %s", m, expectedHTTPPathPattern) + } } func TestAnnotateContext_ForwardGrpcBinaryMetadata(t *testing.T) { @@ -250,12 +258,13 @@ func TestAnnotateContext_SupportsCustomAnnotators(t *testing.T) { func TestAnnotateIncomingContext_WorksWithEmpty(t *testing.T) { ctx := context.Background() expectedRPCName := "/example.Example/Example" - request, err := http.NewRequest("GET", "http://www.example.com", nil) + expectedHTTPPathPattern := "/v1" + request, err := http.NewRequest("GET", "http://www.example.com/v1", nil) if err != nil { t.Fatalf("http.NewRequest(%q, %q, nil) failed with %v; want success", "GET", "http://www.example.com", err) } request.Header.Add("Some-Irrelevant-Header", "some value") - annotated, err := runtime.AnnotateIncomingContext(ctx, runtime.NewServeMux(), request, expectedRPCName) + annotated, err := runtime.AnnotateIncomingContext(ctx, runtime.NewServeMux(), request, expectedRPCName, runtime.WithHTTPPathPattern(expectedHTTPPathPattern)) if err != nil { t.Errorf("runtime.AnnotateIncomingContext(ctx, %#v) failed with %v; want success", request, err) return @@ -274,7 +283,8 @@ func TestAnnotateIncomingContext_WorksWithEmpty(t *testing.T) { func TestAnnotateIncomingContext_ForwardsGrpcMetadata(t *testing.T) { ctx := context.Background() expectedRPCName := "/example.Example/Example" - request, err := http.NewRequest("GET", "http://www.example.com", nil) + expectedHTTPPathPattern := "/v1" + request, err := http.NewRequest("GET", "http://www.example.com/v1", nil) if err != nil { t.Fatalf("http.NewRequest(%q, %q, nil) failed with %v; want success", "GET", "http://www.example.com", err) } @@ -283,7 +293,7 @@ func TestAnnotateIncomingContext_ForwardsGrpcMetadata(t *testing.T) { request.Header.Add("Grpc-Metadata-Foo-BAZ", "Value2") request.Header.Add("Grpc-Metadata-foo-bAz", "Value3") request.Header.Add("Authorization", "Token 1234567890") - annotated, err := runtime.AnnotateIncomingContext(ctx, runtime.NewServeMux(), request, expectedRPCName) + annotated, err := runtime.AnnotateIncomingContext(ctx, runtime.NewServeMux(), request, expectedRPCName, runtime.WithHTTPPathPattern(expectedHTTPPathPattern)) if err != nil { t.Errorf("runtime.AnnotateIncomingContext(ctx, %#v) failed with %v; want success", request, err) return @@ -309,6 +319,11 @@ func TestAnnotateIncomingContext_ForwardsGrpcMetadata(t *testing.T) { } else if m != expectedRPCName { t.Errorf("runtime.RPCMethod(annotated) failed with %s; want %s", m, expectedRPCName) } + if m, ok := runtime.HTTPPathPattern(annotated); !ok { + t.Errorf("runtime.HTTPPathPattern(annotated) failed with no value; want %s", expectedHTTPPathPattern) + } else if m != expectedHTTPPathPattern { + t.Errorf("runtime.HTTPPathPattern(annotated) failed with %s; want %s", m, expectedHTTPPathPattern) + } } func TestAnnotateIncomingContext_ForwardGrpcBinaryMetadata(t *testing.T) { diff --git a/gateway/runtime/convert.go b/gateway/runtime/convert.go index e122dd3..cfa5407 100644 --- a/gateway/runtime/convert.go +++ b/gateway/runtime/convert.go @@ -6,10 +6,10 @@ import ( "strconv" "strings" - durationpb "github.com/golang/protobuf/ptypes/duration" - timestamppb "github.com/golang/protobuf/ptypes/timestamp" - wrapperspb "github.com/golang/protobuf/ptypes/wrappers" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/types/known/durationpb" + "google.golang.org/protobuf/types/known/timestamppb" + "google.golang.org/protobuf/types/known/wrapperspb" ) // String just returns the given string. @@ -207,6 +207,7 @@ func BytesSlice(val, sep string) ([][]byte, error) { // Timestamp converts the given RFC3339 formatted string into a timestamp.Timestamp. func Timestamp(val string) (*timestamppb.Timestamp, error) { var r timestamppb.Timestamp + val = strconv.Quote(strings.Trim(val, `"`)) unmarshaler := &protojson.UnmarshalOptions{} err := unmarshaler.Unmarshal([]byte(val), &r) if err != nil { @@ -218,6 +219,7 @@ func Timestamp(val string) (*timestamppb.Timestamp, error) { // Duration converts the given string into a timestamp.Duration. func Duration(val string) (*durationpb.Duration, error) { var r durationpb.Duration + val = strconv.Quote(strings.Trim(val, `"`)) unmarshaler := &protojson.UnmarshalOptions{} err := unmarshaler.Unmarshal([]byte(val), &r) if err != nil { @@ -263,7 +265,7 @@ func EnumSlice(val, sep string, enumValMap map[string]int32) ([]int32, error) { } /* - Support fot google.protobuf.wrappers on top of primitive types + Support for google.protobuf.wrappers on top of primitive types */ // StringValue well-known type support as wrapper around string type diff --git a/gateway/runtime/convert_test.go b/gateway/runtime/convert_test.go index 2c95fa1..457c0f8 100644 --- a/gateway/runtime/convert_test.go +++ b/gateway/runtime/convert_test.go @@ -3,11 +3,11 @@ package runtime_test import ( "testing" - durationpb "github.com/golang/protobuf/ptypes/duration" - timestamppb "github.com/golang/protobuf/ptypes/timestamp" // "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" "github.com/binchencoder/ease-gateway/gateway/runtime" "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/durationpb" + "google.golang.org/protobuf/types/known/timestamppb" ) func TestConvertTimestamp(t *testing.T) { @@ -26,6 +26,15 @@ func TestConvertTimestamp(t *testing.T) { }, wanterr: false, }, + { + name: "a valid RFC3339 timestamp without double quotation", + input: "2016-05-10T10:19:13.123Z", + output: ×tamppb.Timestamp{ + Seconds: 1462875553, + Nanos: 123000000, + }, + wanterr: false, + }, { name: "invalid timestamp", input: `"05-10-2016T10:19:13.123Z"`, @@ -82,6 +91,15 @@ func TestConvertDuration(t *testing.T) { }, wanterr: false, }, + { + name: "a valid duration without double quotation", + input: "123.456s", + output: &durationpb.Duration{ + Seconds: 123, + Nanos: 456000000, + }, + wanterr: false, + }, { name: "invalid duration", input: `"123years"`, diff --git a/gateway/runtime/errors.go b/gateway/runtime/errors.go index 43fbb9c..0acfcda 100644 --- a/gateway/runtime/errors.go +++ b/gateway/runtime/errors.go @@ -2,9 +2,9 @@ package runtime import ( "context" + "errors" "io" "net/http" - "strings" "github.com/golang/protobuf/jsonpb" @@ -25,6 +25,17 @@ type StreamErrorHandlerFunc func(context.Context, error) *status.Status // RoutingErrorHandlerFunc is the signature used to configure error handling for routing errors. type RoutingErrorHandlerFunc func(context.Context, *ServeMux, Marshaler, http.ResponseWriter, *http.Request, int) +// HTTPStatusError is the error to use when needing to provide a different HTTP status code for an error +// passed to the DefaultRoutingErrorHandler. +type HTTPStatusError struct { + HTTPStatus int + Err error +} + +func (e *HTTPStatusError) Error() string { + return e.Err.Error() +} + // HTTPStatusFromCode converts a gRPC error code into the corresponding HTTP response status. // See: https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto func HTTPStatusFromCode(code codes.Code) int { @@ -77,6 +88,10 @@ func HTTPError(ctx context.Context, mux *ServeMux, marshaler Marshaler, w http.R // DefaultHTTPErrorHandler is the default error handler. // If "err" is a gRPC Status, the function replies with the status code mapped by HTTPStatusFromCode. +// If "err" is a HTTPStatusError, the function replies with the status code provide by that struct. This is +// intended to allow passing through of specific statuses via the function set via WithRoutingErrorHandler +// for the ServeMux constructor to handle edge cases which the standard mappings in HTTPStatusFromCode +// are insufficient for. // If otherwise, it replies with http.StatusInternalServerError. // // The response body written by this function is a Status message marshaled by the Marshaler. @@ -84,6 +99,11 @@ func DefaultHTTPErrorHandler(ctx context.Context, mux *ServeMux, marshaler Marsh // return Internal when Marshal failed const fallback = `{"code": 13, "message": "failed to marshal error message"}` + var customStatus *HTTPStatusError + if errors.As(err, &customStatus) { + err = customStatus.Err + } + s := status.Convert(err) pb := s.Proto() @@ -93,6 +113,9 @@ func DefaultHTTPErrorHandler(ctx context.Context, mux *ServeMux, marshaler Marsh contentType := marshaler.ContentType(pb) w.Header().Set("Content-Type", contentType) + if s.Code() == codes.Unauthenticated { + w.Header().Set("WWW-Authenticate", s.Message()) + } e := fpb.Error{} desc := s.Message() if erru := jsonpb.UnmarshalString(desc, &e); erru != nil { @@ -103,7 +126,7 @@ func DefaultHTTPErrorHandler(ctx context.Context, mux *ServeMux, marshaler Marsh Error: &e, Message: s.Message(), Code: int32(s.Code()), - Details: s.Proto().GetDetails(), + Details: pb.GetDetails(), } buf, merr := marshaler.Marshal(body) @@ -128,21 +151,24 @@ func DefaultHTTPErrorHandler(ctx context.Context, mux *ServeMux, marshaler Marsh // is acceptable, as described in Section 4.3, a server SHOULD NOT // generate trailer fields that it believes are necessary for the user // agent to receive. - var wantsTrailers bool + doForwardTrailers := requestAcceptsTrailers(r) - if te := r.Header.Get("TE"); strings.Contains(strings.ToLower(te), "trailers") { - wantsTrailers = true + if doForwardTrailers { handleForwardResponseTrailerHeader(w, md) w.Header().Set("Transfer-Encoding", "chunked") } st := HTTPStatusFromCode(s.Code()) + if customStatus != nil { + st = customStatus.HTTPStatus + } + w.WriteHeader(st) if _, err := w.Write(buf); err != nil { grpclog.Infof("Failed to write response: %v", err) } - if wantsTrailers { + if doForwardTrailers { handleForwardResponseTrailer(w, md) } } diff --git a/gateway/runtime/errors_test.go b/gateway/runtime/errors_test.go index 7f91013..a761001 100644 --- a/gateway/runtime/errors_test.go +++ b/gateway/runtime/errors_test.go @@ -61,6 +61,16 @@ func TestDefaultHTTPError(t *testing.T) { contentType: "Custom-Content-Type", msg: "example error", }, + { + err: &runtime.HTTPStatusError{ + HTTPStatus: http.StatusMethodNotAllowed, + Err: status.Error(codes.Unimplemented, http.StatusText(http.StatusMethodNotAllowed)), + }, + status: http.StatusMethodNotAllowed, + marshaler: &runtime.JSONPb{}, + contentType: "application/json", + msg: "Method Not Allowed", + }, } { t.Run(strconv.Itoa(i), func(t *testing.T) { w := httptest.NewRecorder() diff --git a/gateway/runtime/fieldmask.go b/gateway/runtime/fieldmask.go index bdaa79d..0138ed2 100644 --- a/gateway/runtime/fieldmask.go +++ b/gateway/runtime/fieldmask.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "io" + "sort" "google.golang.org/genproto/protobuf/field_mask" "google.golang.org/protobuf/proto" @@ -32,7 +33,6 @@ func FieldMaskFromRequestBody(r io.Reader, msg proto.Message) (*field_mask.Field } queue := []fieldMaskPathItem{{node: root, msg: msg.ProtoReflect()}} - var repeatedChild *fieldMaskPathItem for len(queue) > 0 { // dequeue an item item := queue[0] @@ -63,6 +63,17 @@ func FieldMaskFromRequestBody(r io.Reader, msg proto.Message) (*field_mask.Field continue } + if isProtobufAnyMessage(fd.Message()) { + _, hasTypeField := v.(map[string]interface{})["@type"] + if hasTypeField { + queue = append(queue, fieldMaskPathItem{path: k}) + continue + } else { + return nil, fmt.Errorf("could not find field @type in %q in message %q", k, item.msg.Descriptor().FullName()) + } + + } + child := fieldMaskPathItem{ node: v, } @@ -74,14 +85,9 @@ func FieldMaskFromRequestBody(r io.Reader, msg proto.Message) (*field_mask.Field switch { case fd.IsList(), fd.IsMap(): - if repeatedChild != nil { - // This is implied by the rule that any repeated fields must be - // last in the paths. - // Ref: https://github.com/protocolbuffers/protobuf/blob/6b0ff74ecf63e26c7315f6745de36aff66deb59d/src/google/protobuf/field_mask.proto#L85-L86 - return nil, fmt.Errorf("only one repeated value is allowed per field_mask") - } - repeatedChild = &child - // Don't add to paths until the end + // As per: https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/field_mask.proto#L85-L86 + // Do not recurse into repeated fields. The repeated field goes on the end of the path and we stop. + fm.Paths = append(fm.Paths, child.path) case fd.Message() != nil: child.msg = item.msg.Get(fd).Message() fallthrough @@ -95,15 +101,17 @@ func FieldMaskFromRequestBody(r io.Reader, msg proto.Message) (*field_mask.Field } } - // Add any repeated fields last, as per - // https://github.com/protocolbuffers/protobuf/blob/6b0ff74ecf63e26c7315f6745de36aff66deb59d/src/google/protobuf/field_mask.proto#L85-L86 - if repeatedChild != nil { - fm.Paths = append(fm.Paths, repeatedChild.path) - } + // Sort for deterministic output in the presence + // of repeated fields. + sort.Strings(fm.Paths) return fm, nil } +func isProtobufAnyMessage(md protoreflect.MessageDescriptor) bool { + return md != nil && (md.FullName() == "google.protobuf.Any") +} + func isDynamicProtoMessage(md protoreflect.MessageDescriptor) bool { return md != nil && (md.FullName() == "google.protobuf.Struct" || md.FullName() == "google.protobuf.Value") } diff --git a/gateway/runtime/handler.go b/gateway/runtime/handler.go index 2628c2b..d1e21df 100644 --- a/gateway/runtime/handler.go +++ b/gateway/runtime/handler.go @@ -6,6 +6,7 @@ import ( "io" "net/http" "net/textproto" + "strings" "google.golang.org/genproto/googleapis/api/httpbody" "google.golang.org/grpc/codes" @@ -137,6 +138,19 @@ func ForwardResponseMessage(ctx context.Context, mux *ServeMux, marshaler Marsha } handleForwardResponseServerMetadata(w, mux, md) + + // RFC 7230 https://tools.ietf.org/html/rfc7230#section-4.1.2 + // Unless the request includes a TE header field indicating "trailers" + // is acceptable, as described in Section 4.3, a server SHOULD NOT + // generate trailer fields that it believes are necessary for the user + // agent to receive. + doForwardTrailers := requestAcceptsTrailers(req) + + if doForwardTrailers { + handleForwardResponseTrailerHeader(w, md) + w.Header().Set("Transfer-Encoding", "chunked") + } + handleForwardResponseTrailerHeader(w, md) contentType := marshaler.ContentType(resp) @@ -163,7 +177,14 @@ func ForwardResponseMessage(ctx context.Context, mux *ServeMux, marshaler Marsha grpclog.Infof("Failed to write response: %v", err) } - handleForwardResponseTrailer(w, md) + if doForwardTrailers { + handleForwardResponseTrailer(w, md) + } +} + +func requestAcceptsTrailers(req *http.Request) bool { + te := req.Header.Get("TE") + return strings.Contains(strings.ToLower(te), "trailers") } func handleForwardResponseOptions(ctx context.Context, w http.ResponseWriter, resp proto.Message, opts []func(context.Context, http.ResponseWriter, proto.Message) error) error { @@ -181,10 +202,12 @@ func handleForwardResponseOptions(ctx context.Context, w http.ResponseWriter, re func handleForwardResponseStreamError(ctx context.Context, wroteHeader bool, marshaler Marshaler, w http.ResponseWriter, req *http.Request, mux *ServeMux, err error) { st := mux.streamErrorHandler(ctx, err) + msg := errorChunk(st) if !wroteHeader { + w.Header().Set("Content-Type", marshaler.ContentType(msg)) w.WriteHeader(HTTPStatusFromCode(st.Code())) } - buf, merr := marshaler.Marshal(errorChunk(st)) + buf, merr := marshaler.Marshal(msg) if merr != nil { grpclog.Infof("Failed to marshal an error: %v", merr) return diff --git a/gateway/runtime/handler_test.go b/gateway/runtime/handler_test.go index d0c171e..13de50d 100644 --- a/gateway/runtime/handler_test.go +++ b/gateway/runtime/handler_test.go @@ -111,6 +111,9 @@ func TestForwardResponseStream(t *testing.T) { t.Errorf("Failed to read response body with %v", err) } w.Body.Close() + if len(body) > 0 && w.Header.Get("Content-Type") != "application/json" { + t.Errorf("Content-Type %s want application/json", w.Header.Get("Content-Type")) + } var want []byte for i, msg := range tt.msgs { @@ -241,6 +244,9 @@ func TestForwardResponseStreamCustomMarshaler(t *testing.T) { t.Errorf("Failed to read response body with %v", err) } w.Body.Close() + if len(body) > 0 && w.Header.Get("Content-Type") != "Custom-Content-Type" { + t.Errorf("Content-Type %s want Custom-Content-Type", w.Header.Get("Content-Type")) + } var want []byte for _, msg := range tt.msgs { diff --git a/gateway/runtime/internal/examplepb/BUILD.bazel b/gateway/runtime/internal/examplepb/BUILD.bazel index c6f1a1d..2acced4 100644 --- a/gateway/runtime/internal/examplepb/BUILD.bazel +++ b/gateway/runtime/internal/examplepb/BUILD.bazel @@ -12,6 +12,7 @@ proto_library( "proto3.proto", ], deps = [ + "@com_google_protobuf//:any_proto", "@com_google_protobuf//:duration_proto", "@com_google_protobuf//:empty_proto", "@com_google_protobuf//:field_mask_proto", @@ -34,7 +35,13 @@ go_proto_library( ) go_library( - name = "go_default_library", + name = "examplepb", embed = [":examplepb_go_proto"], importpath = "github.com/binchencoder/ease-gateway/gateway/runtime/internal/examplepb", ) + +alias( + name = "go_default_library", + actual = ":examplepb", + visibility = ["//runtime:__subpackages__"], +) diff --git a/gateway/runtime/internal/examplepb/proto3.pb.go b/gateway/runtime/internal/examplepb/proto3.pb.go old mode 100644 new mode 100755 index 023c967..faacca3 --- a/gateway/runtime/internal/examplepb/proto3.pb.go +++ b/gateway/runtime/internal/examplepb/proto3.pb.go @@ -1,19 +1,18 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.23.0 -// protoc v3.12.3 +// protoc-gen-go v1.27.1 +// protoc v3.19.4 // source: gateway/runtime/internal/examplepb/proto3.proto package examplepb import ( - proto "github.com/golang/protobuf/proto" - duration "github.com/golang/protobuf/ptypes/duration" - timestamp "github.com/golang/protobuf/ptypes/timestamp" - wrappers "github.com/golang/protobuf/ptypes/wrappers" - field_mask "google.golang.org/genproto/protobuf/field_mask" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + durationpb "google.golang.org/protobuf/types/known/durationpb" + fieldmaskpb "google.golang.org/protobuf/types/known/fieldmaskpb" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + wrapperspb "google.golang.org/protobuf/types/known/wrapperspb" reflect "reflect" sync "sync" ) @@ -25,10 +24,6 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - type EnumValue int32 const ( @@ -83,51 +78,53 @@ type Proto3Message struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // Next number: 46 - Nested *Proto3Message `protobuf:"bytes,41,opt,name=nested,proto3" json:"nested,omitempty"` - FloatValue float32 `protobuf:"fixed32,42,opt,name=float_value,json=floatValue,proto3" json:"float_value,omitempty"` - DoubleValue float64 `protobuf:"fixed64,43,opt,name=double_value,json=doubleValue,proto3" json:"double_value,omitempty"` - Int64Value int64 `protobuf:"varint,3,opt,name=int64_value,json=int64Value,proto3" json:"int64_value,omitempty"` - Int32Value int32 `protobuf:"varint,4,opt,name=int32_value,json=int32Value,proto3" json:"int32_value,omitempty"` - Uint64Value uint64 `protobuf:"varint,5,opt,name=uint64_value,json=uint64Value,proto3" json:"uint64_value,omitempty"` - Uint32Value uint32 `protobuf:"varint,6,opt,name=uint32_value,json=uint32Value,proto3" json:"uint32_value,omitempty"` - BoolValue bool `protobuf:"varint,7,opt,name=bool_value,json=boolValue,proto3" json:"bool_value,omitempty"` - StringValue string `protobuf:"bytes,8,opt,name=string_value,json=stringValue,proto3" json:"string_value,omitempty"` - BytesValue []byte `protobuf:"bytes,9,opt,name=bytes_value,json=bytesValue,proto3" json:"bytes_value,omitempty"` - RepeatedValue []string `protobuf:"bytes,10,rep,name=repeated_value,json=repeatedValue,proto3" json:"repeated_value,omitempty"` - RepeatedMessage []*wrappers.UInt64Value `protobuf:"bytes,44,rep,name=repeated_message,json=repeatedMessage,proto3" json:"repeated_message,omitempty"` - EnumValue EnumValue `protobuf:"varint,11,opt,name=enum_value,json=enumValue,proto3,enum=ease.gateway.runtime.internal.examplepb.EnumValue" json:"enum_value,omitempty"` - RepeatedEnum []EnumValue `protobuf:"varint,12,rep,packed,name=repeated_enum,json=repeatedEnum,proto3,enum=ease.gateway.runtime.internal.examplepb.EnumValue" json:"repeated_enum,omitempty"` - TimestampValue *timestamp.Timestamp `protobuf:"bytes,13,opt,name=timestamp_value,json=timestampValue,proto3" json:"timestamp_value,omitempty"` - DurationValue *duration.Duration `protobuf:"bytes,14,opt,name=duration_value,json=durationValue,proto3" json:"duration_value,omitempty"` - FieldmaskValue *field_mask.FieldMask `protobuf:"bytes,15,opt,name=fieldmask_value,json=fieldmaskValue,proto3" json:"fieldmask_value,omitempty"` + Nested *Proto3Message `protobuf:"bytes,41,opt,name=nested,proto3" json:"nested,omitempty"` + FloatValue float32 `protobuf:"fixed32,42,opt,name=float_value,json=floatValue,proto3" json:"float_value,omitempty"` + DoubleValue float64 `protobuf:"fixed64,43,opt,name=double_value,json=doubleValue,proto3" json:"double_value,omitempty"` + Int64Value int64 `protobuf:"varint,3,opt,name=int64_value,json=int64Value,proto3" json:"int64_value,omitempty"` + Int32Value int32 `protobuf:"varint,4,opt,name=int32_value,json=int32Value,proto3" json:"int32_value,omitempty"` + Uint64Value uint64 `protobuf:"varint,5,opt,name=uint64_value,json=uint64Value,proto3" json:"uint64_value,omitempty"` + Uint32Value uint32 `protobuf:"varint,6,opt,name=uint32_value,json=uint32Value,proto3" json:"uint32_value,omitempty"` + BoolValue bool `protobuf:"varint,7,opt,name=bool_value,json=boolValue,proto3" json:"bool_value,omitempty"` + StringValue string `protobuf:"bytes,8,opt,name=string_value,json=stringValue,proto3" json:"string_value,omitempty"` + BytesValue []byte `protobuf:"bytes,9,opt,name=bytes_value,json=bytesValue,proto3" json:"bytes_value,omitempty"` + RepeatedValue []string `protobuf:"bytes,10,rep,name=repeated_value,json=repeatedValue,proto3" json:"repeated_value,omitempty"` + RepeatedMessage []*wrapperspb.UInt64Value `protobuf:"bytes,44,rep,name=repeated_message,json=repeatedMessage,proto3" json:"repeated_message,omitempty"` + EnumValue EnumValue `protobuf:"varint,11,opt,name=enum_value,json=enumValue,proto3,enum=ease.gateway.runtime.internal.examplepb.EnumValue" json:"enum_value,omitempty"` + RepeatedEnum []EnumValue `protobuf:"varint,12,rep,packed,name=repeated_enum,json=repeatedEnum,proto3,enum=ease.gateway.runtime.internal.examplepb.EnumValue" json:"repeated_enum,omitempty"` + TimestampValue *timestamppb.Timestamp `protobuf:"bytes,13,opt,name=timestamp_value,json=timestampValue,proto3" json:"timestamp_value,omitempty"` + DurationValue *durationpb.Duration `protobuf:"bytes,14,opt,name=duration_value,json=durationValue,proto3" json:"duration_value,omitempty"` + FieldmaskValue *fieldmaskpb.FieldMask `protobuf:"bytes,15,opt,name=fieldmask_value,json=fieldmaskValue,proto3" json:"fieldmask_value,omitempty"` // Types that are assignable to OneofValue: // *Proto3Message_OneofBoolValue // *Proto3Message_OneofStringValue - OneofValue isProto3Message_OneofValue `protobuf_oneof:"oneof_value"` - WrapperDoubleValue *wrappers.DoubleValue `protobuf:"bytes,17,opt,name=wrapper_double_value,json=wrapperDoubleValue,proto3" json:"wrapper_double_value,omitempty"` - WrapperFloatValue *wrappers.FloatValue `protobuf:"bytes,18,opt,name=wrapper_float_value,json=wrapperFloatValue,proto3" json:"wrapper_float_value,omitempty"` - WrapperInt64Value *wrappers.Int64Value `protobuf:"bytes,19,opt,name=wrapper_int64_value,json=wrapperInt64Value,proto3" json:"wrapper_int64_value,omitempty"` - WrapperInt32Value *wrappers.Int32Value `protobuf:"bytes,20,opt,name=wrapper_int32_value,json=wrapperInt32Value,proto3" json:"wrapper_int32_value,omitempty"` - WrapperUInt64Value *wrappers.UInt64Value `protobuf:"bytes,21,opt,name=wrapper_u_int64_value,json=wrapperUInt64Value,proto3" json:"wrapper_u_int64_value,omitempty"` - WrapperUInt32Value *wrappers.UInt32Value `protobuf:"bytes,22,opt,name=wrapper_u_int32_value,json=wrapperUInt32Value,proto3" json:"wrapper_u_int32_value,omitempty"` - WrapperBoolValue *wrappers.BoolValue `protobuf:"bytes,23,opt,name=wrapper_bool_value,json=wrapperBoolValue,proto3" json:"wrapper_bool_value,omitempty"` - WrapperStringValue *wrappers.StringValue `protobuf:"bytes,24,opt,name=wrapper_string_value,json=wrapperStringValue,proto3" json:"wrapper_string_value,omitempty"` - WrapperBytesValue *wrappers.BytesValue `protobuf:"bytes,25,opt,name=wrapper_bytes_value,json=wrapperBytesValue,proto3" json:"wrapper_bytes_value,omitempty"` - MapValue map[string]string `protobuf:"bytes,26,rep,name=map_value,json=mapValue,proto3" json:"map_value,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - MapValue2 map[string]int32 `protobuf:"bytes,27,rep,name=map_value2,json=mapValue2,proto3" json:"map_value2,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` - MapValue3 map[int32]string `protobuf:"bytes,28,rep,name=map_value3,json=mapValue3,proto3" json:"map_value3,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - MapValue4 map[string]int64 `protobuf:"bytes,29,rep,name=map_value4,json=mapValue4,proto3" json:"map_value4,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` - MapValue5 map[int64]string `protobuf:"bytes,30,rep,name=map_value5,json=mapValue5,proto3" json:"map_value5,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - MapValue6 map[string]uint32 `protobuf:"bytes,31,rep,name=map_value6,json=mapValue6,proto3" json:"map_value6,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` - MapValue7 map[uint32]string `protobuf:"bytes,32,rep,name=map_value7,json=mapValue7,proto3" json:"map_value7,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - MapValue8 map[string]uint64 `protobuf:"bytes,33,rep,name=map_value8,json=mapValue8,proto3" json:"map_value8,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` - MapValue9 map[uint64]string `protobuf:"bytes,34,rep,name=map_value9,json=mapValue9,proto3" json:"map_value9,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - MapValue10 map[string]float32 `protobuf:"bytes,35,rep,name=map_value10,json=mapValue10,proto3" json:"map_value10,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"fixed32,2,opt,name=value,proto3"` - MapValue12 map[string]float64 `protobuf:"bytes,37,rep,name=map_value12,json=mapValue12,proto3" json:"map_value12,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"fixed64,2,opt,name=value,proto3"` - MapValue14 map[string]bool `protobuf:"bytes,39,rep,name=map_value14,json=mapValue14,proto3" json:"map_value14,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` - MapValue15 map[bool]string `protobuf:"bytes,40,rep,name=map_value15,json=mapValue15,proto3" json:"map_value15,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - MapValue16 map[string]*wrappers.UInt64Value `protobuf:"bytes,45,rep,name=map_value16,json=mapValue16,proto3" json:"map_value16,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + OneofValue isProto3Message_OneofValue `protobuf_oneof:"oneof_value"` + // Types that are assignable to NestedOneofValue: + // *Proto3Message_NestedOneofValueOne + NestedOneofValue isProto3Message_NestedOneofValue `protobuf_oneof:"nested_oneof_value"` + WrapperDoubleValue *wrapperspb.DoubleValue `protobuf:"bytes,17,opt,name=wrapper_double_value,json=wrapperDoubleValue,proto3" json:"wrapper_double_value,omitempty"` + WrapperFloatValue *wrapperspb.FloatValue `protobuf:"bytes,18,opt,name=wrapper_float_value,json=wrapperFloatValue,proto3" json:"wrapper_float_value,omitempty"` + WrapperInt64Value *wrapperspb.Int64Value `protobuf:"bytes,19,opt,name=wrapper_int64_value,json=wrapperInt64Value,proto3" json:"wrapper_int64_value,omitempty"` + WrapperInt32Value *wrapperspb.Int32Value `protobuf:"bytes,20,opt,name=wrapper_int32_value,json=wrapperInt32Value,proto3" json:"wrapper_int32_value,omitempty"` + WrapperUInt64Value *wrapperspb.UInt64Value `protobuf:"bytes,21,opt,name=wrapper_u_int64_value,json=wrapperUInt64Value,proto3" json:"wrapper_u_int64_value,omitempty"` + WrapperUInt32Value *wrapperspb.UInt32Value `protobuf:"bytes,22,opt,name=wrapper_u_int32_value,json=wrapperUInt32Value,proto3" json:"wrapper_u_int32_value,omitempty"` + WrapperBoolValue *wrapperspb.BoolValue `protobuf:"bytes,23,opt,name=wrapper_bool_value,json=wrapperBoolValue,proto3" json:"wrapper_bool_value,omitempty"` + WrapperStringValue *wrapperspb.StringValue `protobuf:"bytes,24,opt,name=wrapper_string_value,json=wrapperStringValue,proto3" json:"wrapper_string_value,omitempty"` + WrapperBytesValue *wrapperspb.BytesValue `protobuf:"bytes,25,opt,name=wrapper_bytes_value,json=wrapperBytesValue,proto3" json:"wrapper_bytes_value,omitempty"` + MapValue map[string]string `protobuf:"bytes,26,rep,name=map_value,json=mapValue,proto3" json:"map_value,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + MapValue2 map[string]int32 `protobuf:"bytes,27,rep,name=map_value2,json=mapValue2,proto3" json:"map_value2,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` + MapValue3 map[int32]string `protobuf:"bytes,28,rep,name=map_value3,json=mapValue3,proto3" json:"map_value3,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + MapValue4 map[string]int64 `protobuf:"bytes,29,rep,name=map_value4,json=mapValue4,proto3" json:"map_value4,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` + MapValue5 map[int64]string `protobuf:"bytes,30,rep,name=map_value5,json=mapValue5,proto3" json:"map_value5,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + MapValue6 map[string]uint32 `protobuf:"bytes,31,rep,name=map_value6,json=mapValue6,proto3" json:"map_value6,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` + MapValue7 map[uint32]string `protobuf:"bytes,32,rep,name=map_value7,json=mapValue7,proto3" json:"map_value7,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + MapValue8 map[string]uint64 `protobuf:"bytes,33,rep,name=map_value8,json=mapValue8,proto3" json:"map_value8,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` + MapValue9 map[uint64]string `protobuf:"bytes,34,rep,name=map_value9,json=mapValue9,proto3" json:"map_value9,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + MapValue10 map[string]float32 `protobuf:"bytes,35,rep,name=map_value10,json=mapValue10,proto3" json:"map_value10,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"fixed32,2,opt,name=value,proto3"` + MapValue12 map[string]float64 `protobuf:"bytes,37,rep,name=map_value12,json=mapValue12,proto3" json:"map_value12,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"fixed64,2,opt,name=value,proto3"` + MapValue14 map[string]bool `protobuf:"bytes,39,rep,name=map_value14,json=mapValue14,proto3" json:"map_value14,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` + MapValue15 map[bool]string `protobuf:"bytes,40,rep,name=map_value15,json=mapValue15,proto3" json:"map_value15,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + MapValue16 map[string]*wrapperspb.UInt64Value `protobuf:"bytes,45,rep,name=map_value16,json=mapValue16,proto3" json:"map_value16,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } func (x *Proto3Message) Reset() { @@ -239,7 +236,7 @@ func (x *Proto3Message) GetRepeatedValue() []string { return nil } -func (x *Proto3Message) GetRepeatedMessage() []*wrappers.UInt64Value { +func (x *Proto3Message) GetRepeatedMessage() []*wrapperspb.UInt64Value { if x != nil { return x.RepeatedMessage } @@ -260,21 +257,21 @@ func (x *Proto3Message) GetRepeatedEnum() []EnumValue { return nil } -func (x *Proto3Message) GetTimestampValue() *timestamp.Timestamp { +func (x *Proto3Message) GetTimestampValue() *timestamppb.Timestamp { if x != nil { return x.TimestampValue } return nil } -func (x *Proto3Message) GetDurationValue() *duration.Duration { +func (x *Proto3Message) GetDurationValue() *durationpb.Duration { if x != nil { return x.DurationValue } return nil } -func (x *Proto3Message) GetFieldmaskValue() *field_mask.FieldMask { +func (x *Proto3Message) GetFieldmaskValue() *fieldmaskpb.FieldMask { if x != nil { return x.FieldmaskValue } @@ -302,63 +299,77 @@ func (x *Proto3Message) GetOneofStringValue() string { return "" } -func (x *Proto3Message) GetWrapperDoubleValue() *wrappers.DoubleValue { +func (m *Proto3Message) GetNestedOneofValue() isProto3Message_NestedOneofValue { + if m != nil { + return m.NestedOneofValue + } + return nil +} + +func (x *Proto3Message) GetNestedOneofValueOne() *Proto3Message { + if x, ok := x.GetNestedOneofValue().(*Proto3Message_NestedOneofValueOne); ok { + return x.NestedOneofValueOne + } + return nil +} + +func (x *Proto3Message) GetWrapperDoubleValue() *wrapperspb.DoubleValue { if x != nil { return x.WrapperDoubleValue } return nil } -func (x *Proto3Message) GetWrapperFloatValue() *wrappers.FloatValue { +func (x *Proto3Message) GetWrapperFloatValue() *wrapperspb.FloatValue { if x != nil { return x.WrapperFloatValue } return nil } -func (x *Proto3Message) GetWrapperInt64Value() *wrappers.Int64Value { +func (x *Proto3Message) GetWrapperInt64Value() *wrapperspb.Int64Value { if x != nil { return x.WrapperInt64Value } return nil } -func (x *Proto3Message) GetWrapperInt32Value() *wrappers.Int32Value { +func (x *Proto3Message) GetWrapperInt32Value() *wrapperspb.Int32Value { if x != nil { return x.WrapperInt32Value } return nil } -func (x *Proto3Message) GetWrapperUInt64Value() *wrappers.UInt64Value { +func (x *Proto3Message) GetWrapperUInt64Value() *wrapperspb.UInt64Value { if x != nil { return x.WrapperUInt64Value } return nil } -func (x *Proto3Message) GetWrapperUInt32Value() *wrappers.UInt32Value { +func (x *Proto3Message) GetWrapperUInt32Value() *wrapperspb.UInt32Value { if x != nil { return x.WrapperUInt32Value } return nil } -func (x *Proto3Message) GetWrapperBoolValue() *wrappers.BoolValue { +func (x *Proto3Message) GetWrapperBoolValue() *wrapperspb.BoolValue { if x != nil { return x.WrapperBoolValue } return nil } -func (x *Proto3Message) GetWrapperStringValue() *wrappers.StringValue { +func (x *Proto3Message) GetWrapperStringValue() *wrapperspb.StringValue { if x != nil { return x.WrapperStringValue } return nil } -func (x *Proto3Message) GetWrapperBytesValue() *wrappers.BytesValue { +func (x *Proto3Message) GetWrapperBytesValue() *wrapperspb.BytesValue { if x != nil { return x.WrapperBytesValue } @@ -456,7 +467,7 @@ func (x *Proto3Message) GetMapValue15() map[bool]string { return nil } -func (x *Proto3Message) GetMapValue16() map[string]*wrappers.UInt64Value { +func (x *Proto3Message) GetMapValue16() map[string]*wrapperspb.UInt64Value { if x != nil { return x.MapValue16 } @@ -479,6 +490,16 @@ func (*Proto3Message_OneofBoolValue) isProto3Message_OneofValue() {} func (*Proto3Message_OneofStringValue) isProto3Message_OneofValue() {} +type isProto3Message_NestedOneofValue interface { + isProto3Message_NestedOneofValue() +} + +type Proto3Message_NestedOneofValueOne struct { + NestedOneofValueOne *Proto3Message `protobuf:"bytes,46,opt,name=nested_oneof_value_one,json=nestedOneofValueOne,proto3,oneof"` +} + +func (*Proto3Message_NestedOneofValueOne) isProto3Message_NestedOneofValue() {} + var File_gateway_runtime_internal_examplepb_proto3_proto protoreflect.FileDescriptor var file_gateway_runtime_internal_examplepb_proto3_proto_rawDesc = []byte{ @@ -495,7 +516,7 @@ var file_gateway_runtime_internal_examplepb_proto3_proto_rawDesc = []byte{ 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x77, - 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc7, 0x1f, + 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xcc, 0x20, 0x0a, 0x0d, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x4e, 0x0a, 0x06, 0x6e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x18, 0x29, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, @@ -557,205 +578,214 @@ var file_gateway_runtime_internal_examplepb_proto3_proto_rawDesc = []byte{ 0x75, 0x65, 0x12, 0x2e, 0x0a, 0x12, 0x6f, 0x6e, 0x65, 0x6f, 0x66, 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x10, 0x6f, 0x6e, 0x65, 0x6f, 0x66, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, - 0x75, 0x65, 0x12, 0x4e, 0x0a, 0x14, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x5f, 0x64, 0x6f, - 0x75, 0x62, 0x6c, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x44, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x12, - 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x44, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, - 0x75, 0x65, 0x12, 0x4b, 0x0a, 0x13, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x5f, 0x66, 0x6c, - 0x6f, 0x61, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x11, 0x77, 0x72, - 0x61, 0x70, 0x70, 0x65, 0x72, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, - 0x4b, 0x0a, 0x13, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x74, 0x36, 0x34, - 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, - 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x11, 0x77, 0x72, 0x61, 0x70, 0x70, - 0x65, 0x72, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x4b, 0x0a, 0x13, - 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x5f, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, 0x6e, 0x74, 0x33, - 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x11, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x49, - 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x4f, 0x0a, 0x15, 0x77, 0x72, 0x61, - 0x70, 0x70, 0x65, 0x72, 0x5f, 0x75, 0x5f, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x5f, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x36, - 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x12, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x55, - 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x4f, 0x0a, 0x15, 0x77, 0x72, - 0x61, 0x70, 0x70, 0x65, 0x72, 0x5f, 0x75, 0x5f, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x5f, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, - 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x12, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, - 0x55, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x48, 0x0a, 0x12, 0x77, - 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x5f, 0x62, 0x6f, 0x6f, 0x6c, 0x5f, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x18, 0x17, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, - 0x6c, 0x75, 0x65, 0x52, 0x10, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x42, 0x6f, 0x6f, 0x6c, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x4e, 0x0a, 0x14, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, - 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x18, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, - 0x65, 0x52, 0x12, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x4b, 0x0a, 0x13, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, - 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x19, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x79, 0x74, 0x65, 0x73, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, - 0x11, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x42, 0x79, 0x74, 0x65, 0x73, 0x56, 0x61, 0x6c, - 0x75, 0x65, 0x12, 0x61, 0x0a, 0x09, 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, - 0x1a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x44, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, - 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, - 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, - 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, - 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x61, 0x70, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x64, 0x0a, 0x0a, 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x32, 0x18, 0x1b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x65, 0x61, 0x73, 0x65, + 0x75, 0x65, 0x12, 0x6d, 0x0a, 0x16, 0x6e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x6f, 0x6e, 0x65, + 0x6f, 0x66, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x6f, 0x6e, 0x65, 0x18, 0x2e, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, + 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, + 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, + 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x01, 0x52, 0x13, 0x6e, 0x65, + 0x73, 0x74, 0x65, 0x64, 0x4f, 0x6e, 0x65, 0x6f, 0x66, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4f, 0x6e, + 0x65, 0x12, 0x4e, 0x0a, 0x14, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x5f, 0x64, 0x6f, 0x75, + 0x62, 0x6c, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x44, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x12, 0x77, + 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x44, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x12, 0x4b, 0x0a, 0x13, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x5f, 0x66, 0x6c, 0x6f, + 0x61, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x11, 0x77, 0x72, 0x61, + 0x70, 0x70, 0x65, 0x72, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x4b, + 0x0a, 0x13, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x5f, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, 0x6e, + 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x11, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, + 0x72, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x4b, 0x0a, 0x13, 0x77, + 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x5f, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, 0x6e, 0x74, 0x33, 0x32, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x11, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x49, 0x6e, + 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x4f, 0x0a, 0x15, 0x77, 0x72, 0x61, 0x70, + 0x70, 0x65, 0x72, 0x5f, 0x75, 0x5f, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x5f, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x36, 0x34, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x12, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x55, 0x49, + 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x4f, 0x0a, 0x15, 0x77, 0x72, 0x61, + 0x70, 0x70, 0x65, 0x72, 0x5f, 0x75, 0x5f, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x5f, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x33, + 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x12, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x55, + 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x48, 0x0a, 0x12, 0x77, 0x72, + 0x61, 0x70, 0x70, 0x65, 0x72, 0x5f, 0x62, 0x6f, 0x6f, 0x6c, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0x17, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x52, 0x10, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x42, 0x6f, 0x6f, 0x6c, 0x56, + 0x61, 0x6c, 0x75, 0x65, 0x12, 0x4e, 0x0a, 0x14, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x5f, + 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x18, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x52, 0x12, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, + 0x61, 0x6c, 0x75, 0x65, 0x12, 0x4b, 0x0a, 0x13, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x5f, + 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x19, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x42, 0x79, 0x74, 0x65, 0x73, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x11, + 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x42, 0x79, 0x74, 0x65, 0x73, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x12, 0x61, 0x0a, 0x09, 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x1a, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x44, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, + 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, + 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, + 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x61, 0x70, 0x56, + 0x61, 0x6c, 0x75, 0x65, 0x12, 0x64, 0x0a, 0x0a, 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x32, 0x18, 0x1b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, + 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, + 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, + 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x2e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x32, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, + 0x09, 0x6d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x32, 0x12, 0x64, 0x0a, 0x0a, 0x6d, 0x61, + 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x33, 0x18, 0x1c, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, + 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, + 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x65, + 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x33, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x6d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x33, + 0x12, 0x64, 0x0a, 0x0a, 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x34, 0x18, 0x1d, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, + 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, + 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, + 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x34, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x6d, 0x61, 0x70, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x34, 0x12, 0x64, 0x0a, 0x0a, 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x35, 0x18, 0x1e, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x65, 0x61, 0x73, + 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, + 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, + 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x35, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x52, 0x09, 0x6d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x35, 0x12, 0x64, 0x0a, 0x0a, + 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x36, 0x18, 0x1f, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x45, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, + 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, + 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, + 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x36, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x6d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x36, 0x12, 0x64, 0x0a, 0x0a, 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x37, + 0x18, 0x20, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, + 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, + 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, + 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x37, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x6d, + 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x37, 0x12, 0x64, 0x0a, 0x0a, 0x6d, 0x61, 0x70, 0x5f, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x38, 0x18, 0x21, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x65, + 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, + 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, + 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x38, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x09, 0x6d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x38, 0x12, 0x64, + 0x0a, 0x0a, 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x39, 0x18, 0x22, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, + 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, + 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, + 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, 0x56, 0x61, + 0x6c, 0x75, 0x65, 0x39, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x6d, 0x61, 0x70, 0x56, 0x61, + 0x6c, 0x75, 0x65, 0x39, 0x12, 0x67, 0x0a, 0x0b, 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x31, 0x30, 0x18, 0x23, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x46, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x2e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x32, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x52, 0x09, 0x6d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x32, 0x12, 0x64, 0x0a, 0x0a, 0x6d, - 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x33, 0x18, 0x1c, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x45, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, - 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, - 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x33, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, - 0x33, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x6d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, - 0x33, 0x12, 0x64, 0x0a, 0x0a, 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x34, 0x18, - 0x1d, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, - 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, - 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, - 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, - 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x34, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x6d, 0x61, - 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x34, 0x12, 0x64, 0x0a, 0x0a, 0x6d, 0x61, 0x70, 0x5f, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x35, 0x18, 0x1e, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x65, 0x61, + 0x65, 0x2e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x30, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x52, 0x0a, 0x6d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x30, 0x12, 0x67, 0x0a, + 0x0b, 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x32, 0x18, 0x25, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x46, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, + 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, + 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, + 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, 0x56, 0x61, + 0x6c, 0x75, 0x65, 0x31, 0x32, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x6d, 0x61, 0x70, 0x56, + 0x61, 0x6c, 0x75, 0x65, 0x31, 0x32, 0x12, 0x67, 0x0a, 0x0b, 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x31, 0x34, 0x18, 0x27, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x46, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x35, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x52, 0x09, 0x6d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x35, 0x12, 0x64, 0x0a, - 0x0a, 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x36, 0x18, 0x1f, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x45, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, - 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, - 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x74, - 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, - 0x75, 0x65, 0x36, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x6d, 0x61, 0x70, 0x56, 0x61, 0x6c, - 0x75, 0x65, 0x36, 0x12, 0x64, 0x0a, 0x0a, 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x37, 0x18, 0x20, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, - 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, - 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, - 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, - 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x37, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, - 0x6d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x37, 0x12, 0x64, 0x0a, 0x0a, 0x6d, 0x61, 0x70, - 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x38, 0x18, 0x21, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, + 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x34, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x0a, 0x6d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x34, 0x12, + 0x67, 0x0a, 0x0b, 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x35, 0x18, 0x28, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x46, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, + 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, + 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, + 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x35, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x6d, 0x61, + 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x35, 0x12, 0x67, 0x0a, 0x0b, 0x6d, 0x61, 0x70, 0x5f, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x36, 0x18, 0x2d, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x46, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x38, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x6d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x38, 0x12, - 0x64, 0x0a, 0x0a, 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x39, 0x18, 0x22, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, - 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, - 0x6e, 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, 0x72, - 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, 0x56, - 0x61, 0x6c, 0x75, 0x65, 0x39, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x6d, 0x61, 0x70, 0x56, - 0x61, 0x6c, 0x75, 0x65, 0x39, 0x12, 0x67, 0x0a, 0x0b, 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x31, 0x30, 0x18, 0x23, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x46, 0x2e, 0x65, 0x61, 0x73, - 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, - 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, - 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x30, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x52, 0x0a, 0x6d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x30, 0x12, 0x67, - 0x0a, 0x0b, 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x32, 0x18, 0x25, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x46, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, - 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, - 0x6e, 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, 0x72, - 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, 0x56, - 0x61, 0x6c, 0x75, 0x65, 0x31, 0x32, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x6d, 0x61, 0x70, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x32, 0x12, 0x67, 0x0a, 0x0b, 0x6d, 0x61, 0x70, 0x5f, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x31, 0x34, 0x18, 0x27, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x46, 0x2e, 0x65, - 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, - 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, - 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x34, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x6d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x34, - 0x12, 0x67, 0x0a, 0x0b, 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x35, 0x18, - 0x28, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x46, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, - 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, - 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, - 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, - 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x35, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x6d, - 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x35, 0x12, 0x67, 0x0a, 0x0b, 0x6d, 0x61, 0x70, - 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x36, 0x18, 0x2d, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x46, - 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, - 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x65, - 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, - 0x36, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x6d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, - 0x31, 0x36, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x45, 0x6e, - 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, - 0x3c, 0x0a, 0x0e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x32, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, - 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x05, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3c, 0x0a, - 0x0e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x33, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, - 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x6b, 0x65, - 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3c, 0x0a, 0x0e, 0x4d, - 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x34, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, - 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, - 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3c, 0x0a, 0x0e, 0x4d, 0x61, 0x70, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x35, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, - 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3c, 0x0a, 0x0e, 0x4d, 0x61, 0x70, 0x56, 0x61, - 0x6c, 0x75, 0x65, 0x36, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3c, 0x0a, 0x0e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, - 0x65, 0x37, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, - 0x02, 0x38, 0x01, 0x1a, 0x3c, 0x0a, 0x0e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x38, - 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, - 0x01, 0x1a, 0x3c, 0x0a, 0x0e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x39, 0x45, 0x6e, - 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, - 0x3d, 0x0a, 0x0f, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x30, 0x45, 0x6e, 0x74, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x36, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x6d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, + 0x36, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x02, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3d, - 0x0a, 0x0f, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x32, 0x45, 0x6e, 0x74, 0x72, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3c, + 0x0a, 0x0e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x32, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, + 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3c, 0x0a, 0x0e, + 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x33, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, + 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x6b, 0x65, 0x79, + 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3c, 0x0a, 0x0e, 0x4d, 0x61, + 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x34, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, + 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, + 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3c, 0x0a, 0x0e, 0x4d, 0x61, 0x70, 0x56, + 0x61, 0x6c, 0x75, 0x65, 0x35, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3c, 0x0a, 0x0e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x36, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3c, 0x0a, 0x0e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x37, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, + 0x38, 0x01, 0x1a, 0x3c, 0x0a, 0x0e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x38, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, + 0x1a, 0x3c, 0x0a, 0x0e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x39, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3d, + 0x0a, 0x0f, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x30, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x01, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3d, 0x0a, - 0x0f, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x34, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x28, 0x02, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3d, 0x0a, + 0x0f, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x32, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3d, 0x0a, 0x0f, - 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x35, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, - 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x6b, 0x65, - 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x5b, 0x0a, 0x0f, 0x4d, - 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x36, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, - 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, - 0x12, 0x32, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x0d, 0x0a, 0x0b, 0x6f, 0x6e, 0x65, 0x6f, - 0x66, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2a, 0x20, 0x0a, 0x09, 0x45, 0x6e, 0x75, 0x6d, 0x56, - 0x61, 0x6c, 0x75, 0x65, 0x12, 0x05, 0x0a, 0x01, 0x58, 0x10, 0x00, 0x12, 0x05, 0x0a, 0x01, 0x59, - 0x10, 0x01, 0x12, 0x05, 0x0a, 0x01, 0x5a, 0x10, 0x02, 0x42, 0x49, 0x5a, 0x47, 0x67, 0x69, 0x74, - 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x69, 0x6e, 0x63, 0x68, 0x65, 0x6e, 0x63, - 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x65, 0x61, 0x73, 0x65, 0x2d, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, - 0x79, 0x2f, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2f, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, - 0x65, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, - 0x6c, 0x65, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x01, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3d, 0x0a, 0x0f, + 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x34, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, + 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, + 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3d, 0x0a, 0x0f, 0x4d, + 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x35, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, + 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x6b, 0x65, 0x79, + 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x5b, 0x0a, 0x0f, 0x4d, 0x61, + 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x36, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, + 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, + 0x32, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x0d, 0x0a, 0x0b, 0x6f, 0x6e, 0x65, 0x6f, 0x66, + 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x14, 0x0a, 0x12, 0x6e, 0x65, 0x73, 0x74, 0x65, 0x64, + 0x5f, 0x6f, 0x6e, 0x65, 0x6f, 0x66, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2a, 0x20, 0x0a, 0x09, + 0x45, 0x6e, 0x75, 0x6d, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x05, 0x0a, 0x01, 0x58, 0x10, 0x00, + 0x12, 0x05, 0x0a, 0x01, 0x59, 0x10, 0x01, 0x12, 0x05, 0x0a, 0x01, 0x5a, 0x10, 0x02, 0x42, 0x49, + 0x5a, 0x47, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x69, 0x6e, + 0x63, 0x68, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x65, 0x61, 0x73, 0x65, 0x2d, 0x67, + 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2f, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2f, 0x72, + 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, + 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, } var ( @@ -773,34 +803,34 @@ func file_gateway_runtime_internal_examplepb_proto3_proto_rawDescGZIP() []byte { var file_gateway_runtime_internal_examplepb_proto3_proto_enumTypes = make([]protoimpl.EnumInfo, 1) var file_gateway_runtime_internal_examplepb_proto3_proto_msgTypes = make([]protoimpl.MessageInfo, 15) var file_gateway_runtime_internal_examplepb_proto3_proto_goTypes = []interface{}{ - (EnumValue)(0), // 0: ease.gateway.runtime.internal.examplepb.EnumValue - (*Proto3Message)(nil), // 1: ease.gateway.runtime.internal.examplepb.Proto3Message - nil, // 2: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValueEntry - nil, // 3: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue2Entry - nil, // 4: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue3Entry - nil, // 5: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue4Entry - nil, // 6: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue5Entry - nil, // 7: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue6Entry - nil, // 8: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue7Entry - nil, // 9: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue8Entry - nil, // 10: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue9Entry - nil, // 11: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue10Entry - nil, // 12: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue12Entry - nil, // 13: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue14Entry - nil, // 14: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue15Entry - nil, // 15: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue16Entry - (*wrappers.UInt64Value)(nil), // 16: google.protobuf.UInt64Value - (*timestamp.Timestamp)(nil), // 17: google.protobuf.Timestamp - (*duration.Duration)(nil), // 18: google.protobuf.Duration - (*field_mask.FieldMask)(nil), // 19: google.protobuf.FieldMask - (*wrappers.DoubleValue)(nil), // 20: google.protobuf.DoubleValue - (*wrappers.FloatValue)(nil), // 21: google.protobuf.FloatValue - (*wrappers.Int64Value)(nil), // 22: google.protobuf.Int64Value - (*wrappers.Int32Value)(nil), // 23: google.protobuf.Int32Value - (*wrappers.UInt32Value)(nil), // 24: google.protobuf.UInt32Value - (*wrappers.BoolValue)(nil), // 25: google.protobuf.BoolValue - (*wrappers.StringValue)(nil), // 26: google.protobuf.StringValue - (*wrappers.BytesValue)(nil), // 27: google.protobuf.BytesValue + (EnumValue)(0), // 0: ease.gateway.runtime.internal.examplepb.EnumValue + (*Proto3Message)(nil), // 1: ease.gateway.runtime.internal.examplepb.Proto3Message + nil, // 2: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValueEntry + nil, // 3: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue2Entry + nil, // 4: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue3Entry + nil, // 5: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue4Entry + nil, // 6: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue5Entry + nil, // 7: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue6Entry + nil, // 8: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue7Entry + nil, // 9: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue8Entry + nil, // 10: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue9Entry + nil, // 11: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue10Entry + nil, // 12: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue12Entry + nil, // 13: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue14Entry + nil, // 14: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue15Entry + nil, // 15: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue16Entry + (*wrapperspb.UInt64Value)(nil), // 16: google.protobuf.UInt64Value + (*timestamppb.Timestamp)(nil), // 17: google.protobuf.Timestamp + (*durationpb.Duration)(nil), // 18: google.protobuf.Duration + (*fieldmaskpb.FieldMask)(nil), // 19: google.protobuf.FieldMask + (*wrapperspb.DoubleValue)(nil), // 20: google.protobuf.DoubleValue + (*wrapperspb.FloatValue)(nil), // 21: google.protobuf.FloatValue + (*wrapperspb.Int64Value)(nil), // 22: google.protobuf.Int64Value + (*wrapperspb.Int32Value)(nil), // 23: google.protobuf.Int32Value + (*wrapperspb.UInt32Value)(nil), // 24: google.protobuf.UInt32Value + (*wrapperspb.BoolValue)(nil), // 25: google.protobuf.BoolValue + (*wrapperspb.StringValue)(nil), // 26: google.protobuf.StringValue + (*wrapperspb.BytesValue)(nil), // 27: google.protobuf.BytesValue } var file_gateway_runtime_internal_examplepb_proto3_proto_depIdxs = []int32{ 1, // 0: ease.gateway.runtime.internal.examplepb.Proto3Message.nested:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message @@ -810,35 +840,36 @@ var file_gateway_runtime_internal_examplepb_proto3_proto_depIdxs = []int32{ 17, // 4: ease.gateway.runtime.internal.examplepb.Proto3Message.timestamp_value:type_name -> google.protobuf.Timestamp 18, // 5: ease.gateway.runtime.internal.examplepb.Proto3Message.duration_value:type_name -> google.protobuf.Duration 19, // 6: ease.gateway.runtime.internal.examplepb.Proto3Message.fieldmask_value:type_name -> google.protobuf.FieldMask - 20, // 7: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_double_value:type_name -> google.protobuf.DoubleValue - 21, // 8: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_float_value:type_name -> google.protobuf.FloatValue - 22, // 9: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_int64_value:type_name -> google.protobuf.Int64Value - 23, // 10: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_int32_value:type_name -> google.protobuf.Int32Value - 16, // 11: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_u_int64_value:type_name -> google.protobuf.UInt64Value - 24, // 12: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_u_int32_value:type_name -> google.protobuf.UInt32Value - 25, // 13: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_bool_value:type_name -> google.protobuf.BoolValue - 26, // 14: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_string_value:type_name -> google.protobuf.StringValue - 27, // 15: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_bytes_value:type_name -> google.protobuf.BytesValue - 2, // 16: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValueEntry - 3, // 17: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value2:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue2Entry - 4, // 18: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value3:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue3Entry - 5, // 19: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value4:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue4Entry - 6, // 20: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value5:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue5Entry - 7, // 21: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value6:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue6Entry - 8, // 22: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value7:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue7Entry - 9, // 23: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value8:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue8Entry - 10, // 24: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value9:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue9Entry - 11, // 25: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value10:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue10Entry - 12, // 26: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value12:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue12Entry - 13, // 27: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value14:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue14Entry - 14, // 28: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value15:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue15Entry - 15, // 29: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value16:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue16Entry - 16, // 30: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue16Entry.value:type_name -> google.protobuf.UInt64Value - 31, // [31:31] is the sub-list for method output_type - 31, // [31:31] is the sub-list for method input_type - 31, // [31:31] is the sub-list for extension type_name - 31, // [31:31] is the sub-list for extension extendee - 0, // [0:31] is the sub-list for field type_name + 1, // 7: ease.gateway.runtime.internal.examplepb.Proto3Message.nested_oneof_value_one:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message + 20, // 8: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_double_value:type_name -> google.protobuf.DoubleValue + 21, // 9: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_float_value:type_name -> google.protobuf.FloatValue + 22, // 10: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_int64_value:type_name -> google.protobuf.Int64Value + 23, // 11: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_int32_value:type_name -> google.protobuf.Int32Value + 16, // 12: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_u_int64_value:type_name -> google.protobuf.UInt64Value + 24, // 13: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_u_int32_value:type_name -> google.protobuf.UInt32Value + 25, // 14: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_bool_value:type_name -> google.protobuf.BoolValue + 26, // 15: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_string_value:type_name -> google.protobuf.StringValue + 27, // 16: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_bytes_value:type_name -> google.protobuf.BytesValue + 2, // 17: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValueEntry + 3, // 18: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value2:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue2Entry + 4, // 19: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value3:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue3Entry + 5, // 20: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value4:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue4Entry + 6, // 21: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value5:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue5Entry + 7, // 22: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value6:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue6Entry + 8, // 23: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value7:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue7Entry + 9, // 24: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value8:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue8Entry + 10, // 25: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value9:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue9Entry + 11, // 26: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value10:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue10Entry + 12, // 27: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value12:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue12Entry + 13, // 28: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value14:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue14Entry + 14, // 29: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value15:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue15Entry + 15, // 30: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value16:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue16Entry + 16, // 31: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue16Entry.value:type_name -> google.protobuf.UInt64Value + 32, // [32:32] is the sub-list for method output_type + 32, // [32:32] is the sub-list for method input_type + 32, // [32:32] is the sub-list for extension type_name + 32, // [32:32] is the sub-list for extension extendee + 0, // [0:32] is the sub-list for field type_name } func init() { file_gateway_runtime_internal_examplepb_proto3_proto_init() } @@ -863,6 +894,7 @@ func file_gateway_runtime_internal_examplepb_proto3_proto_init() { file_gateway_runtime_internal_examplepb_proto3_proto_msgTypes[0].OneofWrappers = []interface{}{ (*Proto3Message_OneofBoolValue)(nil), (*Proto3Message_OneofStringValue)(nil), + (*Proto3Message_NestedOneofValueOne)(nil), } type x struct{} out := protoimpl.TypeBuilder{ diff --git a/gateway/runtime/internal/examplepb/proto3.proto b/gateway/runtime/internal/examplepb/proto3.proto index a81fc4d..c5b0f10 100644 --- a/gateway/runtime/internal/examplepb/proto3.proto +++ b/gateway/runtime/internal/examplepb/proto3.proto @@ -10,7 +10,7 @@ import "google/protobuf/timestamp.proto"; import "google/protobuf/wrappers.proto"; message Proto3Message { - // Next number: 46 + // Next number: 47 Proto3Message nested = 41; float float_value = 42; double double_value = 43; @@ -32,6 +32,9 @@ message Proto3Message { bool oneof_bool_value = 1; string oneof_string_value = 2; } + oneof nested_oneof_value { + Proto3Message nested_oneof_value_one = 46; + } google.protobuf.DoubleValue wrapper_double_value = 17; google.protobuf.FloatValue wrapper_float_value = 18; google.protobuf.Int64Value wrapper_int64_value = 19; diff --git a/gateway/runtime/marshal_json_test.go b/gateway/runtime/marshal_json_test.go deleted file mode 100644 index f13c0b1..0000000 --- a/gateway/runtime/marshal_json_test.go +++ /dev/null @@ -1,255 +0,0 @@ -package runtime_test - -import ( - "bytes" - "encoding/json" - "reflect" - "strings" - "testing" - - emptypb "github.com/golang/protobuf/ptypes/empty" - timestamppb "github.com/golang/protobuf/ptypes/timestamp" - wrapperspb "github.com/golang/protobuf/ptypes/wrappers" - "github.com/google/go-cmp/cmp" - "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" - "github.com/grpc-ecosystem/grpc-gateway/v2/runtime/internal/examplepb" - "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/testing/protocmp" -) - -func TestJSONBuiltinMarshal(t *testing.T) { - var m runtime.JSONBuiltin - msg := &examplepb.SimpleMessage{ - Id: "foo", - } - - buf, err := m.Marshal(msg) - if err != nil { - t.Errorf("m.Marshal(%v) failed with %v; want success", msg, err) - } - - got := new(examplepb.SimpleMessage) - if err := json.Unmarshal(buf, got); err != nil { - t.Errorf("json.Unmarshal(%q, got) failed with %v; want success", buf, err) - } - if diff := cmp.Diff(got, msg, protocmp.Transform()); diff != "" { - t.Error(diff) - } -} - -func TestJSONBuiltinMarshalField(t *testing.T) { - var m runtime.JSONBuiltin - for _, fixt := range builtinFieldFixtures { - buf, err := m.Marshal(fixt.data) - if err != nil { - t.Errorf("m.Marshal(%v) failed with %v; want success", fixt.data, err) - } - if got, want := string(buf), fixt.json; got != want { - t.Errorf("got = %q; want %q; data = %#v", got, want, fixt.data) - } - } -} - -func TestJSONBuiltinMarshalFieldKnownErrors(t *testing.T) { - var m runtime.JSONBuiltin - for _, fixt := range builtinKnownErrors { - buf, err := m.Marshal(fixt.data) - if err != nil { - t.Errorf("m.Marshal(%v) failed with %v; want success", fixt.data, err) - } - if got, want := string(buf), fixt.json; got == want { - t.Errorf("surprisingly got = %q; as want %q; data = %#v", got, want, fixt.data) - } - } -} - -func TestJSONBuiltinsnmarshal(t *testing.T) { - var ( - m runtime.JSONBuiltin - got = new(examplepb.SimpleMessage) - - data = []byte(`{"id": "foo"}`) - ) - if err := m.Unmarshal(data, got); err != nil { - t.Errorf("m.Unmarshal(%q, got) failed with %v; want success", data, err) - } - - want := &examplepb.SimpleMessage{ - Id: "foo", - } - if diff := cmp.Diff(got, want, protocmp.Transform()); diff != "" { - t.Errorf(diff) - } -} - -func TestJSONBuiltinUnmarshalField(t *testing.T) { - var m runtime.JSONBuiltin - for _, fixt := range builtinFieldFixtures { - dest := alloc(reflect.TypeOf(fixt.data)) - if err := m.Unmarshal([]byte(fixt.json), dest.Interface()); err != nil { - t.Errorf("m.Unmarshal(%q, dest) failed with %v; want success", fixt.json, err) - } - - got, want := dest.Elem().Interface(), fixt.data - if diff := cmp.Diff(got, want, protocmp.Transform()); diff != "" { - t.Error(diff) - } - } -} - -func alloc(t reflect.Type) reflect.Value { - if t == nil { - return reflect.ValueOf(new(interface{})) - } else { - return reflect.New(t) - } -} - -func TestJSONBuiltinUnmarshalFieldKnownErrors(t *testing.T) { - var m runtime.JSONBuiltin - for _, fixt := range builtinKnownErrors { - dest := reflect.New(reflect.TypeOf(fixt.data)) - if err := m.Unmarshal([]byte(fixt.json), dest.Interface()); err == nil { - t.Errorf("m.Unmarshal(%q, dest) succeeded; want ane error", fixt.json) - } - } -} - -func TestJSONBuiltinEncoder(t *testing.T) { - var m runtime.JSONBuiltin - msg := &examplepb.SimpleMessage{ - Id: "foo", - } - - var buf bytes.Buffer - enc := m.NewEncoder(&buf) - if err := enc.Encode(msg); err != nil { - t.Errorf("enc.Encode(%v) failed with %v; want success", msg, err) - } - - got := new(examplepb.SimpleMessage) - if err := json.Unmarshal(buf.Bytes(), got); err != nil { - t.Errorf("json.Unmarshal(%q, got) failed with %v; want success", buf.String(), err) - } - if diff := cmp.Diff(got, msg, protocmp.Transform()); diff != "" { - t.Error(diff) - } -} - -func TestJSONBuiltinEncoderFields(t *testing.T) { - var m runtime.JSONBuiltin - for _, fixt := range builtinFieldFixtures { - var buf bytes.Buffer - enc := m.NewEncoder(&buf) - if err := enc.Encode(fixt.data); err != nil { - t.Errorf("enc.Encode(%#v) failed with %v; want success", fixt.data, err) - } - - if got, want := buf.String(), fixt.json+"\n"; got != want { - t.Errorf("got = %q; want %q; data = %#v", got, want, fixt.data) - } - } -} - -func TestJSONBuiltinDecoder(t *testing.T) { - var ( - m runtime.JSONBuiltin - got = new(examplepb.SimpleMessage) - - data = `{"id": "foo"}` - ) - r := strings.NewReader(data) - dec := m.NewDecoder(r) - if err := dec.Decode(got); err != nil { - t.Errorf("m.Unmarshal(got) failed with %v; want success", err) - } - - want := &examplepb.SimpleMessage{ - Id: "foo", - } - if diff := cmp.Diff(got, want, protocmp.Transform()); diff != "" { - t.Errorf("got = %v; want = %v", got, want) - } -} - -func TestJSONBuiltinDecoderFields(t *testing.T) { - var m runtime.JSONBuiltin - for _, fixt := range builtinFieldFixtures { - r := strings.NewReader(fixt.json) - dec := m.NewDecoder(r) - dest := alloc(reflect.TypeOf(fixt.data)) - if err := dec.Decode(dest.Interface()); err != nil { - t.Errorf("dec.Decode(dest) failed with %v; want success; data = %q", err, fixt.json) - } - - got, want := dest.Elem().Interface(), fixt.data - if diff := cmp.Diff(got, want, protocmp.Transform()); diff != "" { - t.Error(diff) - } - } -} - -var ( - builtinFieldFixtures = []struct { - data interface{} - json string - }{ - {data: "", json: `""`}, - {data: proto.String(""), json: `""`}, - {data: "foo", json: `"foo"`}, - {data: proto.String("foo"), json: `"foo"`}, - {data: int32(-1), json: "-1"}, - {data: proto.Int32(-1), json: "-1"}, - {data: int64(-1), json: "-1"}, - {data: proto.Int64(-1), json: "-1"}, - {data: uint32(123), json: "123"}, - {data: proto.Uint32(123), json: "123"}, - {data: uint64(123), json: "123"}, - {data: proto.Uint64(123), json: "123"}, - {data: float32(-1.5), json: "-1.5"}, - {data: proto.Float32(-1.5), json: "-1.5"}, - {data: float64(-1.5), json: "-1.5"}, - {data: proto.Float64(-1.5), json: "-1.5"}, - {data: true, json: "true"}, - {data: proto.Bool(true), json: "true"}, - {data: (*string)(nil), json: "null"}, - {data: new(emptypb.Empty), json: "{}"}, - {data: examplepb.NumericEnum_ONE, json: "1"}, - {data: nil, json: "null"}, - {data: (*string)(nil), json: "null"}, - {data: []interface{}{nil, "foo", -1.0, 1.234, true}, json: `[null,"foo",-1,1.234,true]`}, - { - data: map[string]interface{}{"bar": nil, "baz": -1.0, "fiz": 1.234, "foo": true}, - json: `{"bar":null,"baz":-1,"fiz":1.234,"foo":true}`, - }, - { - data: (*examplepb.NumericEnum)(proto.Int32(int32(examplepb.NumericEnum_ONE))), - json: "1", - }, - } - builtinKnownErrors = []struct { - data interface{} - json string - }{ - {data: examplepb.NumericEnum_ONE, json: "ONE"}, - { - data: (*examplepb.NumericEnum)(proto.Int32(int32(examplepb.NumericEnum_ONE))), - json: "ONE", - }, - { - data: &examplepb.ABitOfEverything_OneofString{OneofString: "abc"}, - json: `"abc"`, - }, - { - data: ×tamppb.Timestamp{ - Seconds: 1462875553, - Nanos: 123000000, - }, - json: `"2016-05-10T10:19:13.123Z"`, - }, - { - data: &wrapperspb.Int32Value{Value: 123}, - json: "123", - }, - } -) diff --git a/gateway/runtime/marshal_jsonpb.go b/gateway/runtime/marshal_jsonpb.go index 38ac3dd..7387c8e 100644 --- a/gateway/runtime/marshal_jsonpb.go +++ b/gateway/runtime/marshal_jsonpb.go @@ -6,6 +6,7 @@ import ( "fmt" "io" "reflect" + "strconv" "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" @@ -113,6 +114,36 @@ func (j *JSONPb) marshalNonProtoField(v interface{}) ([]byte, error) { return buf.Bytes(), nil } + + if rv.Type().Elem().Implements(typeProtoEnum) { + var buf bytes.Buffer + err := buf.WriteByte('[') + if err != nil { + return nil, err + } + for i := 0; i < rv.Len(); i++ { + if i != 0 { + err = buf.WriteByte(',') + if err != nil { + return nil, err + } + } + if j.UseEnumNumbers { + _, err = buf.WriteString(strconv.FormatInt(rv.Index(i).Int(), 10)) + } else { + _, err = buf.WriteString("\"" + rv.Index(i).Interface().(protoEnum).String() + "\"") + } + if err != nil { + return nil, err + } + } + err = buf.WriteByte(']') + if err != nil { + return nil, err + } + + return buf.Bytes(), nil + } } if rv.Kind() == reflect.Map { @@ -237,6 +268,10 @@ func decodeNonProtoField(d *json.Decoder, unmarshaler protojson.UnmarshalOptions } bk := result[0] bv := reflect.New(rv.Type().Elem()) + if v == nil { + null := json.RawMessage("null") + v = &null + } if err := unmarshalJSONPb([]byte(*v), unmarshaler, bv.Interface()); err != nil { return err } @@ -285,6 +320,8 @@ type protoEnum interface { EnumDescriptor() ([]byte, []int) } +var typeProtoEnum = reflect.TypeOf((*protoEnum)(nil)).Elem() + var typeProtoMessage = reflect.TypeOf((*proto.Message)(nil)).Elem() // Delimiter for newline encoded JSON streams. diff --git a/gateway/runtime/marshal_jsonpb_test.go b/gateway/runtime/marshal_jsonpb_test.go deleted file mode 100644 index e508562..0000000 --- a/gateway/runtime/marshal_jsonpb_test.go +++ /dev/null @@ -1,877 +0,0 @@ -package runtime_test - -import ( - "bytes" - "reflect" - "strconv" - "strings" - "testing" - - durationpb "github.com/golang/protobuf/ptypes/duration" - emptypb "github.com/golang/protobuf/ptypes/empty" - structpb "github.com/golang/protobuf/ptypes/struct" - timestamppb "github.com/golang/protobuf/ptypes/timestamp" - wrapperspb "github.com/golang/protobuf/ptypes/wrappers" - "github.com/google/go-cmp/cmp" - "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" - "github.com/grpc-ecosystem/grpc-gateway/v2/runtime/internal/examplepb" - "google.golang.org/protobuf/encoding/protojson" - "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/testing/protocmp" -) - -func TestJSONPbMarshal(t *testing.T) { - msg := examplepb.ABitOfEverything{ - SingleNested: &examplepb.ABitOfEverything_Nested{}, - RepeatedStringValue: []string{}, - MappedStringValue: map[string]string{}, - MappedNestedValue: map[string]*examplepb.ABitOfEverything_Nested{}, - RepeatedEnumValue: []examplepb.NumericEnum{}, - TimestampValue: ×tamppb.Timestamp{}, - Uuid: "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", - Nested: []*examplepb.ABitOfEverything_Nested{ - { - Name: "foo", - Amount: 12345, - }, - }, - Uint64Value: 0xFFFFFFFFFFFFFFFF, - EnumValue: examplepb.NumericEnum_ONE, - OneofValue: &examplepb.ABitOfEverything_OneofString{ - OneofString: "bar", - }, - MapValue: map[string]examplepb.NumericEnum{ - "a": examplepb.NumericEnum_ONE, - "b": examplepb.NumericEnum_ZERO, - }, - RepeatedEnumAnnotation: []examplepb.NumericEnum{}, - EnumValueAnnotation: examplepb.NumericEnum_ONE, - RepeatedStringAnnotation: []string{}, - RepeatedNestedAnnotation: []*examplepb.ABitOfEverything_Nested{}, - NestedAnnotation: &examplepb.ABitOfEverything_Nested{}, - } - - for i, spec := range []struct { - useEnumNumbers, emitUnpopulated bool - indent string - useProtoNames bool - verifier func(json string) - }{ - { - verifier: func(json string) { - if !strings.Contains(json, "ONE") { - t.Errorf(`strings.Contains(%q, "ONE") = false; want true`, json) - } - if want := "uint64Value"; !strings.Contains(json, want) { - t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want) - } - }, - }, - { - useEnumNumbers: true, - verifier: func(json string) { - if strings.Contains(json, "ONE") { - t.Errorf(`strings.Contains(%q, "ONE") = true; want false`, json) - } - }, - }, - { - emitUnpopulated: true, - verifier: func(json string) { - if want := `"sfixed32Value"`; !strings.Contains(json, want) { - t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want) - } - }, - }, - { - indent: "\t\t", - verifier: func(json string) { - if want := "\t\t\"amount\":"; !strings.Contains(json, want) { - t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want) - } - }, - }, - { - useProtoNames: true, - verifier: func(json string) { - if want := "uint64_value"; !strings.Contains(json, want) { - t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want) - } - }, - }, - } { - t.Run(strconv.Itoa(i), func(t *testing.T) { - m := runtime.JSONPb{ - MarshalOptions: protojson.MarshalOptions{ - EmitUnpopulated: spec.emitUnpopulated, - Indent: spec.indent, - UseProtoNames: spec.useProtoNames, - UseEnumNumbers: spec.useEnumNumbers, - }, - } - buf, err := m.Marshal(&msg) - if err != nil { - t.Errorf("m.Marshal(%v) failed with %v; want success; spec=%v", &msg, err, spec) - } - - var got examplepb.ABitOfEverything - unmarshaler := &protojson.UnmarshalOptions{} - if err = unmarshaler.Unmarshal(buf, &got); err != nil { - t.Errorf("jsonpb.UnmarshalString(%q, &got) failed with %v; want success; spec=%v", string(buf), err, spec) - } - if diff := cmp.Diff(&got, &msg, protocmp.Transform()); diff != "" { - t.Errorf("case %d: spec=%v; %s", i, spec, diff) - } - if spec.verifier != nil { - spec.verifier(string(buf)) - } - }) - } -} - -func TestJSONPbMarshalFields(t *testing.T) { - var m runtime.JSONPb - m.UseEnumNumbers = true // builtin fixtures include an enum, expected to be marshaled as int - for _, spec := range builtinFieldFixtures { - buf, err := m.Marshal(spec.data) - if err != nil { - t.Errorf("m.Marshal(%#v) failed with %v; want success", spec.data, err) - } - if got, want := string(buf), spec.json; got != want { - t.Errorf("m.Marshal(%#v) = %q; want %q", spec.data, got, want) - } - } - - m.UseEnumNumbers = false - buf, err := m.Marshal(examplepb.NumericEnum_ONE) - if err != nil { - t.Errorf("m.Marshal(%#v) failed with %v; want success", examplepb.NumericEnum_ONE, err) - } - if got, want := string(buf), `"ONE"`; got != want { - t.Errorf("m.Marshal(%#v) = %q; want %q", examplepb.NumericEnum_ONE, got, want) - } -} - -func TestJSONPbUnmarshal(t *testing.T) { - var ( - m runtime.JSONPb - got examplepb.ABitOfEverything - ) - for i, data := range []string{ - `{ - "uuid": "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", - "nested": [ - {"name": "foo", "amount": 12345} - ], - "uint64Value": 18446744073709551615, - "enumValue": "ONE", - "oneofString": "bar", - "mapValue": { - "a": 1, - "b": 0 - } - }`, - `{ - "uuid": "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", - "nested": [ - {"name": "foo", "amount": 12345} - ], - "uint64Value": "18446744073709551615", - "enumValue": "ONE", - "oneofString": "bar", - "mapValue": { - "a": 1, - "b": 0 - } - }`, - `{ - "uuid": "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", - "nested": [ - {"name": "foo", "amount": 12345} - ], - "uint64Value": 18446744073709551615, - "enumValue": 1, - "oneofString": "bar", - "mapValue": { - "a": 1, - "b": 0 - } - }`, - } { - if err := m.Unmarshal([]byte(data), &got); err != nil { - t.Errorf("case %d: m.Unmarshal(%q, &got) failed with %v; want success", i, data, err) - } - - want := examplepb.ABitOfEverything{ - Uuid: "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", - Nested: []*examplepb.ABitOfEverything_Nested{ - { - Name: "foo", - Amount: 12345, - }, - }, - Uint64Value: 0xFFFFFFFFFFFFFFFF, - EnumValue: examplepb.NumericEnum_ONE, - OneofValue: &examplepb.ABitOfEverything_OneofString{ - OneofString: "bar", - }, - MapValue: map[string]examplepb.NumericEnum{ - "a": examplepb.NumericEnum_ONE, - "b": examplepb.NumericEnum_ZERO, - }, - } - - if diff := cmp.Diff(&got, &want, protocmp.Transform()); diff != "" { - t.Errorf("case %d: %s", i, diff) - } - } -} - -func TestJSONPbUnmarshalFields(t *testing.T) { - var m runtime.JSONPb - for _, fixt := range fieldFixtures { - if fixt.skipUnmarshal { - continue - } - - dest := reflect.New(reflect.TypeOf(fixt.data)) - if err := m.Unmarshal([]byte(fixt.json), dest.Interface()); err != nil { - t.Errorf("m.Unmarshal(%q, %T) failed with %v; want success", fixt.json, dest.Interface(), err) - } - if diff := cmp.Diff(dest.Elem().Interface(), fixt.data, protocmp.Transform()); diff != "" { - t.Errorf("dest = %#v; want %#v; input = %v", dest.Elem().Interface(), fixt.data, fixt.json) - } - } -} - -func TestJSONPbEncoder(t *testing.T) { - msg := examplepb.ABitOfEverything{ - SingleNested: &examplepb.ABitOfEverything_Nested{}, - RepeatedStringValue: []string{}, - MappedStringValue: map[string]string{}, - MappedNestedValue: map[string]*examplepb.ABitOfEverything_Nested{}, - RepeatedEnumValue: []examplepb.NumericEnum{}, - TimestampValue: ×tamppb.Timestamp{}, - Uuid: "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", - Nested: []*examplepb.ABitOfEverything_Nested{ - { - Name: "foo", - Amount: 12345, - }, - }, - Uint64Value: 0xFFFFFFFFFFFFFFFF, - OneofValue: &examplepb.ABitOfEverything_OneofString{ - OneofString: "bar", - }, - MapValue: map[string]examplepb.NumericEnum{ - "a": examplepb.NumericEnum_ONE, - "b": examplepb.NumericEnum_ZERO, - }, - RepeatedEnumAnnotation: []examplepb.NumericEnum{}, - EnumValueAnnotation: examplepb.NumericEnum_ONE, - RepeatedStringAnnotation: []string{}, - RepeatedNestedAnnotation: []*examplepb.ABitOfEverything_Nested{}, - NestedAnnotation: &examplepb.ABitOfEverything_Nested{}, - } - - for i, spec := range []struct { - useEnumNumbers, emitUnpopulated bool - indent string - useProtoNames bool - verifier func(json string) - }{ - { - verifier: func(json string) { - if !strings.Contains(json, "ONE") { - t.Errorf(`strings.Contains(%q, "ONE") = false; want true`, json) - } - if want := "uint64Value"; !strings.Contains(json, want) { - t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want) - } - }, - }, - { - useEnumNumbers: true, - verifier: func(json string) { - if strings.Contains(json, "ONE") { - t.Errorf(`strings.Contains(%q, "ONE") = true; want false`, json) - } - }, - }, - { - emitUnpopulated: true, - verifier: func(json string) { - if want := `"sfixed32Value"`; !strings.Contains(json, want) { - t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want) - } - }, - }, - { - indent: "\t\t", - verifier: func(json string) { - if want := "\t\t\"amount\":"; !strings.Contains(json, want) { - t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want) - } - }, - }, - { - useProtoNames: true, - verifier: func(json string) { - if want := "uint64_value"; !strings.Contains(json, want) { - t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want) - } - }, - }, - } { - m := runtime.JSONPb{ - MarshalOptions: protojson.MarshalOptions{ - EmitUnpopulated: spec.emitUnpopulated, - Indent: spec.indent, - UseProtoNames: spec.useProtoNames, - UseEnumNumbers: spec.useEnumNumbers, - }, - } - - var buf bytes.Buffer - enc := m.NewEncoder(&buf) - if err := enc.Encode(&msg); err != nil { - t.Errorf("enc.Encode(%v) failed with %v; want success; spec=%v", &msg, err, spec) - } - - var got examplepb.ABitOfEverything - unmarshaler := &protojson.UnmarshalOptions{} - if err := unmarshaler.Unmarshal(buf.Bytes(), &got); err != nil { - t.Errorf("jsonpb.UnmarshalString(%q, &got) failed with %v; want success; spec=%v", buf.String(), err, spec) - } - if diff := cmp.Diff(&got, &msg, protocmp.Transform()); diff != "" { - t.Errorf("case %d: %s", i, diff) - } - if spec.verifier != nil { - spec.verifier(buf.String()) - } - } -} - -func TestJSONPbEncoderFields(t *testing.T) { - var m runtime.JSONPb - for _, fixt := range fieldFixtures { - var buf bytes.Buffer - enc := m.NewEncoder(&buf) - if err := enc.Encode(fixt.data); err != nil { - t.Errorf("enc.Encode(%#v) failed with %v; want success", fixt.data, err) - } - if got, want := buf.String(), fixt.json+string(m.Delimiter()); got != want { - t.Errorf("enc.Encode(%#v) = %q; want %q", fixt.data, got, want) - } - } - - m.UseEnumNumbers = true - buf, err := m.Marshal(examplepb.NumericEnum_ONE) - if err != nil { - t.Errorf("m.Marshal(%#v) failed with %v; want success", examplepb.NumericEnum_ONE, err) - } - if got, want := string(buf), "1"; got != want { - t.Errorf("m.Marshal(%#v) = %q; want %q", examplepb.NumericEnum_ONE, got, want) - } -} - -func TestJSONPbDecoder(t *testing.T) { - var ( - m runtime.JSONPb - got examplepb.ABitOfEverything - ) - for _, data := range []string{ - `{ - "uuid": "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", - "nested": [ - {"name": "foo", "amount": 12345} - ], - "uint64Value": 18446744073709551615, - "enumValue": "ONE", - "oneofString": "bar", - "mapValue": { - "a": 1, - "b": 0 - } - }`, - `{ - "uuid": "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", - "nested": [ - {"name": "foo", "amount": 12345} - ], - "uint64Value": "18446744073709551615", - "enumValue": "ONE", - "oneofString": "bar", - "mapValue": { - "a": 1, - "b": 0 - } - }`, - `{ - "uuid": "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", - "nested": [ - {"name": "foo", "amount": 12345} - ], - "uint64Value": 18446744073709551615, - "enumValue": 1, - "oneofString": "bar", - "mapValue": { - "a": 1, - "b": 0 - } - }`, - } { - r := strings.NewReader(data) - dec := m.NewDecoder(r) - if err := dec.Decode(&got); err != nil { - t.Errorf("m.Unmarshal(&got) failed with %v; want success; data=%q", err, data) - } - - want := examplepb.ABitOfEverything{ - Uuid: "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", - Nested: []*examplepb.ABitOfEverything_Nested{ - { - Name: "foo", - Amount: 12345, - }, - }, - Uint64Value: 0xFFFFFFFFFFFFFFFF, - EnumValue: examplepb.NumericEnum_ONE, - OneofValue: &examplepb.ABitOfEverything_OneofString{ - OneofString: "bar", - }, - MapValue: map[string]examplepb.NumericEnum{ - "a": examplepb.NumericEnum_ONE, - "b": examplepb.NumericEnum_ZERO, - }, - } - if diff := cmp.Diff(&got, &want, protocmp.Transform()); diff != "" { - t.Errorf("data %q: %s", data, diff) - } - } -} - -func TestJSONPbDecoderFields(t *testing.T) { - var m runtime.JSONPb - for _, fixt := range fieldFixtures { - if fixt.skipUnmarshal { - continue - } - - dest := reflect.New(reflect.TypeOf(fixt.data)) - dec := m.NewDecoder(strings.NewReader(fixt.json)) - if err := dec.Decode(dest.Interface()); err != nil { - t.Errorf("dec.Decode(%T) failed with %v; want success; input = %q", dest.Interface(), err, fixt.json) - } - if got, want := dest.Elem().Interface(), fixt.data; !reflect.DeepEqual(got, want) { - t.Errorf("dest = %#v; want %#v; input = %v", got, want, fixt.json) - } - } -} - -func TestJSONPbDecoderUnknownField(t *testing.T) { - var ( - m = runtime.JSONPb{ - UnmarshalOptions: protojson.UnmarshalOptions{ - DiscardUnknown: false, - }, - } - got examplepb.ABitOfEverything - ) - data := `{ - "uuid": "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", - "unknownField": "111" - }` - - r := strings.NewReader(data) - dec := m.NewDecoder(r) - if err := dec.Decode(&got); err == nil { - t.Errorf("m.Unmarshal(&got) not failed; want `unknown field` error; data=%q", data) - } -} - -var ( - fieldFixtures = []struct { - data interface{} - json string - skipUnmarshal bool - }{ - {data: int32(1), json: "1"}, - {data: proto.Int32(1), json: "1"}, - {data: int64(1), json: "1"}, - {data: proto.Int64(1), json: "1"}, - {data: uint32(1), json: "1"}, - {data: proto.Uint32(1), json: "1"}, - {data: uint64(1), json: "1"}, - {data: proto.Uint64(1), json: "1"}, - {data: "abc", json: `"abc"`}, - {data: proto.String("abc"), json: `"abc"`}, - {data: float32(1.5), json: "1.5"}, - {data: proto.Float32(1.5), json: "1.5"}, - {data: float64(1.5), json: "1.5"}, - {data: proto.Float64(1.5), json: "1.5"}, - {data: true, json: "true"}, - {data: false, json: "false"}, - {data: (*string)(nil), json: "null"}, - { - data: examplepb.NumericEnum_ONE, - json: `"ONE"`, - // TODO(yugui) support unmarshaling of symbolic enum - skipUnmarshal: true, - }, - { - data: (*examplepb.NumericEnum)(proto.Int32(int32(examplepb.NumericEnum_ONE))), - json: `"ONE"`, - // TODO(yugui) support unmarshaling of symbolic enum - skipUnmarshal: true, - }, - - { - data: map[string]int32{ - "foo": 1, - }, - json: `{"foo":1}`, - }, - { - data: map[string]*examplepb.SimpleMessage{ - "foo": {Id: "bar"}, - }, - json: `{"foo":{"id":"bar"}}`, - }, - { - data: map[int32]*examplepb.SimpleMessage{ - 1: {Id: "foo"}, - }, - json: `{"1":{"id":"foo"}}`, - }, - { - data: map[bool]*examplepb.SimpleMessage{ - true: {Id: "foo"}, - }, - json: `{"true":{"id":"foo"}}`, - }, - { - data: &durationpb.Duration{ - Seconds: 123, - Nanos: 456000000, - }, - json: `"123.456s"`, - }, - { - data: ×tamppb.Timestamp{ - Seconds: 1462875553, - Nanos: 123000000, - }, - json: `"2016-05-10T10:19:13.123Z"`, - }, - { - data: new(emptypb.Empty), - json: "{}", - }, - { - data: &structpb.Value{ - Kind: new(structpb.Value_NullValue), - }, - json: "null", - skipUnmarshal: true, - }, - { - data: &structpb.Value{ - Kind: &structpb.Value_NumberValue{ - NumberValue: 123.4, - }, - }, - json: "123.4", - skipUnmarshal: true, - }, - { - data: &structpb.Value{ - Kind: &structpb.Value_StringValue{ - StringValue: "abc", - }, - }, - json: `"abc"`, - skipUnmarshal: true, - }, - { - data: &structpb.Value{ - Kind: &structpb.Value_BoolValue{ - BoolValue: true, - }, - }, - json: "true", - skipUnmarshal: true, - }, - { - data: &structpb.Struct{ - Fields: map[string]*structpb.Value{ - "foo_bar": { - Kind: &structpb.Value_BoolValue{ - BoolValue: true, - }, - }, - }, - }, - json: `{"foo_bar":true}`, - skipUnmarshal: true, - }, - - { - data: &wrapperspb.BoolValue{Value: true}, - json: "true", - }, - { - data: &wrapperspb.DoubleValue{Value: 123.456}, - json: "123.456", - }, - { - data: &wrapperspb.FloatValue{Value: 123.456}, - json: "123.456", - }, - { - data: &wrapperspb.Int32Value{Value: -123}, - json: "-123", - }, - { - data: &wrapperspb.Int64Value{Value: -123}, - json: `"-123"`, - }, - { - data: &wrapperspb.UInt32Value{Value: 123}, - json: "123", - }, - { - data: &wrapperspb.UInt64Value{Value: 123}, - json: `"123"`, - }, - // TODO(yugui) Add other well-known types once jsonpb supports them - } -) - -func TestJSONPbMarshalResponseBodies(t *testing.T) { - marshaler := &runtime.JSONPb{} - for i, spec := range []struct { - input interface{} - emitUnpopulated bool - verifier func(*testing.T, interface{}, []byte) - }{ - { - input: &examplepb.ResponseBodyOut{ - Response: &examplepb.ResponseBodyOut_Response{Data: "abcdef"}, - }, - verifier: func(t *testing.T, input interface{}, json []byte) { - var out examplepb.ResponseBodyOut - err := marshaler.Unmarshal(json, &out) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - diff := cmp.Diff(input, &out, protocmp.Transform()) - if diff != "" { - t.Errorf("json not equal:\n%s", diff) - } - }, - }, - { - emitUnpopulated: true, - input: &examplepb.ResponseBodyOut{}, - verifier: func(t *testing.T, input interface{}, json []byte) { - var out examplepb.ResponseBodyOut - err := marshaler.Unmarshal(json, &out) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - diff := cmp.Diff(input, &out, protocmp.Transform()) - if diff != "" { - t.Errorf("json not equal:\n%s", diff) - } - }, - }, - { - input: &examplepb.RepeatedResponseBodyOut_Response{}, - verifier: func(t *testing.T, input interface{}, json []byte) { - var out examplepb.RepeatedResponseBodyOut_Response - err := marshaler.Unmarshal(json, &out) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - diff := cmp.Diff(input, &out, protocmp.Transform()) - if diff != "" { - t.Errorf("json not equal:\n%s", diff) - } - }, - }, - { - emitUnpopulated: true, - input: &examplepb.RepeatedResponseBodyOut_Response{}, - verifier: func(t *testing.T, input interface{}, json []byte) { - var out examplepb.RepeatedResponseBodyOut_Response - err := marshaler.Unmarshal(json, &out) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - diff := cmp.Diff(input, &out, protocmp.Transform()) - if diff != "" { - t.Errorf("json not equal:\n%s", diff) - } - }, - }, - { - input: ([]*examplepb.RepeatedResponseBodyOut_Response)(nil), - verifier: func(t *testing.T, input interface{}, json []byte) { - var out []*examplepb.RepeatedResponseBodyOut_Response - err := marshaler.Unmarshal(json, &out) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - diff := cmp.Diff(input, out, protocmp.Transform()) - if diff != "" { - t.Errorf("json not equal:\n%s", diff) - } - }, - }, - { - emitUnpopulated: true, - input: ([]*examplepb.RepeatedResponseBodyOut_Response)(nil), - verifier: func(t *testing.T, _ interface{}, json []byte) { - var out []*examplepb.RepeatedResponseBodyOut_Response - err := marshaler.Unmarshal(json, &out) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - diff := cmp.Diff([]*examplepb.RepeatedResponseBodyOut_Response{}, out, protocmp.Transform()) - if diff != "" { - t.Errorf("json not equal:\n%s", diff) - } - }, - }, - { - input: []*examplepb.RepeatedResponseBodyOut_Response{}, - verifier: func(t *testing.T, input interface{}, json []byte) { - var out []*examplepb.RepeatedResponseBodyOut_Response - err := marshaler.Unmarshal(json, &out) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - diff := cmp.Diff(input, out, protocmp.Transform()) - if diff != "" { - t.Errorf("json not equal:\n%s", diff) - } - }, - }, - { - input: []string{"something"}, - verifier: func(t *testing.T, input interface{}, json []byte) { - var out []string - err := marshaler.Unmarshal(json, &out) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - diff := cmp.Diff(input, out, protocmp.Transform()) - if diff != "" { - t.Errorf("json not equal:\n%s", diff) - } - }, - }, - { - input: []string{}, - verifier: func(t *testing.T, input interface{}, json []byte) { - var out []string - err := marshaler.Unmarshal(json, &out) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - diff := cmp.Diff(input, out, protocmp.Transform()) - if diff != "" { - t.Errorf("json not equal:\n%s", diff) - } - }, - }, - { - input: ([]string)(nil), - verifier: func(t *testing.T, input interface{}, json []byte) { - var out []string - err := marshaler.Unmarshal(json, &out) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - diff := cmp.Diff(input, out, protocmp.Transform()) - if diff != "" { - t.Errorf("json not equal:\n%s", diff) - } - }, - }, - { - emitUnpopulated: true, - input: ([]string)(nil), - verifier: func(t *testing.T, _ interface{}, json []byte) { - var out []string - err := marshaler.Unmarshal(json, &out) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - diff := cmp.Diff([]string{}, out, protocmp.Transform()) - if diff != "" { - t.Errorf("json not equal:\n%s", diff) - } - }, - }, - { - input: []*examplepb.RepeatedResponseBodyOut_Response{ - {}, - { - Data: "abc", - Type: examplepb.RepeatedResponseBodyOut_Response_A, - }, - }, - verifier: func(t *testing.T, input interface{}, json []byte) { - var out []*examplepb.RepeatedResponseBodyOut_Response - err := marshaler.Unmarshal(json, &out) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - diff := cmp.Diff(input, out, protocmp.Transform()) - if diff != "" { - t.Errorf("json not equal:\n%s", diff) - } - }, - }, - { - emitUnpopulated: true, - input: []*examplepb.RepeatedResponseBodyOut_Response{ - {}, - { - Data: "abc", - Type: examplepb.RepeatedResponseBodyOut_Response_B, - }, - }, - verifier: func(t *testing.T, input interface{}, json []byte) { - var out []*examplepb.RepeatedResponseBodyOut_Response - err := marshaler.Unmarshal(json, &out) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - diff := cmp.Diff(input, out, protocmp.Transform()) - if diff != "" { - t.Errorf("json not equal:\n%s", diff) - } - }, - }, - } { - - t.Run(strconv.Itoa(i), func(t *testing.T) { - m := runtime.JSONPb{ - MarshalOptions: protojson.MarshalOptions{ - EmitUnpopulated: spec.emitUnpopulated, - }, - } - val := spec.input - buf, err := m.Marshal(val) - if err != nil { - t.Errorf("m.Marshal(%v) failed with %v; want success; spec=%v", val, err, spec) - } - if spec.verifier != nil { - spec.verifier(t, spec.input, buf) - } - }) - } -} diff --git a/gateway/runtime/marshal_proto_test.go b/gateway/runtime/marshal_proto_test.go deleted file mode 100644 index df156ac..0000000 --- a/gateway/runtime/marshal_proto_test.go +++ /dev/null @@ -1,91 +0,0 @@ -package runtime_test - -import ( - "bytes" - "testing" - - timestamppb "github.com/golang/protobuf/ptypes/timestamp" - "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" - "github.com/grpc-ecosystem/grpc-gateway/v2/runtime/internal/examplepb" - "google.golang.org/protobuf/proto" -) - -var message = &examplepb.ABitOfEverything{ - SingleNested: &examplepb.ABitOfEverything_Nested{}, - RepeatedStringValue: nil, - MappedStringValue: nil, - MappedNestedValue: nil, - RepeatedEnumValue: nil, - TimestampValue: ×tamppb.Timestamp{}, - Uuid: "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", - Nested: []*examplepb.ABitOfEverything_Nested{ - { - Name: "foo", - Amount: 12345, - }, - }, - Uint64Value: 0xFFFFFFFFFFFFFFFF, - EnumValue: examplepb.NumericEnum_ONE, - OneofValue: &examplepb.ABitOfEverything_OneofString{ - OneofString: "bar", - }, - MapValue: map[string]examplepb.NumericEnum{ - "a": examplepb.NumericEnum_ONE, - "b": examplepb.NumericEnum_ZERO, - }, -} - -func TestProtoMarshalUnmarshal(t *testing.T) { - marshaller := runtime.ProtoMarshaller{} - - // Marshal - buffer, err := marshaller.Marshal(message) - if err != nil { - t.Fatalf("Marshalling returned error: %s", err.Error()) - } - - // Unmarshal - unmarshalled := &examplepb.ABitOfEverything{} - err = marshaller.Unmarshal(buffer, unmarshalled) - if err != nil { - t.Fatalf("Unmarshalling returned error: %s", err.Error()) - } - - if !proto.Equal(unmarshalled, message) { - t.Errorf( - "Unmarshalled didn't match original message: (original = %v) != (unmarshalled = %v)", - unmarshalled, - message, - ) - } -} - -func TestProtoEncoderDecodert(t *testing.T) { - marshaller := runtime.ProtoMarshaller{} - - var buf bytes.Buffer - - encoder := marshaller.NewEncoder(&buf) - decoder := marshaller.NewDecoder(&buf) - - // Encode - err := encoder.Encode(message) - if err != nil { - t.Fatalf("Encoding returned error: %s", err.Error()) - } - - // Decode - unencoded := &examplepb.ABitOfEverything{} - err = decoder.Decode(unencoded) - if err != nil { - t.Fatalf("Unmarshalling returned error: %s", err.Error()) - } - - if !proto.Equal(unencoded, message) { - t.Errorf( - "Unencoded didn't match original message: (original = %v) != (unencoded = %v)", - unencoded, - message, - ) - } -} diff --git a/gateway/runtime/mux.go b/gateway/runtime/mux.go index 289bcca..fa8e9bf 100644 --- a/gateway/runtime/mux.go +++ b/gateway/runtime/mux.go @@ -2,20 +2,53 @@ package runtime import ( "context" + "errors" "fmt" "net/http" "net/textproto" + "regexp" "strings" - + "github.com/grpc-ecosystem/grpc-gateway/v2/internal/httprule" "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/health/grpc_health_v1" "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" "google.golang.org/protobuf/proto" - + "github.com/binchencoder/gateway-proto/data" ) +// UnescapingMode defines the behavior of ServeMux when unescaping path parameters. +type UnescapingMode int + +const ( + // UnescapingModeLegacy is the default V2 behavior, which escapes the entire + // path string before doing any routing. + UnescapingModeLegacy UnescapingMode = iota + + // UnescapingModeAllExceptReserved unescapes all path parameters except RFC 6570 + // reserved characters. + UnescapingModeAllExceptReserved + + // UnescapingModeAllExceptSlash unescapes URL path parameters except path + // separators, which will be left as "%2F". + UnescapingModeAllExceptSlash + + // UnescapingModeAllCharacters unescapes all URL path parameters. + UnescapingModeAllCharacters + + // UnescapingModeDefault is the default escaping type. + // TODO(v3): default this to UnescapingModeAllExceptReserved per grpc-httpjson-transcoding's + // reference implementation + UnescapingModeDefault = UnescapingModeLegacy +) + +var ( + encodedPathSplitter = regexp.MustCompile("(/|%2F)") +) + // A HandlerFunc handles a specific pair of path pattern and HTTP method. type HandlerFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request, pathParams map[string]string) @@ -33,6 +66,7 @@ type ServeMux struct { streamErrorHandler StreamErrorHandlerFunc routingErrorHandler RoutingErrorHandlerFunc disablePathLengthFallback bool + unescapingMode UnescapingMode } // ServeMuxOption is an option that can be given to a ServeMux on construction. @@ -50,6 +84,14 @@ func WithForwardResponseOption(forwardResponseOption func(context.Context, http. } } +// WithEscapingType sets the escaping type. See the definitions of UnescapingMode +// for more information. +func WithUnescapingMode(mode UnescapingMode) ServeMuxOption { + return func(serveMux *ServeMux) { + serveMux.unescapingMode = mode + } +} + // SetQueryParameterParser sets the query parameter parser, used to populate message from query parameters. // Configuring this will mean the generated OpenAPI output is no longer correct, and it should be // done with careful consideration. @@ -80,11 +122,30 @@ func DefaultHeaderMatcher(key string) (string, bool) { // This matcher will be called with each header in http.Request. If matcher returns true, that header will be // passed to gRPC context. To transform the header before passing to gRPC context, matcher should return modified header. func WithIncomingHeaderMatcher(fn HeaderMatcherFunc) ServeMuxOption { + for _, header := range fn.matchedMalformedHeaders() { + grpclog.Warningf("The configured forwarding filter would allow %q to be sent to the gRPC server, which will likely cause errors. See https://github.com/grpc/grpc-go/pull/4803#issuecomment-986093310 for more information.", header) + } + return func(mux *ServeMux) { mux.incomingHeaderMatcher = fn } } +// matchedMalformedHeaders returns the malformed headers that would be forwarded to gRPC server. +func (fn HeaderMatcherFunc) matchedMalformedHeaders() []string { + if fn == nil { + return nil + } + headers := make([]string, 0) + for header := range malformedHTTPHeaders { + out, accept := fn(header) + if accept && isMalformedHTTPHeader(out) { + headers = append(headers, out) + } + } + return headers +} + // WithOutgoingHeaderMatcher returns a ServeMuxOption representing a headerMatcher for outgoing response from gateway. // // This matcher will be called with each header in response header metadata. If matcher returns true, that header will be @@ -146,6 +207,55 @@ func WithDisablePathLengthFallback() ServeMuxOption { } } +// WithHealthEndpointAt returns a ServeMuxOption that will add an endpoint to the created ServeMux at the path specified by endpointPath. +// When called the handler will forward the request to the upstream grpc service health check (defined in the +// gRPC Health Checking Protocol). +// +// See here https://grpc-ecosystem.github.io/grpc-gateway/docs/operations/health_check/ for more information on how +// to setup the protocol in the grpc server. +// +// If you define a service as query parameter, this will also be forwarded as service in the HealthCheckRequest. +func WithHealthEndpointAt(healthCheckClient grpc_health_v1.HealthClient, endpointPath string, sid data.ServiceId) ServeMuxOption { + return func(s *ServeMux) { + // error can be ignored since pattern is definitely valid + _ = s.HandlePath( + http.MethodGet, endpointPath, sid, func(ctx context.Context, w http.ResponseWriter, r *http.Request, _ map[string]string, + ) { + _, outboundMarshaler := MarshalerForRequest(s, r) + + resp, err := healthCheckClient.Check(r.Context(), &grpc_health_v1.HealthCheckRequest{ + Service: r.URL.Query().Get("service"), + }) + if err != nil { + s.errorHandler(r.Context(), s, outboundMarshaler, w, r, err) + return + } + + if resp.GetStatus() != grpc_health_v1.HealthCheckResponse_SERVING { + var err error + switch resp.GetStatus() { + case grpc_health_v1.HealthCheckResponse_NOT_SERVING, grpc_health_v1.HealthCheckResponse_UNKNOWN: + err = status.Error(codes.Unavailable, resp.String()) + case grpc_health_v1.HealthCheckResponse_SERVICE_UNKNOWN: + err = status.Error(codes.NotFound, resp.String()) + } + + s.errorHandler(r.Context(), s, outboundMarshaler, w, r, err) + return + } + + _ = outboundMarshaler.NewEncoder(w).Encode(resp) + }) + } +} + +// WithHealthzEndpoint returns a ServeMuxOption that will add a /healthz endpoint to the created ServeMux. +// +// See WithHealthEndpointAt for the general implementation. +func WithHealthzEndpoint(healthCheckClient grpc_health_v1.HealthClient, sid data.ServiceId) ServeMuxOption { + return WithHealthEndpointAt(healthCheckClient, "/healthz", sid) +} + // NewServeMux returns a new ServeMux whose internal mapping is empty. func NewServeMux(opts ...ServeMuxOption) *ServeMux { serveMux := &ServeMux{ @@ -155,6 +265,7 @@ func NewServeMux(opts ...ServeMuxOption) *ServeMux { errorHandler: DefaultHTTPErrorHandler, streamErrorHandler: DefaultStreamErrorHandler, routingErrorHandler: DefaultRoutingErrorHandler, + unescapingMode: UnescapingModeDefault, } for _, opt := range opts { @@ -180,7 +291,7 @@ func (s *ServeMux) Handle(meth string, pat Pattern, sid data.ServiceId, h Handle } // HandlePath allows users to configure custom path handlers. -// refer: https://grpc-ecosystem.github.io/grpc-gateway/docs/inject_router.html +// refer: https://grpc-ecosystem.github.io/grpc-gateway/docs/operations/inject_router/ func (s *ServeMux) HandlePath(meth string, pathPattern string, sid data.ServiceId, h HandlerFunc) error { compiler, err := httprule.Parse(pathPattern) if err != nil { @@ -195,7 +306,7 @@ func (s *ServeMux) HandlePath(meth string, pathPattern string, sid data.ServiceI return nil } -// ServeHTTP dispatches the request to the first handler whose pattern matches to r.Method and r.Path. +// ServeHTTP dispatches the request to the first handler whose pattern matches to r.Method and r.URL.Path. func (s *ServeMux) ServeHTTP(w http.ResponseWriter, r *http.Request) { ctx, err := RequestReceived(w, r) if err != nil { @@ -210,18 +321,20 @@ func (s *ServeMux) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } - components := strings.Split(path[1:], "/") - l := len(components) - var verb string - idx := strings.LastIndex(components[l-1], ":") - if idx == 0 { - _, outboundMarshaler := MarshalerForRequest(s, r) - s.routingErrorHandler(ctx, s, outboundMarshaler, w, r, http.StatusNotFound) - return + // TODO(v3): remove UnescapingModeLegacy + if s.unescapingMode != UnescapingModeLegacy && r.URL.RawPath != "" { + path = r.URL.RawPath } - if idx > 0 { - c := components[l-1] - components[l-1], verb = c[:idx], c[idx+1:] + + var components []string + // since in UnescapeModeLegacy, the URL will already have been fully unescaped, if we also split on "%2F" + // in this escaping mode we would be double unescaping but in UnescapingModeAllCharacters, we still do as the + // path is the RawPath (i.e. unescaped). That does mean that the behavior of this function will change its default + // behavior when the UnescapingModeDefault gets changed from UnescapingModeLegacy to UnescapingModeAllExceptReserved + if s.unescapingMode == UnescapingModeAllCharacters { + components = encodedPathSplitter.Split(path[1:], -1) + } else { + components = strings.Split(path[1:], "/") } if override := r.Header.Get("X-HTTP-Method-Override"); override != "" && s.isPathLengthFallback(r) { @@ -233,9 +346,45 @@ func (s *ServeMux) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } } + + // Verb out here is to memoize for the fallback case below + var verb string + for _, h := range s.handlers[r.Method] { - pathParams, err := h.pat.Match(components, verb) + // If the pattern has a verb, explicitly look for a suffix in the last + // component that matches a colon plus the verb. This allows us to + // handle some cases that otherwise can't be correctly handled by the + // former LastIndex case, such as when the verb literal itself contains + // a colon. This should work for all cases that have run through the + // parser because we know what verb we're looking for, however, there + // are still some cases that the parser itself cannot disambiguate. See + // the comment there if interested. + patVerb := h.pat.Verb() + l := len(components) + lastComponent := components[l-1] + var idx int = -1 + if patVerb != "" && strings.HasSuffix(lastComponent, ":"+patVerb) { + idx = len(lastComponent) - len(patVerb) - 1 + } + if idx == 0 { + _, outboundMarshaler := MarshalerForRequest(s, r) + s.routingErrorHandler(ctx, s, outboundMarshaler, w, r, http.StatusNotFound) + return + } + if idx > 0 { + components[l-1], verb = lastComponent[:idx], lastComponent[idx+1:] + } + + pathParams, err := h.pat.MatchAndEscape(components, verb, s.unescapingMode) if err != nil { + var mse MalformedSequenceError + if ok := errors.As(err, &mse); ok { + _, outboundMarshaler := MarshalerForRequest(s, r) + s.errorHandler(ctx, s, outboundMarshaler, w, r, &HTTPStatusError{ + HTTPStatus: http.StatusBadRequest, + Err: mse, + }) + } continue } h.h(ctx, w, r, pathParams) @@ -249,8 +398,16 @@ func (s *ServeMux) ServeHTTP(w http.ResponseWriter, r *http.Request) { continue } for _, h := range handlers { - pathParams, err := h.pat.Match(components, verb) + pathParams, err := h.pat.MatchAndEscape(components, verb, s.unescapingMode) if err != nil { + var mse MalformedSequenceError + if ok := errors.As(err, &mse); ok { + _, outboundMarshaler := MarshalerForRequest(s, r) + s.errorHandler(ctx, s, outboundMarshaler, w, r, &HTTPStatusError{ + HTTPStatus: http.StatusBadRequest, + Err: mse, + }) + } continue } // X-HTTP-Method-Override is optional. Always allow fallback to POST. diff --git a/gateway/runtime/mux_test.go b/gateway/runtime/mux_test.go index b73be95..96d0836 100644 --- a/gateway/runtime/mux_test.go +++ b/gateway/runtime/mux_test.go @@ -6,12 +6,18 @@ import ( "fmt" "net/http" "net/http/httptest" + "net/url" "strconv" + "strings" "testing" // "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" "github.com/binchencoder/ease-gateway/gateway/runtime" "github.com/grpc-ecosystem/grpc-gateway/v2/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/health/grpc_health_v1" + "google.golang.org/grpc/status" ) func TestMuxServeHTTP(t *testing.T) { @@ -32,6 +38,7 @@ func TestMuxServeHTTP(t *testing.T) { respContent string disablePathLengthFallback bool + unescapingMode runtime.UnescapingMode }{ { patterns: nil, @@ -310,11 +317,163 @@ func TestMuxServeHTTP(t *testing.T) { }, respStatus: http.StatusBadRequest, }, + { + patterns: []stubPattern{ + { + method: "POST", + ops: []int{int(utilities.OpLitPush), 0, int(utilities.OpPush), 0, int(utilities.OpConcatN), 1, int(utilities.OpCapture), 1}, + pool: []string{"foo", "id"}, + }, + { + method: "POST", + ops: []int{int(utilities.OpLitPush), 0, int(utilities.OpPush), 0, int(utilities.OpConcatN), 1, int(utilities.OpCapture), 1}, + pool: []string{"foo", "id"}, + verb: "verb:subverb", + }, + }, + reqMethod: "POST", + reqPath: "/foo/bar:verb:subverb", + headers: map[string]string{ + "Content-Type": "application/json", + }, + respStatus: http.StatusOK, + respContent: "POST /foo/{id=*}:verb:subverb", + }, + { + patterns: []stubPattern{ + { + method: "GET", + ops: []int{int(utilities.OpLitPush), 0, int(utilities.OpPush), 1, int(utilities.OpCapture), 1, int(utilities.OpLitPush), 2}, + pool: []string{"foo", "id", "bar"}, + }, + }, + reqMethod: "POST", + reqPath: "/foo/404%2fwith%2Fspace/bar", + headers: map[string]string{ + "Content-Type": "application/json", + }, + respStatus: http.StatusNotFound, + unescapingMode: runtime.UnescapingModeLegacy, + }, + { + patterns: []stubPattern{ + { + method: "GET", + ops: []int{ + int(utilities.OpLitPush), 0, + int(utilities.OpPush), 0, + int(utilities.OpConcatN), 1, + int(utilities.OpCapture), 1, + int(utilities.OpLitPush), 2}, + pool: []string{"foo", "id", "bar"}, + }, + }, + reqMethod: "GET", + reqPath: "/foo/success%2fwith%2Fspace/bar", + headers: map[string]string{ + "Content-Type": "application/json", + }, + respStatus: http.StatusOK, + unescapingMode: runtime.UnescapingModeAllExceptReserved, + respContent: "GET /foo/{id=*}/bar", + }, + { + patterns: []stubPattern{ + { + method: "GET", + ops: []int{ + int(utilities.OpLitPush), 0, + int(utilities.OpPush), 0, + int(utilities.OpConcatN), 1, + int(utilities.OpCapture), 1, + int(utilities.OpLitPush), 2}, + pool: []string{"foo", "id", "bar"}, + }, + }, + reqMethod: "GET", + reqPath: "/foo/success%2fwith%2Fspace/bar", + headers: map[string]string{ + "Content-Type": "application/json", + }, + respStatus: http.StatusNotFound, + unescapingMode: runtime.UnescapingModeAllCharacters, + }, + { + patterns: []stubPattern{ + { + method: "GET", + ops: []int{ + int(utilities.OpLitPush), 0, + int(utilities.OpPush), 0, + int(utilities.OpConcatN), 1, + int(utilities.OpCapture), 1, + int(utilities.OpLitPush), 2}, + pool: []string{"foo", "id", "bar"}, + }, + }, + reqMethod: "GET", + reqPath: "/foo/success%2fwith%2Fspace/bar", + headers: map[string]string{ + "Content-Type": "application/json", + }, + respStatus: http.StatusNotFound, + unescapingMode: runtime.UnescapingModeLegacy, + }, + { + patterns: []stubPattern{ + { + method: "GET", + ops: []int{ + int(utilities.OpLitPush), 0, + int(utilities.OpPushM), 0, + int(utilities.OpConcatN), 1, + int(utilities.OpCapture), 1, + }, + pool: []string{"foo", "id", "bar"}, + }, + }, + reqMethod: "GET", + reqPath: "/foo/success%2fwith%2Fspace", + headers: map[string]string{ + "Content-Type": "application/json", + }, + respStatus: http.StatusOK, + unescapingMode: runtime.UnescapingModeAllExceptReserved, + respContent: "GET /foo/{id=**}", + }, + { + patterns: []stubPattern{ + { + method: "POST", + ops: []int{ + int(utilities.OpLitPush), 0, + int(utilities.OpLitPush), 1, + int(utilities.OpLitPush), 2, + int(utilities.OpPush), 0, + int(utilities.OpConcatN), 2, + int(utilities.OpCapture), 3, + }, + pool: []string{"api", "v1", "organizations", "name"}, + verb: "action", + }, + }, + reqMethod: "POST", + reqPath: "/api/v1/" + url.QueryEscape("organizations/foo") + ":action", + headers: map[string]string{ + "Content-Type": "application/json", + }, + respStatus: http.StatusOK, + unescapingMode: runtime.UnescapingModeAllCharacters, + respContent: "POST /api/v1/{name=organizations/*}:action", + }, } { t.Run(strconv.Itoa(i), func(t *testing.T) { var opts []runtime.ServeMuxOption + opts = append(opts, runtime.WithUnescapingMode(spec.unescapingMode)) if spec.disablePathLengthFallback { - opts = append(opts, runtime.WithDisablePathLengthFallback()) + opts = append(opts, + runtime.WithDisablePathLengthFallback(), + ) } mux := runtime.NewServeMux(opts...) for _, p := range spec.patterns { @@ -329,10 +488,10 @@ func TestMuxServeHTTP(t *testing.T) { }(p) } - url := fmt.Sprintf("http://host.example%s", spec.reqPath) - r, err := http.NewRequest(spec.reqMethod, url, bytes.NewReader(nil)) + reqUrl := fmt.Sprintf("https://host.example%s", spec.reqPath) + r, err := http.NewRequest(spec.reqMethod, reqUrl, bytes.NewReader(nil)) if err != nil { - t.Fatalf("http.NewRequest(%q, %q, nil) failed with %v; want success", spec.reqMethod, url, err) + t.Fatalf("http.NewRequest(%q, %q, nil) failed with %v; want success", spec.reqMethod, reqUrl, err) } for name, value := range spec.headers { r.Header.Set(name, value) @@ -398,6 +557,12 @@ var defaultRouteMatcherTests = []struct { path string valid bool }{ + { + "Test route /", + "GET", + "/", + true, + }, { "Simple Endpoint", "GET", @@ -439,5 +604,137 @@ func TestServeMux_HandlePath(t *testing.T) { } }) } +} -} \ No newline at end of file +var healthCheckTests = []struct { + name string + code codes.Code + status grpc_health_v1.HealthCheckResponse_ServingStatus + httpStatusCode int +}{ + { + "Test grpc error code", + codes.NotFound, + grpc_health_v1.HealthCheckResponse_UNKNOWN, + http.StatusNotFound, + }, + { + "Test HealthCheckResponse_SERVING", + codes.OK, + grpc_health_v1.HealthCheckResponse_SERVING, + http.StatusOK, + }, + { + "Test HealthCheckResponse_NOT_SERVING", + codes.OK, + grpc_health_v1.HealthCheckResponse_NOT_SERVING, + http.StatusServiceUnavailable, + }, + { + "Test HealthCheckResponse_UNKNOWN", + codes.OK, + grpc_health_v1.HealthCheckResponse_UNKNOWN, + http.StatusServiceUnavailable, + }, + { + "Test HealthCheckResponse_SERVICE_UNKNOWN", + codes.OK, + grpc_health_v1.HealthCheckResponse_SERVICE_UNKNOWN, + http.StatusNotFound, + }, +} + +func TestWithHealthzEndpoint_codes(t *testing.T) { + for _, tt := range healthCheckTests { + t.Run(tt.name, func(t *testing.T) { + mux := runtime.NewServeMux(runtime.WithHealthzEndpoint(&dummyHealthCheckClient{status: tt.status, code: tt.code}, 1 /* sid */)) + + r := httptest.NewRequest(http.MethodGet, "/healthz", nil) + rr := httptest.NewRecorder() + + mux.ServeHTTP(rr, r) + + if rr.Code != tt.httpStatusCode { + t.Errorf( + "result http status code for grpc code %q and status %q should be %d, got %d", + tt.code, tt.status, tt.httpStatusCode, rr.Code, + ) + } + }) + } +} + +func TestWithHealthEndpointAt_consistentWithHealthz(t *testing.T) { + const endpointPath = "/healthz" + + r := httptest.NewRequest(http.MethodGet, endpointPath, nil) + + for _, tt := range healthCheckTests { + tt := tt + + t.Run(tt.name, func(t *testing.T) { + client := &dummyHealthCheckClient{ + status: tt.status, + code: tt.code, + } + + w := httptest.NewRecorder() + + runtime.NewServeMux( + runtime.WithHealthEndpointAt(client, endpointPath), + ).ServeHTTP(w, r) + + refW := httptest.NewRecorder() + + runtime.NewServeMux( + runtime.WithHealthzEndpoint(client, 1 /* sid */), + ).ServeHTTP(refW, r) + + if w.Code != refW.Code { + t.Errorf( + "result http status code for grpc code %q and status %q should be equal to %d, but got %d", + tt.code, tt.status, refW.Code, w.Code, + ) + } + }) + } +} + +func TestWithHealthzEndpoint_serviceParam(t *testing.T) { + service := "test" + + // trigger error to output service in body + dummyClient := dummyHealthCheckClient{status: grpc_health_v1.HealthCheckResponse_UNKNOWN, code: codes.Unknown} + mux := runtime.NewServeMux(runtime.WithHealthzEndpoint(&dummyClient, 1 /* sid */)) + + r := httptest.NewRequest(http.MethodGet, "/healthz?service="+service, nil) + rr := httptest.NewRecorder() + + mux.ServeHTTP(rr, r) + + if !strings.Contains(rr.Body.String(), service) { + t.Errorf( + "service query parameter should be translated to HealthCheckRequest: expected %s to contain %s", + rr.Body.String(), service, + ) + } +} + +var _ grpc_health_v1.HealthClient = (*dummyHealthCheckClient)(nil) + +type dummyHealthCheckClient struct { + status grpc_health_v1.HealthCheckResponse_ServingStatus + code codes.Code +} + +func (g *dummyHealthCheckClient) Check(ctx context.Context, r *grpc_health_v1.HealthCheckRequest, opts ...grpc.CallOption) (*grpc_health_v1.HealthCheckResponse, error) { + if g.code != codes.OK { + return nil, status.Error(g.code, r.GetService()) + } + + return &grpc_health_v1.HealthCheckResponse{Status: g.status}, nil +} + +func (g *dummyHealthCheckClient) Watch(ctx context.Context, r *grpc_health_v1.HealthCheckRequest, opts ...grpc.CallOption) (grpc_health_v1.Health_WatchClient, error) { + return nil, status.Error(codes.Unimplemented, "unimplemented") +} diff --git a/gateway/runtime/pattern.go b/gateway/runtime/pattern.go index f319664..df7cb81 100644 --- a/gateway/runtime/pattern.go +++ b/gateway/runtime/pattern.go @@ -3,6 +3,7 @@ package runtime import ( "errors" "fmt" + "strconv" "strings" "github.com/grpc-ecosystem/grpc-gateway/v2/utilities" @@ -14,8 +15,16 @@ var ( ErrNotMatch = errors.New("not match to the path pattern") // ErrInvalidPattern indicates that the given definition of Pattern is not valid. ErrInvalidPattern = errors.New("invalid pattern") + // ErrMalformedSequence indicates that an escape sequence was malformed. + ErrMalformedSequence = errors.New("malformed escape sequence") ) +type MalformedSequenceError string + +func (e MalformedSequenceError) Error() string { + return "malformed path escape " + strconv.Quote(string(e)) +} + type op struct { code utilities.OpCode operand int @@ -140,10 +149,11 @@ func MustPattern(p Pattern, err error) Pattern { return p } -// Match examines components if it matches to the Pattern. -// If it matches, the function returns a mapping from field paths to their captured values. -// If otherwise, the function returns an error. -func (p Pattern) Match(components []string, verb string) (map[string]string, error) { +// MatchAndEscape examines components to determine if they match to a Pattern. +// MatchAndEscape will return an error if no Patterns matched or if a pattern +// matched but contained malformed escape sequences. If successful, the function +// returns a mapping from field paths to their captured values. +func (p Pattern) MatchAndEscape(components []string, verb string, unescapingMode UnescapingMode) (map[string]string, error) { if p.verb != verb { if p.verb != "" { return nil, ErrNotMatch @@ -154,7 +164,6 @@ func (p Pattern) Match(components []string, verb string) (map[string]string, err components = append([]string{}, components...) components[len(components)-1] += ":" + verb } - verb = "" } var pos int @@ -162,6 +171,8 @@ func (p Pattern) Match(components []string, verb string) (map[string]string, err captured := make([]string, len(p.vars)) l := len(components) for _, op := range p.ops { + var err error + switch op.code { case utilities.OpNop: continue @@ -174,6 +185,10 @@ func (p Pattern) Match(components []string, verb string) (map[string]string, err if lit := p.pool[op.operand]; c != lit { return nil, ErrNotMatch } + } else if op.code == utilities.OpPush { + if c, err = unescape(c, unescapingMode, false); err != nil { + return nil, err + } } stack = append(stack, c) pos++ @@ -183,7 +198,11 @@ func (p Pattern) Match(components []string, verb string) (map[string]string, err return nil, ErrNotMatch } end -= p.tailLen - stack = append(stack, strings.Join(components[pos:end], "/")) + c := strings.Join(components[pos:end], "/") + if c, err = unescape(c, unescapingMode, true); err != nil { + return nil, err + } + stack = append(stack, c) pos = end case utilities.OpConcatN: n := op.operand @@ -205,6 +224,16 @@ func (p Pattern) Match(components []string, verb string) (map[string]string, err return bindings, nil } +// MatchAndEscape examines components to determine if they match to a Pattern. +// It will never perform per-component unescaping (see: UnescapingModeLegacy). +// MatchAndEscape will return an error if no Patterns matched. If successful, +// the function returns a mapping from field paths to their captured values. +// +// Deprecated: Use MatchAndEscape. +func (p Pattern) Match(components []string, verb string) (map[string]string, error) { + return p.MatchAndEscape(components, verb, UnescapingModeDefault) +} + // Verb returns the verb part of the Pattern. func (p Pattern) Verb() string { return p.verb } @@ -235,3 +264,120 @@ func (p Pattern) String() string { } return "/" + segs } + +/* + * The following code is adopted and modified from Go's standard library + * and carries the attached license. + * + * Copyright 2009 The Go Authors. All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + */ + +// ishex returns whether or not the given byte is a valid hex character +func ishex(c byte) bool { + switch { + case '0' <= c && c <= '9': + return true + case 'a' <= c && c <= 'f': + return true + case 'A' <= c && c <= 'F': + return true + } + return false +} + +func isRFC6570Reserved(c byte) bool { + switch c { + case '!', '#', '$', '&', '\'', '(', ')', '*', + '+', ',', '/', ':', ';', '=', '?', '@', '[', ']': + return true + default: + return false + } +} + +// unhex converts a hex point to the bit representation +func unhex(c byte) byte { + switch { + case '0' <= c && c <= '9': + return c - '0' + case 'a' <= c && c <= 'f': + return c - 'a' + 10 + case 'A' <= c && c <= 'F': + return c - 'A' + 10 + } + return 0 +} + +// shouldUnescapeWithMode returns true if the character is escapable with the +// given mode +func shouldUnescapeWithMode(c byte, mode UnescapingMode) bool { + switch mode { + case UnescapingModeAllExceptReserved: + if isRFC6570Reserved(c) { + return false + } + case UnescapingModeAllExceptSlash: + if c == '/' { + return false + } + case UnescapingModeAllCharacters: + return true + } + return true +} + +// unescape unescapes a path string using the provided mode +func unescape(s string, mode UnescapingMode, multisegment bool) (string, error) { + // TODO(v3): remove UnescapingModeLegacy + if mode == UnescapingModeLegacy { + return s, nil + } + + if !multisegment { + mode = UnescapingModeAllCharacters + } + + // Count %, check that they're well-formed. + n := 0 + for i := 0; i < len(s); { + if s[i] == '%' { + n++ + if i+2 >= len(s) || !ishex(s[i+1]) || !ishex(s[i+2]) { + s = s[i:] + if len(s) > 3 { + s = s[:3] + } + + return "", MalformedSequenceError(s) + } + i += 3 + } else { + i++ + } + } + + if n == 0 { + return s, nil + } + + var t strings.Builder + t.Grow(len(s)) + for i := 0; i < len(s); i++ { + switch s[i] { + case '%': + c := unhex(s[i+1])<<4 | unhex(s[i+2]) + if shouldUnescapeWithMode(c, mode) { + t.WriteByte(c) + i += 2 + continue + } + fallthrough + default: + t.WriteByte(s[i]) + } + } + + return t.String(), nil +} diff --git a/gateway/runtime/pattern_test.go b/gateway/runtime/pattern_test.go deleted file mode 100644 index 1b856a5..0000000 --- a/gateway/runtime/pattern_test.go +++ /dev/null @@ -1,590 +0,0 @@ -package runtime - -import ( - "fmt" - "reflect" - "strings" - "testing" - - "github.com/grpc-ecosystem/grpc-gateway/v2/utilities" -) - -const ( - validVersion = 1 - anything = 0 -) - -func TestNewPattern(t *testing.T) { - for _, spec := range []struct { - ops []int - pool []string - verb string - - stackSizeWant, tailLenWant int - }{ - {}, - { - ops: []int{int(utilities.OpNop), anything}, - stackSizeWant: 0, - tailLenWant: 0, - }, - { - ops: []int{int(utilities.OpPush), anything}, - stackSizeWant: 1, - tailLenWant: 0, - }, - { - ops: []int{int(utilities.OpLitPush), 0}, - pool: []string{"abc"}, - stackSizeWant: 1, - tailLenWant: 0, - }, - { - ops: []int{int(utilities.OpPushM), anything}, - stackSizeWant: 1, - tailLenWant: 0, - }, - { - ops: []int{ - int(utilities.OpPush), anything, - int(utilities.OpConcatN), 1, - }, - stackSizeWant: 1, - tailLenWant: 0, - }, - { - ops: []int{ - int(utilities.OpPush), anything, - int(utilities.OpConcatN), 1, - int(utilities.OpCapture), 0, - }, - pool: []string{"abc"}, - stackSizeWant: 1, - tailLenWant: 0, - }, - { - ops: []int{ - int(utilities.OpPush), anything, - int(utilities.OpLitPush), 0, - int(utilities.OpLitPush), 1, - int(utilities.OpPushM), anything, - int(utilities.OpConcatN), 2, - int(utilities.OpCapture), 2, - }, - pool: []string{"lit1", "lit2", "var1"}, - stackSizeWant: 4, - tailLenWant: 0, - }, - { - ops: []int{ - int(utilities.OpPushM), anything, - int(utilities.OpConcatN), 1, - int(utilities.OpCapture), 2, - int(utilities.OpLitPush), 0, - int(utilities.OpLitPush), 1, - }, - pool: []string{"lit1", "lit2", "var1"}, - stackSizeWant: 2, - tailLenWant: 2, - }, - { - ops: []int{ - int(utilities.OpLitPush), 0, - int(utilities.OpLitPush), 1, - int(utilities.OpPushM), anything, - int(utilities.OpLitPush), 2, - int(utilities.OpConcatN), 3, - int(utilities.OpLitPush), 3, - int(utilities.OpCapture), 4, - }, - pool: []string{"lit1", "lit2", "lit3", "lit4", "var1"}, - stackSizeWant: 4, - tailLenWant: 2, - }, - { - ops: []int{int(utilities.OpLitPush), 0}, - pool: []string{"abc"}, - verb: "LOCK", - stackSizeWant: 1, - tailLenWant: 0, - }, - } { - pat, err := NewPattern(validVersion, spec.ops, spec.pool, spec.verb) - if err != nil { - t.Errorf("NewPattern(%d, %v, %q, %q) failed with %v; want success", validVersion, spec.ops, spec.pool, spec.verb, err) - continue - } - if got, want := pat.stacksize, spec.stackSizeWant; got != want { - t.Errorf("pat.stacksize = %d; want %d", got, want) - } - if got, want := pat.tailLen, spec.tailLenWant; got != want { - t.Errorf("pat.stacksize = %d; want %d", got, want) - } - } -} - -func TestNewPatternWithWrongOp(t *testing.T) { - for _, spec := range []struct { - ops []int - pool []string - verb string - }{ - { - // op code out of bound - ops: []int{-1, anything}, - }, - { - // op code out of bound - ops: []int{int(utilities.OpEnd), 0}, - }, - { - // odd number of items - ops: []int{int(utilities.OpPush)}, - }, - { - // negative index - ops: []int{int(utilities.OpLitPush), -1}, - pool: []string{"abc"}, - }, - { - // index out of bound - ops: []int{int(utilities.OpLitPush), 1}, - pool: []string{"abc"}, - }, - { - // negative # of segments - ops: []int{int(utilities.OpConcatN), -1}, - pool: []string{"abc"}, - }, - { - // negative index - ops: []int{int(utilities.OpCapture), -1}, - pool: []string{"abc"}, - }, - { - // index out of bound - ops: []int{int(utilities.OpCapture), 1}, - pool: []string{"abc"}, - }, - { - // pushM appears twice - ops: []int{ - int(utilities.OpPushM), anything, - int(utilities.OpLitPush), 0, - int(utilities.OpPushM), anything, - }, - pool: []string{"abc"}, - }, - } { - _, err := NewPattern(validVersion, spec.ops, spec.pool, spec.verb) - if err == nil { - t.Errorf("NewPattern(%d, %v, %q, %q) succeeded; want failure with %v", validVersion, spec.ops, spec.pool, spec.verb, ErrInvalidPattern) - continue - } - if err != ErrInvalidPattern { - t.Errorf("NewPattern(%d, %v, %q, %q) failed with %v; want failure with %v", validVersion, spec.ops, spec.pool, spec.verb, err, ErrInvalidPattern) - continue - } - } -} - -func TestNewPatternWithStackUnderflow(t *testing.T) { - for _, spec := range []struct { - ops []int - pool []string - verb string - }{ - { - ops: []int{int(utilities.OpConcatN), 1}, - }, - { - ops: []int{int(utilities.OpCapture), 0}, - pool: []string{"abc"}, - }, - } { - _, err := NewPattern(validVersion, spec.ops, spec.pool, spec.verb) - if err == nil { - t.Errorf("NewPattern(%d, %v, %q, %q) succeeded; want failure with %v", validVersion, spec.ops, spec.pool, spec.verb, ErrInvalidPattern) - continue - } - if err != ErrInvalidPattern { - t.Errorf("NewPattern(%d, %v, %q, %q) failed with %v; want failure with %v", validVersion, spec.ops, spec.pool, spec.verb, err, ErrInvalidPattern) - continue - } - } -} - -func TestMatch(t *testing.T) { - for _, spec := range []struct { - ops []int - pool []string - verb string - - match []string - notMatch []string - }{ - { - match: []string{""}, - notMatch: []string{"example"}, - }, - { - ops: []int{int(utilities.OpNop), anything}, - match: []string{""}, - notMatch: []string{"example", "path/to/example"}, - }, - { - ops: []int{int(utilities.OpPush), anything}, - match: []string{"abc", "def"}, - notMatch: []string{"", "abc/def"}, - }, - { - ops: []int{int(utilities.OpLitPush), 0}, - pool: []string{"v1"}, - match: []string{"v1"}, - notMatch: []string{"", "v2"}, - }, - { - ops: []int{int(utilities.OpPushM), anything}, - match: []string{"", "abc", "abc/def", "abc/def/ghi"}, - }, - { - ops: []int{ - int(utilities.OpPushM), anything, - int(utilities.OpLitPush), 0, - }, - pool: []string{"tail"}, - match: []string{"tail", "abc/tail", "abc/def/tail"}, - notMatch: []string{ - "", "abc", "abc/def", - "tail/extra", "abc/tail/extra", "abc/def/tail/extra", - }, - }, - { - ops: []int{ - int(utilities.OpLitPush), 0, - int(utilities.OpLitPush), 1, - int(utilities.OpPush), anything, - int(utilities.OpConcatN), 1, - int(utilities.OpCapture), 2, - }, - pool: []string{"v1", "bucket", "name"}, - match: []string{"v1/bucket/my-bucket", "v1/bucket/our-bucket"}, - notMatch: []string{ - "", - "v1", - "v1/bucket", - "v2/bucket/my-bucket", - "v1/pubsub/my-topic", - }, - }, - { - ops: []int{ - int(utilities.OpLitPush), 0, - int(utilities.OpLitPush), 1, - int(utilities.OpPushM), anything, - int(utilities.OpConcatN), 2, - int(utilities.OpCapture), 2, - }, - pool: []string{"v1", "o", "name"}, - match: []string{ - "v1/o", - "v1/o/my-bucket", - "v1/o/our-bucket", - "v1/o/my-bucket/dir", - "v1/o/my-bucket/dir/dir2", - "v1/o/my-bucket/dir/dir2/obj", - }, - notMatch: []string{ - "", - "v1", - "v2/o/my-bucket", - "v1/b/my-bucket", - }, - }, - { - ops: []int{ - int(utilities.OpLitPush), 0, - int(utilities.OpLitPush), 1, - int(utilities.OpPush), anything, - int(utilities.OpConcatN), 2, - int(utilities.OpCapture), 2, - int(utilities.OpLitPush), 3, - int(utilities.OpPush), anything, - int(utilities.OpConcatN), 1, - int(utilities.OpCapture), 4, - }, - pool: []string{"v2", "b", "name", "o", "oname"}, - match: []string{ - "v2/b/my-bucket/o/obj", - "v2/b/our-bucket/o/obj", - "v2/b/my-bucket/o/dir", - }, - notMatch: []string{ - "", - "v2", - "v2/b", - "v2/b/my-bucket", - "v2/b/my-bucket/o", - }, - }, - { - ops: []int{int(utilities.OpLitPush), 0}, - pool: []string{"v1"}, - verb: "LOCK", - match: []string{"v1:LOCK"}, - notMatch: []string{"v1", "LOCK"}, - }, - } { - pat, err := NewPattern(validVersion, spec.ops, spec.pool, spec.verb) - if err != nil { - t.Errorf("NewPattern(%d, %v, %q, %q) failed with %v; want success", validVersion, spec.ops, spec.pool, spec.verb, err) - continue - } - - for _, path := range spec.match { - _, err = pat.Match(segments(path)) - if err != nil { - t.Errorf("pat.Match(%q) failed with %v; want success; pattern = (%v, %q)", path, err, spec.ops, spec.pool) - } - } - - for _, path := range spec.notMatch { - _, err = pat.Match(segments(path)) - if err == nil { - t.Errorf("pat.Match(%q) succeeded; want failure with %v; pattern = (%v, %q)", path, ErrNotMatch, spec.ops, spec.pool) - continue - } - if err != ErrNotMatch { - t.Errorf("pat.Match(%q) failed with %v; want failure with %v; pattern = (%v, %q)", spec.notMatch, err, ErrNotMatch, spec.ops, spec.pool) - } - } - } -} - -func TestMatchWithBinding(t *testing.T) { - for _, spec := range []struct { - ops []int - pool []string - path string - verb string - - want map[string]string - }{ - { - want: make(map[string]string), - }, - { - ops: []int{int(utilities.OpNop), anything}, - want: make(map[string]string), - }, - { - ops: []int{int(utilities.OpPush), anything}, - path: "abc", - want: make(map[string]string), - }, - { - ops: []int{int(utilities.OpPush), anything}, - verb: "LOCK", - path: "abc:LOCK", - want: make(map[string]string), - }, - { - ops: []int{int(utilities.OpLitPush), 0}, - pool: []string{"endpoint"}, - path: "endpoint", - want: make(map[string]string), - }, - { - ops: []int{int(utilities.OpPushM), anything}, - path: "abc/def/ghi", - want: make(map[string]string), - }, - { - ops: []int{ - int(utilities.OpLitPush), 0, - int(utilities.OpLitPush), 1, - int(utilities.OpPush), anything, - int(utilities.OpConcatN), 1, - int(utilities.OpCapture), 2, - }, - pool: []string{"v1", "bucket", "name"}, - path: "v1/bucket/my-bucket", - want: map[string]string{ - "name": "my-bucket", - }, - }, - { - ops: []int{ - int(utilities.OpLitPush), 0, - int(utilities.OpLitPush), 1, - int(utilities.OpPush), anything, - int(utilities.OpConcatN), 1, - int(utilities.OpCapture), 2, - }, - pool: []string{"v1", "bucket", "name"}, - verb: "LOCK", - path: "v1/bucket/my-bucket:LOCK", - want: map[string]string{ - "name": "my-bucket", - }, - }, - { - ops: []int{ - int(utilities.OpLitPush), 0, - int(utilities.OpLitPush), 1, - int(utilities.OpPushM), anything, - int(utilities.OpConcatN), 2, - int(utilities.OpCapture), 2, - }, - pool: []string{"v1", "o", "name"}, - path: "v1/o/my-bucket/dir/dir2/obj", - want: map[string]string{ - "name": "o/my-bucket/dir/dir2/obj", - }, - }, - { - ops: []int{ - int(utilities.OpLitPush), 0, - int(utilities.OpLitPush), 1, - int(utilities.OpPushM), anything, - int(utilities.OpLitPush), 2, - int(utilities.OpConcatN), 3, - int(utilities.OpCapture), 4, - int(utilities.OpLitPush), 3, - }, - pool: []string{"v1", "o", ".ext", "tail", "name"}, - path: "v1/o/my-bucket/dir/dir2/obj/.ext/tail", - want: map[string]string{ - "name": "o/my-bucket/dir/dir2/obj/.ext", - }, - }, - { - ops: []int{ - int(utilities.OpLitPush), 0, - int(utilities.OpLitPush), 1, - int(utilities.OpPush), anything, - int(utilities.OpConcatN), 2, - int(utilities.OpCapture), 2, - int(utilities.OpLitPush), 3, - int(utilities.OpPush), anything, - int(utilities.OpConcatN), 1, - int(utilities.OpCapture), 4, - }, - pool: []string{"v2", "b", "name", "o", "oname"}, - path: "v2/b/my-bucket/o/obj", - want: map[string]string{ - "name": "b/my-bucket", - "oname": "obj", - }, - }, - } { - pat, err := NewPattern(validVersion, spec.ops, spec.pool, spec.verb) - if err != nil { - t.Errorf("NewPattern(%d, %v, %q, %q) failed with %v; want success", validVersion, spec.ops, spec.pool, spec.verb, err) - continue - } - - got, err := pat.Match(segments(spec.path)) - if err != nil { - t.Errorf("pat.Match(%q) failed with %v; want success; pattern = (%v, %q)", spec.path, err, spec.ops, spec.pool) - } - if !reflect.DeepEqual(got, spec.want) { - t.Errorf("pat.Match(%q) = %q; want %q; pattern = (%v, %q)", spec.path, got, spec.want, spec.ops, spec.pool) - } - } -} - -func segments(path string) (components []string, verb string) { - if path == "" { - return nil, "" - } - components = strings.Split(path, "/") - l := len(components) - c := components[l-1] - if idx := strings.LastIndex(c, ":"); idx >= 0 { - components[l-1], verb = c[:idx], c[idx+1:] - } - return components, verb -} - -func TestPatternString(t *testing.T) { - for _, spec := range []struct { - ops []int - pool []string - - want string - }{ - { - want: "/", - }, - { - ops: []int{int(utilities.OpNop), anything}, - want: "/", - }, - { - ops: []int{int(utilities.OpPush), anything}, - want: "/*", - }, - { - ops: []int{int(utilities.OpLitPush), 0}, - pool: []string{"endpoint"}, - want: "/endpoint", - }, - { - ops: []int{int(utilities.OpPushM), anything}, - want: "/**", - }, - { - ops: []int{ - int(utilities.OpPush), anything, - int(utilities.OpConcatN), 1, - }, - want: "/*", - }, - { - ops: []int{ - int(utilities.OpPush), anything, - int(utilities.OpConcatN), 1, - int(utilities.OpCapture), 0, - }, - pool: []string{"name"}, - want: "/{name=*}", - }, - { - ops: []int{ - int(utilities.OpLitPush), 0, - int(utilities.OpLitPush), 1, - int(utilities.OpPush), anything, - int(utilities.OpConcatN), 2, - int(utilities.OpCapture), 2, - int(utilities.OpLitPush), 3, - int(utilities.OpPushM), anything, - int(utilities.OpLitPush), 4, - int(utilities.OpConcatN), 3, - int(utilities.OpCapture), 6, - int(utilities.OpLitPush), 5, - }, - pool: []string{"v1", "buckets", "bucket_name", "objects", ".ext", "tail", "name"}, - want: "/v1/{bucket_name=buckets/*}/{name=objects/**/.ext}/tail", - }, - } { - p, err := NewPattern(validVersion, spec.ops, spec.pool, "") - if err != nil { - t.Errorf("NewPattern(%d, %v, %q, %q) failed with %v; want success", validVersion, spec.ops, spec.pool, "", err) - continue - } - if got, want := p.String(), spec.want; got != want { - t.Errorf("%#v.String() = %q; want %q", p, got, want) - } - - verb := "LOCK" - p, err = NewPattern(validVersion, spec.ops, spec.pool, verb) - if err != nil { - t.Errorf("NewPattern(%d, %v, %q, %q) failed with %v; want success", validVersion, spec.ops, spec.pool, verb, err) - continue - } - if got, want := p.String(), fmt.Sprintf("%s:%s", spec.want, verb); got != want { - t.Errorf("%#v.String() = %q; want %q", p, got, want) - } - } -} diff --git a/gateway/runtime/proto2_convert.go b/gateway/runtime/proto2_convert.go deleted file mode 100644 index d549407..0000000 --- a/gateway/runtime/proto2_convert.go +++ /dev/null @@ -1,80 +0,0 @@ -package runtime - -import ( - "google.golang.org/protobuf/proto" -) - -// StringP returns a pointer to a string whose pointee is same as the given string value. -func StringP(val string) (*string, error) { - return proto.String(val), nil -} - -// BoolP parses the given string representation of a boolean value, -// and returns a pointer to a bool whose value is same as the parsed value. -func BoolP(val string) (*bool, error) { - b, err := Bool(val) - if err != nil { - return nil, err - } - return proto.Bool(b), nil -} - -// Float64P parses the given string representation of a floating point number, -// and returns a pointer to a float64 whose value is same as the parsed number. -func Float64P(val string) (*float64, error) { - f, err := Float64(val) - if err != nil { - return nil, err - } - return proto.Float64(f), nil -} - -// Float32P parses the given string representation of a floating point number, -// and returns a pointer to a float32 whose value is same as the parsed number. -func Float32P(val string) (*float32, error) { - f, err := Float32(val) - if err != nil { - return nil, err - } - return proto.Float32(f), nil -} - -// Int64P parses the given string representation of an integer -// and returns a pointer to a int64 whose value is same as the parsed integer. -func Int64P(val string) (*int64, error) { - i, err := Int64(val) - if err != nil { - return nil, err - } - return proto.Int64(i), nil -} - -// Int32P parses the given string representation of an integer -// and returns a pointer to a int32 whose value is same as the parsed integer. -func Int32P(val string) (*int32, error) { - i, err := Int32(val) - if err != nil { - return nil, err - } - return proto.Int32(i), err -} - -// Uint64P parses the given string representation of an integer -// and returns a pointer to a uint64 whose value is same as the parsed integer. -func Uint64P(val string) (*uint64, error) { - i, err := Uint64(val) - if err != nil { - return nil, err - } - return proto.Uint64(i), err -} - -// Uint32P parses the given string representation of an integer -// and returns a pointer to a uint32 whose value is same as the parsed integer. -func Uint32P(val string) (*uint32, error) { - i, err := Uint32(val) - if err != nil { - return nil, err - } - return proto.Uint32(i), err -} diff --git a/gateway/runtime/query.go b/gateway/runtime/query.go index 9a9f3d3..fb0c84e 100644 --- a/gateway/runtime/query.go +++ b/gateway/runtime/query.go @@ -10,14 +10,15 @@ import ( "strings" "time" - "github.com/golang/protobuf/ptypes" - wrapperspb "github.com/golang/protobuf/ptypes/wrappers" "github.com/grpc-ecosystem/grpc-gateway/v2/utilities" "google.golang.org/genproto/protobuf/field_mask" "google.golang.org/grpc/grpclog" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/reflect/protoreflect" "google.golang.org/protobuf/reflect/protoregistry" + "google.golang.org/protobuf/types/known/durationpb" + "google.golang.org/protobuf/types/known/timestamppb" + "google.golang.org/protobuf/types/known/wrapperspb" ) var valuesKeyRegexp = regexp.MustCompile(`^(.*)\[(.*)\]$`) @@ -233,7 +234,7 @@ func parseField(fieldDescriptor protoreflect.FieldDescriptor, value string) (pro case protoreflect.StringKind: return protoreflect.ValueOfString(value), nil case protoreflect.BytesKind: - v, err := base64.StdEncoding.DecodeString(value) + v, err := base64.URLEncoding.DecodeString(value) if err != nil { return protoreflect.Value{}, err } @@ -256,10 +257,7 @@ func parseMessage(msgDescriptor protoreflect.MessageDescriptor, value string) (p if err != nil { return protoreflect.Value{}, err } - msg, err = ptypes.TimestampProto(t) - if err != nil { - return protoreflect.Value{}, err - } + msg = timestamppb.New(t) case "google.protobuf.Duration": if value == "null" { break @@ -268,7 +266,7 @@ func parseMessage(msgDescriptor protoreflect.MessageDescriptor, value string) (p if err != nil { return protoreflect.Value{}, err } - msg = ptypes.DurationProto(d) + msg = durationpb.New(d) case "google.protobuf.DoubleValue": v, err := strconv.ParseFloat(value, 64) if err != nil { @@ -314,7 +312,7 @@ func parseMessage(msgDescriptor protoreflect.MessageDescriptor, value string) (p case "google.protobuf.StringValue": msg = &wrapperspb.StringValue{Value: value} case "google.protobuf.BytesValue": - v, err := base64.StdEncoding.DecodeString(value) + v, err := base64.URLEncoding.DecodeString(value) if err != nil { return protoreflect.Value{}, err } diff --git a/gateway/runtime/query_test.go b/gateway/runtime/query_test.go deleted file mode 100644 index ee6667a..0000000 --- a/gateway/runtime/query_test.go +++ /dev/null @@ -1,610 +0,0 @@ -package runtime_test - -import ( - "errors" - "net/url" - "strconv" - "testing" - "time" - - "github.com/golang/protobuf/ptypes" - wrapperspb "github.com/golang/protobuf/ptypes/wrappers" - "github.com/google/go-cmp/cmp" - // "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" - "github.com/binchencoder/ease-gateway/gateway/runtime" - "github.com/grpc-ecosystem/grpc-gateway/v2/runtime/internal/examplepb" - "github.com/grpc-ecosystem/grpc-gateway/v2/utilities" - "google.golang.org/genproto/protobuf/field_mask" - "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/testing/protocmp" -) - -func BenchmarkPopulateQueryParameters(b *testing.B) { - timeT := time.Date(2016, time.December, 15, 12, 23, 32, 49, time.UTC) - timeStr := timeT.Format(time.RFC3339Nano) - - durationT := 13 * time.Hour - durationStr := durationT.String() - - fieldmaskStr := "float_value,double_value" - - msg := &examplepb.Proto3Message{} - values := url.Values{ - "float_value": {"1.5"}, - "double_value": {"2.5"}, - "int64_value": {"-1"}, - "int32_value": {"-2"}, - "uint64_value": {"3"}, - "uint32_value": {"4"}, - "bool_value": {"true"}, - "string_value": {"str"}, - "bytes_value": {"Ynl0ZXM="}, - "repeated_value": {"a", "b", "c"}, - "enum_value": {"1"}, - "repeated_enum": {"1", "2", "0"}, - "timestamp_value": {timeStr}, - "duration_value": {durationStr}, - "fieldmask_value": {fieldmaskStr}, - "wrapper_float_value": {"1.5"}, - "wrapper_double_value": {"2.5"}, - "wrapper_int64_value": {"-1"}, - "wrapper_int32_value": {"-2"}, - "wrapper_u_int64_value": {"3"}, - "wrapper_u_int32_value": {"4"}, - "wrapper_bool_value": {"true"}, - "wrapper_string_value": {"str"}, - "wrapper_bytes_value": {"Ynl0ZXM="}, - "map_value[key]": {"value"}, - "map_value[second]": {"bar"}, - "map_value[third]": {"zzz"}, - "map_value[fourth]": {""}, - `map_value[~!@#$%^&*()]`: {"value"}, - "map_value2[key]": {"-2"}, - "map_value3[-2]": {"value"}, - "map_value4[key]": {"-1"}, - "map_value5[-1]": {"value"}, - "map_value6[key]": {"3"}, - "map_value7[3]": {"value"}, - "map_value8[key]": {"4"}, - "map_value9[4]": {"value"}, - "map_value10[key]": {"1.5"}, - "map_value11[1.5]": {"value"}, - "map_value12[key]": {"2.5"}, - "map_value13[2.5]": {"value"}, - "map_value14[key]": {"true"}, - "map_value15[true]": {"value"}, - } - filter := utilities.NewDoubleArray([][]string{ - {"bool_value"}, {"repeated_value"}, - }) - - for i := 0; i < b.N; i++ { - _ = runtime.PopulateQueryParameters(msg, values, filter) - } -} - -func TestPopulateParameters(t *testing.T) { - timeT := time.Date(2016, time.December, 15, 12, 23, 32, 49, time.UTC) - timeStr := timeT.Format(time.RFC3339Nano) - timePb, err := ptypes.TimestampProto(timeT) - if err != nil { - t.Fatalf("Couldn't setup timestamp in Protobuf format: %v", err) - } - - durationT := 13 * time.Hour - durationStr := durationT.String() - durationPb := ptypes.DurationProto(durationT) - - fieldmaskStr := "float_value,double_value" - fieldmaskPb := &field_mask.FieldMask{Paths: []string{"float_value", "double_value"}} - - for i, spec := range []struct { - values url.Values - filter *utilities.DoubleArray - want proto.Message - wanterr error - }{ - { - values: url.Values{ - "float_value": {"1.5"}, - "double_value": {"2.5"}, - "int64_value": {"-1"}, - "int32_value": {"-2"}, - "uint64_value": {"3"}, - "uint32_value": {"4"}, - "bool_value": {"true"}, - "string_value": {"str"}, - "bytes_value": {"Ynl0ZXM="}, - "repeated_value": {"a", "b", "c"}, - "repeated_message": {"1", "2", "3"}, - "enum_value": {"1"}, - "repeated_enum": {"1", "2", "0"}, - "timestamp_value": {timeStr}, - "duration_value": {durationStr}, - "fieldmask_value": {fieldmaskStr}, - "wrapper_float_value": {"1.5"}, - "wrapper_double_value": {"2.5"}, - "wrapper_int64_value": {"-1"}, - "wrapper_int32_value": {"-2"}, - "wrapper_u_int64_value": {"3"}, - "wrapper_u_int32_value": {"4"}, - "wrapper_bool_value": {"true"}, - "wrapper_string_value": {"str"}, - "wrapper_bytes_value": {"Ynl0ZXM="}, - "map_value[key]": {"value"}, - "map_value[second]": {"bar"}, - "map_value[third]": {"zzz"}, - "map_value[fourth]": {""}, - `map_value[~!@#$%^&*()]`: {"value"}, - "map_value2[key]": {"-2"}, - "map_value3[-2]": {"value"}, - "map_value4[key]": {"-1"}, - "map_value5[-1]": {"value"}, - "map_value6[key]": {"3"}, - "map_value7[3]": {"value"}, - "map_value8[key]": {"4"}, - "map_value9[4]": {"value"}, - "map_value10[key]": {"1.5"}, - "map_value11[1.5]": {"value"}, - "map_value12[key]": {"2.5"}, - "map_value13[2.5]": {"value"}, - "map_value14[key]": {"true"}, - "map_value15[true]": {"value"}, - "map_value16[key]": {"2"}, - }, - filter: utilities.NewDoubleArray(nil), - want: &examplepb.Proto3Message{ - FloatValue: 1.5, - DoubleValue: 2.5, - Int64Value: -1, - Int32Value: -2, - Uint64Value: 3, - Uint32Value: 4, - BoolValue: true, - StringValue: "str", - BytesValue: []byte("bytes"), - RepeatedValue: []string{"a", "b", "c"}, - RepeatedMessage: []*wrapperspb.UInt64Value{{Value: 1}, {Value: 2}, {Value: 3}}, - EnumValue: examplepb.EnumValue_Y, - RepeatedEnum: []examplepb.EnumValue{examplepb.EnumValue_Y, examplepb.EnumValue_Z, examplepb.EnumValue_X}, - TimestampValue: timePb, - DurationValue: durationPb, - FieldmaskValue: fieldmaskPb, - WrapperFloatValue: &wrapperspb.FloatValue{Value: 1.5}, - WrapperDoubleValue: &wrapperspb.DoubleValue{Value: 2.5}, - WrapperInt64Value: &wrapperspb.Int64Value{Value: -1}, - WrapperInt32Value: &wrapperspb.Int32Value{Value: -2}, - WrapperUInt64Value: &wrapperspb.UInt64Value{Value: 3}, - WrapperUInt32Value: &wrapperspb.UInt32Value{Value: 4}, - WrapperBoolValue: &wrapperspb.BoolValue{Value: true}, - WrapperStringValue: &wrapperspb.StringValue{Value: "str"}, - WrapperBytesValue: &wrapperspb.BytesValue{Value: []byte("bytes")}, - MapValue: map[string]string{ - "key": "value", - "second": "bar", - "third": "zzz", - "fourth": "", - `~!@#$%^&*()`: "value", - }, - MapValue2: map[string]int32{"key": -2}, - MapValue3: map[int32]string{-2: "value"}, - MapValue4: map[string]int64{"key": -1}, - MapValue5: map[int64]string{-1: "value"}, - MapValue6: map[string]uint32{"key": 3}, - MapValue7: map[uint32]string{3: "value"}, - MapValue8: map[string]uint64{"key": 4}, - MapValue9: map[uint64]string{4: "value"}, - MapValue10: map[string]float32{"key": 1.5}, - MapValue12: map[string]float64{"key": 2.5}, - MapValue14: map[string]bool{"key": true}, - MapValue15: map[bool]string{true: "value"}, - MapValue16: map[string]*wrapperspb.UInt64Value{"key": {Value: 2}}, - }, - }, - { - values: url.Values{ - "floatValue": {"1.5"}, - "doubleValue": {"2.5"}, - "int64Value": {"-1"}, - "int32Value": {"-2"}, - "uint64Value": {"3"}, - "uint32Value": {"4"}, - "boolValue": {"true"}, - "stringValue": {"str"}, - "bytesValue": {"Ynl0ZXM="}, - "repeatedValue": {"a", "b", "c"}, - "enumValue": {"1"}, - "repeatedEnum": {"1", "2", "0"}, - "timestampValue": {timeStr}, - "durationValue": {durationStr}, - "fieldmaskValue": {fieldmaskStr}, - "wrapperFloatValue": {"1.5"}, - "wrapperDoubleValue": {"2.5"}, - "wrapperInt64Value": {"-1"}, - "wrapperInt32Value": {"-2"}, - "wrapperUInt64Value": {"3"}, - "wrapperUInt32Value": {"4"}, - "wrapperBoolValue": {"true"}, - "wrapperStringValue": {"str"}, - "wrapperBytesValue": {"Ynl0ZXM="}, - }, - filter: utilities.NewDoubleArray(nil), - want: &examplepb.Proto3Message{ - FloatValue: 1.5, - DoubleValue: 2.5, - Int64Value: -1, - Int32Value: -2, - Uint64Value: 3, - Uint32Value: 4, - BoolValue: true, - StringValue: "str", - BytesValue: []byte("bytes"), - RepeatedValue: []string{"a", "b", "c"}, - EnumValue: examplepb.EnumValue_Y, - RepeatedEnum: []examplepb.EnumValue{examplepb.EnumValue_Y, examplepb.EnumValue_Z, examplepb.EnumValue_X}, - TimestampValue: timePb, - DurationValue: durationPb, - FieldmaskValue: fieldmaskPb, - WrapperFloatValue: &wrapperspb.FloatValue{Value: 1.5}, - WrapperDoubleValue: &wrapperspb.DoubleValue{Value: 2.5}, - WrapperInt64Value: &wrapperspb.Int64Value{Value: -1}, - WrapperInt32Value: &wrapperspb.Int32Value{Value: -2}, - WrapperUInt64Value: &wrapperspb.UInt64Value{Value: 3}, - WrapperUInt32Value: &wrapperspb.UInt32Value{Value: 4}, - WrapperBoolValue: &wrapperspb.BoolValue{Value: true}, - WrapperStringValue: &wrapperspb.StringValue{Value: "str"}, - WrapperBytesValue: &wrapperspb.BytesValue{Value: []byte("bytes")}, - }, - }, - { - values: url.Values{ - "enum_value": {"Z"}, - "repeated_enum": {"X", "2", "0"}, - }, - filter: utilities.NewDoubleArray(nil), - want: &examplepb.Proto3Message{ - EnumValue: examplepb.EnumValue_Z, - RepeatedEnum: []examplepb.EnumValue{examplepb.EnumValue_X, examplepb.EnumValue_Z, examplepb.EnumValue_X}, - }, - }, - { - values: url.Values{ - "float_value": {"1.5"}, - "double_value": {"2.5"}, - "int64_value": {"-1"}, - "int32_value": {"-2"}, - "uint64_value": {"3"}, - "uint32_value": {"4"}, - "bool_value": {"true"}, - "string_value": {"str"}, - "repeated_value": {"a", "b", "c"}, - }, - filter: utilities.NewDoubleArray(nil), - want: &examplepb.Proto2Message{ - FloatValue: proto.Float32(1.5), - DoubleValue: proto.Float64(2.5), - Int64Value: proto.Int64(-1), - Int32Value: proto.Int32(-2), - Uint64Value: proto.Uint64(3), - Uint32Value: proto.Uint32(4), - BoolValue: proto.Bool(true), - StringValue: proto.String("str"), - RepeatedValue: []string{"a", "b", "c"}, - }, - }, - { - values: url.Values{ - "floatValue": {"1.5"}, - "doubleValue": {"2.5"}, - "int64Value": {"-1"}, - "int32Value": {"-2"}, - "uint64Value": {"3"}, - "uint32Value": {"4"}, - "boolValue": {"true"}, - "stringValue": {"str"}, - "repeatedValue": {"a", "b", "c"}, - }, - filter: utilities.NewDoubleArray(nil), - want: &examplepb.Proto2Message{ - FloatValue: proto.Float32(1.5), - DoubleValue: proto.Float64(2.5), - Int64Value: proto.Int64(-1), - Int32Value: proto.Int32(-2), - Uint64Value: proto.Uint64(3), - Uint32Value: proto.Uint32(4), - BoolValue: proto.Bool(true), - StringValue: proto.String("str"), - RepeatedValue: []string{"a", "b", "c"}, - }, - }, - { - values: url.Values{ - "nested.nested.nested.repeated_value": {"a", "b", "c"}, - "nested.nested.nested.string_value": {"s"}, - "nested.nested.string_value": {"t"}, - "nested.string_value": {"u"}, - "nested.nested.map_value[first]": {"foo"}, - "nested.nested.map_value[second]": {"bar"}, - }, - filter: utilities.NewDoubleArray(nil), - want: &examplepb.Proto3Message{ - Nested: &examplepb.Proto3Message{ - Nested: &examplepb.Proto3Message{ - MapValue: map[string]string{ - "first": "foo", - "second": "bar", - }, - Nested: &examplepb.Proto3Message{ - RepeatedValue: []string{"a", "b", "c"}, - StringValue: "s", - }, - StringValue: "t", - }, - StringValue: "u", - }, - }, - }, - { - values: url.Values{ - "oneof_string_value": {"foobar"}, - }, - filter: utilities.NewDoubleArray(nil), - want: &examplepb.Proto3Message{ - OneofValue: &examplepb.Proto3Message_OneofStringValue{ - OneofStringValue: "foobar", - }, - }, - }, - { - values: url.Values{ - "oneofStringValue": {"foobar"}, - }, - filter: utilities.NewDoubleArray(nil), - want: &examplepb.Proto3Message{ - OneofValue: &examplepb.Proto3Message_OneofStringValue{ - OneofStringValue: "foobar", - }, - }, - }, - { - values: url.Values{ - "oneof_bool_value": {"true"}, - }, - filter: utilities.NewDoubleArray(nil), - want: &examplepb.Proto3Message{ - OneofValue: &examplepb.Proto3Message_OneofBoolValue{ - OneofBoolValue: true, - }, - }, - }, - { - // Don't allow setting a oneof more than once - values: url.Values{ - "oneof_bool_value": {"true"}, - "oneof_string_value": {"foobar"}, - }, - filter: utilities.NewDoubleArray(nil), - want: &examplepb.Proto3Message{}, - wanterr: errors.New("field already set for oneof \"oneof_value\""), - }, - { - // Error when there are too many values - values: url.Values{ - "uint64_value": {"1", "2"}, - }, - filter: utilities.NewDoubleArray(nil), - want: &examplepb.Proto3Message{}, - wanterr: errors.New("too many values for field \"uint64_value\": 1, 2"), - }, - { - // Error when dereferencing a list of messages - values: url.Values{ - "repeated_message.value": {"1"}, - }, - filter: utilities.NewDoubleArray(nil), - want: &examplepb.Proto3Message{}, - wanterr: errors.New("invalid path: \"repeated_message\" is not a message"), - }, - } { - t.Run(strconv.Itoa(i), func(t *testing.T) { - msg := spec.want.ProtoReflect().New().Interface() - err := runtime.PopulateQueryParameters(msg, spec.values, spec.filter) - if spec.wanterr != nil { - if err == nil || err.Error() != spec.wanterr.Error() { - t.Errorf("runtime.PopulateQueryParameters(msg, %v, %v) failed with %q; want error %q", spec.values, spec.filter, err, spec.wanterr) - } - return - } - - if err != nil { - t.Errorf("runtime.PopulateQueryParameters(msg, %v, %v) failed with %v; want success", spec.values, spec.filter, err) - return - } - if diff := cmp.Diff(spec.want, msg, protocmp.Transform()); diff != "" { - t.Errorf("runtime.PopulateQueryParameters(msg, %v, %v): %s", spec.values, spec.filter, diff) - } - }) - } -} - -func TestPopulateParametersWithFilters(t *testing.T) { - for _, spec := range []struct { - values url.Values - filter *utilities.DoubleArray - want proto.Message - }{ - { - values: url.Values{ - "bool_value": {"true"}, - "string_value": {"str"}, - "repeated_value": {"a", "b", "c"}, - }, - filter: utilities.NewDoubleArray([][]string{ - {"bool_value"}, {"repeated_value"}, - }), - want: &examplepb.Proto3Message{ - StringValue: "str", - }, - }, - { - values: url.Values{ - "nested.nested.bool_value": {"true"}, - "nested.nested.string_value": {"str"}, - "nested.string_value": {"str"}, - "string_value": {"str"}, - }, - filter: utilities.NewDoubleArray([][]string{ - {"nested"}, - }), - want: &examplepb.Proto3Message{ - StringValue: "str", - }, - }, - { - values: url.Values{ - "nested.nested.bool_value": {"true"}, - "nested.nested.string_value": {"str"}, - "nested.string_value": {"str"}, - "string_value": {"str"}, - }, - filter: utilities.NewDoubleArray([][]string{ - {"nested", "nested"}, - }), - want: &examplepb.Proto3Message{ - Nested: &examplepb.Proto3Message{ - StringValue: "str", - }, - StringValue: "str", - }, - }, - { - values: url.Values{ - "nested.nested.bool_value": {"true"}, - "nested.nested.string_value": {"str"}, - "nested.string_value": {"str"}, - "string_value": {"str"}, - }, - filter: utilities.NewDoubleArray([][]string{ - {"nested", "nested", "string_value"}, - }), - want: &examplepb.Proto3Message{ - Nested: &examplepb.Proto3Message{ - StringValue: "str", - Nested: &examplepb.Proto3Message{ - BoolValue: true, - }, - }, - StringValue: "str", - }, - }, - } { - msg := spec.want.ProtoReflect().New().Interface() - err := runtime.PopulateQueryParameters(msg, spec.values, spec.filter) - if err != nil { - t.Errorf("runtime.PoplateQueryParameters(msg, %v, %v) failed with %v; want success", spec.values, spec.filter, err) - continue - } - if got, want := msg, spec.want; !proto.Equal(got, want) { - t.Errorf("runtime.PopulateQueryParameters(msg, %v, %v = %v; want %v", spec.values, spec.filter, got, want) - } - } -} - -func TestPopulateQueryParametersWithInvalidNestedParameters(t *testing.T) { - for _, spec := range []struct { - msg proto.Message - values url.Values - filter *utilities.DoubleArray - }{ - { - msg: &examplepb.Proto3Message{}, - values: url.Values{ - "float_value.nested": {"test"}, - }, - filter: utilities.NewDoubleArray(nil), - }, - { - msg: &examplepb.Proto3Message{}, - values: url.Values{ - "double_value.nested": {"test"}, - }, - filter: utilities.NewDoubleArray(nil), - }, - { - msg: &examplepb.Proto3Message{}, - values: url.Values{ - "int64_value.nested": {"test"}, - }, - filter: utilities.NewDoubleArray(nil), - }, - { - msg: &examplepb.Proto3Message{}, - values: url.Values{ - "int32_value.nested": {"test"}, - }, - filter: utilities.NewDoubleArray(nil), - }, - { - msg: &examplepb.Proto3Message{}, - values: url.Values{ - "uint64_value.nested": {"test"}, - }, - filter: utilities.NewDoubleArray(nil), - }, - { - msg: &examplepb.Proto3Message{}, - values: url.Values{ - "uint32_value.nested": {"test"}, - }, - filter: utilities.NewDoubleArray(nil), - }, - { - msg: &examplepb.Proto3Message{}, - values: url.Values{ - "bool_value.nested": {"test"}, - }, - filter: utilities.NewDoubleArray(nil), - }, - { - msg: &examplepb.Proto3Message{}, - values: url.Values{ - "string_value.nested": {"test"}, - }, - filter: utilities.NewDoubleArray(nil), - }, - { - msg: &examplepb.Proto3Message{}, - values: url.Values{ - "repeated_value.nested": {"test"}, - }, - filter: utilities.NewDoubleArray(nil), - }, - { - msg: &examplepb.Proto3Message{}, - values: url.Values{ - "enum_value.nested": {"test"}, - }, - filter: utilities.NewDoubleArray(nil), - }, - { - msg: &examplepb.Proto3Message{}, - values: url.Values{ - "enum_value.nested": {"test"}, - }, - filter: utilities.NewDoubleArray(nil), - }, - { - msg: &examplepb.Proto3Message{}, - values: url.Values{ - "repeated_enum.nested": {"test"}, - }, - filter: utilities.NewDoubleArray(nil), - }, - } { - spec.msg = spec.msg.ProtoReflect().New().Interface() - err := runtime.PopulateQueryParameters(spec.msg, spec.values, spec.filter) - if err == nil { - t.Errorf("runtime.PopulateQueryParameters(msg, %v, %v) did not fail; want error", spec.values, spec.filter) - } - } -} diff --git a/go.mod b/go.mod index 5c9000c..5b4d68e 100644 --- a/go.mod +++ b/go.mod @@ -1,29 +1,37 @@ module github.com/binchencoder/ease-gateway -go 1.13 +go 1.17 require ( github.com/binchencoder/gateway-proto v0.0.7 github.com/binchencoder/letsgo v0.0.3 github.com/binchencoder/skylb-api v0.0.5 - github.com/fatih/color v1.9.0 - github.com/ghodss/yaml v1.0.0 - github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b - github.com/golang/protobuf v1.4.3 - github.com/google/go-cmp v0.5.2 - github.com/grpc-ecosystem/grpc-gateway/v2 v2.0.1 - github.com/klauspost/compress v1.10.10 - github.com/pborman/uuid v1.2.0 - github.com/prometheus/client_golang v1.7.1 - golang.org/x/net v0.0.0-20200822124328-c89045814202 - google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154 - google.golang.org/grpc v1.33.1 - google.golang.org/protobuf v1.25.0 + github.com/antihax/optional v1.0.0 + github.com/golang/glog v1.0.0 + github.com/golang/protobuf v1.5.2 + github.com/google/go-cmp v0.5.7 + github.com/grpc-ecosystem/grpc-gateway/v2 v2.8.0 + github.com/rogpeppe/fastuuid v1.2.0 + golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a + google.golang.org/genproto v0.0.0-20220314164441-57ef72a4c106 + google.golang.org/grpc v1.45.0 + google.golang.org/protobuf v1.27.1 + gopkg.in/yaml.v2 v2.4.0 + sigs.k8s.io/yaml v1.3.0 +) + +require ( + golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect + golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect + golang.org/x/text v0.3.7 // indirect + golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect + google.golang.org/appengine v1.6.6 // indirect ) replace ( github.com/coreos/bbolt v1.3.4 => go.etcd.io/bbolt v1.3.4 github.com/coreos/bbolt v1.3.5 => go.etcd.io/bbolt v1.3.5 - google.golang.org/grpc v1.30.0 => google.golang.org/grpc v1.29.1 - google.golang.org/grpc v1.33.1 => google.golang.org/grpc v1.29.1 + // google.golang.org/grpc v1.30.0 => google.golang.org/grpc v1.29.1 + // google.golang.org/grpc v1.33.1 => google.golang.org/grpc v1.29.1 + // google.golang.org/grpc => google.golang.org/grpc v1.29.1 ) diff --git a/go.sum b/go.sum index 2960acb..97044f8 100644 --- a/go.sum +++ b/go.sum @@ -133,6 +133,7 @@ github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -160,6 +161,9 @@ github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0 github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -173,6 +177,8 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -208,6 +214,7 @@ github.com/grpc-ecosystem/grpc-gateway v1.14.6/go.mod h1:zdiPV4Yse/1gnckTHtghG4G github.com/grpc-ecosystem/grpc-gateway v1.15.2 h1:HC+hWRWf+v5zTMPyoaYTKIJih+4sd4XRWmj0qlG87Co= github.com/grpc-ecosystem/grpc-gateway/v2 v2.0.1 h1:X2vfSnm1WC8HEo0MBHZg2TcuDUHJj6kd1TmEAQncnSA= github.com/grpc-ecosystem/grpc-gateway/v2 v2.0.1/go.mod h1:oVMjMN64nzEcepv1kdZKgx1qNYt4Ro0Gqefiq2JWdis= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.8.0/go.mod h1:/fckq3NE+vGiJsd4fDt4ge1XrK8cN+e5G5QWIzdg7Q8= github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 h1:MJG/KsmcqMwFAkh8mTnAwhyKoB+sTAnY4CACC110tbU= github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw= github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= @@ -492,12 +499,15 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201026091529-146b70c837a4 h1:awiuzyrRjJDb+OXi9ceHO3SDxVoN3JER57mhtqkdQBs= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -547,6 +557,13 @@ golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642 h1:B6caxRw+hozq68X2MY7jEpZh/cr4/aHLv9xU8Kkadrw= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -554,6 +571,8 @@ golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -673,6 +692,7 @@ google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154 h1:bFFRpT+e8JJVY7lMMfvezL1ZIwqiwmPl2bsE2yx4HqM= google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20220314164441-57ef72a4c106/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= @@ -710,6 +730,10 @@ google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEG google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -729,6 +753,7 @@ gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= @@ -744,6 +769,7 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8 rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= upper.io/db.v3 v3.7.1+incompatible h1:GiK/NmDUClH3LrZd54qj5OQsz8brGFv652QXyRXtg2U= upper.io/db.v3 v3.7.1+incompatible/go.mod h1:FgTdD24eBjJAbPKsQSiHUNgXjOR4Lub3u1UMHSIh82Y= diff --git a/httpoptions/BUILD.bazel b/httpoptions/BUILD.bazel index 0bd1eba..11e15fe 100644 --- a/httpoptions/BUILD.bazel +++ b/httpoptions/BUILD.bazel @@ -12,7 +12,7 @@ filegroup( ) go_library( - name = "go_default_library", + name = "httpoptions", embed = [":options_go_proto"], importpath = "github.com/binchencoder/ease-gateway/httpoptions", ) @@ -35,22 +35,28 @@ go_proto_library( name = "options_go_proto", compilers = ["@io_bazel_rules_go//proto:go_grpc"], importpath = "github.com/binchencoder/ease-gateway/httpoptions", - proto = ":ease_api_proto", + proto = ":options_proto", deps = [ "@com_github_binchencoder_gateway_proto//data:go_default_library", "@com_github_binchencoder_gateway_proto//frontend:go_default_library", ], ) -proto_library( - name = "ease_api_proto", - srcs = [ - "annotations.proto", - "http.proto", - ], - deps = [ - "@com_github_binchencoder_gateway_proto//data:data_proto", - "@com_github_binchencoder_gateway_proto//frontend:error_proto", - "@com_google_protobuf//:descriptor_proto", - ], +# proto_library( +# name = "ease_api_proto", +# srcs = [ +# "annotations.proto", +# "http.proto", +# ], +# deps = [ +# "@com_github_binchencoder_gateway_proto//data:data_proto", +# "@com_github_binchencoder_gateway_proto//frontend:error_proto", +# "@com_google_protobuf//:descriptor_proto", +# ], +# ) + +alias( + name = "go_default_library", + actual = ":options_go_proto", + visibility = ["//visibility:public"], ) diff --git a/httpoptions/annotations.pb.go b/httpoptions/annotations.pb.go old mode 100644 new mode 100755 index 75acf02..599940e --- a/httpoptions/annotations.pb.go +++ b/httpoptions/annotations.pb.go @@ -1,34 +1,17 @@ -// Copyright (c) 2015, Google 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. - -// See `https://github.com/googleapis/googleapis/blob/master/google/api/annotations.proto` - // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.23.0 -// protoc v3.12.3 +// protoc-gen-go v1.27.1 +// protoc v3.19.4 // source: httpoptions/annotations.proto -package ease_api +package annotations import ( - data "data" - _ "frontend" - proto "github.com/golang/protobuf/proto" - descriptor "github.com/golang/protobuf/protoc-gen-go/descriptor" + data "github.com/binchencoder/gateway-proto/data" + _ "github.com/binchencoder/gateway-proto/frontend" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + descriptorpb "google.golang.org/protobuf/types/descriptorpb" reflect "reflect" sync "sync" ) @@ -40,16 +23,11 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - -// Api regist gateway. type ApiSourceType int32 const ( - ApiSourceType_EASE_GATEWAY ApiSourceType = 0 // ease-gateway apis. - ApiSourceType_OPEN_GATEWAY ApiSourceType = 1 // open-gateway open apis. + ApiSourceType_EASE_GATEWAY ApiSourceType = 0 + ApiSourceType_OPEN_GATEWAY ApiSourceType = 1 ) // Enum value maps for ApiSourceType. @@ -91,12 +69,11 @@ func (ApiSourceType) EnumDescriptor() ([]byte, []int) { return file_httpoptions_annotations_proto_rawDescGZIP(), []int{0} } -// Auth token type. type AuthTokenType int32 const ( - AuthTokenType_EASE_AUTH_TOKEN AuthTokenType = 0 // ease gateway auth type. - AuthTokenType_BASE_ACCESS_TOKEN AuthTokenType = 1 // open platform baseAccessToken. + AuthTokenType_EASE_AUTH_TOKEN AuthTokenType = 0 + AuthTokenType_BASE_ACCESS_TOKEN AuthTokenType = 1 ) // Enum value maps for AuthTokenType. @@ -138,12 +115,11 @@ func (AuthTokenType) EnumDescriptor() ([]byte, []int) { return file_httpoptions_annotations_proto_rawDescGZIP(), []int{1} } -// Specified source Type. type SpecSourceType int32 const ( - SpecSourceType_UNSPECIFIED SpecSourceType = 0 // use the value of x-source about header. - SpecSourceType_WEB SpecSourceType = 1 // specify x-source as "web". + SpecSourceType_UNSPECIFIED SpecSourceType = 0 + SpecSourceType_WEB SpecSourceType = 1 ) // Enum value maps for SpecSourceType. @@ -185,12 +161,11 @@ func (SpecSourceType) EnumDescriptor() ([]byte, []int) { return file_httpoptions_annotations_proto_rawDescGZIP(), []int{2} } -// The load balancer enums. type LoadBalancer int32 const ( LoadBalancer_ROUND_ROBIN LoadBalancer = 0 - LoadBalancer_CONSISTENT LoadBalancer = 1 // Consistent hashing. + LoadBalancer_CONSISTENT LoadBalancer = 1 ) // Enum value maps for LoadBalancer. @@ -232,19 +207,18 @@ func (LoadBalancer) EnumDescriptor() ([]byte, []int) { return file_httpoptions_annotations_proto_rawDescGZIP(), []int{3} } -// The opertaion type. type OperatorType int32 const ( OperatorType_OPERATOR_TYPE_UNKNOWN OperatorType = 0 - OperatorType_GT OperatorType = 1 // Greater than - OperatorType_LT OperatorType = 2 // Less than - OperatorType_EQ OperatorType = 3 // Equals - OperatorType_MATCH OperatorType = 4 // String pattern match. - OperatorType_NON_NIL OperatorType = 5 // Not nil - OperatorType_LEN_GT OperatorType = 6 // String length great than - OperatorType_LEN_LT OperatorType = 7 // String length less than - OperatorType_LEN_EQ OperatorType = 8 // String length equals + OperatorType_GT OperatorType = 1 + OperatorType_LT OperatorType = 2 + OperatorType_EQ OperatorType = 3 + OperatorType_MATCH OperatorType = 4 + OperatorType_NON_NIL OperatorType = 5 + OperatorType_LEN_GT OperatorType = 6 + OperatorType_LEN_LT OperatorType = 7 + OperatorType_LEN_EQ OperatorType = 8 ) // Enum value maps for OperatorType. @@ -300,12 +274,11 @@ func (OperatorType) EnumDescriptor() ([]byte, []int) { return file_httpoptions_annotations_proto_rawDescGZIP(), []int{4} } -// The supported function type list type FunctionType int32 const ( FunctionType_FUNCTION_TYPE_UNKNOWN FunctionType = 0 - FunctionType_TRIM FunctionType = 1 // String trim. + FunctionType_TRIM FunctionType = 1 ) // Enum value maps for FunctionType. @@ -347,13 +320,12 @@ func (FunctionType) EnumDescriptor() ([]byte, []int) { return file_httpoptions_annotations_proto_rawDescGZIP(), []int{5} } -// ValueType is the type of the field. type ValueType int32 const ( ValueType_VALUE_TYPE_UNKNOWN ValueType = 0 - ValueType_NUMBER ValueType = 1 // Represent all number type like int,real - ValueType_STRING ValueType = 2 // String + ValueType_NUMBER ValueType = 1 + ValueType_STRING ValueType = 2 ValueType_OBJ ValueType = 3 ) @@ -400,33 +372,19 @@ func (ValueType) EnumDescriptor() ([]byte, []int) { return file_httpoptions_annotations_proto_rawDescGZIP(), []int{6} } -// The api method. type ApiMethod struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - LoginNotRequired bool `protobuf:"varint,1,opt,name=login_not_required,json=loginNotRequired,proto3" json:"login_not_required,omitempty"` - ClientSignRequired bool `protobuf:"varint,2,opt,name=client_sign_required,json=clientSignRequired,proto3" json:"client_sign_required,omitempty"` - // Used only for CONSISTENT load balancer. - // Can take the following formats: - // - "field.field.field": hash key from a proto field. - // - "@uuid": generated UUID as hash key. - // - "@session": hash key from session (session sticky). - HashKey string `protobuf:"bytes,3,opt,name=hash_key,json=hashKey,proto3" json:"hash_key,omitempty"` - // If the client of this call come from third party. - // When this field is true, gateway will not check - // X-Source. - IsThirdParty bool `protobuf:"varint,4,opt,name=is_third_party,json=isThirdParty,proto3" json:"is_third_party,omitempty"` - // Used to call the GRPC service timeout. - // duration string, such as "300ms", "1m30s". - Timeout string `protobuf:"bytes,5,opt,name=timeout,proto3" json:"timeout,omitempty"` - // Api regist gateway. - ApiSource ApiSourceType `protobuf:"varint,6,opt,name=api_source,json=apiSource,proto3,enum=ease.api.ApiSourceType" json:"api_source,omitempty"` - // Auth token type. - TokenType AuthTokenType `protobuf:"varint,7,opt,name=token_type,json=tokenType,proto3,enum=ease.api.AuthTokenType" json:"token_type,omitempty"` - // Specified source Type. - SpecSourceType SpecSourceType `protobuf:"varint,8,opt,name=spec_source_type,json=specSourceType,proto3,enum=ease.api.SpecSourceType" json:"spec_source_type,omitempty"` + LoginNotRequired bool `protobuf:"varint,1,opt,name=login_not_required,json=loginNotRequired,proto3" json:"login_not_required,omitempty"` + ClientSignRequired bool `protobuf:"varint,2,opt,name=client_sign_required,json=clientSignRequired,proto3" json:"client_sign_required,omitempty"` + HashKey string `protobuf:"bytes,3,opt,name=hash_key,json=hashKey,proto3" json:"hash_key,omitempty"` + IsThirdParty bool `protobuf:"varint,4,opt,name=is_third_party,json=isThirdParty,proto3" json:"is_third_party,omitempty"` + Timeout string `protobuf:"bytes,5,opt,name=timeout,proto3" json:"timeout,omitempty"` + ApiSource ApiSourceType `protobuf:"varint,6,opt,name=api_source,json=apiSource,proto3,enum=ease.api.ApiSourceType" json:"api_source,omitempty"` + TokenType AuthTokenType `protobuf:"varint,7,opt,name=token_type,json=tokenType,proto3,enum=ease.api.AuthTokenType" json:"token_type,omitempty"` + SpecSourceType SpecSourceType `protobuf:"varint,8,opt,name=spec_source_type,json=specSourceType,proto3,enum=ease.api.SpecSourceType" json:"spec_source_type,omitempty"` } func (x *ApiMethod) Reset() { @@ -517,19 +475,16 @@ func (x *ApiMethod) GetSpecSourceType() SpecSourceType { return SpecSourceType_UNSPECIFIED } -// The service spec used for skylb/vexillary type ServiceSpec struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // The identity of the service. - ServiceId data.ServiceId `protobuf:"varint,1,opt,name=service_id,json=serviceId,proto3,enum=data.ServiceId" json:"service_id,omitempty"` - // For skylb integration. - PortName string `protobuf:"bytes,2,opt,name=port_name,json=portName,proto3" json:"port_name,omitempty"` - Namespace string `protobuf:"bytes,3,opt,name=namespace,proto3" json:"namespace,omitempty"` - GenController bool `protobuf:"varint,4,opt,name=gen_controller,json=genController,proto3" json:"gen_controller,omitempty"` - Balancer LoadBalancer `protobuf:"varint,5,opt,name=balancer,proto3,enum=ease.api.LoadBalancer" json:"balancer,omitempty"` + ServiceId data.ServiceId `protobuf:"varint,1,opt,name=service_id,json=serviceId,proto3,enum=data.ServiceId" json:"service_id,omitempty"` + PortName string `protobuf:"bytes,2,opt,name=port_name,json=portName,proto3" json:"port_name,omitempty"` + Namespace string `protobuf:"bytes,3,opt,name=namespace,proto3" json:"namespace,omitempty"` + GenController bool `protobuf:"varint,4,opt,name=gen_controller,json=genController,proto3" json:"gen_controller,omitempty"` + Balancer LoadBalancer `protobuf:"varint,5,opt,name=balancer,proto3,enum=ease.api.LoadBalancer" json:"balancer,omitempty"` } func (x *ServiceSpec) Reset() { @@ -568,7 +523,7 @@ func (x *ServiceSpec) GetServiceId() data.ServiceId { if x != nil { return x.ServiceId } - return data.ServiceId_SERVICE_NONE + return data.ServiceId(0) } func (x *ServiceSpec) GetPortName() string { @@ -599,7 +554,6 @@ func (x *ServiceSpec) GetBalancer() LoadBalancer { return LoadBalancer_ROUND_ROBIN } -// ValidationRule defines the rule to validate the input value. type ValidationRule struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -671,7 +625,6 @@ func (x *ValidationRule) GetFunction() FunctionType { return FunctionType_FUNCTION_TYPE_UNKNOWN } -// ValidationRules holds a list of validation rules. type ValidationRules struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -721,7 +674,7 @@ func (x *ValidationRules) GetRules() []*ValidationRule { var file_httpoptions_annotations_proto_extTypes = []protoimpl.ExtensionInfo{ { - ExtendedType: (*descriptor.MethodOptions)(nil), + ExtendedType: (*descriptorpb.MethodOptions)(nil), ExtensionType: (*HttpRule)(nil), Field: 108345, Name: "ease.api.http", @@ -729,7 +682,7 @@ var file_httpoptions_annotations_proto_extTypes = []protoimpl.ExtensionInfo{ Filename: "httpoptions/annotations.proto", }, { - ExtendedType: (*descriptor.MethodOptions)(nil), + ExtendedType: (*descriptorpb.MethodOptions)(nil), ExtensionType: (*ApiMethod)(nil), Field: 108361, Name: "ease.api.method", @@ -737,7 +690,7 @@ var file_httpoptions_annotations_proto_extTypes = []protoimpl.ExtensionInfo{ Filename: "httpoptions/annotations.proto", }, { - ExtendedType: (*descriptor.ServiceOptions)(nil), + ExtendedType: (*descriptorpb.ServiceOptions)(nil), ExtensionType: (*ServiceSpec)(nil), Field: 108349, Name: "ease.api.service_spec", @@ -745,7 +698,7 @@ var file_httpoptions_annotations_proto_extTypes = []protoimpl.ExtensionInfo{ Filename: "httpoptions/annotations.proto", }, { - ExtendedType: (*descriptor.FieldOptions)(nil), + ExtendedType: (*descriptorpb.FieldOptions)(nil), ExtensionType: (*ValidationRules)(nil), Field: 108102, Name: "ease.api.rules", @@ -754,28 +707,22 @@ var file_httpoptions_annotations_proto_extTypes = []protoimpl.ExtensionInfo{ }, } -// Extension fields to descriptor.MethodOptions. +// Extension fields to descriptorpb.MethodOptions. var ( - // See `HttpRule`. - // // optional ease.api.HttpRule http = 108345; E_Http = &file_httpoptions_annotations_proto_extTypes[0] // optional ease.api.ApiMethod method = 108361; E_Method = &file_httpoptions_annotations_proto_extTypes[1] ) -// Extension fields to descriptor.ServiceOptions. +// Extension fields to descriptorpb.ServiceOptions. var ( // optional ease.api.ServiceSpec service_spec = 108349; E_ServiceSpec = &file_httpoptions_annotations_proto_extTypes[2] ) -// Extension fields to descriptor.FieldOptions. +// Extension fields to descriptorpb.FieldOptions. var ( - // The validation rules, if there are more than - // one rules, validtion will pass only if all - // the rules are complied (AND). - // // optional ease.api.ValidationRules rules = 108102; E_Rules = &file_httpoptions_annotations_proto_extTypes[3] ) @@ -893,10 +840,14 @@ var file_httpoptions_annotations_proto_rawDesc = []byte{ 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xc6, 0xcc, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x75, 0x6c, 0x65, 0x73, 0x52, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x42, 0x29, 0x0a, 0x0c, 0x63, + 0x75, 0x6c, 0x65, 0x73, 0x52, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x42, 0x67, 0x0a, 0x0c, 0x63, 0x6f, 0x6d, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x42, 0x10, 0x41, 0x6e, 0x6e, - 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0xa2, - 0x02, 0x04, 0x45, 0x41, 0x50, 0x49, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, + 0x3c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x69, 0x6e, 0x63, + 0x68, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x65, 0x61, 0x73, 0x65, 0x2d, 0x67, 0x61, + 0x74, 0x65, 0x77, 0x61, 0x79, 0x2f, 0x68, 0x74, 0x74, 0x70, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x3b, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0xa2, 0x02, 0x04, + 0x45, 0x41, 0x50, 0x49, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -914,22 +865,22 @@ func file_httpoptions_annotations_proto_rawDescGZIP() []byte { var file_httpoptions_annotations_proto_enumTypes = make([]protoimpl.EnumInfo, 7) var file_httpoptions_annotations_proto_msgTypes = make([]protoimpl.MessageInfo, 4) var file_httpoptions_annotations_proto_goTypes = []interface{}{ - (ApiSourceType)(0), // 0: ease.api.ApiSourceType - (AuthTokenType)(0), // 1: ease.api.AuthTokenType - (SpecSourceType)(0), // 2: ease.api.SpecSourceType - (LoadBalancer)(0), // 3: ease.api.LoadBalancer - (OperatorType)(0), // 4: ease.api.OperatorType - (FunctionType)(0), // 5: ease.api.FunctionType - (ValueType)(0), // 6: ease.api.ValueType - (*ApiMethod)(nil), // 7: ease.api.ApiMethod - (*ServiceSpec)(nil), // 8: ease.api.ServiceSpec - (*ValidationRule)(nil), // 9: ease.api.ValidationRule - (*ValidationRules)(nil), // 10: ease.api.ValidationRules - (data.ServiceId)(0), // 11: data.ServiceId - (*descriptor.MethodOptions)(nil), // 12: google.protobuf.MethodOptions - (*descriptor.ServiceOptions)(nil), // 13: google.protobuf.ServiceOptions - (*descriptor.FieldOptions)(nil), // 14: google.protobuf.FieldOptions - (*HttpRule)(nil), // 15: ease.api.HttpRule + (ApiSourceType)(0), // 0: ease.api.ApiSourceType + (AuthTokenType)(0), // 1: ease.api.AuthTokenType + (SpecSourceType)(0), // 2: ease.api.SpecSourceType + (LoadBalancer)(0), // 3: ease.api.LoadBalancer + (OperatorType)(0), // 4: ease.api.OperatorType + (FunctionType)(0), // 5: ease.api.FunctionType + (ValueType)(0), // 6: ease.api.ValueType + (*ApiMethod)(nil), // 7: ease.api.ApiMethod + (*ServiceSpec)(nil), // 8: ease.api.ServiceSpec + (*ValidationRule)(nil), // 9: ease.api.ValidationRule + (*ValidationRules)(nil), // 10: ease.api.ValidationRules + (data.ServiceId)(0), // 11: data.ServiceId + (*descriptorpb.MethodOptions)(nil), // 12: google.protobuf.MethodOptions + (*descriptorpb.ServiceOptions)(nil), // 13: google.protobuf.ServiceOptions + (*descriptorpb.FieldOptions)(nil), // 14: google.protobuf.FieldOptions + (*HttpRule)(nil), // 15: ease.api.HttpRule } var file_httpoptions_annotations_proto_depIdxs = []int32{ 0, // 0: ease.api.ApiMethod.api_source:type_name -> ease.api.ApiSourceType diff --git a/httpoptions/http.pb.go b/httpoptions/http.pb.go old mode 100644 new mode 100755 index d644dbf..7b6ae47 --- a/httpoptions/http.pb.go +++ b/httpoptions/http.pb.go @@ -1,28 +1,12 @@ -// Copyright 2019 Google LLC. -// -// 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. -// See `https://github.com/googleapis/googleapis/blob/master/google/api/http.proto` - // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.23.0 -// protoc v3.12.3 +// protoc-gen-go v1.27.1 +// protoc v3.19.4 // source: httpoptions/http.proto -package ease_api +package annotations import ( - proto "github.com/golang/protobuf/proto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" @@ -36,29 +20,13 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - -// Defines the HTTP configuration for an API service. It contains a list of -// [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method -// to one or more HTTP REST API methods. type Http struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // A list of HTTP configuration rules that apply to individual API methods. - // - // **NOTE:** All service configuration rules follow "last one wins" order. - Rules []*HttpRule `protobuf:"bytes,1,rep,name=rules,proto3" json:"rules,omitempty"` - // When set to true, URL path parameters will be fully URI-decoded except in - // cases of single segment matches in reserved expansion, where "%2F" will be - // left encoded. - // - // The default behavior is to not decode RFC 6570 reserved characters in multi - // segment matches. - FullyDecodeReservedExpansion bool `protobuf:"varint,2,opt,name=fully_decode_reserved_expansion,json=fullyDecodeReservedExpansion,proto3" json:"fully_decode_reserved_expansion,omitempty"` + Rules []*HttpRule `protobuf:"bytes,1,rep,name=rules,proto3" json:"rules,omitempty"` + FullyDecodeReservedExpansion bool `protobuf:"varint,2,opt,name=fully_decode_reserved_expansion,json=fullyDecodeReservedExpansion,proto3" json:"fully_decode_reserved_expansion,omitempty"` } func (x *Http) Reset() { @@ -107,288 +75,12 @@ func (x *Http) GetFullyDecodeReservedExpansion() bool { return false } -// # gRPC Transcoding -// -// gRPC Transcoding is a feature for mapping between a gRPC method and one or -// more HTTP REST endpoints. It allows developers to build a single API service -// that supports both gRPC APIs and REST APIs. Many systems, including [Google -// APIs](https://github.com/googleapis/googleapis), -// [Cloud Endpoints](https://cloud.google.com/endpoints), [gRPC -// Gateway](https://github.com/grpc-ecosystem/grpc-gateway), -// and [Envoy](https://github.com/envoyproxy/envoy) proxy support this feature -// and use it for large scale production services. -// -// `HttpRule` defines the schema of the gRPC/REST mapping. The mapping specifies -// how different portions of the gRPC request message are mapped to the URL -// path, URL query parameters, and HTTP request body. It also controls how the -// gRPC response message is mapped to the HTTP response body. `HttpRule` is -// typically specified as an `google.api.http` annotation on the gRPC method. -// -// Each mapping specifies a URL path template and an HTTP method. The path -// template may refer to one or more fields in the gRPC request message, as long -// as each field is a non-repeated field with a primitive (non-message) type. -// The path template controls how fields of the request message are mapped to -// the URL path. -// -// Example: -// -// service Messaging { -// rpc GetMessage(GetMessageRequest) returns (Message) { -// option (google.api.http) = { -// get: "/v1/{name=messages/*}" -// }; -// } -// } -// message GetMessageRequest { -// string name = 1; // Mapped to URL path. -// } -// message Message { -// string text = 1; // The resource content. -// } -// -// This enables an HTTP REST to gRPC mapping as below: -// -// HTTP | gRPC -// -----|----- -// `GET /v1/messages/123456` | `GetMessage(name: "messages/123456")` -// -// Any fields in the request message which are not bound by the path template -// automatically become HTTP query parameters if there is no HTTP request body. -// For example: -// -// service Messaging { -// rpc GetMessage(GetMessageRequest) returns (Message) { -// option (google.api.http) = { -// get:"/v1/messages/{message_id}" -// }; -// } -// } -// message GetMessageRequest { -// message SubMessage { -// string subfield = 1; -// } -// string message_id = 1; // Mapped to URL path. -// int64 revision = 2; // Mapped to URL query parameter `revision`. -// SubMessage sub = 3; // Mapped to URL query parameter `sub.subfield`. -// } -// -// This enables a HTTP JSON to RPC mapping as below: -// -// HTTP | gRPC -// -----|----- -// `GET /v1/messages/123456?revision=2&sub.subfield=foo` | -// `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield: -// "foo"))` -// -// Note that fields which are mapped to URL query parameters must have a -// primitive type or a repeated primitive type or a non-repeated message type. -// In the case of a repeated type, the parameter can be repeated in the URL -// as `...?param=A¶m=B`. In the case of a message type, each field of the -// message is mapped to a separate parameter, such as -// `...?foo.a=A&foo.b=B&foo.c=C`. -// -// For HTTP methods that allow a request body, the `body` field -// specifies the mapping. Consider a REST update method on the -// message resource collection: -// -// service Messaging { -// rpc UpdateMessage(UpdateMessageRequest) returns (Message) { -// option (google.api.http) = { -// patch: "/v1/messages/{message_id}" -// body: "message" -// }; -// } -// } -// message UpdateMessageRequest { -// string message_id = 1; // mapped to the URL -// Message message = 2; // mapped to the body -// } -// -// The following HTTP JSON to RPC mapping is enabled, where the -// representation of the JSON in the request body is determined by -// protos JSON encoding: -// -// HTTP | gRPC -// -----|----- -// `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: -// "123456" message { text: "Hi!" })` -// -// The special name `*` can be used in the body mapping to define that -// every field not bound by the path template should be mapped to the -// request body. This enables the following alternative definition of -// the update method: -// -// service Messaging { -// rpc UpdateMessage(Message) returns (Message) { -// option (google.api.http) = { -// patch: "/v1/messages/{message_id}" -// body: "*" -// }; -// } -// } -// message Message { -// string message_id = 1; -// string text = 2; -// } -// -// -// The following HTTP JSON to RPC mapping is enabled: -// -// HTTP | gRPC -// -----|----- -// `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: -// "123456" text: "Hi!")` -// -// Note that when using `*` in the body mapping, it is not possible to -// have HTTP parameters, as all fields not bound by the path end in -// the body. This makes this option more rarely used in practice when -// defining REST APIs. The common usage of `*` is in custom methods -// which don't use the URL at all for transferring data. -// -// It is possible to define multiple HTTP methods for one RPC by using -// the `additional_bindings` option. Example: -// -// service Messaging { -// rpc GetMessage(GetMessageRequest) returns (Message) { -// option (google.api.http) = { -// get: "/v1/messages/{message_id}" -// additional_bindings { -// get: "/v1/users/{user_id}/messages/{message_id}" -// } -// }; -// } -// } -// message GetMessageRequest { -// string message_id = 1; -// string user_id = 2; -// } -// -// This enables the following two alternative HTTP JSON to RPC mappings: -// -// HTTP | gRPC -// -----|----- -// `GET /v1/messages/123456` | `GetMessage(message_id: "123456")` -// `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id: -// "123456")` -// -// ## Rules for HTTP mapping -// -// 1. Leaf request fields (recursive expansion nested messages in the request -// message) are classified into three categories: -// - Fields referred by the path template. They are passed via the URL path. -// - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They are passed via the HTTP -// request body. -// - All other fields are passed via the URL query parameters, and the -// parameter name is the field path in the request message. A repeated -// field can be represented as multiple query parameters under the same -// name. -// 2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL query parameter, all fields -// are passed via URL path and HTTP request body. -// 3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP request body, all -// fields are passed via URL path and URL query parameters. -// -// ### Path template syntax -// -// Template = "/" Segments [ Verb ] ; -// Segments = Segment { "/" Segment } ; -// Segment = "*" | "**" | LITERAL | Variable ; -// Variable = "{" FieldPath [ "=" Segments ] "}" ; -// FieldPath = IDENT { "." IDENT } ; -// Verb = ":" LITERAL ; -// -// The syntax `*` matches a single URL path segment. The syntax `**` matches -// zero or more URL path segments, which must be the last part of the URL path -// except the `Verb`. -// -// The syntax `Variable` matches part of the URL path as specified by its -// template. A variable template must not contain other variables. If a variable -// matches a single path segment, its template may be omitted, e.g. `{var}` -// is equivalent to `{var=*}`. -// -// The syntax `LITERAL` matches literal text in the URL path. If the `LITERAL` -// contains any reserved character, such characters should be percent-encoded -// before the matching. -// -// If a variable contains exactly one path segment, such as `"{var}"` or -// `"{var=*}"`, when such a variable is expanded into a URL path on the client -// side, all characters except `[-_.~0-9a-zA-Z]` are percent-encoded. The -// server side does the reverse decoding. Such variables show up in the -// [Discovery -// Document](https://developers.google.com/discovery/v1/reference/apis) as -// `{var}`. -// -// If a variable contains multiple path segments, such as `"{var=foo/*}"` -// or `"{var=**}"`, when such a variable is expanded into a URL path on the -// client side, all characters except `[-_.~/0-9a-zA-Z]` are percent-encoded. -// The server side does the reverse decoding, except "%2F" and "%2f" are left -// unchanged. Such variables show up in the -// [Discovery -// Document](https://developers.google.com/discovery/v1/reference/apis) as -// `{+var}`. -// -// ## Using gRPC API Service Configuration -// -// gRPC API Service Configuration (service config) is a configuration language -// for configuring a gRPC service to become a user-facing product. The -// service config is simply the YAML representation of the `google.api.Service` -// proto message. -// -// As an alternative to annotating your proto file, you can configure gRPC -// transcoding in your service config YAML files. You do this by specifying a -// `HttpRule` that maps the gRPC method to a REST endpoint, achieving the same -// effect as the proto annotation. This can be particularly useful if you -// have a proto that is reused in multiple services. Note that any transcoding -// specified in the service config will override any matching transcoding -// configuration in the proto. -// -// Example: -// -// http: -// rules: -// # Selects a gRPC method and applies HttpRule to it. -// - selector: example.v1.Messaging.GetMessage -// get: /v1/messages/{message_id}/{sub.subfield} -// -// ## Special notes -// -// When gRPC Transcoding is used to map a gRPC to JSON REST endpoints, the -// proto to JSON conversion must follow the [proto3 -// specification](https://developers.google.com/protocol-buffers/docs/proto3#json). -// -// While the single segment variable follows the semantics of -// [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 Simple String -// Expansion, the multi segment variable **does not** follow RFC 6570 Section -// 3.2.3 Reserved Expansion. The reason is that the Reserved Expansion -// does not expand special characters like `?` and `#`, which would lead -// to invalid URLs. As the result, gRPC Transcoding uses a custom encoding -// for multi segment variables. -// -// The path variables **must not** refer to any repeated or mapped field, -// because client libraries are not capable of handling such variable expansion. -// -// The path variables **must not** capture the leading "/" character. The reason -// is that the most common use case "{var}" does not capture the leading "/" -// character. For consistency, all path variables must share the same behavior. -// -// Repeated message fields must not be mapped to URL query parameters, because -// no client library can support such complicated mapping. -// -// If an API needs to use a JSON array for request or response body, it can map -// the request or response body to a repeated field. However, some gRPC -// Transcoding implementations may not support this feature. type HttpRule struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // Selects a method to which this rule applies. - // - // Refer to [selector][google.api.DocumentationRule.selector] for syntax details. Selector string `protobuf:"bytes,1,opt,name=selector,proto3" json:"selector,omitempty"` - // Determines the URL pattern is matched by this rules. This pattern can be - // used with any of the {get|put|post|delete|patch} methods. A custom method - // can be defined using the 'custom' field. - // // Types that are assignable to Pattern: // *HttpRule_Get // *HttpRule_Put @@ -396,25 +88,10 @@ type HttpRule struct { // *HttpRule_Delete // *HttpRule_Patch // *HttpRule_Custom - Pattern isHttpRule_Pattern `protobuf_oneof:"pattern"` - // The name of the request field whose value is mapped to the HTTP request - // body, or `*` for mapping all request fields not captured by the path - // pattern to the HTTP body, or omitted for not having any HTTP request body. - // - // NOTE: the referred field must be present at the top-level of the request - // message type. - Body string `protobuf:"bytes,7,opt,name=body,proto3" json:"body,omitempty"` - // Optional. The name of the response field whose value is mapped to the HTTP - // response body. When omitted, the entire response message will be used - // as the HTTP response body. - // - // NOTE: The referred field must be present at the top-level of the response - // message type. - ResponseBody string `protobuf:"bytes,12,opt,name=response_body,json=responseBody,proto3" json:"response_body,omitempty"` - // Additional HTTP bindings for the selector. Nested bindings must - // not contain an `additional_bindings` field themselves (that is, - // the nesting may only be one level deep). - AdditionalBindings []*HttpRule `protobuf:"bytes,11,rep,name=additional_bindings,json=additionalBindings,proto3" json:"additional_bindings,omitempty"` + Pattern isHttpRule_Pattern `protobuf_oneof:"pattern"` + Body string `protobuf:"bytes,7,opt,name=body,proto3" json:"body,omitempty"` + ResponseBody string `protobuf:"bytes,12,opt,name=response_body,json=responseBody,proto3" json:"response_body,omitempty"` + AdditionalBindings []*HttpRule `protobuf:"bytes,11,rep,name=additional_bindings,json=additionalBindings,proto3" json:"additional_bindings,omitempty"` } func (x *HttpRule) Reset() { @@ -531,36 +208,26 @@ type isHttpRule_Pattern interface { } type HttpRule_Get struct { - // Maps to HTTP GET. Used for listing and getting information about - // resources. Get string `protobuf:"bytes,2,opt,name=get,proto3,oneof"` } type HttpRule_Put struct { - // Maps to HTTP PUT. Used for replacing a resource. Put string `protobuf:"bytes,3,opt,name=put,proto3,oneof"` } type HttpRule_Post struct { - // Maps to HTTP POST. Used for creating a resource or performing an action. Post string `protobuf:"bytes,4,opt,name=post,proto3,oneof"` } type HttpRule_Delete struct { - // Maps to HTTP DELETE. Used for deleting a resource. Delete string `protobuf:"bytes,5,opt,name=delete,proto3,oneof"` } type HttpRule_Patch struct { - // Maps to HTTP PATCH. Used for updating a resource. Patch string `protobuf:"bytes,6,opt,name=patch,proto3,oneof"` } type HttpRule_Custom struct { - // The custom pattern is used for specifying an HTTP method that is not - // included in the `pattern` field, such as HEAD, or "*" to leave the - // HTTP method unspecified for this rule. The wild-card rule is useful - // for services that provide content to Web (HTML) clients. Custom *CustomHttpPattern `protobuf:"bytes,8,opt,name=custom,proto3,oneof"` } @@ -576,15 +243,12 @@ func (*HttpRule_Patch) isHttpRule_Pattern() {} func (*HttpRule_Custom) isHttpRule_Pattern() {} -// A custom pattern is used for defining custom HTTP verb. type CustomHttpPattern struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // The name of this custom HTTP verb. Kind string `protobuf:"bytes,1,opt,name=kind,proto3" json:"kind,omitempty"` - // The path matched by this custom verb. Path string `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"` } @@ -672,9 +336,13 @@ var file_httpoptions_http_proto_rawDesc = []byte{ 0x74, 0x70, 0x50, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, - 0x68, 0x42, 0x25, 0x0a, 0x0c, 0x63, 0x6f, 0x6d, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x61, 0x70, - 0x69, 0x42, 0x09, 0x48, 0x74, 0x74, 0x70, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0xf8, 0x01, - 0x01, 0xa2, 0x02, 0x04, 0x45, 0x41, 0x50, 0x49, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x68, 0x42, 0x63, 0x0a, 0x0c, 0x63, 0x6f, 0x6d, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x61, 0x70, + 0x69, 0x42, 0x09, 0x48, 0x74, 0x74, 0x70, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3c, + 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x69, 0x6e, 0x63, 0x68, + 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x65, 0x61, 0x73, 0x65, 0x2d, 0x67, 0x61, 0x74, + 0x65, 0x77, 0x61, 0x79, 0x2f, 0x68, 0x74, 0x74, 0x70, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x3b, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0xf8, 0x01, 0x01, 0xa2, + 0x02, 0x04, 0x45, 0x41, 0x50, 0x49, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000..b731f05 --- /dev/null +++ b/renovate.json @@ -0,0 +1,53 @@ +{ + "extends": [ + "config:base" + ], + "baseBranches": [ + "v1", + "master" + ], + "postUpdateOptions": [ + "gomodTidy" + ], + "packageRules": [ + { + "updateTypes": [ + "minor", + "patch", + "pin", + "digest" + ], + "automerge": true + }, + { + "baseBranchList": [ + "v1" + ], + "packageNames": [ + "github.com/golang/protobuf", + "google.golang.org/genproto", + "io_bazel_rules_go", + "golang.org/x/oauth2", + "google.golang.org/grpc" + ], + "enabled": false + }, + { + "baseBranchList": [ + "master" + ], + "packageNames": [ + "github.com/golang/protobuf", + "google.golang.org/protobuf" + ], + "groupName": "golang/protobuf" + }, + { + "packagePatterns": [ + "jekyll.*", + "github-pages" + ], + "enabled": false + } + ] +} diff --git a/repositories.bzl b/repositories.bzl index 421c22b..2c22a00 100644 --- a/repositories.bzl +++ b/repositories.bzl @@ -4,8 +4,8 @@ def go_repositories(): go_repository( name = "com_github_binchencoder_letsgo", importpath = "github.com/binchencoder/letsgo", - sum = "h1:hEDDOeGdX9R/JPYMdVo9N/9iQa5BeBLluTssrNYy/ng=", - version = "v0.0.3", + sum = "h1:wYZv8TO4TGO2U8HjEO5Odf8OYWQjfrXS8ddfGZWQfHI=", + version = "v0.0.5", ) go_repository( name = "com_github_binchencoder_skylb_api", @@ -23,8 +23,8 @@ def go_repositories(): go_repository( name = "com_github_grpc_ecosystem_grpc_gateway", importpath = "github.com/grpc-ecosystem/grpc-gateway/v2", - sum = "h1:X2vfSnm1WC8HEo0MBHZg2TcuDUHJj6kd1TmEAQncnSA=", - version = "v2.0.1", + sum = "h1:SLkFeyLhrg86Ny5Wme4MGGace7EHfgsb07uWX/QUGEQ=", + version = "v2.9.0", ) go_repository( name = "com_github_grpc_ecosystem_grpc_opentracing", @@ -53,8 +53,8 @@ def go_repositories(): go_repository( name = "com_github_fatih_color", importpath = "github.com/fatih/color", - sum = "h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=", - version = "v1.9.0", + sum = "h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=", + version = "v1.7.0", ) go_repository( name = "com_github_ghodss_yaml", @@ -65,26 +65,26 @@ def go_repositories(): go_repository( name = "com_github_golang_glog", importpath = "github.com/golang/glog", - sum = "h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=", - version = "v0.0.0-20160126235308-23def4e6c14b", + sum = "h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ=", + version = "v1.0.0", ) go_repository( name = "com_github_golang_protobuf", importpath = "github.com/golang/protobuf", - sum = "h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=", - version = "v1.4.2", + sum = "h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=", + version = "v1.5.2", ) go_repository( name = "com_github_google_uuid", importpath = "github.com/google/uuid", - sum = "h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=", - version = "v1.1.1", + sum = "h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=", + version = "v1.1.2", ) go_repository( name = "com_github_google_go_cmp", importpath = "github.com/google/go-cmp", - sum = "h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=", - version = "v0.5.0", + sum = "h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=", + version = "v0.5.7", ) go_repository( name = "com_github_klauspost_cpuid", @@ -131,8 +131,8 @@ def go_repositories(): go_repository( name = "com_github_klauspost_compress", importpath = "github.com/klauspost/compress", - sum = "h1:a/y8CglcM7gLGYmlbP/stPE5sR3hbhFRUjCBfd/0B3I=", - version = "v1.10.10", + sum = "h1:0hzRabrMN4tSTvMfnL3SCv1ZGeAP23ynzodBgaHeMeg=", + version = "v1.11.7", ) go_repository( name = "com_github_opentracing_opentracing_go", @@ -141,7 +141,7 @@ def go_repositories(): version = "v1.2.0", ) go_repository( - name = "com_github_matttproud_golang_protobuf_extension", + name = "com_github_matttproud_golang_protobuf_extensions", importpath = "github.com/matttproud/golang_protobuf_extensions", sum = "h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=", version = "v1.0.1", @@ -149,8 +149,8 @@ def go_repositories(): go_repository( name = "com_github_stretchr_testify", importpath = "github.com/stretchr/testify", - sum = "h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=", - version = "v1.6.1", + sum = "h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=", + version = "v1.7.0", ) go_repository( name = "com_github_soheilhy_cmux", @@ -204,8 +204,8 @@ def go_repositories(): go_repository( name = "in_gopkg_yaml_v2", importpath = "gopkg.in/yaml.v2", - sum = "h1:uUkhRGrsEyx/laRdeS6YIQKIys8pg+lRSRdVMTYjivs=", - version = "v2.0.0", + sum = "h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=", + version = "v2.4.0", ) go_repository( name = "in_gopkg_yaml_v3", @@ -213,37 +213,54 @@ def go_repositories(): sum = "h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=", version = "v3.0.0-20200615113413-eeeca48fe776", ) + go_repository( + name = "io_etcd_go_bbolt", + importpath = "go.etcd.io/bbolt", + sum = "h1:Z/90sZLPOeCy2PwprqkFa25PdkusRzaj9P8zm/KNyvk=", + version = "v1.3.2", + ) + go_repository( + name = "io_k8s_sigs_yaml", + importpath = "sigs.k8s.io/yaml", + sum = "h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=", + version = "v1.3.0", + ) go_repository( name = "org_golang_google_genproto", importpath = "google.golang.org/genproto", - sum = "h1:7RoRaOmOAXwqnurgQ5g5/d0yCi9ha2UxuTZULXudK7A=", - version = "v0.0.0-20201028140639-c77dae4b0522", + sum = "h1:ErU+UA6wxadoU8nWrsy5MZUVBs75K17zUCsUCIfrXCE=", + version = "v0.0.0-20220314164441-57ef72a4c106", ) go_repository( name = "org_golang_google_grpc", importpath = "google.golang.org/grpc", - sum = "h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4=", - version = "v1.29.1", + sum = "h1:NEpgUqV3Z+ZjkqMsxMg11IaDrXY4RY6CQukSGK0uI1M=", + version = "v1.45.0", ) - + # go_repository( + # name = "org_golang_google_grpc", + # importpath = "google.golang.org/grpc", + # sum = "h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4=", + # version = "v1.29.1", + # ) go_repository( name = "org_golang_google_grpc_cmd_protoc_gen_go_grpc", importpath = "google.golang.org/grpc/cmd/protoc-gen-go-grpc", - sum = "h1:KNluVV5ay+orsSPJ6XTpwJQ8qBhrBkOTmtBFGeDlBcY=", - version = "v0.0.0-20200527211525-6c9e30c09db2", + sum = "h1:lQ+dE99pFsb8osbJB3oRfE5eW4Hx6a/lZQr8Jh+eoT4=", + version = "v1.0.0", ) go_repository( name = "org_golang_google_protobuf", importpath = "google.golang.org/protobuf", - sum = "h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=", - version = "v1.25.0", + sum = "h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=", + version = "v1.27.1", ) go_repository( name = "org_uber_go_atomic", importpath = "go.uber.org/atomic", - sum = "h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=", - version = "v1.6.0", + sum = "h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=", + version = "v1.7.0", ) go_repository( name = "org_golang_x_crypto", @@ -286,14 +303,14 @@ def go_repositories(): go_repository( name = "org_golang_x_net", importpath = "golang.org/x/net", - sum = "h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA=", - version = "v0.0.0-20200822124328-c89045814202", + sum = "h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk=", + version = "v0.0.0-20220127200216-cd36cc0744dd", ) go_repository( name = "org_golang_x_oauth2", importpath = "golang.org/x/oauth2", - sum = "h1:ld7aEMNHoBnnDAX15v1T6z31v8HwR2A9FYOuAhWqkwc=", - version = "v0.0.0-20200902213428-5d25da1a8d43", + sum = "h1:qfl7ob3DIEs3Ml9oLuPwY2N04gymzAW04WsUQHIClgM=", + version = "v0.0.0-20220309155454-6242fa91716a", ) go_repository( name = "org_golang_x_sync", @@ -304,14 +321,21 @@ def go_repositories(): go_repository( name = "org_golang_x_sys", importpath = "golang.org/x/sys", - sum = "h1:B6caxRw+hozq68X2MY7jEpZh/cr4/aHLv9xU8Kkadrw=", - version = "v0.0.0-20200803210538-64077c9b5642", + sum = "h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=", + version = "v0.0.0-20211216021012-1d35b9e2eb4e", ) + go_repository( + name = "org_golang_x_term", + importpath = "golang.org/x/term", + sum = "h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=", + version = "v0.0.0-20210927222741-03fcf44c2211", + ) + go_repository( name = "org_golang_x_text", importpath = "golang.org/x/text", - sum = "h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=", - version = "v0.3.3", + sum = "h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=", + version = "v0.3.7", ) go_repository( From efb0fd0ac1dfbbf0fc7160d9ee32eb3e05fae11b Mon Sep 17 00:00:00 2001 From: chenbin1314 Date: Sun, 27 Mar 2022 16:03:43 +0800 Subject: [PATCH 41/56] Upgrade github.com/grpc-ecosystem/grpc-gateway version to v2.9.0 --- WORKSPACE | 18 +- cmd/custom-gateway/BUILD.bazel | 4 +- cmd/gateway/BUILD.bazel | 6 +- cmd/gateway/registryprod.go | 2 +- .../cmd => }/grpc-server/BUILD.bazel | 6 +- .../{internal/cmd => }/grpc-server/echo.go | 10 +- .../{internal/cmd => }/grpc-server/main.go | 4 +- examples/internal/README.md | 24 +- .../internal/cmd/example-grpc-server/main.go | 33 +- examples/internal/gateway/BUILD.bazel | 15 +- examples/internal/integration/BUILD.bazel | 27 +- .../internal/integration/integration_test.go | 262 +++--- examples/internal/proto/examplepb/BUILD.bazel | 15 +- .../proto/examplepb/echo_service.pb.go | 753 ++++++++++++++++++ .../proto/examplepb}/echo_service.pb.gw.go | 449 ++++++++--- .../proto/examplepb/echo_service_grpc.pb.go | 239 ++++++ .../proto/examplepb/generated_input.proto | 20 + .../examplepb/generated_input.swagger.json | 347 ++++++++ .../standalone_echo_service.buf.gen.yaml | 8 + ...vice.yaml => unannotated_echo_servic.yaml} | 0 .../unannotated_echo_service.buf.gen.yaml | 12 + .../examplepb/unannotated_echo_service.pb.go | 437 ++++++++++ .../unannotated_echo_service.pb.gw.go | 3 + .../unannotated_echo_service.swagger.yaml | 112 +++ .../unannotated_echo_service_grpc.pb.go | 167 ++++ examples/internal/server/BUILD.bazel | 32 +- examples/internal/server/echo.go | 2 +- examples/internal/server/main.go | 4 +- .../internal/gengateway/generator.go | 19 +- .../internal/gengateway/template.go | 25 +- gateway/runtime/BUILD.bazel | 8 +- gateway/runtime/mux_test.go | 2 +- go.mod | 5 +- go.sum | 108 +-- integrate/BUILD.bazel | 4 +- proto/{examples => examplepb}/BUILD.bazel | 26 +- .../echo_service.proto | 6 +- .../echo_service.swagger.json | 0 proto/{examples => examplepb}/pom.xml | 0 proto/examples/echo_service.pb.go | 425 ---------- proto/examples/echo_service_grpc.pb.go | 158 ---- repositories.bzl | 240 ++++-- 42 files changed, 2908 insertions(+), 1129 deletions(-) rename examples/{internal/cmd => }/grpc-server/BUILD.bazel (83%) rename examples/{internal/cmd => }/grpc-server/echo.go (60%) rename examples/{internal/cmd => }/grpc-server/main.go (85%) create mode 100755 examples/internal/proto/examplepb/echo_service.pb.go rename {proto/examples => examples/internal/proto/examplepb}/echo_service.pb.gw.go (70%) create mode 100755 examples/internal/proto/examplepb/echo_service_grpc.pb.go create mode 100644 examples/internal/proto/examplepb/generated_input.proto create mode 100644 examples/internal/proto/examplepb/generated_input.swagger.json create mode 100644 examples/internal/proto/examplepb/standalone_echo_service.buf.gen.yaml rename examples/internal/proto/examplepb/{unannotated_echo_service.yaml => unannotated_echo_servic.yaml} (100%) create mode 100644 examples/internal/proto/examplepb/unannotated_echo_service.buf.gen.yaml create mode 100755 examples/internal/proto/examplepb/unannotated_echo_service.pb.go create mode 100755 examples/internal/proto/examplepb/unannotated_echo_service.pb.gw.go create mode 100644 examples/internal/proto/examplepb/unannotated_echo_service.swagger.yaml create mode 100755 examples/internal/proto/examplepb/unannotated_echo_service_grpc.pb.go rename proto/{examples => examplepb}/BUILD.bazel (79%) rename proto/{examples => examplepb}/echo_service.proto (95%) rename proto/{examples => examplepb}/echo_service.swagger.json (100%) rename proto/{examples => examplepb}/pom.xml (100%) delete mode 100755 proto/examples/echo_service.pb.go delete mode 100755 proto/examples/echo_service_grpc.pb.go diff --git a/WORKSPACE b/WORKSPACE index 796ce44..bf71513 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -6,9 +6,9 @@ load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") # Define before rules_proto, otherwise we receive the version of com_google_protobuf from there http_archive( name = "com_google_protobuf", - sha256 = "3bd7828aa5af4b13b99c191e8b1e884ebfa9ad371b0ce264605d347f135d2568", - strip_prefix = "protobuf-3.19.4", - urls = ["https://github.com/protocolbuffers/protobuf/archive/v3.19.4.tar.gz"], + sha256 = "b07772d38ab07e55eca4d50f4b53da2d998bb221575c60a4f81100242d4b4889", + strip_prefix = "protobuf-3.20.0", + urls = ["https://github.com/protocolbuffers/protobuf/archive/v3.20.0.tar.gz"], ) http_archive( @@ -42,10 +42,10 @@ rules_proto_toolchains() http_archive( name = "io_bazel_rules_go", - sha256 = "d6b2513456fe2229811da7eb67a444be7785f5323c6708b38d851d2b51e54d83", + sha256 = "f2dcd210c7095febe54b804bb1cd3a58fe8435a909db2ec04e31542631cf715c", urls = [ - "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.30.0/rules_go-v0.30.0.zip", - "https://github.com/bazelbuild/rules_go/releases/download/v0.30.0/rules_go-v0.30.0.zip", + "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.31.0/rules_go-v0.31.0.zip", + "https://github.com/bazelbuild/rules_go/releases/download/v0.31.0/rules_go-v0.31.0.zip", ], ) @@ -64,9 +64,9 @@ http_archive( # https://github.com/bazelbuild/bazel-gazelle/pull/1194 is merged git_repository( name = "bazel_gazelle", - commit = "4a1aeae7cab962fd8088f42038d3a477cdca91a5", - remote = "https://github.com/johanbrandhorst/bazel-gazelle", - shallow_since = "1647116890 +0000", + commit = "f377e6eff8e24508feb1a34b1e5e681982482a9f", + remote = "https://github.com/bazelbuild/bazel-gazelle", + shallow_since = "1648046534 -0400", ) # 从下载的扩展里载入 go_rules_dependencies go_register_toolchains 函数 diff --git a/cmd/custom-gateway/BUILD.bazel b/cmd/custom-gateway/BUILD.bazel index 3215f79..2d65430 100644 --- a/cmd/custom-gateway/BUILD.bazel +++ b/cmd/custom-gateway/BUILD.bazel @@ -15,8 +15,8 @@ go_library( ], importpath = "github.com/binchencoder/ease-gateway/cmd/custom-gateway", deps = [ - "//examples/internal/proto/examplepb:go_default_library", - "//gateway/runtime:go_default_library", + "//examples/internal/proto/examplepb", + "//gateway/runtime", "//integrate:go_default_library", "@com_github_binchencoder_gateway_proto//data:go_default_library", "@com_github_binchencoder_letsgo//:go_default_library", diff --git a/cmd/gateway/BUILD.bazel b/cmd/gateway/BUILD.bazel index b7a3a43..494226f 100644 --- a/cmd/gateway/BUILD.bazel +++ b/cmd/gateway/BUILD.bazel @@ -10,14 +10,14 @@ go_library( importpath = "github.com/binchencoder/ease-gateway/cmd/gateway", visibility = ["//visibility:public"], deps = [ - "//gateway/runtime:go_default_library", + "//proto/examplepb", + "//gateway/runtime", "//integrate:go_default_library", - "//proto/examples:go_default_library", "//util:go_default_library", "@com_github_binchencoder_gateway_proto//data:go_default_library", "@com_github_binchencoder_letsgo//:go_default_library", "@com_github_binchencoder_letsgo//service/naming:go_default_library", - "@com_github_golang_glog//:go_default_library", + "@com_github_golang_glog//:glog", ], ) diff --git a/cmd/gateway/registryprod.go b/cmd/gateway/registryprod.go index fc761a6..bd4c0cf 100755 --- a/cmd/gateway/registryprod.go +++ b/cmd/gateway/registryprod.go @@ -2,5 +2,5 @@ package main // Import so that applications register themselves to gateway. import ( - _ "github.com/binchencoder/ease-gateway/proto/examples" + _ "github.com/binchencoder/ease-gateway/proto/examplepb" ) diff --git a/examples/internal/cmd/grpc-server/BUILD.bazel b/examples/grpc-server/BUILD.bazel similarity index 83% rename from examples/internal/cmd/grpc-server/BUILD.bazel rename to examples/grpc-server/BUILD.bazel index 493438a..4c9fcd7 100644 --- a/examples/internal/cmd/grpc-server/BUILD.bazel +++ b/examples/grpc-server/BUILD.bazel @@ -8,12 +8,12 @@ go_library( "main.go", "echo.go", ], - importpath = "github.com/binchencoder/ease-gateway/examples/internal/cmd/custom-grpc-server", + importpath = "github.com/binchencoder/ease-gateway/examples/grpc-server", deps = [ - "//proto/examples:go_default_library", + "//proto/examplepb", "@com_github_binchencoder_gateway_proto//data:go_default_library", "@com_github_binchencoder_skylb_api//server:go_default_library", - "@com_github_golang_glog//:go_default_library", + "@com_github_golang_glog//:glog", "@org_golang_google_grpc//:go_default_library", "@org_golang_google_grpc//metadata:go_default_library", ], diff --git a/examples/internal/cmd/grpc-server/echo.go b/examples/grpc-server/echo.go similarity index 60% rename from examples/internal/cmd/grpc-server/echo.go rename to examples/grpc-server/echo.go index ccb99b5..181a464 100644 --- a/examples/internal/cmd/grpc-server/echo.go +++ b/examples/grpc-server/echo.go @@ -3,7 +3,7 @@ package main import ( "context" - examples "github.com/binchencoder/ease-gateway/proto/examples" + "github.com/binchencoder/ease-gateway/proto/examplepb" "github.com/golang/glog" "google.golang.org/grpc" "google.golang.org/grpc/metadata" @@ -14,16 +14,16 @@ import ( type echoServer struct{} // NewEchoServer new echo server -func NewEchoServer() examples.EchoServiceServer { +func NewEchoServer() examplepb.EchoServiceServer { return new(echoServer) } -func (s *echoServer) Echo(ctx context.Context, msg *examples.SimpleMessage) (*examples.SimpleMessage, error) { +func (s *echoServer) Echo(ctx context.Context, msg *examplepb.SimpleMessage) (*examplepb.SimpleMessage, error) { glog.Info(msg) return msg, nil } -func (s *echoServer) EchoBody(ctx context.Context, msg *examples.SimpleMessage) (*examples.SimpleMessage, error) { +func (s *echoServer) EchoBody(ctx context.Context, msg *examplepb.SimpleMessage) (*examplepb.SimpleMessage, error) { glog.Info(msg) grpc.SendHeader(ctx, metadata.New(map[string]string{ "foo": "foo1", @@ -36,7 +36,7 @@ func (s *echoServer) EchoBody(ctx context.Context, msg *examples.SimpleMessage) return msg, nil } -func (s *echoServer) EchoDelete(ctx context.Context, msg *examples.SimpleMessage) (*examples.SimpleMessage, error) { +func (s *echoServer) EchoDelete(ctx context.Context, msg *examplepb.SimpleMessage) (*examplepb.SimpleMessage, error) { glog.Info(msg) return msg, nil } diff --git a/examples/internal/cmd/grpc-server/main.go b/examples/grpc-server/main.go similarity index 85% rename from examples/internal/cmd/grpc-server/main.go rename to examples/grpc-server/main.go index e4e6369..5b07a39 100644 --- a/examples/internal/cmd/grpc-server/main.go +++ b/examples/grpc-server/main.go @@ -8,7 +8,7 @@ import ( "flag" "fmt" - examples "github.com/binchencoder/ease-gateway/proto/examples" + examplepb "github.com/binchencoder/ease-gateway/proto/examplepb" "github.com/binchencoder/gateway-proto/data" skylb "github.com/binchencoder/skylb-api/server" "github.com/golang/glog" @@ -29,7 +29,7 @@ func main() { skylb.Register(data.ServiceId_CUSTOM_EASE_GATEWAY_TEST, "grpc", *port) skylb.EnableHistogram() skylb.Start(fmt.Sprintf(":%d", *port), func(s *grpc.Server) error { - examples.RegisterEchoServiceServer(s, NewEchoServer()) + examplepb.RegisterEchoServiceServer(s, NewEchoServer()) return nil }) } diff --git a/examples/internal/README.md b/examples/internal/README.md index d46322b..59660c2 100644 --- a/examples/internal/README.md +++ b/examples/internal/README.md @@ -1,43 +1,43 @@ # Overrview -ease-gateway/examples 是使用ease-gateway的一个完整示例,包含gateway-server 和 gRPC-server. 还有Java实现gRPC Server的例子 [https://github.com/binchencoder/spring-boot-grpc/tree/master/spring-boot-grpc-examples] +ease-gateway/examples/internal 是使用ease-gateway的一个完整示例,包含gateway-server 和 gRPC-server. 还有Java实现gRPC Server的例子 [https://github.com/binchencoder/spring-boot-grpc/tree/master/spring-boot-grpc-examples] # Build the example build gateway server ``` -bazel build ease-gateway/examples/cmd/example-gateway-server/... +bazel build examples/internal/cmd/example-gateway-server/... ``` build gRPC server ``` -bazel build ease-gateway/examples/cmd/example-grpc-server/... +bazel build examples/internal/cmd/example-grpc-server/... ``` # Run the example start gateway server -``` -ease-gateway/bazel-bin/examples/cmd/example-gateway-server/example-gateway-server_/example-gateway-server -skylb-endpoints="127.0.0.1:1900" -debug-svc-endpoint=custom-ease-gateway-test=localhost:9090 +```shell +ease-gateway/bazel-bin/examples/internal/cmd/example-gateway-server/example-gateway-server_/example-gateway-server -skylb-endpoints="127.0.0.1:1900" -debug-svc-endpoint=custom-ease-gateway-test=localhost:9090 ``` start custom-gateway server -``` +```shell ease-gateway/bazel-bin/cmd/custom-gateway/custom-ease-gateway_/custom-ease-gateway -skylb-endpoints="127.0.0.1:1900" -debug-service=custom-ease-gateway-test -debug-svc-endpoint=custom-ease-gateway-test=localhost:9090 ``` -start examples gRPC server for test //examples/cmd/example-gateway-server -``` -ease-gateway/bazel-bin/examples/cmd/example-grpc-server/example-grpc-server_/example-grpc-server +start examples gRPC server for test //examples/internal/cmd/example-grpc-server +```shell +ease-gateway/bazel-bin/examples/internal/cmd/example-grpc-server/example-grpc-server_/example-grpc-server -skylb-endpoints="127.0.0.1:1900,127.0.0.1:1901" ``` start gRPC server for test //cmd/gateway -``` -ease-gateway/bazel-bin/examples/cmd/grpc-server/grpc-server_/grpc-server -skylb-endpoints="127.0.0.1:1900" +```shell +ease-gateway/bazel-bin/examples/grpc-server/grpc-server_/grpc-server -skylb-endpoints="127.0.0.1:1900" ``` start //cmd/gateway -``` +```shell ease-gateway/bazel-bin/cmd/gateway/gateway_/gateway -skylb-endpoints="127.0.0.1:1900" -v=2 -log_dir=. ``` diff --git a/examples/internal/cmd/example-grpc-server/main.go b/examples/internal/cmd/example-grpc-server/main.go index 79d17b0..1482ee4 100644 --- a/examples/internal/cmd/example-grpc-server/main.go +++ b/examples/internal/cmd/example-grpc-server/main.go @@ -5,14 +5,17 @@ package main import ( - "context" "flag" + "fmt" + + examplepb "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb" + + "github.com/binchencoder/gateway-proto/data" + skylb "github.com/binchencoder/skylb-api/server" - // examples "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb" "github.com/binchencoder/ease-gateway/examples/internal/server" - // "github.com/binchencoder/gateway-proto/data" - // skylb "github.com/binchencoder/skylb-api/server" "github.com/golang/glog" + "google.golang.org/grpc" ) var ( @@ -27,15 +30,15 @@ func main() { defer glog.Flush() // Don't regist to skylbserver - ctx := context.Background() - if err := server.Run(ctx, *network, *addr); err != nil { - glog.Fatal(err) - } - - // skylb.Register(data.ServiceId_CUSTOM_EASE_GATEWAY_TEST, "grpc", *port) - // skylb.EnableHistogram() - // skylb.Start(fmt.Sprintf(":%d", *port), func(s *grpc.Server) error { - // examples.RegisterEchoServiceServer(s, server.NewEchoServer()) - // return nil - // }) + // ctx := context.Background() + // if err := server.Run(ctx, *network, *addr); err != nil { + // glog.Fatal(err) + // } + + skylb.Register(data.ServiceId_CUSTOM_EASE_GATEWAY_TEST, "grpc", *port) + skylb.EnableHistogram() + skylb.Start(fmt.Sprintf(":%d", *port), func(s *grpc.Server) error { + examplepb.RegisterEchoServiceServer(s, server.NewEchoServer()) + return nil + }) } diff --git a/examples/internal/gateway/BUILD.bazel b/examples/internal/gateway/BUILD.bazel index d0712e2..5739512 100644 --- a/examples/internal/gateway/BUILD.bazel +++ b/examples/internal/gateway/BUILD.bazel @@ -1,7 +1,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( - name = "go_default_library", + name = "gateway", srcs = [ "doc.go", "gateway.go", @@ -11,11 +11,18 @@ go_library( importpath = "github.com/binchencoder/ease-gateway/examples/internal/gateway", visibility = ["//visibility:public"], deps = [ - "//examples/internal/proto/examplepb:go_default_library", - "//gateway/runtime:go_default_library", + "//examples/internal/proto/examplepb", + "//gateway/runtime", "//util:go_default_library", "@com_github_golang_glog//:go_default_library", "@org_golang_google_grpc//:go_default_library", - "@org_golang_google_grpc//connectivity:go_default_library", + "@org_golang_google_grpc//connectivity", + "@org_golang_google_grpc//credentials/insecure", ], ) + +alias( + name = "go_default_library", + actual = ":gateway", + visibility = ["//examples:__subpackages__"], +) diff --git a/examples/internal/integration/BUILD.bazel b/examples/internal/integration/BUILD.bazel index 6931ba2..03c89f4 100644 --- a/examples/internal/integration/BUILD.bazel +++ b/examples/internal/integration/BUILD.bazel @@ -1,27 +1,26 @@ load("@io_bazel_rules_go//go:def.bzl", "go_test") go_test( - name = "go_default_test", + name = "integration_test", srcs = [ "integration_test.go", "main_test.go", ], deps = [ - "//examples/internal/gateway:go_default_library", - "//examples/internal/proto/examplepb:go_default_library", - # "//examples/internal/proto/examplepb:unannotated_go_default_library", - "//examples/internal/server:go_default_library", - "//gateway/runtime:go_default_library", + "//examples/internal/gateway", + "//examples/internal/proto/examplepb", + "//examples/internal/server", + "//gateway/runtime", "//httpoptions", - "@com_github_golang_glog//:go_default_library", - "@com_github_google_go_cmp//cmp:go_default_library", + "@com_github_golang_glog//:glog", + "@com_github_google_go_cmp//cmp", "@go_googleapis//google/rpc:status_go_proto", - "@io_bazel_rules_go//proto/wkt:empty_go_proto", "@io_bazel_rules_go//proto/wkt:field_mask_go_proto", - "@org_golang_google_grpc//codes:go_default_library", - "@org_golang_google_protobuf//encoding/protojson:go_default_library", - "@org_golang_google_protobuf//proto:go_default_library", - "@org_golang_google_protobuf//testing/protocmp:go_default_library", - "@org_golang_google_protobuf//types/known/structpb:go_default_library", + "@org_golang_google_grpc//codes", + "@org_golang_google_protobuf//encoding/protojson", + "@org_golang_google_protobuf//proto", + "@org_golang_google_protobuf//testing/protocmp", + "@org_golang_google_protobuf//types/known/emptypb", + "@org_golang_google_protobuf//types/known/structpb", ], ) diff --git a/examples/internal/integration/integration_test.go b/examples/internal/integration/integration_test.go index daa5486..d43092d 100644 --- a/examples/internal/integration/integration_test.go +++ b/examples/internal/integration/integration_test.go @@ -13,6 +13,8 @@ import ( "github.com/binchencoder/ease-gateway/gateway/runtime" "github.com/google/go-cmp/cmp" fieldmaskpb "google.golang.org/genproto/protobuf/field_mask" + + // "google.golang.org/grpc/codes" "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/testing/protocmp" @@ -33,9 +35,11 @@ func TestEcho(t *testing.T) { testEchoOneof(t, 8088, apiPrefix, "application/json") testEchoOneof1(t, 8088, apiPrefix, "application/json") testEchoOneof2(t, 8088, apiPrefix, "application/json") - testEchoBody(t, 8088, apiPrefix) + testEchoBody(t, 8088, apiPrefix, true) + testEchoBody(t, 8088, apiPrefix, false) // Use SendHeader/SetTrailer without gRPC server https://github.com/grpc-ecosystem/grpc-gateway/issues/517#issuecomment-684625645 - testEchoBody(t, 8089, apiPrefix) + testEchoBody(t, 8089, apiPrefix, true) + testEchoBody(t, 8089, apiPrefix, false) }) } t.Run("testEchoValidationRules", func(t *testing.T) { @@ -55,9 +59,12 @@ func TestEchoPatch(t *testing.T) { StructValue: &structpb.Struct{Fields: map[string]*structpb.Value{ "layered_struct_key": {Kind: &structpb.Value_StringValue{StringValue: "struct_val"}}, }}, - }}}}, - ValueField: &structpb.Value{Kind: &structpb.Value_StructValue{StructValue: &structpb.Struct{Fields: map[string]*structpb.Value{ - "value_struct_key": {Kind: &structpb.Value_StringValue{StringValue: "value_struct_val"}}}}, + }}, + }}, + ValueField: &structpb.Value{Kind: &structpb.Value_StructValue{ + StructValue: &structpb.Struct{Fields: map[string]*structpb.Value{ + "value_struct_key": {Kind: &structpb.Value_StringValue{StringValue: "value_struct_val"}}, + }}, }}, } payload, err := protojson.MarshalOptions{UseProtoNames: true}.Marshal(&sent) @@ -135,6 +142,39 @@ func TestForwardResponseOption(t *testing.T) { testEcho(t, port, "v1", "application/vnd.docker.plugins.v1.1+json") } +func TestForwardResponseOptionHTTPPathPattern(t *testing.T) { + if testing.Short() { + t.Skip() + return + } + + ctx := context.Background() + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + port := 7080 + go func() { + if err := runGateway( + ctx, + fmt.Sprintf(":%d", port), + runtime.WithForwardResponseOption( + func(ctx context.Context, w http.ResponseWriter, _ proto.Message) error { + path, _ := runtime.HTTPPathPattern(ctx) + w.Header().Set("Content-Type", path) + return nil + }, + ), + ); err != nil { + t.Errorf("runGateway() failed with %v; want success", err) + return + } + }() + if err := waitForGateway(ctx, uint16(port)); err != nil { + t.Errorf("waitForGateway(ctx, %d) failed with %v; want success", port, err) + } + testEcho(t, port, "v1", "/v1/example/echo/{id}") +} + func testEcho(t *testing.T, port int, apiPrefix string, contentType string) { apiURL := fmt.Sprintf("http://localhost:%d/%s/example/echo/myid", port, apiPrefix) resp, err := http.Post(apiURL, "application/json", strings.NewReader("{}")) @@ -149,39 +189,18 @@ func testEcho(t *testing.T, port int, apiPrefix string, contentType string) { return } - if apiPrefix != "v1" { - if got, want := resp.StatusCode, http.StatusNotFound; got != want { - t.Errorf("resp.StatusCode = %d; want %d", got, want) - t.Logf("%s", buf) - } - } else { - if got, want := resp.StatusCode, http.StatusOK; got != want { - t.Errorf("resp.StatusCode = %d; want %d", got, want) - t.Logf("%s", buf) - } - - msg := new(examplepb.UnannotatedSimpleMessage) - if err := marshaler.Unmarshal(buf, msg); err != nil { - t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) - return - } - if got, want := msg.Id, "myid"; got != want { - t.Errorf("msg.Id = %q; want %q", got, want) - } - - if got, want := resp.Header.Get("Grpc-Metadata-Foo"), "foo1"; got != want { - t.Errorf("Grpc-Metadata-Foo was %q, wanted %q", got, want) - } - if got, want := resp.Header.Get("Grpc-Metadata-Bar"), "bar1"; got != want { - t.Errorf("Grpc-Metadata-Bar was %q, wanted %q", got, want) - } + if got, want := resp.StatusCode, http.StatusOK; got != want { + t.Errorf("resp.StatusCode = %d; want %d", got, want) + t.Logf("%s", buf) + } - if got, want := resp.Trailer.Get("Grpc-Trailer-Foo"), "foo2"; got != want { - t.Errorf("Grpc-Trailer-Foo was %q, wanted %q", got, want) - } - if got, want := resp.Trailer.Get("Grpc-Trailer-Bar"), "bar2"; got != want { - t.Errorf("Grpc-Trailer-Bar was %q, wanted %q", got, want) - } + msg := new(examplepb.UnannotatedSimpleMessage) + if err := marshaler.Unmarshal(buf, msg); err != nil { + t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) + return + } + if got, want := msg.Id, "myid"; got != want { + t.Errorf("msg.Id = %q; want %q", got, want) } if value := resp.Header.Get("Content-Type"); value != contentType { @@ -203,25 +222,18 @@ func testEchoOneof(t *testing.T, port int, apiPrefix string, contentType string) return } - if apiPrefix != "v1" { - if got, want := resp.StatusCode, http.StatusNotFound; got != want { - t.Errorf("resp.StatusCode = %d; want %d", got, want) - t.Logf("%s", buf) - } - } else { - if got, want := resp.StatusCode, http.StatusOK; got != want { - t.Errorf("resp.StatusCode = %d; want %d", got, want) - t.Logf("%s", buf) - } + if got, want := resp.StatusCode, http.StatusOK; got != want { + t.Errorf("resp.StatusCode = %d; want %d", got, want) + t.Logf("%s", buf) + } - msg := new(examplepb.UnannotatedSimpleMessage) - if err := marshaler.Unmarshal(buf, msg); err != nil { - t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) - return - } - if got, want := msg.GetLang(), "golang"; got != want { - t.Errorf("msg.GetLang() = %q; want %q", got, want) - } + msg := new(examplepb.UnannotatedSimpleMessage) + if err := marshaler.Unmarshal(buf, msg); err != nil { + t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) + return + } + if got, want := msg.GetLang(), "golang"; got != want { + t.Errorf("msg.GetLang() = %q; want %q", got, want) } if value := resp.Header.Get("Content-Type"); value != contentType { @@ -243,25 +255,18 @@ func testEchoOneof1(t *testing.T, port int, apiPrefix string, contentType string return } - if apiPrefix != "v1" { - if got, want := resp.StatusCode, http.StatusNotFound; got != want { - t.Errorf("resp.StatusCode = %d; want %d", got, want) - t.Logf("%s", buf) - } - } else { - if got, want := resp.StatusCode, http.StatusOK; got != want { - t.Errorf("resp.StatusCode = %d; want %d", got, want) - t.Logf("%s", buf) - } + if got, want := resp.StatusCode, http.StatusOK; got != want { + t.Errorf("resp.StatusCode = %d; want %d", got, want) + t.Logf("%s", buf) + } - msg := new(examplepb.UnannotatedSimpleMessage) - if err := marshaler.Unmarshal(buf, msg); err != nil { - t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) - return - } - if got, want := msg.GetStatus().GetNote(), "golang"; got != want { - t.Errorf("msg.GetStatus().GetNote() = %q; want %q", got, want) - } + msg := new(examplepb.UnannotatedSimpleMessage) + if err := marshaler.Unmarshal(buf, msg); err != nil { + t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) + return + } + if got, want := msg.GetStatus().GetNote(), "golang"; got != want { + t.Errorf("msg.GetStatus().GetNote() = %q; want %q", got, want) } if value := resp.Header.Get("Content-Type"); value != contentType { @@ -283,25 +288,18 @@ func testEchoOneof2(t *testing.T, port int, apiPrefix string, contentType string return } - if apiPrefix != "v1" { - if got, want := resp.StatusCode, http.StatusNotFound; got != want { - t.Errorf("resp.StatusCode = %d; want %d", got, want) - t.Logf("%s", buf) - } - } else { - if got, want := resp.StatusCode, http.StatusOK; got != want { - t.Errorf("resp.StatusCode = %d; want %d", got, want) - t.Logf("%s", buf) - } + if got, want := resp.StatusCode, http.StatusOK; got != want { + t.Errorf("resp.StatusCode = %d; want %d", got, want) + t.Logf("%s", buf) + } - msg := new(examplepb.UnannotatedSimpleMessage) - if err := marshaler.Unmarshal(buf, msg); err != nil { - t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) - return - } - if got, want := msg.GetNo().GetNote(), "golang"; got != want { - t.Errorf("msg.GetNo().GetNote() = %q; want %q", got, want) - } + msg := new(examplepb.UnannotatedSimpleMessage) + if err := marshaler.Unmarshal(buf, msg); err != nil { + t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) + return + } + if got, want := msg.GetNo().GetNote(), "golang"; got != want { + t.Errorf("msg.GetNo().GetNote() = %q; want %q", got, want) } if value := resp.Header.Get("Content-Type"); value != contentType { @@ -309,7 +307,7 @@ func testEchoOneof2(t *testing.T, port int, apiPrefix string, contentType string } } -func testEchoBody(t *testing.T, port int, apiPrefix string) { +func testEchoBody(t *testing.T, port int, apiPrefix string, useTrailers bool) { sent := examplepb.UnannotatedSimpleMessage{Id: "example"} payload, err := marshaler.Marshal(&sent) if err != nil { @@ -317,9 +315,19 @@ func testEchoBody(t *testing.T, port int, apiPrefix string) { } apiURL := fmt.Sprintf("http://localhost:%d/%s/example/echo_body", port, apiPrefix) - resp, err := http.Post(apiURL, "", bytes.NewReader(payload)) + + req, err := http.NewRequest("POST", apiURL, bytes.NewReader(payload)) if err != nil { - t.Errorf("http.Post(%q) failed with %v; want success", apiURL, err) + t.Errorf("http.NewRequest() failed with %v; want success", err) + return + } + if useTrailers { + req.Header.Set("TE", "trailers") + } + + resp, err := http.DefaultClient.Do(req) + if err != nil { + t.Errorf("client.Do(%v) failed with %v; want success", req, err) return } defer resp.Body.Close() @@ -329,45 +337,39 @@ func testEchoBody(t *testing.T, port int, apiPrefix string) { return } - if apiPrefix != "v1" { - if got, want := resp.StatusCode, http.StatusNotFound; got != want { - t.Errorf("resp.StatusCode = %d; want %d", got, want) - t.Logf("%s", buf) - } - } else { - if got, want := resp.StatusCode, http.StatusOK; got != want { - t.Errorf("resp.StatusCode = %d; want %d", got, want) - t.Logf("%s", buf) - } + if got, want := resp.StatusCode, http.StatusOK; got != want { + t.Errorf("resp.StatusCode = %d; want %d", got, want) + t.Logf("%s", buf) + } - var received examplepb.UnannotatedSimpleMessage - if err := marshaler.Unmarshal(buf, &received); err != nil { - t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) - return - } - if diff := cmp.Diff(&received, &sent, protocmp.Transform()); diff != "" { - t.Errorf(diff) - } + var received examplepb.UnannotatedSimpleMessage + if err := marshaler.Unmarshal(buf, &received); err != nil { + t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) + return + } + if diff := cmp.Diff(&received, &sent, protocmp.Transform()); diff != "" { + t.Errorf(diff) + } - if value := resp.Header.Get("Content-Type"); value != "application/json" { - t.Errorf("Content-Type was %s, wanted %s", value, "application/json") - } + if got, want := resp.Header.Get("Grpc-Metadata-Foo"), "foo1"; got != want { + t.Errorf("Grpc-Metadata-Foo was %q, wanted %q", got, want) + } + if got, want := resp.Header.Get("Grpc-Metadata-Bar"), "bar1"; got != want { + t.Errorf("Grpc-Metadata-Bar was %q, wanted %q", got, want) + } - // fmt.Printf("headers: %v \n", resp.Header) - // fmt.Printf("apiURL: %s \n", apiURL) - // if got, want := resp.Header.Get("Grpc-Metadata-Foo"), "foo1"; got != want { - // t.Errorf("Grpc-Metadata-Foo was %q, wanted %q", got, want) - // } - // if got, want := resp.Header.Get("Grpc-Metadata-Bar"), "bar1"; got != want { - // t.Errorf("Grpc-Metadata-Bar was %q, wanted %q", got, want) - // } - - // if got, want := resp.Trailer.Get("Grpc-Trailer-Foo"), "foo2"; got != want { - // t.Errorf("Grpc-Trailer-Foo was %q, wanted %q", got, want) - // } - // if got, want := resp.Trailer.Get("Grpc-Trailer-Bar"), "bar2"; got != want { - // t.Errorf("Grpc-Trailer-Bar was %q, wanted %q", got, want) - // } + wantedTrailers := map[bool]map[string]string{ + true: { + "Grpc-Trailer-Foo": "foo2", + "Grpc-Trailer-Bar": "bar2", + }, + false: {}, + } + + for trailer, want := range wantedTrailers[useTrailers] { + if got := resp.Trailer.Get(trailer); got != want { + t.Errorf("%s was %q, wanted %q", trailer, got, want) + } } } diff --git a/examples/internal/proto/examplepb/BUILD.bazel b/examples/internal/proto/examplepb/BUILD.bazel index 16e18c5..8084e43 100644 --- a/examples/internal/proto/examplepb/BUILD.bazel +++ b/examples/internal/proto/examplepb/BUILD.bazel @@ -1,7 +1,7 @@ load("@rules_proto//proto:defs.bzl", "proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library") load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") -load("@com_github_binchencoder_ease_gateway//gateway/protoc-gen-openapiv2:defs.bzl", "protoc_gen_openapiv2") +load("//gateway/protoc-gen-openapiv2:defs.bzl", "protoc_gen_openapiv2") package(default_visibility = ["//visibility:public"]) @@ -34,6 +34,13 @@ package(default_visibility = ["//visibility:public"]) # gazelle:exclude openapi_merge_b.proto # gazelle:go_grpc_compilers //:go_apiv2, //:go_grpc, //protoc-gen-grpc-gateway:go_gen_grpc_gateway +genrule( + name = "generated_proto", + srcs = ["generated_input.proto"], + outs = ["generated_output.proto"], + cmd = "cp $< $@", # A simple copy simulates a generated proto file. +) + proto_library( name = "examplepb_proto", srcs = [ @@ -41,8 +48,8 @@ proto_library( # "unannotated_echo_service.proto", ], deps = [ - "//gateway/protoc-gen-openapiv2/options:options_proto", "//httpoptions:options_proto", + "//gateway/protoc-gen-openapiv2/options:options_proto", "@com_github_binchencoder_gateway_proto//data:data_proto", "@com_github_binchencoder_gateway_proto//frontend:error_proto", "@com_google_protobuf//:duration_proto", @@ -83,9 +90,7 @@ go_proto_library( deps = [ "//httpoptions", "@com_github_binchencoder_letsgo//grpc:go_default_library", - "@com_github_binchencoder_skylb_api//balancer:go_default_library", "@com_github_binchencoder_skylb_api//client:go_default_library", - "@com_github_binchencoder_skylb_api//client/option:go_default_library", "@com_github_binchencoder_skylb_api//proto:go_default_library", "//gateway/protoc-gen-openapiv2/options", "@com_github_golang_protobuf//descriptor:go_default_library_gen", # keep @@ -94,7 +99,6 @@ go_proto_library( "@go_googleapis//google/api:visibility_go_proto", "@go_googleapis//google/rpc:status_go_proto", "@org_golang_google_protobuf//proto:go_default_library", # keep - # "@org_golang_google_grpc//naming:go_default_library", ], ) @@ -107,7 +111,6 @@ go_library( "//gateway/runtime", "@com_github_grpc_ecosystem_grpc_gateway//utilities", "@com_github_binchencoder_gateway_proto//frontend:go_default_library", - "@com_github_binchencoder_skylb_api//balancer:go_default_library", "@com_github_binchencoder_skylb_api//client:go_default_library", "@org_golang_google_grpc//:go_default_library", "@org_golang_google_grpc//codes", diff --git a/examples/internal/proto/examplepb/echo_service.pb.go b/examples/internal/proto/examplepb/echo_service.pb.go new file mode 100755 index 0000000..c31ddf4 --- /dev/null +++ b/examples/internal/proto/examplepb/echo_service.pb.go @@ -0,0 +1,753 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.27.1 +// protoc v3.19.4 +// source: examples/internal/proto/examplepb/echo_service.proto + +package examplepb + +import ( + _ "github.com/binchencoder/ease-gateway/httpoptions" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + fieldmaskpb "google.golang.org/protobuf/types/known/fieldmaskpb" + structpb "google.golang.org/protobuf/types/known/structpb" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type Embedded struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Mark: + // *Embedded_Progress + // *Embedded_Note + Mark isEmbedded_Mark `protobuf_oneof:"mark"` +} + +func (x *Embedded) Reset() { + *x = Embedded{} + if protoimpl.UnsafeEnabled { + mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Embedded) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Embedded) ProtoMessage() {} + +func (x *Embedded) ProtoReflect() protoreflect.Message { + mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Embedded.ProtoReflect.Descriptor instead. +func (*Embedded) Descriptor() ([]byte, []int) { + return file_examples_internal_proto_examplepb_echo_service_proto_rawDescGZIP(), []int{0} +} + +func (m *Embedded) GetMark() isEmbedded_Mark { + if m != nil { + return m.Mark + } + return nil +} + +func (x *Embedded) GetProgress() int64 { + if x, ok := x.GetMark().(*Embedded_Progress); ok { + return x.Progress + } + return 0 +} + +func (x *Embedded) GetNote() string { + if x, ok := x.GetMark().(*Embedded_Note); ok { + return x.Note + } + return "" +} + +type isEmbedded_Mark interface { + isEmbedded_Mark() +} + +type Embedded_Progress struct { + Progress int64 `protobuf:"varint,1,opt,name=progress,proto3,oneof"` +} + +type Embedded_Note struct { + Note string `protobuf:"bytes,2,opt,name=note,proto3,oneof"` +} + +func (*Embedded_Progress) isEmbedded_Mark() {} + +func (*Embedded_Note) isEmbedded_Mark() {} + +type SimpleMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Num int64 `protobuf:"varint,2,opt,name=num,proto3" json:"num,omitempty"` + // Types that are assignable to Code: + // *SimpleMessage_LineNum + // *SimpleMessage_Lang + Code isSimpleMessage_Code `protobuf_oneof:"code"` + Status *Embedded `protobuf:"bytes,5,opt,name=status,proto3" json:"status,omitempty"` + // Types that are assignable to Ext: + // *SimpleMessage_En + // *SimpleMessage_No + Ext isSimpleMessage_Ext `protobuf_oneof:"ext"` +} + +func (x *SimpleMessage) Reset() { + *x = SimpleMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SimpleMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SimpleMessage) ProtoMessage() {} + +func (x *SimpleMessage) ProtoReflect() protoreflect.Message { + mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SimpleMessage.ProtoReflect.Descriptor instead. +func (*SimpleMessage) Descriptor() ([]byte, []int) { + return file_examples_internal_proto_examplepb_echo_service_proto_rawDescGZIP(), []int{1} +} + +func (x *SimpleMessage) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *SimpleMessage) GetNum() int64 { + if x != nil { + return x.Num + } + return 0 +} + +func (m *SimpleMessage) GetCode() isSimpleMessage_Code { + if m != nil { + return m.Code + } + return nil +} + +func (x *SimpleMessage) GetLineNum() int64 { + if x, ok := x.GetCode().(*SimpleMessage_LineNum); ok { + return x.LineNum + } + return 0 +} + +func (x *SimpleMessage) GetLang() string { + if x, ok := x.GetCode().(*SimpleMessage_Lang); ok { + return x.Lang + } + return "" +} + +func (x *SimpleMessage) GetStatus() *Embedded { + if x != nil { + return x.Status + } + return nil +} + +func (m *SimpleMessage) GetExt() isSimpleMessage_Ext { + if m != nil { + return m.Ext + } + return nil +} + +func (x *SimpleMessage) GetEn() int64 { + if x, ok := x.GetExt().(*SimpleMessage_En); ok { + return x.En + } + return 0 +} + +func (x *SimpleMessage) GetNo() *Embedded { + if x, ok := x.GetExt().(*SimpleMessage_No); ok { + return x.No + } + return nil +} + +type isSimpleMessage_Code interface { + isSimpleMessage_Code() +} + +type SimpleMessage_LineNum struct { + LineNum int64 `protobuf:"varint,3,opt,name=line_num,json=lineNum,proto3,oneof"` +} + +type SimpleMessage_Lang struct { + Lang string `protobuf:"bytes,4,opt,name=lang,proto3,oneof"` +} + +func (*SimpleMessage_LineNum) isSimpleMessage_Code() {} + +func (*SimpleMessage_Lang) isSimpleMessage_Code() {} + +type isSimpleMessage_Ext interface { + isSimpleMessage_Ext() +} + +type SimpleMessage_En struct { + En int64 `protobuf:"varint,6,opt,name=en,proto3,oneof"` +} + +type SimpleMessage_No struct { + No *Embedded `protobuf:"bytes,7,opt,name=no,proto3,oneof"` +} + +func (*SimpleMessage_En) isSimpleMessage_Ext() {} + +func (*SimpleMessage_No) isSimpleMessage_Ext() {} + +type ValidationRuleTestRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Num int64 `protobuf:"varint,2,opt,name=num,proto3" json:"num,omitempty"` +} + +func (x *ValidationRuleTestRequest) Reset() { + *x = ValidationRuleTestRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ValidationRuleTestRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ValidationRuleTestRequest) ProtoMessage() {} + +func (x *ValidationRuleTestRequest) ProtoReflect() protoreflect.Message { + mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ValidationRuleTestRequest.ProtoReflect.Descriptor instead. +func (*ValidationRuleTestRequest) Descriptor() ([]byte, []int) { + return file_examples_internal_proto_examplepb_echo_service_proto_rawDescGZIP(), []int{2} +} + +func (x *ValidationRuleTestRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *ValidationRuleTestRequest) GetNum() int64 { + if x != nil { + return x.Num + } + return 0 +} + +type ValidationRuleTestResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *ValidationRuleTestResponse) Reset() { + *x = ValidationRuleTestResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ValidationRuleTestResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ValidationRuleTestResponse) ProtoMessage() {} + +func (x *ValidationRuleTestResponse) ProtoReflect() protoreflect.Message { + mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ValidationRuleTestResponse.ProtoReflect.Descriptor instead. +func (*ValidationRuleTestResponse) Descriptor() ([]byte, []int) { + return file_examples_internal_proto_examplepb_echo_service_proto_rawDescGZIP(), []int{3} +} + +type DynamicMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + StructField *structpb.Struct `protobuf:"bytes,1,opt,name=struct_field,json=structField,proto3" json:"struct_field,omitempty"` + ValueField *structpb.Value `protobuf:"bytes,2,opt,name=value_field,json=valueField,proto3" json:"value_field,omitempty"` +} + +func (x *DynamicMessage) Reset() { + *x = DynamicMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DynamicMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DynamicMessage) ProtoMessage() {} + +func (x *DynamicMessage) ProtoReflect() protoreflect.Message { + mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DynamicMessage.ProtoReflect.Descriptor instead. +func (*DynamicMessage) Descriptor() ([]byte, []int) { + return file_examples_internal_proto_examplepb_echo_service_proto_rawDescGZIP(), []int{4} +} + +func (x *DynamicMessage) GetStructField() *structpb.Struct { + if x != nil { + return x.StructField + } + return nil +} + +func (x *DynamicMessage) GetValueField() *structpb.Value { + if x != nil { + return x.ValueField + } + return nil +} + +type DynamicMessageUpdate struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Body *DynamicMessage `protobuf:"bytes,1,opt,name=body,proto3" json:"body,omitempty"` + UpdateMask *fieldmaskpb.FieldMask `protobuf:"bytes,2,opt,name=update_mask,json=updateMask,proto3" json:"update_mask,omitempty"` +} + +func (x *DynamicMessageUpdate) Reset() { + *x = DynamicMessageUpdate{} + if protoimpl.UnsafeEnabled { + mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DynamicMessageUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DynamicMessageUpdate) ProtoMessage() {} + +func (x *DynamicMessageUpdate) ProtoReflect() protoreflect.Message { + mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DynamicMessageUpdate.ProtoReflect.Descriptor instead. +func (*DynamicMessageUpdate) Descriptor() ([]byte, []int) { + return file_examples_internal_proto_examplepb_echo_service_proto_rawDescGZIP(), []int{5} +} + +func (x *DynamicMessageUpdate) GetBody() *DynamicMessage { + if x != nil { + return x.Body + } + return nil +} + +func (x *DynamicMessageUpdate) GetUpdateMask() *fieldmaskpb.FieldMask { + if x != nil { + return x.UpdateMask + } + return nil +} + +var File_examples_internal_proto_examplepb_echo_service_proto protoreflect.FileDescriptor + +var file_examples_internal_proto_examplepb_echo_service_proto_rawDesc = []byte{ + 0x0a, 0x34, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, + 0x65, 0x70, 0x62, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, + 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, + 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x1a, 0x1d, 0x68, 0x74, 0x74, 0x70, 0x6f, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x73, + 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x46, 0x0a, 0x08, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, + 0x64, 0x12, 0x1c, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, + 0x14, 0x0a, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, + 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x42, 0x06, 0x0a, 0x04, 0x6d, 0x61, 0x72, 0x6b, 0x22, 0xa3, 0x02, + 0x0a, 0x0d, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, + 0x10, 0x0a, 0x03, 0x6e, 0x75, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x6e, 0x75, + 0x6d, 0x12, 0x1b, 0x0a, 0x08, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x07, 0x6c, 0x69, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x12, 0x14, + 0x0a, 0x04, 0x6c, 0x61, 0x6e, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, + 0x6c, 0x61, 0x6e, 0x67, 0x12, 0x50, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, + 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, + 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x52, 0x06, + 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x10, 0x0a, 0x02, 0x65, 0x6e, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x03, 0x48, 0x01, 0x52, 0x02, 0x65, 0x6e, 0x12, 0x4a, 0x0a, 0x02, 0x6e, 0x6f, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, + 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, + 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x48, 0x01, + 0x52, 0x02, 0x6e, 0x6f, 0x42, 0x06, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x42, 0x05, 0x0a, 0x03, + 0x65, 0x78, 0x74, 0x22, 0x6f, 0x0a, 0x19, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x75, 0x6c, 0x65, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x31, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x21, 0xb2, 0xe4, + 0x34, 0x1d, 0x0a, 0x04, 0x08, 0x05, 0x10, 0x02, 0x0a, 0x09, 0x08, 0x06, 0x10, 0x02, 0x1a, 0x01, + 0x32, 0x20, 0x01, 0x0a, 0x0a, 0x08, 0x07, 0x10, 0x02, 0x1a, 0x02, 0x36, 0x31, 0x20, 0x01, 0x52, + 0x02, 0x69, 0x64, 0x12, 0x1f, 0x0a, 0x03, 0x6e, 0x75, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, + 0x42, 0x0d, 0xb2, 0xe4, 0x34, 0x09, 0x0a, 0x07, 0x08, 0x01, 0x10, 0x01, 0x1a, 0x01, 0x30, 0x52, + 0x03, 0x6e, 0x75, 0x6d, 0x22, 0x1c, 0x0a, 0x1a, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x75, 0x6c, 0x65, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x85, 0x01, 0x0a, 0x0e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3a, 0x0a, 0x0c, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x5f, + 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, + 0x72, 0x75, 0x63, 0x74, 0x52, 0x0b, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x46, 0x69, 0x65, 0x6c, + 0x64, 0x12, 0x37, 0x0a, 0x0b, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0a, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x22, 0xa7, 0x01, 0x0a, 0x14, 0x44, + 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x12, 0x52, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x3e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, + 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, + 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, + 0x70, 0x62, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x12, 0x3b, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, + 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x4d, 0x61, 0x73, 0x6b, 0x32, 0xd5, 0x08, 0x0a, 0x0b, 0x45, 0x63, 0x68, 0x6f, 0x53, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x12, 0xba, 0x02, 0x0a, 0x04, 0x45, 0x63, 0x68, 0x6f, 0x12, 0x3d, 0x2e, + 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, + 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x53, + 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x3d, 0x2e, 0x67, + 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x53, 0x69, + 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xb3, 0x01, 0xca, 0xf3, + 0x34, 0xae, 0x01, 0x22, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, + 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x5a, 0x1d, 0x12, 0x1b, 0x2f, 0x76, + 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x2f, 0x7b, + 0x69, 0x64, 0x7d, 0x2f, 0x7b, 0x6e, 0x75, 0x6d, 0x7d, 0x5a, 0x24, 0x12, 0x22, 0x2f, 0x76, 0x31, + 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x2f, 0x7b, 0x69, + 0x64, 0x7d, 0x2f, 0x7b, 0x6e, 0x75, 0x6d, 0x7d, 0x2f, 0x7b, 0x6c, 0x61, 0x6e, 0x67, 0x7d, 0x5a, + 0x31, 0x12, 0x2f, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, + 0x63, 0x68, 0x6f, 0x31, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x2f, 0x7b, 0x6c, 0x69, 0x6e, 0x65, 0x5f, + 0x6e, 0x75, 0x6d, 0x7d, 0x2f, 0x7b, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x6e, 0x6f, 0x74, + 0x65, 0x7d, 0x5a, 0x1d, 0x12, 0x1b, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, + 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x32, 0x2f, 0x7b, 0x6e, 0x6f, 0x2e, 0x6e, 0x6f, 0x74, 0x65, + 0x7d, 0x12, 0xa8, 0x01, 0x0a, 0x08, 0x45, 0x63, 0x68, 0x6f, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x3d, + 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, + 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, + 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x3d, 0x2e, + 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, + 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x53, + 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x1e, 0xca, 0xf3, + 0x34, 0x1a, 0x22, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, + 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x62, 0x6f, 0x64, 0x79, 0x3a, 0x01, 0x2a, 0x12, 0xa9, 0x01, 0x0a, + 0x0a, 0x45, 0x63, 0x68, 0x6f, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x3d, 0x2e, 0x67, 0x72, + 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, + 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x53, 0x69, 0x6d, + 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x3d, 0x2e, 0x67, 0x72, 0x70, + 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, + 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x53, 0x69, 0x6d, 0x70, + 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x1d, 0xca, 0xf3, 0x34, 0x19, 0x2a, + 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, + 0x6f, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0xbb, 0x01, 0x0a, 0x09, 0x45, 0x63, 0x68, + 0x6f, 0x50, 0x61, 0x74, 0x63, 0x68, 0x12, 0x44, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, + 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, + 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, + 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x1a, 0x44, 0x2e, 0x67, + 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x44, 0x79, + 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x22, 0x22, 0xca, 0xf3, 0x34, 0x1e, 0x32, 0x16, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, + 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x70, 0x61, 0x74, 0x63, 0x68, + 0x3a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x12, 0xd6, 0x01, 0x0a, 0x12, 0x45, 0x63, 0x68, 0x6f, 0x56, + 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x49, 0x2e, + 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, + 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x56, + 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x75, 0x6c, 0x65, 0x54, 0x65, 0x73, + 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x4a, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, + 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, + 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x75, 0x6c, 0x65, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x29, 0xca, 0xf3, 0x34, 0x25, 0x22, 0x20, 0x2f, 0x76, 0x31, 0x2f, + 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x3a, 0x76, 0x61, 0x6c, + 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x3a, 0x01, 0x2a, 0x1a, + 0x1b, 0xea, 0xf3, 0x34, 0x17, 0x08, 0xb6, 0x95, 0xff, 0xff, 0x07, 0x12, 0x04, 0x67, 0x72, 0x70, + 0x63, 0x1a, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x01, 0x42, 0x52, 0x5a, 0x50, + 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x69, 0x6e, 0x63, 0x68, + 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x65, 0x61, 0x73, 0x65, 0x2d, 0x67, 0x61, 0x74, + 0x65, 0x77, 0x61, 0x79, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x78, 0x61, + 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x3b, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_examples_internal_proto_examplepb_echo_service_proto_rawDescOnce sync.Once + file_examples_internal_proto_examplepb_echo_service_proto_rawDescData = file_examples_internal_proto_examplepb_echo_service_proto_rawDesc +) + +func file_examples_internal_proto_examplepb_echo_service_proto_rawDescGZIP() []byte { + file_examples_internal_proto_examplepb_echo_service_proto_rawDescOnce.Do(func() { + file_examples_internal_proto_examplepb_echo_service_proto_rawDescData = protoimpl.X.CompressGZIP(file_examples_internal_proto_examplepb_echo_service_proto_rawDescData) + }) + return file_examples_internal_proto_examplepb_echo_service_proto_rawDescData +} + +var file_examples_internal_proto_examplepb_echo_service_proto_msgTypes = make([]protoimpl.MessageInfo, 6) +var file_examples_internal_proto_examplepb_echo_service_proto_goTypes = []interface{}{ + (*Embedded)(nil), // 0: grpc.gateway.examples.internal.proto.examplepb.Embedded + (*SimpleMessage)(nil), // 1: grpc.gateway.examples.internal.proto.examplepb.SimpleMessage + (*ValidationRuleTestRequest)(nil), // 2: grpc.gateway.examples.internal.proto.examplepb.ValidationRuleTestRequest + (*ValidationRuleTestResponse)(nil), // 3: grpc.gateway.examples.internal.proto.examplepb.ValidationRuleTestResponse + (*DynamicMessage)(nil), // 4: grpc.gateway.examples.internal.proto.examplepb.DynamicMessage + (*DynamicMessageUpdate)(nil), // 5: grpc.gateway.examples.internal.proto.examplepb.DynamicMessageUpdate + (*structpb.Struct)(nil), // 6: google.protobuf.Struct + (*structpb.Value)(nil), // 7: google.protobuf.Value + (*fieldmaskpb.FieldMask)(nil), // 8: google.protobuf.FieldMask +} +var file_examples_internal_proto_examplepb_echo_service_proto_depIdxs = []int32{ + 0, // 0: grpc.gateway.examples.internal.proto.examplepb.SimpleMessage.status:type_name -> grpc.gateway.examples.internal.proto.examplepb.Embedded + 0, // 1: grpc.gateway.examples.internal.proto.examplepb.SimpleMessage.no:type_name -> grpc.gateway.examples.internal.proto.examplepb.Embedded + 6, // 2: grpc.gateway.examples.internal.proto.examplepb.DynamicMessage.struct_field:type_name -> google.protobuf.Struct + 7, // 3: grpc.gateway.examples.internal.proto.examplepb.DynamicMessage.value_field:type_name -> google.protobuf.Value + 4, // 4: grpc.gateway.examples.internal.proto.examplepb.DynamicMessageUpdate.body:type_name -> grpc.gateway.examples.internal.proto.examplepb.DynamicMessage + 8, // 5: grpc.gateway.examples.internal.proto.examplepb.DynamicMessageUpdate.update_mask:type_name -> google.protobuf.FieldMask + 1, // 6: grpc.gateway.examples.internal.proto.examplepb.EchoService.Echo:input_type -> grpc.gateway.examples.internal.proto.examplepb.SimpleMessage + 1, // 7: grpc.gateway.examples.internal.proto.examplepb.EchoService.EchoBody:input_type -> grpc.gateway.examples.internal.proto.examplepb.SimpleMessage + 1, // 8: grpc.gateway.examples.internal.proto.examplepb.EchoService.EchoDelete:input_type -> grpc.gateway.examples.internal.proto.examplepb.SimpleMessage + 5, // 9: grpc.gateway.examples.internal.proto.examplepb.EchoService.EchoPatch:input_type -> grpc.gateway.examples.internal.proto.examplepb.DynamicMessageUpdate + 2, // 10: grpc.gateway.examples.internal.proto.examplepb.EchoService.EchoValidationRule:input_type -> grpc.gateway.examples.internal.proto.examplepb.ValidationRuleTestRequest + 1, // 11: grpc.gateway.examples.internal.proto.examplepb.EchoService.Echo:output_type -> grpc.gateway.examples.internal.proto.examplepb.SimpleMessage + 1, // 12: grpc.gateway.examples.internal.proto.examplepb.EchoService.EchoBody:output_type -> grpc.gateway.examples.internal.proto.examplepb.SimpleMessage + 1, // 13: grpc.gateway.examples.internal.proto.examplepb.EchoService.EchoDelete:output_type -> grpc.gateway.examples.internal.proto.examplepb.SimpleMessage + 5, // 14: grpc.gateway.examples.internal.proto.examplepb.EchoService.EchoPatch:output_type -> grpc.gateway.examples.internal.proto.examplepb.DynamicMessageUpdate + 3, // 15: grpc.gateway.examples.internal.proto.examplepb.EchoService.EchoValidationRule:output_type -> grpc.gateway.examples.internal.proto.examplepb.ValidationRuleTestResponse + 11, // [11:16] is the sub-list for method output_type + 6, // [6:11] is the sub-list for method input_type + 6, // [6:6] is the sub-list for extension type_name + 6, // [6:6] is the sub-list for extension extendee + 0, // [0:6] is the sub-list for field type_name +} + +func init() { file_examples_internal_proto_examplepb_echo_service_proto_init() } +func file_examples_internal_proto_examplepb_echo_service_proto_init() { + if File_examples_internal_proto_examplepb_echo_service_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Embedded); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SimpleMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ValidationRuleTestRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ValidationRuleTestResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DynamicMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DynamicMessageUpdate); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[0].OneofWrappers = []interface{}{ + (*Embedded_Progress)(nil), + (*Embedded_Note)(nil), + } + file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[1].OneofWrappers = []interface{}{ + (*SimpleMessage_LineNum)(nil), + (*SimpleMessage_Lang)(nil), + (*SimpleMessage_En)(nil), + (*SimpleMessage_No)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_examples_internal_proto_examplepb_echo_service_proto_rawDesc, + NumEnums: 0, + NumMessages: 6, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_examples_internal_proto_examplepb_echo_service_proto_goTypes, + DependencyIndexes: file_examples_internal_proto_examplepb_echo_service_proto_depIdxs, + MessageInfos: file_examples_internal_proto_examplepb_echo_service_proto_msgTypes, + }.Build() + File_examples_internal_proto_examplepb_echo_service_proto = out.File + file_examples_internal_proto_examplepb_echo_service_proto_rawDesc = nil + file_examples_internal_proto_examplepb_echo_service_proto_goTypes = nil + file_examples_internal_proto_examplepb_echo_service_proto_depIdxs = nil +} diff --git a/proto/examples/echo_service.pb.gw.go b/examples/internal/proto/examplepb/echo_service.pb.gw.go similarity index 70% rename from proto/examples/echo_service.pb.gw.go rename to examples/internal/proto/examplepb/echo_service.pb.gw.go index a97a509..b4a4cc8 100755 --- a/proto/examples/echo_service.pb.gw.go +++ b/examples/internal/proto/examplepb/echo_service.pb.gw.go @@ -1,12 +1,12 @@ // Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. -// source: proto/examples/internal/echo_service.proto +// source: examples/internal/proto/examplepb/echo_service.proto /* -Package examples is a reverse proxy. +Package examplepb is a reverse proxy. It translates gRPC into RESTful JSON APIs. */ -package examples +package examplepb import ( "context" @@ -21,15 +21,13 @@ import ( vexpb "github.com/binchencoder/gateway-proto/data" fpb "github.com/binchencoder/gateway-proto/frontend" lgr "github.com/binchencoder/letsgo/grpc" - "github.com/binchencoder/skylb-api/balancer" "github.com/binchencoder/skylb-api/client" - "github.com/binchencoder/skylb-api/client/option" skypb "github.com/binchencoder/skylb-api/proto" "github.com/grpc-ecosystem/grpc-gateway/v2/utilities" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/grpclog" - "google.golang.org/grpc/naming" + "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" "google.golang.org/protobuf/proto" ) @@ -40,6 +38,7 @@ var _ io.Reader var _ status.Status var _ = runtime.String var _ = utilities.NewDoubleArray +var _ = metadata.Join // var _ = descriptor.ForMessage var _ sync.RWMutex @@ -50,18 +49,19 @@ var _ client.ServiceCli var _ vexpb.ServiceId var _ = http.MethodGet var _ regexp.Regexp -var _ = balancer.ConsistentHashing -var _ option.BalancerCreator -var _ naming.Resolver + +// var _ = balancer.ConsistentHashing +// var _ option.BalancerCreator +// var _ naming.Resolver var _ strings.Reader var _ = utf8.UTFMax // TODO (jiezmo): check if there is any rule before create this var. -var proto_examples_echo_service_error = lgr.ToGrpcError(codes.InvalidArgument, &fpb.Error{Code: fpb.ErrorCode_BADPARAM_ERROR, Params: []string{"Validation error"}}) +var examples_internal_proto_examplepb_echo_service_error = lgr.ToGrpcError(codes.InvalidArgument, &fpb.Error{Code: fpb.ErrorCode_BADPARAM_ERROR, Params: []string{"Validation error"}}) // Validation methods start -func Validate__grpc_gateway_proto_examples_SimpleMessage(v *SimpleMessage) error { +func Validate__grpc_gateway_examples_internal_proto_examplepb_ValidationRuleTestRequest(v *ValidationRuleTestRequest) error { if v == nil { return nil } @@ -76,11 +76,11 @@ func Validate__grpc_gateway_proto_examples_SimpleMessage(v *SimpleMessage) error // Err if utf8.RuneCountInString(strings.TrimSpace(vv2)) <= 2 { - return proto_examples_echo_service_error + return examples_internal_proto_examplepb_echo_service_error } if utf8.RuneCountInString(strings.TrimSpace(vv2)) >= 61 { - return proto_examples_echo_service_error + return examples_internal_proto_examplepb_echo_service_error } } @@ -91,21 +91,11 @@ func Validate__grpc_gateway_proto_examples_SimpleMessage(v *SimpleMessage) error // Validation Field: Num if vv2 <= 0 { - return proto_examples_echo_service_error + return examples_internal_proto_examplepb_echo_service_error } } - // Validation Field: GetLineNum() - - // Validation Field: GetLang() - - // Validation Field: Status - - // Validation Field: GetEn() - - // Validation Field: GetNo() - return nil } @@ -147,13 +137,6 @@ func request_EchoService_Echo_0(ctx context.Context, marshaler runtime.Marshaler // Only hook up for non-stream call for now. - // Validate - // SimpleMessage - if err := Validate__grpc_gateway_proto_examples_SimpleMessage(&protoReq); err != nil { - runtime.RequestHandled(ctx, spec, "EchoService", "Echo", nil, &metadata, err) - return nil, metadata, err - } - runtime.RequestParsed(ctx, spec, "EchoService", "Echo", &protoReq, &metadata) ctx = runtime.PreLoadBalance(ctx, "ROUND_ROBIN", "", &protoReq) msg, err := client.Echo(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) @@ -245,13 +228,6 @@ func request_EchoService_Echo_1(ctx context.Context, marshaler runtime.Marshaler // Only hook up for non-stream call for now. - // Validate - // SimpleMessage - if err := Validate__grpc_gateway_proto_examples_SimpleMessage(&protoReq); err != nil { - runtime.RequestHandled(ctx, spec, "EchoService", "Echo", nil, &metadata, err) - return nil, metadata, err - } - runtime.RequestParsed(ctx, spec, "EchoService", "Echo", &protoReq, &metadata) ctx = runtime.PreLoadBalance(ctx, "ROUND_ROBIN", "", &protoReq) msg, err := client.Echo(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) @@ -369,13 +345,6 @@ func request_EchoService_Echo_2(ctx context.Context, marshaler runtime.Marshaler // Only hook up for non-stream call for now. - // Validate - // SimpleMessage - if err := Validate__grpc_gateway_proto_examples_SimpleMessage(&protoReq); err != nil { - runtime.RequestHandled(ctx, spec, "EchoService", "Echo", nil, &metadata, err) - return nil, metadata, err - } - runtime.RequestParsed(ctx, spec, "EchoService", "Echo", &protoReq, &metadata) ctx = runtime.PreLoadBalance(ctx, "ROUND_ROBIN", "", &protoReq) msg, err := client.Echo(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) @@ -508,13 +477,6 @@ func request_EchoService_Echo_3(ctx context.Context, marshaler runtime.Marshaler // Only hook up for non-stream call for now. - // Validate - // SimpleMessage - if err := Validate__grpc_gateway_proto_examples_SimpleMessage(&protoReq); err != nil { - runtime.RequestHandled(ctx, spec, "EchoService", "Echo", nil, &metadata, err) - return nil, metadata, err - } - runtime.RequestParsed(ctx, spec, "EchoService", "Echo", &protoReq, &metadata) ctx = runtime.PreLoadBalance(ctx, "ROUND_ROBIN", "", &protoReq) msg, err := client.Echo(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) @@ -620,13 +582,6 @@ func request_EchoService_Echo_4(ctx context.Context, marshaler runtime.Marshaler // Only hook up for non-stream call for now. - // Validate - // SimpleMessage - if err := Validate__grpc_gateway_proto_examples_SimpleMessage(&protoReq); err != nil { - runtime.RequestHandled(ctx, spec, "EchoService", "Echo", nil, &metadata, err) - return nil, metadata, err - } - runtime.RequestParsed(ctx, spec, "EchoService", "Echo", &protoReq, &metadata) ctx = runtime.PreLoadBalance(ctx, "ROUND_ROBIN", "", &protoReq) msg, err := client.Echo(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) @@ -687,13 +642,6 @@ func request_EchoService_EchoBody_0(ctx context.Context, marshaler runtime.Marsh // Only hook up for non-stream call for now. - // Validate - // SimpleMessage - if err := Validate__grpc_gateway_proto_examples_SimpleMessage(&protoReq); err != nil { - runtime.RequestHandled(ctx, spec, "EchoService", "EchoBody", nil, &metadata, err) - return nil, metadata, err - } - runtime.RequestParsed(ctx, spec, "EchoService", "EchoBody", &protoReq, &metadata) ctx = runtime.PreLoadBalance(ctx, "ROUND_ROBIN", "", &protoReq) msg, err := client.EchoBody(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) @@ -740,13 +688,6 @@ func request_EchoService_EchoDelete_0(ctx context.Context, marshaler runtime.Mar // Only hook up for non-stream call for now. - // Validate - // SimpleMessage - if err := Validate__grpc_gateway_proto_examples_SimpleMessage(&protoReq); err != nil { - runtime.RequestHandled(ctx, spec, "EchoService", "EchoDelete", nil, &metadata, err) - return nil, metadata, err - } - runtime.RequestParsed(ctx, spec, "EchoService", "EchoDelete", &protoReq, &metadata) ctx = runtime.PreLoadBalance(ctx, "ROUND_ROBIN", "", &protoReq) msg, err := client.EchoDelete(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) @@ -774,22 +715,153 @@ func local_request_EchoService_EchoDelete_0(ctx context.Context, marshaler runti } +var ( + filter_EchoService_EchoPatch_0 = &utilities.DoubleArray{Encoding: map[string]int{"body": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} +) + +func request_EchoService_EchoPatch_0(ctx context.Context, marshaler runtime.Marshaler, client EchoServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq DynamicMessageUpdate + var metadata runtime.ServerMetadata + spec := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.Body); err != nil && err != io.EOF { + runtime.RequestHandled(ctx, spec, "EchoService", "EchoPatch", nil, &metadata, err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if protoReq.UpdateMask == nil || len(protoReq.UpdateMask.GetPaths()) == 0 { + if fieldMask, err := runtime.FieldMaskFromRequestBody(newReader(), protoReq.Body); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } else { + protoReq.UpdateMask = fieldMask + } + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EchoService_EchoPatch_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + // Only hook up for non-stream call for now. + + runtime.RequestParsed(ctx, spec, "EchoService", "EchoPatch", &protoReq, &metadata) + ctx = runtime.PreLoadBalance(ctx, "ROUND_ROBIN", "", &protoReq) + msg, err := client.EchoPatch(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + // if err != nil { + // grpclog.Errorf("client.%s returns error: %v", "EchoPatch", err) + // } + runtime.RequestHandled(ctx, spec, "EchoService", "EchoPatch", msg, &metadata, err) + return msg, metadata, err + +} + +func local_request_EchoService_EchoPatch_0(ctx context.Context, marshaler runtime.Marshaler, server EchoServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq DynamicMessageUpdate + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.Body); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if protoReq.UpdateMask == nil || len(protoReq.UpdateMask.GetPaths()) == 0 { + if fieldMask, err := runtime.FieldMaskFromRequestBody(newReader(), protoReq.Body); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } else { + protoReq.UpdateMask = fieldMask + } + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EchoService_EchoPatch_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.EchoPatch(ctx, &protoReq) + return msg, metadata, err + +} + +func request_EchoService_EchoValidationRule_0(ctx context.Context, marshaler runtime.Marshaler, client EchoServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq ValidationRuleTestRequest + var metadata runtime.ServerMetadata + spec := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + runtime.RequestHandled(ctx, spec, "EchoService", "EchoValidationRule", nil, &metadata, err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + // Only hook up for non-stream call for now. + + // Validate + // ValidationRuleTestRequest + if err := Validate__grpc_gateway_examples_internal_proto_examplepb_ValidationRuleTestRequest(&protoReq); err != nil { + runtime.RequestHandled(ctx, spec, "EchoService", "EchoValidationRule", nil, &metadata, err) + return nil, metadata, err + } + + runtime.RequestParsed(ctx, spec, "EchoService", "EchoValidationRule", &protoReq, &metadata) + ctx = runtime.PreLoadBalance(ctx, "ROUND_ROBIN", "", &protoReq) + msg, err := client.EchoValidationRule(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + // if err != nil { + // grpclog.Errorf("client.%s returns error: %v", "EchoValidationRule", err) + // } + runtime.RequestHandled(ctx, spec, "EchoService", "EchoValidationRule", msg, &metadata, err) + return msg, metadata, err + +} + +func local_request_EchoService_EchoValidationRule_0(ctx context.Context, marshaler runtime.Marshaler, server EchoServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq ValidationRuleTestRequest + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.EchoValidationRule(ctx, &protoReq) + return msg, metadata, err + +} + // RegisterEchoServiceHandlerServer registers the http handlers for service EchoService to "mux". // UnaryRPC :call EchoServiceServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. -// Note that using this registration option will cause many gRPC library features (such as grpc.SendHeader, etc) to stop working. Consider using RegisterEchoServiceHandlerFromEndpoint instead. +// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterEchoServiceHandlerFromEndpoint instead. func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server EchoServiceServer) error { mux.Handle("POST", pattern_EchoService_Echo_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.proto.examples.EchoService/Echo") + var err error + ctx, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo", runtime.WithHTTPPathPattern("/v1/example/echo/{id}")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := local_request_EchoService_Echo_0(rctx, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_EchoService_Echo_0(ctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) @@ -803,13 +875,17 @@ func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux mux.Handle("GET", pattern_EchoService_Echo_1, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.proto.examples.EchoService/Echo") + var err error + ctx, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo", runtime.WithHTTPPathPattern("/v1/example/echo/{id}/{num}")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := local_request_EchoService_Echo_1(rctx, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_EchoService_Echo_1(ctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) @@ -823,13 +899,17 @@ func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux mux.Handle("GET", pattern_EchoService_Echo_2, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.proto.examples.EchoService/Echo") + var err error + ctx, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo", runtime.WithHTTPPathPattern("/v1/example/echo/{id}/{num}/{lang}")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := local_request_EchoService_Echo_2(rctx, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_EchoService_Echo_2(ctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) @@ -843,13 +923,17 @@ func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux mux.Handle("GET", pattern_EchoService_Echo_3, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.proto.examples.EchoService/Echo") + var err error + ctx, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo", runtime.WithHTTPPathPattern("/v1/example/echo1/{id}/{line_num}/{status.note}")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := local_request_EchoService_Echo_3(rctx, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_EchoService_Echo_3(ctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) @@ -863,13 +947,17 @@ func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux mux.Handle("GET", pattern_EchoService_Echo_4, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.proto.examples.EchoService/Echo") + var err error + ctx, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo", runtime.WithHTTPPathPattern("/v1/example/echo2/{no.note}")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := local_request_EchoService_Echo_4(rctx, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_EchoService_Echo_4(ctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) @@ -883,13 +971,17 @@ func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux mux.Handle("POST", pattern_EchoService_EchoBody_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.proto.examples.EchoService/EchoBody") + var err error + ctx, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoBody", runtime.WithHTTPPathPattern("/v1/example/echo_body")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := local_request_EchoService_EchoBody_0(rctx, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_EchoService_EchoBody_0(ctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) @@ -903,13 +995,17 @@ func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux mux.Handle("DELETE", pattern_EchoService_EchoDelete_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.proto.examples.EchoService/EchoDelete") + var err error + ctx, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoDelete", runtime.WithHTTPPathPattern("/v1/example/echo_delete")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := local_request_EchoService_EchoDelete_0(rctx, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_EchoService_EchoDelete_0(ctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) @@ -920,6 +1016,54 @@ func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux }) + mux.Handle("PATCH", pattern_EchoService_EchoPatch_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + ctx, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoPatch", runtime.WithHTTPPathPattern("/v1/example/echo_patch")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_EchoService_EchoPatch_0(ctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_EchoService_EchoPatch_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("POST", pattern_EchoService_EchoValidationRule_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + ctx, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoValidationRule", runtime.WithHTTPPathPattern("/v1/example/echo:validationRules")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_EchoService_EchoValidationRule_0(ctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_EchoService_EchoValidationRule_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -1005,12 +1149,14 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux } ctx, cancel := context.WithCancel(req.Context()) defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.proto.examples.EchoService/Echo") + // inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + // var err error + ctx, err = runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo", runtime.WithHTTPPathPattern("/v1/example/echo/{id}")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_EchoService_Echo_0(rctx, inboundMarshaler, client, req, pathParams) + resp, md, err := request_EchoService_Echo_0(ctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) @@ -1042,12 +1188,14 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux } ctx, cancel := context.WithCancel(req.Context()) defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.proto.examples.EchoService/Echo") + // inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + // var err error + ctx, err = runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo", runtime.WithHTTPPathPattern("/v1/example/echo/{id}/{num}")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_EchoService_Echo_1(rctx, inboundMarshaler, client, req, pathParams) + resp, md, err := request_EchoService_Echo_1(ctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) @@ -1079,12 +1227,14 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux } ctx, cancel := context.WithCancel(req.Context()) defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.proto.examples.EchoService/Echo") + // inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + // var err error + ctx, err = runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo", runtime.WithHTTPPathPattern("/v1/example/echo/{id}/{num}/{lang}")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_EchoService_Echo_2(rctx, inboundMarshaler, client, req, pathParams) + resp, md, err := request_EchoService_Echo_2(ctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) @@ -1116,12 +1266,14 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux } ctx, cancel := context.WithCancel(req.Context()) defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.proto.examples.EchoService/Echo") + // inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + // var err error + ctx, err = runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo", runtime.WithHTTPPathPattern("/v1/example/echo1/{id}/{line_num}/{status.note}")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_EchoService_Echo_3(rctx, inboundMarshaler, client, req, pathParams) + resp, md, err := request_EchoService_Echo_3(ctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) @@ -1153,12 +1305,14 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux } ctx, cancel := context.WithCancel(req.Context()) defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.proto.examples.EchoService/Echo") + // inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + // var err error + ctx, err = runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo", runtime.WithHTTPPathPattern("/v1/example/echo2/{no.note}")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_EchoService_Echo_4(rctx, inboundMarshaler, client, req, pathParams) + resp, md, err := request_EchoService_Echo_4(ctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) @@ -1190,12 +1344,14 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux } ctx, cancel := context.WithCancel(req.Context()) defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.proto.examples.EchoService/EchoBody") + // inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + // var err error + ctx, err = runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoBody", runtime.WithHTTPPathPattern("/v1/example/echo_body")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_EchoService_EchoBody_0(rctx, inboundMarshaler, client, req, pathParams) + resp, md, err := request_EchoService_EchoBody_0(ctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) @@ -1227,12 +1383,14 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux } ctx, cancel := context.WithCancel(req.Context()) defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.proto.examples.EchoService/EchoDelete") + // inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + // var err error + ctx, err = runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoDelete", runtime.WithHTTPPathPattern("/v1/example/echo_delete")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_EchoService_EchoDelete_0(rctx, inboundMarshaler, client, req, pathParams) + resp, md, err := request_EchoService_EchoDelete_0(ctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) @@ -1243,6 +1401,84 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux }) + runtime.AddMethod(spec, "EchoService", "EchoPatch", "/v1/example/echo_patch", "PATCH", true, false, false, "UNSPECIFIED", "EASE_GATEWAY", "EASE_AUTH_TOKEN", "") + mux.Handle("PATCH", pattern_EchoService_EchoPatch_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + // TODO(mojz): review all locking/unlocking logic. + // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() + // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() + client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + if client == nil { + err := status.Error(codes.Internal, "service disabled") + runtime.HTTPError(inctx, mux, outboundMarshaler, w, req, err) + return + } + + ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "EchoPatch", w, req) + if err != nil { + grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + // inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + // var err error + ctx, err = runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoPatch", runtime.WithHTTPPathPattern("/v1/example/echo_patch")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_EchoService_EchoPatch_0(ctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_EchoService_EchoPatch_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + runtime.AddMethod(spec, "EchoService", "EchoValidationRule", "/v1/example/echo:validationRules", "POST", true, false, false, "UNSPECIFIED", "EASE_GATEWAY", "EASE_AUTH_TOKEN", "") + mux.Handle("POST", pattern_EchoService_EchoValidationRule_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + // TODO(mojz): review all locking/unlocking logic. + // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() + // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() + client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + if client == nil { + err := status.Error(codes.Internal, "service disabled") + runtime.HTTPError(inctx, mux, outboundMarshaler, w, req, err) + return + } + + ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "EchoValidationRule", w, req) + if err != nil { + grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + // inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + // var err error + ctx, err = runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoValidationRule", runtime.WithHTTPPathPattern("/v1/example/echo:validationRules")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_EchoService_EchoValidationRule_0(ctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_EchoService_EchoValidationRule_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -1273,7 +1509,6 @@ func Enable_CUSTOM_EASE_GATEWAY_TEST__default__grpc_ServiceGroup() { internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_skycli.Resolve(spec) - internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_skycli.EnableResolveFullEps() internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_skycli.Start(func(spec *skypb.ServiceSpec, conn *grpc.ClientConn) { sg := runtime.GetServiceGroup(spec) for _, svc := range sg.Services { @@ -1304,6 +1539,10 @@ var ( pattern_EchoService_EchoBody_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "example", "echo_body"}, "")) pattern_EchoService_EchoDelete_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "example", "echo_delete"}, "")) + + pattern_EchoService_EchoPatch_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "example", "echo_patch"}, "")) + + pattern_EchoService_EchoValidationRule_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "example", "echo"}, "validationRules")) ) var ( @@ -1320,6 +1559,10 @@ var ( forward_EchoService_EchoBody_0 = runtime.ForwardResponseMessage forward_EchoService_EchoDelete_0 = runtime.ForwardResponseMessage + + forward_EchoService_EchoPatch_0 = runtime.ForwardResponseMessage + + forward_EchoService_EchoValidationRule_0 = runtime.ForwardResponseMessage ) var ( diff --git a/examples/internal/proto/examplepb/echo_service_grpc.pb.go b/examples/internal/proto/examplepb/echo_service_grpc.pb.go new file mode 100755 index 0000000..0284d01 --- /dev/null +++ b/examples/internal/proto/examplepb/echo_service_grpc.pb.go @@ -0,0 +1,239 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. + +package examplepb + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// 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.SupportPackageIsVersion7 + +// EchoServiceClient is the client API for EchoService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type EchoServiceClient interface { + Echo(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) + EchoBody(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) + EchoDelete(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) + EchoPatch(ctx context.Context, in *DynamicMessageUpdate, opts ...grpc.CallOption) (*DynamicMessageUpdate, error) + EchoValidationRule(ctx context.Context, in *ValidationRuleTestRequest, opts ...grpc.CallOption) (*ValidationRuleTestResponse, error) +} + +type echoServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewEchoServiceClient(cc grpc.ClientConnInterface) EchoServiceClient { + return &echoServiceClient{cc} +} + +func (c *echoServiceClient) Echo(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) { + out := new(SimpleMessage) + err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *echoServiceClient) EchoBody(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) { + out := new(SimpleMessage) + err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoBody", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *echoServiceClient) EchoDelete(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) { + out := new(SimpleMessage) + err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoDelete", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *echoServiceClient) EchoPatch(ctx context.Context, in *DynamicMessageUpdate, opts ...grpc.CallOption) (*DynamicMessageUpdate, error) { + out := new(DynamicMessageUpdate) + err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoPatch", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *echoServiceClient) EchoValidationRule(ctx context.Context, in *ValidationRuleTestRequest, opts ...grpc.CallOption) (*ValidationRuleTestResponse, error) { + out := new(ValidationRuleTestResponse) + err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoValidationRule", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// EchoServiceServer is the server API for EchoService service. +// All implementations should embed UnimplementedEchoServiceServer +// for forward compatibility +type EchoServiceServer interface { + Echo(context.Context, *SimpleMessage) (*SimpleMessage, error) + EchoBody(context.Context, *SimpleMessage) (*SimpleMessage, error) + EchoDelete(context.Context, *SimpleMessage) (*SimpleMessage, error) + EchoPatch(context.Context, *DynamicMessageUpdate) (*DynamicMessageUpdate, error) + EchoValidationRule(context.Context, *ValidationRuleTestRequest) (*ValidationRuleTestResponse, error) +} + +// UnimplementedEchoServiceServer should be embedded to have forward compatible implementations. +type UnimplementedEchoServiceServer struct { +} + +func (UnimplementedEchoServiceServer) Echo(context.Context, *SimpleMessage) (*SimpleMessage, error) { + return nil, status.Errorf(codes.Unimplemented, "method Echo not implemented") +} +func (UnimplementedEchoServiceServer) EchoBody(context.Context, *SimpleMessage) (*SimpleMessage, error) { + return nil, status.Errorf(codes.Unimplemented, "method EchoBody not implemented") +} +func (UnimplementedEchoServiceServer) EchoDelete(context.Context, *SimpleMessage) (*SimpleMessage, error) { + return nil, status.Errorf(codes.Unimplemented, "method EchoDelete not implemented") +} +func (UnimplementedEchoServiceServer) EchoPatch(context.Context, *DynamicMessageUpdate) (*DynamicMessageUpdate, error) { + return nil, status.Errorf(codes.Unimplemented, "method EchoPatch not implemented") +} +func (UnimplementedEchoServiceServer) EchoValidationRule(context.Context, *ValidationRuleTestRequest) (*ValidationRuleTestResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method EchoValidationRule not implemented") +} + +// UnsafeEchoServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to EchoServiceServer will +// result in compilation errors. +type UnsafeEchoServiceServer interface { + mustEmbedUnimplementedEchoServiceServer() +} + +func RegisterEchoServiceServer(s *grpc.Server, srv EchoServiceServer) { + s.RegisterService(&_EchoService_serviceDesc, srv) +} + +func _EchoService_Echo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SimpleMessage) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(EchoServiceServer).Echo(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(EchoServiceServer).Echo(ctx, req.(*SimpleMessage)) + } + return interceptor(ctx, in, info, handler) +} + +func _EchoService_EchoBody_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SimpleMessage) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(EchoServiceServer).EchoBody(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoBody", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(EchoServiceServer).EchoBody(ctx, req.(*SimpleMessage)) + } + return interceptor(ctx, in, info, handler) +} + +func _EchoService_EchoDelete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SimpleMessage) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(EchoServiceServer).EchoDelete(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoDelete", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(EchoServiceServer).EchoDelete(ctx, req.(*SimpleMessage)) + } + return interceptor(ctx, in, info, handler) +} + +func _EchoService_EchoPatch_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DynamicMessageUpdate) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(EchoServiceServer).EchoPatch(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoPatch", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(EchoServiceServer).EchoPatch(ctx, req.(*DynamicMessageUpdate)) + } + return interceptor(ctx, in, info, handler) +} + +func _EchoService_EchoValidationRule_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ValidationRuleTestRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(EchoServiceServer).EchoValidationRule(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoValidationRule", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(EchoServiceServer).EchoValidationRule(ctx, req.(*ValidationRuleTestRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _EchoService_serviceDesc = grpc.ServiceDesc{ + ServiceName: "grpc.gateway.examples.internal.proto.examplepb.EchoService", + HandlerType: (*EchoServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Echo", + Handler: _EchoService_Echo_Handler, + }, + { + MethodName: "EchoBody", + Handler: _EchoService_EchoBody_Handler, + }, + { + MethodName: "EchoDelete", + Handler: _EchoService_EchoDelete_Handler, + }, + { + MethodName: "EchoPatch", + Handler: _EchoService_EchoPatch_Handler, + }, + { + MethodName: "EchoValidationRule", + Handler: _EchoService_EchoValidationRule_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "examples/internal/proto/examplepb/echo_service.proto", +} diff --git a/examples/internal/proto/examplepb/generated_input.proto b/examples/internal/proto/examplepb/generated_input.proto new file mode 100644 index 0000000..b2ac0c6 --- /dev/null +++ b/examples/internal/proto/examplepb/generated_input.proto @@ -0,0 +1,20 @@ +syntax = "proto3"; +option go_package = "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb"; +package grpc.gateway.examples.internal.proto.examplepb; + +import "google/api/annotations.proto"; +import "google/protobuf/empty.proto"; +import "examples/internal/proto/examplepb/echo_service.proto"; + +// This file is run through a genrule. + +// Defines some more operations to be added to EchoService +service GeneratedService { + rpc Create(SimpleMessage) returns (google.protobuf.Empty) { + option (google.api.http) = { + post: "/v1/example/a_bit_of_everything/generated_create" + body: "*" + }; + } + +} diff --git a/examples/internal/proto/examplepb/generated_input.swagger.json b/examples/internal/proto/examplepb/generated_input.swagger.json new file mode 100644 index 0000000..65bc223 --- /dev/null +++ b/examples/internal/proto/examplepb/generated_input.swagger.json @@ -0,0 +1,347 @@ +{ + "swagger": "2.0", + "info": { + "title": "examples/internal/proto/examplepb/generated_input.proto", + "version": "version not set" + }, + "tags": [ + { + "name": "GeneratedService" + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/v1/example/a_bit_of_everything/generated_create": { + "post": { + "operationId": "GeneratedService_Create", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "properties": {} + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/examplepbABitOfEverything" + } + } + ], + "tags": [ + "GeneratedService" + ] + } + } + }, + "definitions": { + "ABitOfEverythingNested": { + "type": "object", + "example": { + "ok": "TRUE" + }, + "properties": { + "name": { + "type": "string", + "description": "name is nested field." + }, + "amount": { + "type": "integer", + "format": "int64" + }, + "ok": { + "$ref": "#/definitions/NestedDeepEnum", + "description": "DeepEnum description." + } + }, + "description": "Nested is nested type." + }, + "MessagePathEnumNestedPathEnum": { + "type": "string", + "enum": [ + "GHI", + "JKL" + ], + "default": "GHI" + }, + "NestedDeepEnum": { + "type": "string", + "enum": [ + "FALSE", + "TRUE" + ], + "default": "FALSE", + "description": "DeepEnum is one or zero.\n\n - FALSE: FALSE is false.\n - TRUE: TRUE is true." + }, + "examplepbABitOfEverything": { + "type": "object", + "example": { + "int64_value": 12, + "double_value": 12.3 + }, + "properties": { + "singleNested": { + "$ref": "#/definitions/ABitOfEverythingNested" + }, + "uuid": { + "type": "string", + "minLength": 1, + "pattern": "[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}" + }, + "nested": { + "type": "array", + "items": { + "$ref": "#/definitions/ABitOfEverythingNested" + } + }, + "floatValue": { + "type": "number", + "format": "float", + "default": "0.2", + "description": "Float value field", + "required": [ + "floatValue" + ] + }, + "doubleValue": { + "type": "number", + "format": "double" + }, + "int64Value": { + "type": "string", + "format": "int64" + }, + "uint64Value": { + "type": "string", + "format": "uint64" + }, + "int32Value": { + "type": "integer", + "format": "int32" + }, + "fixed64Value": { + "type": "string", + "format": "uint64" + }, + "fixed32Value": { + "type": "integer", + "format": "int64" + }, + "boolValue": { + "type": "boolean" + }, + "stringValue": { + "type": "string" + }, + "bytesValue": { + "type": "string", + "format": "byte" + }, + "uint32Value": { + "type": "integer", + "format": "int64" + }, + "enumValue": { + "$ref": "#/definitions/examplepbNumericEnum" + }, + "pathEnumValue": { + "$ref": "#/definitions/pathenumPathEnum" + }, + "nestedPathEnumValue": { + "$ref": "#/definitions/MessagePathEnumNestedPathEnum" + }, + "sfixed32Value": { + "type": "integer", + "format": "int32" + }, + "sfixed64Value": { + "type": "string", + "format": "int64" + }, + "sint32Value": { + "type": "integer", + "format": "int32" + }, + "sint64Value": { + "type": "string", + "format": "int64" + }, + "repeatedStringValue": { + "type": "array", + "items": { + "type": "string" + } + }, + "oneofEmpty": { + "properties": {} + }, + "oneofString": { + "type": "string" + }, + "mapValue": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/examplepbNumericEnum" + } + }, + "mappedStringValue": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "mappedNestedValue": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/ABitOfEverythingNested" + } + }, + "nonConventionalNameValue": { + "type": "string" + }, + "timestampValue": { + "type": "string", + "format": "date-time" + }, + "repeatedEnumValue": { + "type": "array", + "items": { + "$ref": "#/definitions/examplepbNumericEnum" + }, + "title": "repeated enum value. it is comma-separated in query" + }, + "repeatedEnumAnnotation": { + "type": "array", + "items": { + "$ref": "#/definitions/examplepbNumericEnum" + }, + "description": "Repeated numeric enum description.", + "title": "Repeated numeric enum title" + }, + "enumValueAnnotation": { + "$ref": "#/definitions/examplepbNumericEnum", + "description": "Numeric enum description.", + "title": "Numeric enum title" + }, + "repeatedStringAnnotation": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Repeated string description.", + "title": "Repeated string title" + }, + "repeatedNestedAnnotation": { + "type": "array", + "items": { + "$ref": "#/definitions/ABitOfEverythingNested" + }, + "description": "Repeated nested object description.", + "title": "Repeated nested object title" + }, + "nestedAnnotation": { + "$ref": "#/definitions/ABitOfEverythingNested", + "description": "Nested object description.", + "title": "Nested object title" + }, + "int64OverrideType": { + "type": "integer", + "format": "int64" + }, + "requiredStringViaFieldBehaviorAnnotation": { + "type": "string", + "title": "mark a field as required in Open API definition", + "required": [ + "requiredStringViaFieldBehaviorAnnotation" + ] + }, + "outputOnlyStringViaFieldBehaviorAnnotation": { + "type": "string", + "title": "mark a field as readonly in Open API definition", + "readOnly": true + }, + "optionalStringValue": { + "type": "string" + } + }, + "description": "Intentionally complicated message type to cover many features of Protobuf.", + "title": "A bit of everything", + "externalDocs": { + "description": "Find out more about ABitOfEverything", + "url": "https://github.com/grpc-ecosystem/grpc-gateway" + }, + "required": [ + "uuid", + "int64Value", + "doubleValue", + "floatValue", + "requiredStringViaFieldBehaviorAnnotation" + ] + }, + "examplepbNumericEnum": { + "type": "string", + "enum": [ + "ZERO", + "ONE" + ], + "default": "ZERO", + "description": "NumericEnum is one or zero.\n\n - ZERO: ZERO means 0\n - ONE: ONE means 1" + }, + "pathenumPathEnum": { + "type": "string", + "enum": [ + "ABC", + "DEF" + ], + "default": "ABC" + }, + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." + } + }, + "additionalProperties": {}, + "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(\u0026foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := \u0026pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := \u0026pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": \u003cstring\u003e,\n \"lastName\": \u003cstring\u003e\n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" + }, + "rpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "description": "The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code]." + }, + "message": { + "type": "string", + "description": "A developer-facing error message, which should be in English. Any\nuser-facing error message should be localized and sent in the\n[google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client." + }, + "details": { + "type": "array", + "items": { + "$ref": "#/definitions/protobufAny" + }, + "description": "A list of messages that carry the error details. There is a common set of\nmessage types for APIs to use." + } + }, + "description": "The `Status` type defines a logical error model that is suitable for\ndifferent programming environments, including REST APIs and RPC APIs. It is\nused by [gRPC](https://github.com/grpc). Each `Status` message contains\nthree pieces of data: error code, error message, and error details.\n\nYou can find out more about this error model and how to work with it in the\n[API Design Guide](https://cloud.google.com/apis/design/errors)." + } + } +} diff --git a/examples/internal/proto/examplepb/standalone_echo_service.buf.gen.yaml b/examples/internal/proto/examplepb/standalone_echo_service.buf.gen.yaml new file mode 100644 index 0000000..8673875 --- /dev/null +++ b/examples/internal/proto/examplepb/standalone_echo_service.buf.gen.yaml @@ -0,0 +1,8 @@ +version: v1 +plugins: + - name: grpc-gateway + out: . + opt: + - paths=source_relative + - standalone=true + - grpc_api_configuration=examples/internal/proto/examplepb/standalone_echo_service.yaml diff --git a/examples/internal/proto/examplepb/unannotated_echo_service.yaml b/examples/internal/proto/examplepb/unannotated_echo_servic.yaml similarity index 100% rename from examples/internal/proto/examplepb/unannotated_echo_service.yaml rename to examples/internal/proto/examplepb/unannotated_echo_servic.yaml diff --git a/examples/internal/proto/examplepb/unannotated_echo_service.buf.gen.yaml b/examples/internal/proto/examplepb/unannotated_echo_service.buf.gen.yaml new file mode 100644 index 0000000..6ec699a --- /dev/null +++ b/examples/internal/proto/examplepb/unannotated_echo_service.buf.gen.yaml @@ -0,0 +1,12 @@ +version: v1 +plugins: + - name: grpc-gateway + out: . + opt: + - paths=source_relative + - grpc_api_configuration=examples/internal/proto/examplepb/unannotated_echo_service.yaml + - name: openapiv2 + out: . + opt: + - grpc_api_configuration=examples/internal/proto/examplepb/unannotated_echo_service.yaml + - openapi_configuration=examples/internal/proto/examplepb/unannotated_echo_service.swagger.yaml diff --git a/examples/internal/proto/examplepb/unannotated_echo_service.pb.go b/examples/internal/proto/examplepb/unannotated_echo_service.pb.go new file mode 100755 index 0000000..9ef8067 --- /dev/null +++ b/examples/internal/proto/examplepb/unannotated_echo_service.pb.go @@ -0,0 +1,437 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.27.1 +// protoc v3.19.4 +// source: examples/internal/proto/examplepb/unannotated_echo_service.proto + +package examplepb + +import ( + _ "github.com/binchencoder/ease-gateway/httpoptions" + duration "github.com/golang/protobuf/ptypes/duration" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type UnannotatedEmbedded struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Mark: + // *UnannotatedEmbedded_Progress + // *UnannotatedEmbedded_Note + Mark isUnannotatedEmbedded_Mark `protobuf_oneof:"mark"` +} + +func (x *UnannotatedEmbedded) Reset() { + *x = UnannotatedEmbedded{} + if protoimpl.UnsafeEnabled { + mi := &file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UnannotatedEmbedded) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UnannotatedEmbedded) ProtoMessage() {} + +func (x *UnannotatedEmbedded) ProtoReflect() protoreflect.Message { + mi := &file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UnannotatedEmbedded.ProtoReflect.Descriptor instead. +func (*UnannotatedEmbedded) Descriptor() ([]byte, []int) { + return file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDescGZIP(), []int{0} +} + +func (m *UnannotatedEmbedded) GetMark() isUnannotatedEmbedded_Mark { + if m != nil { + return m.Mark + } + return nil +} + +func (x *UnannotatedEmbedded) GetProgress() int64 { + if x, ok := x.GetMark().(*UnannotatedEmbedded_Progress); ok { + return x.Progress + } + return 0 +} + +func (x *UnannotatedEmbedded) GetNote() string { + if x, ok := x.GetMark().(*UnannotatedEmbedded_Note); ok { + return x.Note + } + return "" +} + +type isUnannotatedEmbedded_Mark interface { + isUnannotatedEmbedded_Mark() +} + +type UnannotatedEmbedded_Progress struct { + Progress int64 `protobuf:"varint,1,opt,name=progress,proto3,oneof"` +} + +type UnannotatedEmbedded_Note struct { + Note string `protobuf:"bytes,2,opt,name=note,proto3,oneof"` +} + +func (*UnannotatedEmbedded_Progress) isUnannotatedEmbedded_Mark() {} + +func (*UnannotatedEmbedded_Note) isUnannotatedEmbedded_Mark() {} + +type UnannotatedSimpleMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Num int64 `protobuf:"varint,2,opt,name=num,proto3" json:"num,omitempty"` + Duration *duration.Duration `protobuf:"bytes,3,opt,name=duration,proto3" json:"duration,omitempty"` + // Types that are assignable to Code: + // *UnannotatedSimpleMessage_LineNum + // *UnannotatedSimpleMessage_Lang + Code isUnannotatedSimpleMessage_Code `protobuf_oneof:"code"` + Status *UnannotatedEmbedded `protobuf:"bytes,6,opt,name=status,proto3" json:"status,omitempty"` + // Types that are assignable to Ext: + // *UnannotatedSimpleMessage_En + // *UnannotatedSimpleMessage_No + Ext isUnannotatedSimpleMessage_Ext `protobuf_oneof:"ext"` +} + +func (x *UnannotatedSimpleMessage) Reset() { + *x = UnannotatedSimpleMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UnannotatedSimpleMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UnannotatedSimpleMessage) ProtoMessage() {} + +func (x *UnannotatedSimpleMessage) ProtoReflect() protoreflect.Message { + mi := &file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UnannotatedSimpleMessage.ProtoReflect.Descriptor instead. +func (*UnannotatedSimpleMessage) Descriptor() ([]byte, []int) { + return file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDescGZIP(), []int{1} +} + +func (x *UnannotatedSimpleMessage) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *UnannotatedSimpleMessage) GetNum() int64 { + if x != nil { + return x.Num + } + return 0 +} + +func (x *UnannotatedSimpleMessage) GetDuration() *duration.Duration { + if x != nil { + return x.Duration + } + return nil +} + +func (m *UnannotatedSimpleMessage) GetCode() isUnannotatedSimpleMessage_Code { + if m != nil { + return m.Code + } + return nil +} + +func (x *UnannotatedSimpleMessage) GetLineNum() int64 { + if x, ok := x.GetCode().(*UnannotatedSimpleMessage_LineNum); ok { + return x.LineNum + } + return 0 +} + +func (x *UnannotatedSimpleMessage) GetLang() string { + if x, ok := x.GetCode().(*UnannotatedSimpleMessage_Lang); ok { + return x.Lang + } + return "" +} + +func (x *UnannotatedSimpleMessage) GetStatus() *UnannotatedEmbedded { + if x != nil { + return x.Status + } + return nil +} + +func (m *UnannotatedSimpleMessage) GetExt() isUnannotatedSimpleMessage_Ext { + if m != nil { + return m.Ext + } + return nil +} + +func (x *UnannotatedSimpleMessage) GetEn() int64 { + if x, ok := x.GetExt().(*UnannotatedSimpleMessage_En); ok { + return x.En + } + return 0 +} + +func (x *UnannotatedSimpleMessage) GetNo() *UnannotatedEmbedded { + if x, ok := x.GetExt().(*UnannotatedSimpleMessage_No); ok { + return x.No + } + return nil +} + +type isUnannotatedSimpleMessage_Code interface { + isUnannotatedSimpleMessage_Code() +} + +type UnannotatedSimpleMessage_LineNum struct { + LineNum int64 `protobuf:"varint,4,opt,name=line_num,json=lineNum,proto3,oneof"` +} + +type UnannotatedSimpleMessage_Lang struct { + Lang string `protobuf:"bytes,5,opt,name=lang,proto3,oneof"` +} + +func (*UnannotatedSimpleMessage_LineNum) isUnannotatedSimpleMessage_Code() {} + +func (*UnannotatedSimpleMessage_Lang) isUnannotatedSimpleMessage_Code() {} + +type isUnannotatedSimpleMessage_Ext interface { + isUnannotatedSimpleMessage_Ext() +} + +type UnannotatedSimpleMessage_En struct { + En int64 `protobuf:"varint,7,opt,name=en,proto3,oneof"` +} + +type UnannotatedSimpleMessage_No struct { + No *UnannotatedEmbedded `protobuf:"bytes,8,opt,name=no,proto3,oneof"` +} + +func (*UnannotatedSimpleMessage_En) isUnannotatedSimpleMessage_Ext() {} + +func (*UnannotatedSimpleMessage_No) isUnannotatedSimpleMessage_Ext() {} + +var File_examples_internal_proto_examplepb_unannotated_echo_service_proto protoreflect.FileDescriptor + +var file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDesc = []byte{ + 0x0a, 0x40, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, + 0x65, 0x70, 0x62, 0x2f, 0x75, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x5f, + 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x12, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, + 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, + 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, + 0x70, 0x62, 0x1a, 0x1d, 0x68, 0x74, 0x74, 0x70, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, + 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x22, 0x51, 0x0a, 0x13, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, + 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x12, 0x1c, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x67, + 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x08, 0x70, 0x72, + 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x14, 0x0a, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x42, 0x06, 0x0a, 0x04, + 0x6d, 0x61, 0x72, 0x6b, 0x22, 0xfb, 0x02, 0x0a, 0x18, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, + 0x61, 0x74, 0x65, 0x64, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, + 0x64, 0x12, 0x10, 0x0a, 0x03, 0x6e, 0x75, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, + 0x6e, 0x75, 0x6d, 0x12, 0x35, 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x08, 0x6c, 0x69, + 0x6e, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x07, + 0x6c, 0x69, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x12, 0x14, 0x0a, 0x04, 0x6c, 0x61, 0x6e, 0x67, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x6c, 0x61, 0x6e, 0x67, 0x12, 0x5b, 0x0a, + 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x43, 0x2e, + 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, + 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x55, + 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, + 0x65, 0x64, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x10, 0x0a, 0x02, 0x65, 0x6e, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x48, 0x01, 0x52, 0x02, 0x65, 0x6e, 0x12, 0x55, 0x0a, 0x02, + 0x6e, 0x6f, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x43, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, + 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, + 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, + 0x74, 0x61, 0x74, 0x65, 0x64, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x48, 0x01, 0x52, + 0x02, 0x6e, 0x6f, 0x42, 0x06, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x42, 0x05, 0x0a, 0x03, 0x65, + 0x78, 0x74, 0x32, 0x94, 0x04, 0x0a, 0x16, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, + 0x65, 0x64, 0x45, 0x63, 0x68, 0x6f, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x9a, 0x01, + 0x0a, 0x04, 0x45, 0x63, 0x68, 0x6f, 0x12, 0x48, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, + 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, + 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, + 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, + 0x74, 0x65, 0x64, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x1a, 0x48, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, + 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, + 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, + 0x62, 0x2e, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x53, 0x69, 0x6d, + 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x9e, 0x01, 0x0a, 0x08, 0x45, + 0x63, 0x68, 0x6f, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x48, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, + 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, + 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, + 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, + 0x61, 0x74, 0x65, 0x64, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x1a, 0x48, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, + 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, + 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, + 0x70, 0x62, 0x2e, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x53, 0x69, + 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0xa0, 0x01, 0x0a, 0x0a, + 0x45, 0x63, 0x68, 0x6f, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x48, 0x2e, 0x67, 0x72, 0x70, + 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, + 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x55, 0x6e, 0x61, 0x6e, + 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x1a, 0x48, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, + 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, + 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, + 0x64, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x19, + 0xea, 0xf3, 0x34, 0x15, 0x08, 0xb6, 0x95, 0xff, 0xff, 0x07, 0x12, 0x04, 0x67, 0x72, 0x70, 0x63, + 0x1a, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x42, 0x52, 0x5a, 0x50, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x69, 0x6e, 0x63, 0x68, 0x65, 0x6e, 0x63, + 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x65, 0x61, 0x73, 0x65, 0x2d, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, + 0x79, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, + 0x65, 0x70, 0x62, 0x3b, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDescOnce sync.Once + file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDescData = file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDesc +) + +func file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDescGZIP() []byte { + file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDescOnce.Do(func() { + file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDescData = protoimpl.X.CompressGZIP(file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDescData) + }) + return file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDescData +} + +var file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_examples_internal_proto_examplepb_unannotated_echo_service_proto_goTypes = []interface{}{ + (*UnannotatedEmbedded)(nil), // 0: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEmbedded + (*UnannotatedSimpleMessage)(nil), // 1: grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage + (*duration.Duration)(nil), // 2: google.protobuf.Duration +} +var file_examples_internal_proto_examplepb_unannotated_echo_service_proto_depIdxs = []int32{ + 2, // 0: grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage.duration:type_name -> google.protobuf.Duration + 0, // 1: grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage.status:type_name -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedEmbedded + 0, // 2: grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage.no:type_name -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedEmbedded + 1, // 3: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.Echo:input_type -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage + 1, // 4: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.EchoBody:input_type -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage + 1, // 5: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.EchoDelete:input_type -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage + 1, // 6: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.Echo:output_type -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage + 1, // 7: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.EchoBody:output_type -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage + 1, // 8: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.EchoDelete:output_type -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage + 6, // [6:9] is the sub-list for method output_type + 3, // [3:6] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name +} + +func init() { file_examples_internal_proto_examplepb_unannotated_echo_service_proto_init() } +func file_examples_internal_proto_examplepb_unannotated_echo_service_proto_init() { + if File_examples_internal_proto_examplepb_unannotated_echo_service_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UnannotatedEmbedded); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UnannotatedSimpleMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes[0].OneofWrappers = []interface{}{ + (*UnannotatedEmbedded_Progress)(nil), + (*UnannotatedEmbedded_Note)(nil), + } + file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes[1].OneofWrappers = []interface{}{ + (*UnannotatedSimpleMessage_LineNum)(nil), + (*UnannotatedSimpleMessage_Lang)(nil), + (*UnannotatedSimpleMessage_En)(nil), + (*UnannotatedSimpleMessage_No)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDesc, + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_examples_internal_proto_examplepb_unannotated_echo_service_proto_goTypes, + DependencyIndexes: file_examples_internal_proto_examplepb_unannotated_echo_service_proto_depIdxs, + MessageInfos: file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes, + }.Build() + File_examples_internal_proto_examplepb_unannotated_echo_service_proto = out.File + file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDesc = nil + file_examples_internal_proto_examplepb_unannotated_echo_service_proto_goTypes = nil + file_examples_internal_proto_examplepb_unannotated_echo_service_proto_depIdxs = nil +} diff --git a/examples/internal/proto/examplepb/unannotated_echo_service.pb.gw.go b/examples/internal/proto/examplepb/unannotated_echo_service.pb.gw.go new file mode 100755 index 0000000..b76fb60 --- /dev/null +++ b/examples/internal/proto/examplepb/unannotated_echo_service.pb.gw.go @@ -0,0 +1,3 @@ +// +build ignore + +package ignore \ No newline at end of file diff --git a/examples/internal/proto/examplepb/unannotated_echo_service.swagger.yaml b/examples/internal/proto/examplepb/unannotated_echo_service.swagger.yaml new file mode 100644 index 0000000..6329dad --- /dev/null +++ b/examples/internal/proto/examplepb/unannotated_echo_service.swagger.yaml @@ -0,0 +1,112 @@ +openapiOptions: + file: + # the file name must be the same as one passed to protoc when generating generating .swagger.json + - file: "examples/internal/proto/examplepb/unannotated_echo_service.proto" + option: + info: + title: Unannotated Echo + contact: + name: gRPC-Gateway project + url: https://github.com/grpc-ecosystem/grpc-gateway + email: none@example.com + license: + name: BSD 3-Clause License + url: https://github.com/grpc-ecosystem/grpc-gateway/blob/master/LICENSE.txt + version: "1.0" + extensions: + x-something-something: yadda + schemes: + - HTTP + - HTTPS + - WSS + consumes: + - application/json + - application/x-foo-mime + produces: + - application/json + - application/x-foo-mime + responses: + "403": + description: Returned when the user does not have permission to access the resource. + "404": + description: Returned when the resource does not exist. + schema: + jsonSchema: + type: + - STRING + securityDefinitions: + security: + ApiKeyAuth: + type: TYPE_API_KEY + name: X-API-Key + in: IN_HEADER + extensions: + x-amazon-apigateway-authorizer: + authorizerResultTtlInSeconds: 60 + type: token + x-amazon-apigateway-authtype: oauth2 + BasicAuth: + type: TYPE_BASIC + security: + - securityRequirement: + ApiKeyAuth: {} + BasicAuth: {} + - securityRequirement: + ApiKeyAuth: {} + OAuth2: + scope: + - read + - write + externalDocs: + description: More about gRPC-Gateway + url: https://github.com/grpc-ecosystem/grpc-gateway + extensions: + x-grpc-gateway-baz-list: + - one + - true + x-grpc-gateway-foo: bar + service: + - service: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService + option: + description: "UnannotatedEchoService description -- which should not be used in place of the documentation comment!" + external_docs: + url: "https://github.com/grpc-ecosystem/grpc-gateway" + description: "Find out more about UnannotatedEchoService" + method: + - method: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.Echo + option: + description: "Description Echo" + summary: "Summary: Echo rpc" + external_docs: + url: "https://github.com/grpc-ecosystem/grpc-gateway" + description: "Find out more Echo" + responses: + "200": + examples: + "application/json": '{"value": "the input value"}' + "503": + description: Returned when the resource is temporarily unavailable. + extensions: + x-number: 100 + "404": + description: Returned when the resource does not exist. + schema: + jsonSchema: + type: [INTEGER] + message: + - message: grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage + option: + json_schema: + title: "A bit of everything" + description: "A simple message with many types" + required: ["id"] + external_docs: + url: "https://github.com/grpc-ecosystem/grpc-gateway" + description: "Find out more about UnannotatedSimpleMessage" + example: '{"id": "myid"}' + field: + - field: grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage.num + option: + description: "Int value field" + default: "42" + required: ["num"] diff --git a/examples/internal/proto/examplepb/unannotated_echo_service_grpc.pb.go b/examples/internal/proto/examplepb/unannotated_echo_service_grpc.pb.go new file mode 100755 index 0000000..8e1bb7c --- /dev/null +++ b/examples/internal/proto/examplepb/unannotated_echo_service_grpc.pb.go @@ -0,0 +1,167 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. + +package examplepb + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// 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.SupportPackageIsVersion7 + +// UnannotatedEchoServiceClient is the client API for UnannotatedEchoService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type UnannotatedEchoServiceClient interface { + Echo(ctx context.Context, in *UnannotatedSimpleMessage, opts ...grpc.CallOption) (*UnannotatedSimpleMessage, error) + EchoBody(ctx context.Context, in *UnannotatedSimpleMessage, opts ...grpc.CallOption) (*UnannotatedSimpleMessage, error) + EchoDelete(ctx context.Context, in *UnannotatedSimpleMessage, opts ...grpc.CallOption) (*UnannotatedSimpleMessage, error) +} + +type unannotatedEchoServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewUnannotatedEchoServiceClient(cc grpc.ClientConnInterface) UnannotatedEchoServiceClient { + return &unannotatedEchoServiceClient{cc} +} + +func (c *unannotatedEchoServiceClient) Echo(ctx context.Context, in *UnannotatedSimpleMessage, opts ...grpc.CallOption) (*UnannotatedSimpleMessage, error) { + out := new(UnannotatedSimpleMessage) + err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService/Echo", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *unannotatedEchoServiceClient) EchoBody(ctx context.Context, in *UnannotatedSimpleMessage, opts ...grpc.CallOption) (*UnannotatedSimpleMessage, error) { + out := new(UnannotatedSimpleMessage) + err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService/EchoBody", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *unannotatedEchoServiceClient) EchoDelete(ctx context.Context, in *UnannotatedSimpleMessage, opts ...grpc.CallOption) (*UnannotatedSimpleMessage, error) { + out := new(UnannotatedSimpleMessage) + err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService/EchoDelete", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// UnannotatedEchoServiceServer is the server API for UnannotatedEchoService service. +// All implementations should embed UnimplementedUnannotatedEchoServiceServer +// for forward compatibility +type UnannotatedEchoServiceServer interface { + Echo(context.Context, *UnannotatedSimpleMessage) (*UnannotatedSimpleMessage, error) + EchoBody(context.Context, *UnannotatedSimpleMessage) (*UnannotatedSimpleMessage, error) + EchoDelete(context.Context, *UnannotatedSimpleMessage) (*UnannotatedSimpleMessage, error) +} + +// UnimplementedUnannotatedEchoServiceServer should be embedded to have forward compatible implementations. +type UnimplementedUnannotatedEchoServiceServer struct { +} + +func (UnimplementedUnannotatedEchoServiceServer) Echo(context.Context, *UnannotatedSimpleMessage) (*UnannotatedSimpleMessage, error) { + return nil, status.Errorf(codes.Unimplemented, "method Echo not implemented") +} +func (UnimplementedUnannotatedEchoServiceServer) EchoBody(context.Context, *UnannotatedSimpleMessage) (*UnannotatedSimpleMessage, error) { + return nil, status.Errorf(codes.Unimplemented, "method EchoBody not implemented") +} +func (UnimplementedUnannotatedEchoServiceServer) EchoDelete(context.Context, *UnannotatedSimpleMessage) (*UnannotatedSimpleMessage, error) { + return nil, status.Errorf(codes.Unimplemented, "method EchoDelete not implemented") +} + +// UnsafeUnannotatedEchoServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to UnannotatedEchoServiceServer will +// result in compilation errors. +type UnsafeUnannotatedEchoServiceServer interface { + mustEmbedUnimplementedUnannotatedEchoServiceServer() +} + +func RegisterUnannotatedEchoServiceServer(s *grpc.Server, srv UnannotatedEchoServiceServer) { + s.RegisterService(&_UnannotatedEchoService_serviceDesc, srv) +} + +func _UnannotatedEchoService_Echo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UnannotatedSimpleMessage) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UnannotatedEchoServiceServer).Echo(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService/Echo", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UnannotatedEchoServiceServer).Echo(ctx, req.(*UnannotatedSimpleMessage)) + } + return interceptor(ctx, in, info, handler) +} + +func _UnannotatedEchoService_EchoBody_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UnannotatedSimpleMessage) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UnannotatedEchoServiceServer).EchoBody(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService/EchoBody", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UnannotatedEchoServiceServer).EchoBody(ctx, req.(*UnannotatedSimpleMessage)) + } + return interceptor(ctx, in, info, handler) +} + +func _UnannotatedEchoService_EchoDelete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UnannotatedSimpleMessage) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UnannotatedEchoServiceServer).EchoDelete(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService/EchoDelete", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UnannotatedEchoServiceServer).EchoDelete(ctx, req.(*UnannotatedSimpleMessage)) + } + return interceptor(ctx, in, info, handler) +} + +var _UnannotatedEchoService_serviceDesc = grpc.ServiceDesc{ + ServiceName: "grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService", + HandlerType: (*UnannotatedEchoServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Echo", + Handler: _UnannotatedEchoService_Echo_Handler, + }, + { + MethodName: "EchoBody", + Handler: _UnannotatedEchoService_EchoBody_Handler, + }, + { + MethodName: "EchoDelete", + Handler: _UnannotatedEchoService_EchoDelete_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "examples/internal/proto/examplepb/unannotated_echo_service.proto", +} diff --git a/examples/internal/server/BUILD.bazel b/examples/internal/server/BUILD.bazel index 84aea9b..458a608 100644 --- a/examples/internal/server/BUILD.bazel +++ b/examples/internal/server/BUILD.bazel @@ -3,29 +3,35 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library") package(default_visibility = ["//visibility:public"]) go_library( - name = "go_default_library", + name = "server", srcs = [ "echo.go", "main.go", ], importpath = "github.com/binchencoder/ease-gateway/examples/internal/server", deps = [ - "//examples/internal/proto/examplepb:go_default_library", - "//gateway/runtime:go_default_library", - "@com_github_golang_glog//:go_default_library", - "@com_github_rogpeppe_fastuuid//:go_default_library", + "//examples/internal/proto/examplepb", + "//gateway/runtime", + "@com_github_golang_glog//:glog", + "@com_github_rogpeppe_fastuuid//:fastuuid", "@go_googleapis//google/api:httpbody_go_proto", "@go_googleapis//google/rpc:errdetails_go_proto", "@go_googleapis//google/rpc:status_go_proto", - "@io_bazel_rules_go//proto/wkt:duration_go_proto", - "@io_bazel_rules_go//proto/wkt:empty_go_proto", "@io_bazel_rules_go//proto/wkt:field_mask_go_proto", - "@io_bazel_rules_go//proto/wkt:wrappers_go_proto", "@org_golang_google_grpc//:go_default_library", - "@org_golang_google_grpc//codes:go_default_library", - "@org_golang_google_grpc//metadata:go_default_library", - "@org_golang_google_grpc//status:go_default_library", - "@org_golang_google_protobuf//proto:go_default_library", - "@org_golang_google_protobuf//reflect/protoreflect:go_default_library", + "@org_golang_google_grpc//codes", + "@org_golang_google_grpc//metadata", + "@org_golang_google_grpc//status", + "@org_golang_google_protobuf//proto", + "@org_golang_google_protobuf//reflect/protoreflect", + "@org_golang_google_protobuf//types/known/durationpb", + "@org_golang_google_protobuf//types/known/emptypb", + "@org_golang_google_protobuf//types/known/wrapperspb", ], ) + +alias( + name = "go_default_library", + actual = ":server", + visibility = ["//examples:__subpackages__"], +) diff --git a/examples/internal/server/echo.go b/examples/internal/server/echo.go index 9cce632..3721fbf 100644 --- a/examples/internal/server/echo.go +++ b/examples/internal/server/echo.go @@ -13,7 +13,7 @@ import ( type echoServer struct{} -func newEchoServer() examples.EchoServiceServer { +func NewEchoServer() examples.EchoServiceServer { return new(echoServer) } diff --git a/examples/internal/server/main.go b/examples/internal/server/main.go index 2971ae1..60729e1 100644 --- a/examples/internal/server/main.go +++ b/examples/internal/server/main.go @@ -25,7 +25,7 @@ func Run(ctx context.Context, network, address string) error { }() s := grpc.NewServer() - examples.RegisterEchoServiceServer(s, newEchoServer()) + examples.RegisterEchoServiceServer(s, NewEchoServer()) go func() { defer s.GracefulStop() @@ -38,7 +38,7 @@ func Run(ctx context.Context, network, address string) error { func RunInProcessGateway(ctx context.Context, addr string, opts ...runtime.ServeMuxOption) error { mux := runtime.NewServeMux(opts...) - examples.RegisterEchoServiceHandlerServer(ctx, mux, newEchoServer()) + examples.RegisterEchoServiceHandlerServer(ctx, mux, NewEchoServer()) s := &http.Server{ Addr: addr, Handler: mux, diff --git a/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator.go b/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator.go index 42f26d3..ce62bb0 100644 --- a/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator.go +++ b/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator.go @@ -47,16 +47,15 @@ func New(reg *descriptor.Registry, useRequestContext bool, registerFuncSuffix st "github.com/binchencoder/gateway-proto/data": "vexpb", "github.com/binchencoder/gateway-proto/frontend": "fpb", "github.com/binchencoder/letsgo/grpc": "lgr", - "github.com/binchencoder/skylb-api/balancer": "", - "github.com/binchencoder/skylb-api/client": "", - "github.com/binchencoder/skylb-api/client/option": "", - "github.com/binchencoder/skylb-api/proto": "skypb", - "google.golang.org/grpc": "", - "google.golang.org/grpc/codes": "", - // "google.golang.org/grpc/naming": "", - "google.golang.org/grpc/grpclog": "", - "google.golang.org/grpc/metadata": "", - "google.golang.org/grpc/status": "", + // "github.com/binchencoder/skylb-api/balancer": "", + "github.com/binchencoder/skylb-api/client": "", + // "github.com/binchencoder/skylb-api/client/option": "", + "github.com/binchencoder/skylb-api/proto": "skypb", + "google.golang.org/grpc": "", + "google.golang.org/grpc/codes": "", + "google.golang.org/grpc/grpclog": "", + "google.golang.org/grpc/metadata": "", + "google.golang.org/grpc/status": "", } { pkg := descriptor.GoPackage{ Path: pkgpath, diff --git a/gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go b/gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go index 5b039c0..4bd2bc5 100644 --- a/gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go +++ b/gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go @@ -173,6 +173,11 @@ func applyTemplate(p param, reg *descriptor.Registry) (string, error) { if err := headerTemplate.Execute(w, p); err != nil { return "", err } + + if err := validatorTemplate.Execute(w, p); err != nil { + return "", err + } + var targetServices []*descriptor.Service for _, msg := range p.Messages { @@ -270,9 +275,9 @@ var _ client.ServiceCli var _ vexpb.ServiceId var _ = http.MethodGet var _ regexp.Regexp -var _ = balancer.ConsistentHashing -var _ option.BalancerCreator -var _ naming.Resolver +// var _ = balancer.ConsistentHashing +// var _ option.BalancerCreator +// var _ naming.Resolver var _ strings.Reader var _ = utf8.UTFMax @@ -867,7 +872,7 @@ func init() { {{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) (err error) { +func Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}FromEndpoint(mux *runtime.ServeMux) (err error) { // conn, err := grpc.Dial(endpoint, opts...) // if err != nil { // return err @@ -887,8 +892,8 @@ func Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}FromEndpoint(ctx context.Co // }() // }() - return Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}(ctx, mux, conn) - // return Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}(nil, mux, nil) + // return Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}(ctx, mux, conn) + return Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}(nil, mux, nil) } // Register{{$svc.GetName}}{{$.RegisterFuncSuffix}} registers the http handlers for service {{$svc.GetName}} to "mux". @@ -934,7 +939,7 @@ func Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}Client(ctx context.Context, {{- end }} defer cancel() // inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - var err error + // var err error {{- if $b.PathTmpl }} ctx, err = runtime.AnnotateContext(ctx, mux, req, "/{{$svc.File.GetPackage}}.{{$svc.GetName}}/{{$m.GetName}}", runtime.WithHTTPPathPattern("{{$b.PathTmpl.Template}}")) {{- else -}} @@ -1016,13 +1021,9 @@ func Enable_{{$svc.ServiceId}}__{{$svc.Namespace}}__{{$svc.PortName}}_ServiceGro {{if eq $svc.Balancer.String "ROUND_ROBIN"}} internal_{{$svc.ServiceId}}__{{$svc.Namespace}}__{{$svc.PortName}}_skycli.Resolve(spec) {{else if eq $svc.Balancer.String "CONSISTENT"}} - internal_{{$svc.ServiceId}}__{{$svc.Namespace}}__{{$svc.PortName}}_skycli.Resolve(spec, - option.WithBalancerCreator(func(r naming.Resolver) grpc.Balancer { - return balancer.ConsistentHashing(r) - }), + internal_{{$svc.ServiceId}}__{{$svc.Namespace}}__{{$svc.PortName}}_skycli.Resolve(spec), ) {{end}} - internal_{{$svc.ServiceId}}__{{$svc.Namespace}}__{{$svc.PortName}}_skycli.EnableResolveFullEps() internal_{{$svc.ServiceId}}__{{$svc.Namespace}}__{{$svc.PortName}}_skycli.Start(func(spec *skypb.ServiceSpec, conn *grpc.ClientConn) { sg := runtime.GetServiceGroup(spec) for _, svc := range sg.Services { diff --git a/gateway/runtime/BUILD.bazel b/gateway/runtime/BUILD.bazel index 55a2770..dab62cc 100644 --- a/gateway/runtime/BUILD.bazel +++ b/gateway/runtime/BUILD.bazel @@ -56,11 +56,11 @@ go_test( ], embed = [":runtime"], deps = [ - "//examples/internal/proto/examplepb:go_default_library", + "//examples/internal/proto/examplepb", "//gateway/internal:go_default_library", - "//gateway/runtime/internal/examplepb:go_default_library", - "@com_github_grpc_ecosystem_grpc_gateway//utilities", - "//httpoptions:go_default_library", + "//gateway/runtime/internal/examplepb", + "@com_github_grpc_ecosystem_grpc_gateway//utilities", + "//httpoptions", "@com_github_binchencoder_letsgo//hashring:go_default_library", "@com_github_binchencoder_skylb_api//proto:go_default_library", "@com_github_google_go_cmp//cmp", diff --git a/gateway/runtime/mux_test.go b/gateway/runtime/mux_test.go index 96d0836..180b7b7 100644 --- a/gateway/runtime/mux_test.go +++ b/gateway/runtime/mux_test.go @@ -681,7 +681,7 @@ func TestWithHealthEndpointAt_consistentWithHealthz(t *testing.T) { w := httptest.NewRecorder() runtime.NewServeMux( - runtime.WithHealthEndpointAt(client, endpointPath), + runtime.WithHealthEndpointAt(client, endpointPath, 1 /* sid */), ).ServeHTTP(w, r) refW := httptest.NewRecorder() diff --git a/go.mod b/go.mod index 5b4d68e..567506a 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.17 require ( github.com/binchencoder/gateway-proto v0.0.7 github.com/binchencoder/letsgo v0.0.3 - github.com/binchencoder/skylb-api v0.0.5 + github.com/binchencoder/skylb-api v0.2.0 github.com/antihax/optional v1.0.0 github.com/golang/glog v1.0.0 github.com/golang/protobuf v1.5.2 @@ -31,7 +31,4 @@ require ( replace ( github.com/coreos/bbolt v1.3.4 => go.etcd.io/bbolt v1.3.4 github.com/coreos/bbolt v1.3.5 => go.etcd.io/bbolt v1.3.5 - // google.golang.org/grpc v1.30.0 => google.golang.org/grpc v1.29.1 - // google.golang.org/grpc v1.33.1 => google.golang.org/grpc v1.29.1 - // google.golang.org/grpc => google.golang.org/grpc v1.29.1 ) diff --git a/go.sum b/go.sum index 97044f8..28d730c 100644 --- a/go.sum +++ b/go.sum @@ -65,12 +65,6 @@ github.com/binchencoder/gateway-proto v0.0.7 h1:+3d1QEBqDxFrTIVrSiao4saXNFNeK/vx github.com/binchencoder/gateway-proto v0.0.7/go.mod h1:DUtwTL1FDBeVIDIHxS8v2YajyWqe444jSvCxexR161A= github.com/binchencoder/letsgo v0.0.3 h1:hEDDOeGdX9R/JPYMdVo9N/9iQa5BeBLluTssrNYy/ng= github.com/binchencoder/letsgo v0.0.3/go.mod h1:WbqNFa5gFsogqe3gtycvPYswprKV7eGJIxScwQhAg44= -github.com/binchencoder/skylb-api v0.0.3 h1:NnlPmEjTgOjH+s9TK3rBEY4Kn9aEzZkuEBUV2aR8UTM= -github.com/binchencoder/skylb-api v0.0.3/go.mod h1:j/ATHuW3TU7M5+fWeTqrvOzmFQI7Z4AVerdP6JYOkUk= -github.com/binchencoder/skylb-api v0.0.4 h1:HFQk6U+IerXWuQD6bxtGR6Zf7Q2Ulj87CZAd9G0vcnc= -github.com/binchencoder/skylb-api v0.0.4/go.mod h1:HoLyR+KbCm7bI2sRp+AA1pj159KRutdVYow6w3tbOLs= -github.com/binchencoder/skylb-api v0.0.5 h1:BM11MtrX7DrUKacLTEqudd4hietFlXRNr8Nh6dLSOCk= -github.com/binchencoder/skylb-api v0.0.5/go.mod h1:fUK5XeSBmuARvLeg+pab1FplK4x2+Q9zsmg4U8KNDBQ= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= @@ -420,12 +414,9 @@ go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+ go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -446,11 +437,9 @@ golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTk golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= @@ -459,29 +448,19 @@ golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -493,20 +472,18 @@ golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201026091529-146b70c837a4 h1:awiuzyrRjJDb+OXi9ceHO3SDxVoN3JER57mhtqkdQBs= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a h1:qfl7ob3DIEs3Ml9oLuPwY2N04gymzAW04WsUQHIClgM= golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -516,31 +493,18 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -553,39 +517,32 @@ golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM/fAoGlaiiHYiFYdm80= -golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642 h1:B6caxRw+hozq68X2MY7jEpZh/cr4/aHLv9xU8Kkadrw= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -595,8 +552,6 @@ golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -604,8 +559,6 @@ golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200103221440-774c71fcf114 h1:DnSr2mCsxyCE6ZgIkmcWUQY2R5cH/6wL7eIxEmQOMSE= -golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= @@ -623,11 +576,9 @@ golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d h1:W07d4xkoAUSNOkOzdzXCdFGxT7o2rW4q8M34tB2i//k= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -655,36 +606,6 @@ google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20190927181202-20e1ac93f88c/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200624020401-64a14ca9d1ad/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200702021140-07506425bd67 h1:4BC1C1i30F3MZeiIO6y6IIo4DxrtOwITK87bQl3lhFA= google.golang.org/genproto v0.0.0-20200702021140-07506425bd67/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= @@ -693,31 +614,14 @@ google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154 h1:bFFRpT+e8JJVY7lMMfvezL1ZIwqiwmPl2bsE2yx4HqM= google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20220314164441-57ef72a4c106/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= -google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0 h1:M5a8xTlYTxwMn5ZFkwhRabsygDY5G8TYLyQDBxJNAxE= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.1 h1:DGeFlSan2f+WEtCERJ4J9GJWk15TxUi8QGagfI87Xyc= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.0.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= -google.golang.org/grpc/examples v0.0.0-20200630190442-3de8449f8555 h1:B6/wMqTY7mM93BBu0wfiO67B9+bcv4oQQsdrcijjfzA= -google.golang.org/grpc/examples v0.0.0-20200630190442-3de8449f8555/go.mod h1:5j1uub0jRGhRiSghIlrThmBUgcgLXOVJQ/l1getT4uo= +google.golang.org/grpc v1.45.0 h1:NEpgUqV3Z+ZjkqMsxMg11IaDrXY4RY6CQukSGK0uI1M= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/integrate/BUILD.bazel b/integrate/BUILD.bazel index 4e1bdfc..f1d2fab 100755 --- a/integrate/BUILD.bazel +++ b/integrate/BUILD.bazel @@ -10,8 +10,8 @@ go_library( ), importpath = "github.com/binchencoder/ease-gateway/integrate", deps = [ - "//httpoptions:go_default_library", - "//gateway/runtime:go_default_library", + "//httpoptions", + "//gateway/runtime", "//integrate/metrics:go_default_library", "//util:go_default_library", "@com_github_binchencoder_gateway_proto//data:go_default_library", diff --git a/proto/examples/BUILD.bazel b/proto/examplepb/BUILD.bazel similarity index 79% rename from proto/examples/BUILD.bazel rename to proto/examplepb/BUILD.bazel index 5816390..7248172 100644 --- a/proto/examples/BUILD.bazel +++ b/proto/examplepb/BUILD.bazel @@ -1,3 +1,4 @@ +load("@rules_proto//proto:defs.bzl", "proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library") load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("//gateway/protoc-gen-openapiv2:defs.bzl", "protoc_gen_openapiv2") @@ -29,30 +30,28 @@ go_proto_library( "//:go_grpc", "//gateway/protoc-gen-grpc-gateway:go_gen_grpc_gateway", # keep ], - importpath = "github.com/binchencoder/ease-gateway/proto/examples", + importpath = "github.com/binchencoder/ease-gateway/proto/examplepb", proto = ":examplepb_proto", deps = [ - "//httpoptions:go_default_library", - "//gateway/runtime:go_default_library", + "//httpoptions", + "//gateway/runtime", + "//gateway/protoc-gen-openapiv2/options", "@com_github_binchencoder_letsgo//grpc:go_default_library", - "@com_github_binchencoder_skylb_api//balancer:go_default_library", "@com_github_binchencoder_skylb_api//client:go_default_library", - "@com_github_binchencoder_skylb_api//client/option:go_default_library", "@com_github_binchencoder_skylb_api//proto:go_default_library", - "@org_golang_google_grpc//naming:go_default_library", ], ) go_library( - name = "go_default_library", + name = "examplepb", embed = [":examplepb_go_proto"], - importpath = "github.com/binchencoder/ease-gateway/proto/examples", + importpath = "github.com/binchencoder/ease-gateway/proto/examplepb", deps = [ - "//httpoptions:go_default_library", - "//gateway/runtime:go_default_library", + "//httpoptions", + "//gateway/runtime", + "@com_github_grpc_ecosystem_grpc_gateway//utilities", "@com_github_binchencoder_gateway_proto//data:go_default_library", "@com_github_binchencoder_gateway_proto//frontend:go_default_library", - "@com_github_binchencoder_skylb_api//balancer:go_default_library", "@com_github_binchencoder_skylb_api//client:go_default_library", ], ) @@ -61,4 +60,9 @@ protoc_gen_openapiv2( name = "examplepb_protoc_gen_openapiv2", proto = ":examplepb_proto", single_output = False, # Outputs a single swagger.json file. +) + +alias( + name = "go_default_library", + actual = ":examplepb", ) \ No newline at end of file diff --git a/proto/examples/echo_service.proto b/proto/examplepb/echo_service.proto similarity index 95% rename from proto/examples/echo_service.proto rename to proto/examplepb/echo_service.proto index 713c6a0..72707da 100644 --- a/proto/examples/echo_service.proto +++ b/proto/examplepb/echo_service.proto @@ -1,10 +1,10 @@ syntax = "proto3"; -option go_package = "github.com/binchencoder/ease-gateway/gateway/proto/examples"; +option go_package = "github.com/binchencoder/ease-gateway/gateway/proto/examplepb"; -package grpc.gateway.proto.examples; +package grpc.gateway.proto.examplepb; -option java_package = "com.binchencoder.easegw.examples"; +option java_package = "com.binchencoder.easegw.examplepb"; option java_outer_classname = "ExamplesProto"; // import "google/api/annotations.proto"; diff --git a/proto/examples/echo_service.swagger.json b/proto/examplepb/echo_service.swagger.json similarity index 100% rename from proto/examples/echo_service.swagger.json rename to proto/examplepb/echo_service.swagger.json diff --git a/proto/examples/pom.xml b/proto/examplepb/pom.xml similarity index 100% rename from proto/examples/pom.xml rename to proto/examplepb/pom.xml diff --git a/proto/examples/echo_service.pb.go b/proto/examples/echo_service.pb.go deleted file mode 100755 index bdda4c4..0000000 --- a/proto/examples/echo_service.pb.go +++ /dev/null @@ -1,425 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.22.0 -// protoc v3.8.0 -// source: proto/examples/internal/echo_service.proto - -package examples - -import ( - _ "github.com/binchencoder/ease-gateway/httpoptions" - proto "github.com/golang/protobuf/proto" - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - reflect "reflect" - sync "sync" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - -type Embedded struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Types that are assignable to Mark: - // *Embedded_Progress - // *Embedded_Note - Mark isEmbedded_Mark `protobuf_oneof:"mark"` -} - -func (x *Embedded) Reset() { - *x = Embedded{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_examples_echo_service_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Embedded) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Embedded) ProtoMessage() {} - -func (x *Embedded) ProtoReflect() protoreflect.Message { - mi := &file_proto_examples_echo_service_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Embedded.ProtoReflect.Descriptor instead. -func (*Embedded) Descriptor() ([]byte, []int) { - return file_proto_examples_echo_service_proto_rawDescGZIP(), []int{0} -} - -func (m *Embedded) GetMark() isEmbedded_Mark { - if m != nil { - return m.Mark - } - return nil -} - -func (x *Embedded) GetProgress() int64 { - if x, ok := x.GetMark().(*Embedded_Progress); ok { - return x.Progress - } - return 0 -} - -func (x *Embedded) GetNote() string { - if x, ok := x.GetMark().(*Embedded_Note); ok { - return x.Note - } - return "" -} - -type isEmbedded_Mark interface { - isEmbedded_Mark() -} - -type Embedded_Progress struct { - Progress int64 `protobuf:"varint,1,opt,name=progress,proto3,oneof"` -} - -type Embedded_Note struct { - Note string `protobuf:"bytes,2,opt,name=note,proto3,oneof"` -} - -func (*Embedded_Progress) isEmbedded_Mark() {} - -func (*Embedded_Note) isEmbedded_Mark() {} - -type SimpleMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Num int64 `protobuf:"varint,2,opt,name=num,proto3" json:"num,omitempty"` - // Types that are assignable to Code: - // *SimpleMessage_LineNum - // *SimpleMessage_Lang - Code isSimpleMessage_Code `protobuf_oneof:"code"` - Status *Embedded `protobuf:"bytes,5,opt,name=status,proto3" json:"status,omitempty"` - // Types that are assignable to Ext: - // *SimpleMessage_En - // *SimpleMessage_No - Ext isSimpleMessage_Ext `protobuf_oneof:"ext"` -} - -func (x *SimpleMessage) Reset() { - *x = SimpleMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_examples_echo_service_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *SimpleMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*SimpleMessage) ProtoMessage() {} - -func (x *SimpleMessage) ProtoReflect() protoreflect.Message { - mi := &file_proto_examples_echo_service_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use SimpleMessage.ProtoReflect.Descriptor instead. -func (*SimpleMessage) Descriptor() ([]byte, []int) { - return file_proto_examples_echo_service_proto_rawDescGZIP(), []int{1} -} - -func (x *SimpleMessage) GetId() string { - if x != nil { - return x.Id - } - return "" -} - -func (x *SimpleMessage) GetNum() int64 { - if x != nil { - return x.Num - } - return 0 -} - -func (m *SimpleMessage) GetCode() isSimpleMessage_Code { - if m != nil { - return m.Code - } - return nil -} - -func (x *SimpleMessage) GetLineNum() int64 { - if x, ok := x.GetCode().(*SimpleMessage_LineNum); ok { - return x.LineNum - } - return 0 -} - -func (x *SimpleMessage) GetLang() string { - if x, ok := x.GetCode().(*SimpleMessage_Lang); ok { - return x.Lang - } - return "" -} - -func (x *SimpleMessage) GetStatus() *Embedded { - if x != nil { - return x.Status - } - return nil -} - -func (m *SimpleMessage) GetExt() isSimpleMessage_Ext { - if m != nil { - return m.Ext - } - return nil -} - -func (x *SimpleMessage) GetEn() int64 { - if x, ok := x.GetExt().(*SimpleMessage_En); ok { - return x.En - } - return 0 -} - -func (x *SimpleMessage) GetNo() *Embedded { - if x, ok := x.GetExt().(*SimpleMessage_No); ok { - return x.No - } - return nil -} - -type isSimpleMessage_Code interface { - isSimpleMessage_Code() -} - -type SimpleMessage_LineNum struct { - LineNum int64 `protobuf:"varint,3,opt,name=line_num,json=lineNum,proto3,oneof"` -} - -type SimpleMessage_Lang struct { - Lang string `protobuf:"bytes,4,opt,name=lang,proto3,oneof"` -} - -func (*SimpleMessage_LineNum) isSimpleMessage_Code() {} - -func (*SimpleMessage_Lang) isSimpleMessage_Code() {} - -type isSimpleMessage_Ext interface { - isSimpleMessage_Ext() -} - -type SimpleMessage_En struct { - En int64 `protobuf:"varint,6,opt,name=en,proto3,oneof"` -} - -type SimpleMessage_No struct { - No *Embedded `protobuf:"bytes,7,opt,name=no,proto3,oneof"` -} - -func (*SimpleMessage_En) isSimpleMessage_Ext() {} - -func (*SimpleMessage_No) isSimpleMessage_Ext() {} - -var File_proto_examples_echo_service_proto protoreflect.FileDescriptor - -var file_proto_examples_echo_service_proto_rawDesc = []byte{ - 0x0a, 0x21, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, - 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x12, 0x1b, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, - 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, - 0x1a, 0x1d, 0x68, 0x74, 0x74, 0x70, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x61, 0x6e, - 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, - 0x46, 0x0a, 0x08, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x12, 0x1c, 0x0a, 0x08, 0x70, - 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, - 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x14, 0x0a, 0x04, 0x6e, 0x6f, 0x74, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x42, - 0x06, 0x0a, 0x04, 0x6d, 0x61, 0x72, 0x6b, 0x22, 0xaf, 0x02, 0x0a, 0x0d, 0x53, 0x69, 0x6d, 0x70, - 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x31, 0x0a, 0x02, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x21, 0xb2, 0xe4, 0x34, 0x1d, 0x0a, 0x04, 0x08, 0x05, 0x10, - 0x02, 0x0a, 0x09, 0x08, 0x06, 0x10, 0x02, 0x1a, 0x01, 0x32, 0x20, 0x01, 0x0a, 0x0a, 0x08, 0x07, - 0x10, 0x02, 0x1a, 0x02, 0x36, 0x31, 0x20, 0x01, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1f, 0x0a, 0x03, - 0x6e, 0x75, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x42, 0x0d, 0xb2, 0xe4, 0x34, 0x09, 0x0a, - 0x07, 0x08, 0x01, 0x10, 0x01, 0x1a, 0x01, 0x30, 0x52, 0x03, 0x6e, 0x75, 0x6d, 0x12, 0x1b, 0x0a, - 0x08, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x48, - 0x00, 0x52, 0x07, 0x6c, 0x69, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x12, 0x14, 0x0a, 0x04, 0x6c, 0x61, - 0x6e, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x6c, 0x61, 0x6e, 0x67, - 0x12, 0x3d, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x25, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x45, - 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, - 0x10, 0x0a, 0x02, 0x65, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x48, 0x01, 0x52, 0x02, 0x65, - 0x6e, 0x12, 0x37, 0x0a, 0x02, 0x6e, 0x6f, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, - 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x45, 0x6d, 0x62, 0x65, - 0x64, 0x64, 0x65, 0x64, 0x48, 0x01, 0x52, 0x02, 0x6e, 0x6f, 0x42, 0x06, 0x0a, 0x04, 0x63, 0x6f, - 0x64, 0x65, 0x42, 0x05, 0x0a, 0x03, 0x65, 0x78, 0x74, 0x32, 0xcc, 0x04, 0x0a, 0x0b, 0x45, 0x63, - 0x68, 0x6f, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x94, 0x02, 0x0a, 0x04, 0x45, 0x63, - 0x68, 0x6f, 0x12, 0x2a, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, - 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, - 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x2a, - 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x53, 0x69, 0x6d, - 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xb3, 0x01, 0xca, 0xf3, 0x34, - 0xae, 0x01, 0x22, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, - 0x65, 0x63, 0x68, 0x6f, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x5a, 0x1d, 0x12, 0x1b, 0x2f, 0x76, 0x31, - 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x2f, 0x7b, 0x69, - 0x64, 0x7d, 0x2f, 0x7b, 0x6e, 0x75, 0x6d, 0x7d, 0x5a, 0x24, 0x12, 0x22, 0x2f, 0x76, 0x31, 0x2f, - 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x2f, 0x7b, 0x69, 0x64, - 0x7d, 0x2f, 0x7b, 0x6e, 0x75, 0x6d, 0x7d, 0x2f, 0x7b, 0x6c, 0x61, 0x6e, 0x67, 0x7d, 0x5a, 0x31, - 0x12, 0x2f, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, - 0x68, 0x6f, 0x31, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x2f, 0x7b, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x6e, - 0x75, 0x6d, 0x7d, 0x2f, 0x7b, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x6e, 0x6f, 0x74, 0x65, - 0x7d, 0x5a, 0x1d, 0x12, 0x1b, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, - 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x32, 0x2f, 0x7b, 0x6e, 0x6f, 0x2e, 0x6e, 0x6f, 0x74, 0x65, 0x7d, - 0x12, 0x82, 0x01, 0x0a, 0x08, 0x45, 0x63, 0x68, 0x6f, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x2a, 0x2e, - 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x53, 0x69, 0x6d, 0x70, - 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x2a, 0x2e, 0x67, 0x72, 0x70, 0x63, - 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, - 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x1e, 0xca, 0xf3, 0x34, 0x1a, 0x22, 0x15, 0x2f, 0x76, 0x31, - 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x62, 0x6f, - 0x64, 0x79, 0x3a, 0x01, 0x2a, 0x12, 0x83, 0x01, 0x0a, 0x0a, 0x45, 0x63, 0x68, 0x6f, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x12, 0x2a, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, - 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, - 0x65, 0x73, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x1a, 0x2a, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x53, - 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x1d, 0xca, 0xf3, - 0x34, 0x19, 0x2a, 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, - 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x1a, 0x1b, 0xea, 0xf3, 0x34, - 0x17, 0x08, 0xb6, 0x95, 0xff, 0xff, 0x07, 0x12, 0x04, 0x67, 0x72, 0x70, 0x63, 0x1a, 0x07, 0x64, - 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x01, 0x42, 0x6e, 0x0a, 0x20, 0x63, 0x6f, 0x6d, 0x2e, - 0x62, 0x69, 0x6e, 0x63, 0x68, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x65, 0x61, 0x73, - 0x65, 0x67, 0x77, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x42, 0x0d, 0x45, 0x78, - 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x5a, 0x3b, 0x67, 0x69, 0x74, - 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x69, 0x6e, 0x63, 0x68, 0x65, 0x6e, 0x63, - 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x65, 0x61, 0x73, 0x65, 0x2d, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, - 0x79, 0x2f, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, - 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} - -var ( - file_proto_examples_echo_service_proto_rawDescOnce sync.Once - file_proto_examples_echo_service_proto_rawDescData = file_proto_examples_echo_service_proto_rawDesc -) - -func file_proto_examples_echo_service_proto_rawDescGZIP() []byte { - file_proto_examples_echo_service_proto_rawDescOnce.Do(func() { - file_proto_examples_echo_service_proto_rawDescData = protoimpl.X.CompressGZIP(file_proto_examples_echo_service_proto_rawDescData) - }) - return file_proto_examples_echo_service_proto_rawDescData -} - -var file_proto_examples_echo_service_proto_msgTypes = make([]protoimpl.MessageInfo, 2) -var file_proto_examples_echo_service_proto_goTypes = []interface{}{ - (*Embedded)(nil), // 0: grpc.gateway.proto.examples.Embedded - (*SimpleMessage)(nil), // 1: grpc.gateway.proto.examples.SimpleMessage -} -var file_proto_examples_echo_service_proto_depIdxs = []int32{ - 0, // 0: grpc.gateway.proto.examples.SimpleMessage.status:type_name -> grpc.gateway.proto.examples.Embedded - 0, // 1: grpc.gateway.proto.examples.SimpleMessage.no:type_name -> grpc.gateway.proto.examples.Embedded - 1, // 2: grpc.gateway.proto.examples.EchoService.Echo:input_type -> grpc.gateway.proto.examples.SimpleMessage - 1, // 3: grpc.gateway.proto.examples.EchoService.EchoBody:input_type -> grpc.gateway.proto.examples.SimpleMessage - 1, // 4: grpc.gateway.proto.examples.EchoService.EchoDelete:input_type -> grpc.gateway.proto.examples.SimpleMessage - 1, // 5: grpc.gateway.proto.examples.EchoService.Echo:output_type -> grpc.gateway.proto.examples.SimpleMessage - 1, // 6: grpc.gateway.proto.examples.EchoService.EchoBody:output_type -> grpc.gateway.proto.examples.SimpleMessage - 1, // 7: grpc.gateway.proto.examples.EchoService.EchoDelete:output_type -> grpc.gateway.proto.examples.SimpleMessage - 5, // [5:8] is the sub-list for method output_type - 2, // [2:5] is the sub-list for method input_type - 2, // [2:2] is the sub-list for extension type_name - 2, // [2:2] is the sub-list for extension extendee - 0, // [0:2] is the sub-list for field type_name -} - -func init() { file_proto_examples_echo_service_proto_init() } -func file_proto_examples_echo_service_proto_init() { - if File_proto_examples_echo_service_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_proto_examples_echo_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Embedded); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_examples_echo_service_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SimpleMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - file_proto_examples_echo_service_proto_msgTypes[0].OneofWrappers = []interface{}{ - (*Embedded_Progress)(nil), - (*Embedded_Note)(nil), - } - file_proto_examples_echo_service_proto_msgTypes[1].OneofWrappers = []interface{}{ - (*SimpleMessage_LineNum)(nil), - (*SimpleMessage_Lang)(nil), - (*SimpleMessage_En)(nil), - (*SimpleMessage_No)(nil), - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_proto_examples_echo_service_proto_rawDesc, - NumEnums: 0, - NumMessages: 2, - NumExtensions: 0, - NumServices: 1, - }, - GoTypes: file_proto_examples_echo_service_proto_goTypes, - DependencyIndexes: file_proto_examples_echo_service_proto_depIdxs, - MessageInfos: file_proto_examples_echo_service_proto_msgTypes, - }.Build() - File_proto_examples_echo_service_proto = out.File - file_proto_examples_echo_service_proto_rawDesc = nil - file_proto_examples_echo_service_proto_goTypes = nil - file_proto_examples_echo_service_proto_depIdxs = nil -} diff --git a/proto/examples/echo_service_grpc.pb.go b/proto/examples/echo_service_grpc.pb.go deleted file mode 100755 index 91e6993..0000000 --- a/proto/examples/echo_service_grpc.pb.go +++ /dev/null @@ -1,158 +0,0 @@ -// Code generated by protoc-gen-go-grpc. DO NOT EDIT. - -package examples - -import ( - context "context" - grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" -) - -// 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.SupportPackageIsVersion6 - -// EchoServiceClient is the client API for EchoService service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. -type EchoServiceClient interface { - Echo(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) - EchoBody(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) - EchoDelete(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) -} - -type echoServiceClient struct { - cc grpc.ClientConnInterface -} - -func NewEchoServiceClient(cc grpc.ClientConnInterface) EchoServiceClient { - return &echoServiceClient{cc} -} - -func (c *echoServiceClient) Echo(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) { - out := new(SimpleMessage) - err := c.cc.Invoke(ctx, "/grpc.gateway.proto.examples.EchoService/Echo", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *echoServiceClient) EchoBody(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) { - out := new(SimpleMessage) - err := c.cc.Invoke(ctx, "/grpc.gateway.proto.examples.EchoService/EchoBody", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *echoServiceClient) EchoDelete(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) { - out := new(SimpleMessage) - err := c.cc.Invoke(ctx, "/grpc.gateway.proto.examples.EchoService/EchoDelete", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -// EchoServiceServer is the server API for EchoService service. -type EchoServiceServer interface { - Echo(context.Context, *SimpleMessage) (*SimpleMessage, error) - EchoBody(context.Context, *SimpleMessage) (*SimpleMessage, error) - EchoDelete(context.Context, *SimpleMessage) (*SimpleMessage, error) -} - -// UnimplementedEchoServiceServer can be embedded to have forward compatible implementations. -type UnimplementedEchoServiceServer struct { -} - -func (*UnimplementedEchoServiceServer) Echo(context.Context, *SimpleMessage) (*SimpleMessage, error) { - return nil, status.Errorf(codes.Unimplemented, "method Echo not implemented") -} -func (*UnimplementedEchoServiceServer) EchoBody(context.Context, *SimpleMessage) (*SimpleMessage, error) { - return nil, status.Errorf(codes.Unimplemented, "method EchoBody not implemented") -} -func (*UnimplementedEchoServiceServer) EchoDelete(context.Context, *SimpleMessage) (*SimpleMessage, error) { - return nil, status.Errorf(codes.Unimplemented, "method EchoDelete not implemented") -} - -func RegisterEchoServiceServer(s *grpc.Server, srv EchoServiceServer) { - s.RegisterService(&_EchoService_serviceDesc, srv) -} - -func _EchoService_Echo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(SimpleMessage) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(EchoServiceServer).Echo(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/grpc.gateway.proto.examples.EchoService/Echo", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(EchoServiceServer).Echo(ctx, req.(*SimpleMessage)) - } - return interceptor(ctx, in, info, handler) -} - -func _EchoService_EchoBody_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(SimpleMessage) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(EchoServiceServer).EchoBody(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/grpc.gateway.proto.examples.EchoService/EchoBody", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(EchoServiceServer).EchoBody(ctx, req.(*SimpleMessage)) - } - return interceptor(ctx, in, info, handler) -} - -func _EchoService_EchoDelete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(SimpleMessage) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(EchoServiceServer).EchoDelete(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/grpc.gateway.proto.examples.EchoService/EchoDelete", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(EchoServiceServer).EchoDelete(ctx, req.(*SimpleMessage)) - } - return interceptor(ctx, in, info, handler) -} - -var _EchoService_serviceDesc = grpc.ServiceDesc{ - ServiceName: "grpc.gateway.proto.examples.EchoService", - HandlerType: (*EchoServiceServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "Echo", - Handler: _EchoService_Echo_Handler, - }, - { - MethodName: "EchoBody", - Handler: _EchoService_EchoBody_Handler, - }, - { - MethodName: "EchoDelete", - Handler: _EchoService_EchoDelete_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "proto/examples/internal/echo_service.proto", -} diff --git a/repositories.bzl b/repositories.bzl index 2c22a00..7b65028 100644 --- a/repositories.bzl +++ b/repositories.bzl @@ -1,6 +1,12 @@ load("@bazel_gazelle//:deps.bzl", "go_repository") def go_repositories(): + go_repository( + name = "com_github_binchencoder_ease_gateway", + importpath = "github.com/binchencoder/ease-gateway", + sum = "h1:wYZv8TO4TGO2U8HjEO5Odf8OYWQjfrXS8ddfGZWQfHI=", + version = "v1.0.3", + ) go_repository( name = "com_github_binchencoder_letsgo", importpath = "github.com/binchencoder/letsgo", @@ -10,8 +16,8 @@ def go_repositories(): go_repository( name = "com_github_binchencoder_skylb_api", importpath = "github.com/binchencoder/skylb-api", - sum = "h1:neSwlmR8As4mQkT9ITFv5SLBZ5f45i+HwXzKPso8gn0=", - version = "v0.0.6", + sum = "h1:CUhectaG+rrLs9pnfS9lvg6LqLD8Il4GyRTlNXNmS8Q=", + version = "v0.3.1", ) go_repository( name = "com_github_binchencoder_gateway_proto", @@ -19,24 +25,23 @@ def go_repositories(): sum = "h1:ZvjzhU0CR93EdhqGtQj0Wkwd76D+KsvMuNEMAS1XVos=", version = "v0.0.8", ) - go_repository( - name = "com_github_grpc_ecosystem_grpc_gateway", - importpath = "github.com/grpc-ecosystem/grpc-gateway/v2", - sum = "h1:SLkFeyLhrg86Ny5Wme4MGGace7EHfgsb07uWX/QUGEQ=", - version = "v2.9.0", + name = "com_github_armon_circbuf", + importpath = "github.com/armon/circbuf", + sum = "h1:QEF07wC0T1rKkctt1RINW/+RMTVmiwxETico2l3gxJA=", + version = "v0.0.0-20150827004946-bbbad097214e", ) go_repository( - name = "com_github_grpc_ecosystem_grpc_opentracing", - importpath = "github.com/grpc-ecosystem/grpc-opentracing", - sum = "h1:MJG/KsmcqMwFAkh8mTnAwhyKoB+sTAnY4CACC110tbU=", - version = "v0.0.0-20180507213350-8e809c8a8645", + name = "com_github_armon_go_metrics", + importpath = "github.com/armon/go-metrics", + sum = "h1:8GUt8eRujhVEGZFFEjBj46YV4rDjvGrNxb0KMWYkL2I=", + version = "v0.0.0-20180917152333-f0300d1749da", ) go_repository( - name = "com_github_grpc_ecosystem_go_grpc_middleware", - importpath = "github.com/grpc-ecosystem/go-grpc-middleware", - sum = "h1:0IKlLyQ3Hs9nDaiK5cSHAGmcQEIC8l2Ts1u6x5Dfrqg=", - version = "v1.2.0", + name = "com_github_armon_go_radix", + importpath = "github.com/armon/go-radix", + sum = "h1:BUAU3CGlLvorLI26FmByPp2eC2qla6E1Tw+scpcg/to=", + version = "v0.0.0-20180808171621-7fddfc383310", ) go_repository( name = "com_github_beorn7_perks", @@ -56,6 +61,13 @@ def go_repositories(): sum = "h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=", version = "v1.7.0", ) + go_repository( + name = "com_github_fsnotify_fsnotify", + importpath = "github.com/fsnotify/fsnotify", + sum = "h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=", + version = "v1.4.7", + ) + go_repository( name = "com_github_ghodss_yaml", importpath = "github.com/ghodss/yaml", @@ -68,17 +80,31 @@ def go_repositories(): sum = "h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ=", version = "v1.0.0", ) + + go_repository( + name = "com_github_golang_groupcache", + importpath = "github.com/golang/groupcache", + sum = "h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=", + version = "v0.0.0-20200121045136-8c9f03a8e57e", + ) + go_repository( + name = "com_github_golang_mock", + importpath = "github.com/golang/mock", + sum = "h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=", + version = "v1.4.4", + ) go_repository( name = "com_github_golang_protobuf", importpath = "github.com/golang/protobuf", sum = "h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=", version = "v1.5.2", ) + go_repository( - name = "com_github_google_uuid", - importpath = "github.com/google/uuid", - sum = "h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=", - version = "v1.1.2", + name = "com_github_google_btree", + importpath = "github.com/google/btree", + sum = "h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=", + version = "v1.0.0", ) go_repository( name = "com_github_google_go_cmp", @@ -86,6 +112,7 @@ def go_repositories(): sum = "h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=", version = "v0.5.7", ) + go_repository( name = "com_github_klauspost_cpuid", importpath = "github.com/klauspost/cpuid", @@ -105,11 +132,36 @@ def go_repositories(): version = "v0.1.7", ) go_repository( - name = "com_github_pborman_uuid", - importpath = "github.com/pborman/uuid", - sum = "h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g=", + name = "com_github_google_uuid", + importpath = "github.com/google/uuid", + sum = "h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=", + version = "v1.1.2", + ) + + go_repository( + name = "com_github_grpc_ecosystem_go_grpc_middleware", + importpath = "github.com/grpc-ecosystem/go-grpc-middleware", + sum = "h1:Iju5GlWwrvL6UBg4zJJt3btmonfrMlCDdsejg4CZE7c=", + version = "v1.0.0", + ) + go_repository( + name = "com_github_grpc_ecosystem_go_grpc_prometheus", + importpath = "github.com/grpc-ecosystem/go-grpc-prometheus", + sum = "h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=", version = "v1.2.0", ) + go_repository( + name = "com_github_grpc_ecosystem_grpc_gateway", + importpath = "github.com/grpc-ecosystem/grpc-gateway/v2", + sum = "h1:SLkFeyLhrg86Ny5Wme4MGGace7EHfgsb07uWX/QUGEQ=", + version = "v2.9.0", + ) + go_repository( + name = "com_github_grpc_ecosystem_grpc_opentracing", + importpath = "github.com/grpc-ecosystem/grpc-opentracing", + sum = "h1:MJG/KsmcqMwFAkh8mTnAwhyKoB+sTAnY4CACC110tbU=", + version = "v0.0.0-20180507213350-8e809c8a8645", + ) go_repository( name = "com_github_go_kit_kit", importpath = "github.com/go-kit/kit", @@ -122,12 +174,6 @@ def go_repositories(): sum = "h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=", version = "v0.9.1", ) - go_repository( - name = "com_github_vividcortex_gohistogram", - importpath = "github.com/VividCortex/gohistogram", - sum = "h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE=", - version = "v1.0.0", - ) go_repository( name = "com_github_klauspost_compress", importpath = "github.com/klauspost/compress", @@ -146,11 +192,54 @@ def go_repositories(): sum = "h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=", version = "v1.0.1", ) + go_repository( - name = "com_github_stretchr_testify", - importpath = "github.com/stretchr/testify", - sum = "h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=", - version = "v1.7.0", + name = "com_github_pborman_uuid", + importpath = "github.com/pborman/uuid", + sum = "h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g=", + version = "v1.2.0", + ) + go_repository( + name = "com_github_prometheus_client_golang", + importpath = "github.com/prometheus/client_golang", + sum = "h1:9iH4JKXLzFbOAdtqv/a+j8aewx2Y8lAjAydhbaScPF8=", + version = "v0.9.3", + ) + go_repository( + name = "com_github_prometheus_client_model", + importpath = "github.com/prometheus/client_model", + sum = "h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM=", + version = "v0.0.0-20190812154241-14fe0d1b01d4", + ) + go_repository( + name = "com_github_prometheus_common", + importpath = "github.com/prometheus/common", + sum = "h1:7etb9YClo3a6HjLzfl6rIQaU+FDfi0VSX39io3aQ+DM=", + version = "v0.4.0", + ) + go_repository( + name = "com_github_prometheus_procfs", + importpath = "github.com/prometheus/procfs", + sum = "h1:sofwID9zm4tzrgykg80hfFph1mryUeLRsUfoocVVmRY=", + version = "v0.0.0-20190507164030-5867b95ac084", + ) + go_repository( + name = "com_github_prometheus_tsdb", + importpath = "github.com/prometheus/tsdb", + sum = "h1:YZcsG11NqnK4czYLrWd9mpEuAJIHVQLwdrleYfszMAA=", + version = "v0.7.1", + ) + go_repository( + name = "com_github_smartystreets_assertions", + importpath = "github.com/smartystreets/assertions", + sum = "h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=", + version = "v0.0.0-20180927180507-b2de0cb4f26d", + ) + go_repository( + name = "com_github_smartystreets_goconvey", + importpath = "github.com/smartystreets/goconvey", + sum = "h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=", + version = "v1.6.4", ) go_repository( name = "com_github_soheilhy_cmux", @@ -171,34 +260,28 @@ def go_repositories(): version = "v2.2.0+incompatible", ) go_repository( - name = "com_github_prometheus_client_golang", - importpath = "github.com/prometheus/client_golang", - sum = "h1:Y8E/JaaPbmFSW2V81Ab/d8yZFYQQGbni1b1jPcG9Y6A=", - version = "v0.9.4", - ) - go_repository( - name = "com_github_prometheus_client_model", - importpath = "github.com/prometheus/client_model", - sum = "h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=", - version = "v0.2.0", + name = "com_github_rogpeppe_fastuuid", + importpath = "github.com/rogpeppe/fastuuid", + sum = "h1:Ppwyp6VYCF1nvBTXL3trRso7mXMlRrw9ooo375wvi2s=", + version = "v1.2.0", ) go_repository( - name = "com_github_prometheus_common", - importpath = "github.com/prometheus/common", - sum = "h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc=", - version = "v0.10.0", + name = "com_github_stretchr_objx", + importpath = "github.com/stretchr/objx", + sum = "h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=", + version = "v0.1.0", ) go_repository( - name = "com_github_prometheus_procfs", - importpath = "github.com/prometheus/procfs", - sum = "h1:F0+tqvhOksq22sc6iCHF5WGlWjdwj92p0udFh1VFBS8=", - version = "v0.1.3", + name = "com_github_stretchr_testify", + importpath = "github.com/stretchr/testify", + sum = "h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=", + version = "v1.7.0", ) go_repository( - name = "com_github_rogpeppe_fastuuid", - importpath = "github.com/rogpeppe/fastuuid", - sum = "h1:Ppwyp6VYCF1nvBTXL3trRso7mXMlRrw9ooo375wvi2s=", - version = "v1.2.0", + name = "com_github_vividcortex_gohistogram", + importpath = "github.com/VividCortex/gohistogram", + sum = "h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE=", + version = "v1.0.0", ) go_repository( @@ -210,8 +293,8 @@ def go_repositories(): go_repository( name = "in_gopkg_yaml_v3", importpath = "gopkg.in/yaml.v3", - sum = "h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=", - version = "v3.0.0-20200615113413-eeeca48fe776", + sum = "h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=", + version = "v3.0.0-20200313102051-9f266ea9e77c", ) go_repository( name = "io_etcd_go_bbolt", @@ -229,8 +312,8 @@ def go_repositories(): go_repository( name = "org_golang_google_genproto", importpath = "google.golang.org/genproto", - sum = "h1:ErU+UA6wxadoU8nWrsy5MZUVBs75K17zUCsUCIfrXCE=", - version = "v0.0.0-20220314164441-57ef72a4c106", + sum = "h1:0m9wktIpOxGw+SSKmydXWB3Z3GTfcPP6+q75HCQa6HI=", + version = "v0.0.0-20220324131243-acbaeb5b85eb", ) go_repository( name = "org_golang_google_grpc", @@ -238,12 +321,7 @@ def go_repositories(): sum = "h1:NEpgUqV3Z+ZjkqMsxMg11IaDrXY4RY6CQukSGK0uI1M=", version = "v1.45.0", ) - # go_repository( - # name = "org_golang_google_grpc", - # importpath = "google.golang.org/grpc", - # sum = "h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4=", - # version = "v1.29.1", - # ) + go_repository( name = "org_golang_google_grpc_cmd_protoc_gen_go_grpc", importpath = "google.golang.org/grpc/cmd/protoc-gen-go-grpc", @@ -253,14 +331,8 @@ def go_repositories(): go_repository( name = "org_golang_google_protobuf", importpath = "google.golang.org/protobuf", - sum = "h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=", - version = "v1.27.1", - ) - go_repository( - name = "org_uber_go_atomic", - importpath = "go.uber.org/atomic", - sum = "h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=", - version = "v1.7.0", + sum = "h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=", + version = "v1.28.0", ) go_repository( name = "org_golang_x_crypto", @@ -356,4 +428,28 @@ def go_repositories(): importpath = "golang.org/x/xerrors", sum = "h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=", version = "v0.0.0-20200804184101-5ec99f83aff1", + ) + go_repository( + name = "org_uber_go_atomic", + importpath = "go.uber.org/atomic", + sum = "h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=", + version = "v1.7.0", + ) + go_repository( + name = "org_uber_go_multierr", + importpath = "go.uber.org/multierr", + sum = "h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=", + version = "v1.6.0", + ) + go_repository( + name = "org_uber_go_tools", + importpath = "go.uber.org/tools", + sum = "h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=", + version = "v0.0.0-20190618225709-2cfd321de3ee", + ) + go_repository( + name = "org_uber_go_zap", + importpath = "go.uber.org/zap", + sum = "h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM=", + version = "v1.16.0", ) \ No newline at end of file From d128c779803715527823cbffd1cb076077fa8902 Mon Sep 17 00:00:00 2001 From: chenbin1314 Date: Sun, 27 Mar 2022 16:14:39 +0800 Subject: [PATCH 42/56] Upgrade google.golang.org/protobuf to v1.28.0 --- go.mod | 2 +- go.sum | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 567506a..afdf64f 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a google.golang.org/genproto v0.0.0-20220314164441-57ef72a4c106 google.golang.org/grpc v1.45.0 - google.golang.org/protobuf v1.27.1 + google.golang.org/protobuf v1.28.0 gopkg.in/yaml.v2 v2.4.0 sigs.k8s.io/yaml v1.3.0 ) diff --git a/go.sum b/go.sum index 28d730c..43f6716 100644 --- a/go.sum +++ b/go.sum @@ -630,14 +630,13 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From 59f7bffc30a09684d8be7c65bcf38af8ed031a94 Mon Sep 17 00:00:00 2001 From: chenbin1314 Date: Sun, 27 Mar 2022 16:32:30 +0800 Subject: [PATCH 43/56] Update go.mod --- go.mod | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index afdf64f..8788eaa 100644 --- a/go.mod +++ b/go.mod @@ -5,12 +5,12 @@ go 1.17 require ( github.com/binchencoder/gateway-proto v0.0.7 github.com/binchencoder/letsgo v0.0.3 - github.com/binchencoder/skylb-api v0.2.0 + github.com/binchencoder/skylb-api v0.3.1 github.com/antihax/optional v1.0.0 github.com/golang/glog v1.0.0 github.com/golang/protobuf v1.5.2 github.com/google/go-cmp v0.5.7 - github.com/grpc-ecosystem/grpc-gateway/v2 v2.8.0 + github.com/grpc-ecosystem/grpc-gateway/v2 v2.9.0 github.com/rogpeppe/fastuuid v1.2.0 golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a google.golang.org/genproto v0.0.0-20220314164441-57ef72a4c106 From 3a3fd5829dd1be9c48ca02bed23ce0bc23c4cb10 Mon Sep 17 00:00:00 2001 From: binchencoder <15811514091@163.com> Date: Thu, 7 Apr 2022 17:59:37 +0800 Subject: [PATCH 44/56] Update Ease-Gateway.drawio --- docs/images/Ease-Gateway.drawio | 2 +- docs/images/Ease-Gateway.png | Bin 117260 -> 130330 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/images/Ease-Gateway.drawio b/docs/images/Ease-Gateway.drawio index eb6fe35..1019253 100644 --- a/docs/images/Ease-Gateway.drawio +++ b/docs/images/Ease-Gateway.drawio @@ -1 +1 @@ -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 \ No newline at end of file +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 \ No newline at end of file diff --git a/docs/images/Ease-Gateway.png b/docs/images/Ease-Gateway.png index 29674e2981c493388af6573d50a39486774a64a5..69d1ae2877d5eb84bb0d1a9e2aca5e7b4beb2555 100644 GIT binary patch literal 130330 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%0AYHy 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 b_g+v?x2~*?zO^12`1e5R;r&tt%aH#E8(#K; literal 117260 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 A@&Et; From 33da86511d1a9fc4992cea459f3db9a5d3049075 Mon Sep 17 00:00:00 2001 From: binchencoder <15811514091@163.com> Date: Thu, 14 Apr 2022 12:38:46 +0800 Subject: [PATCH 45/56] Add example-grpc-client --- .../cmd/example-grpc-client/BUILD.bazel | 29 ++++++ .../internal/cmd/example-grpc-client/main.go | 97 +++++++++++++++++++ .../cmd/example-grpc-server/BUILD.bazel | 1 + .../internal/cmd/example-grpc-server/main.go | 17 +++- repositories.bzl | 17 ++-- 5 files changed, 151 insertions(+), 10 deletions(-) create mode 100644 examples/internal/cmd/example-grpc-client/BUILD.bazel create mode 100644 examples/internal/cmd/example-grpc-client/main.go diff --git a/examples/internal/cmd/example-grpc-client/BUILD.bazel b/examples/internal/cmd/example-grpc-client/BUILD.bazel new file mode 100644 index 0000000..1d2326d --- /dev/null +++ b/examples/internal/cmd/example-grpc-client/BUILD.bazel @@ -0,0 +1,29 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library") + +package(default_visibility = ["//visibility:private"]) + +go_library( + name = "go_default_library", + srcs = ["main.go"], + importpath = "github.com/binchencoder/ease-gateway/examples/internal/cmd/example-grpc-client", + deps = [ + "//examples/internal/proto/examplepb:go_default_library", + "//examples/internal/server:go_default_library", + "@com_github_binchencoder_letsgo//:go_default_library", + "@com_github_binchencoder_gateway_proto//data:go_default_library", + "@com_github_binchencoder_skylb_api//client:go_default_library", + "@com_github_binchencoder_skylb_api//proto:go_default_library", + "@com_github_binchencoder_skylb_api//server:go_default_library", + "@com_github_golang_glog//:go_default_library", + "@com_github_prometheus_client_golang//prometheus:go_default_library", + "@org_golang_x_net//context:go_default_library", + "@org_golang_google_grpc//:go_default_library", + "@org_golang_google_grpc//health/grpc_health_v1:go_default_library", + ], +) + +go_binary( + name = "example-grpc-client", + embed = [":go_default_library"], + visibility = ["//visibility:public"], +) \ No newline at end of file diff --git a/examples/internal/cmd/example-grpc-client/main.go b/examples/internal/cmd/example-grpc-client/main.go new file mode 100644 index 0000000..35d689d --- /dev/null +++ b/examples/internal/cmd/example-grpc-client/main.go @@ -0,0 +1,97 @@ +package main + +import ( + "flag" + "fmt" + "os" + "time" + + "github.com/golang/glog" + prom "github.com/prometheus/client_golang/prometheus" + "golang.org/x/net/context" + "google.golang.org/grpc" + hpb "google.golang.org/grpc/health/grpc_health_v1" + + examplepb "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb" + vexpb "github.com/binchencoder/gateway-proto/data" + "github.com/binchencoder/letsgo" + skylb "github.com/binchencoder/skylb-api/client" + skypb "github.com/binchencoder/skylb-api/proto" +) + +var ( + nBatchRequest = flag.Int("n-batch-request", 10000, "The number of batched request") + requestSleep = flag.Duration("request-sleep", 100*time.Millisecond, "The sleep time after each request") + requestTimeout = flag.Duration("request-timeout", 100*time.Millisecond, "The timeout of each request") + + spec = skylb.NewServiceSpec(skylb.DefaultNameSpace, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, skylb.DefaultPortName) + + grpcFailCount = prom.NewCounter( + prom.CounterOpts{ + Namespace: "skytest", + Subsystem: "client", + Name: "grpc_call_failure", + Help: "The number of failed gRPC calls.", + }, + ) +) + +func startSkylb(sid vexpb.ServiceId) (skylb.ServiceCli, examplepb.EchoServiceClient, hpb.HealthClient) { + skycli := skylb.NewServiceCli(vexpb.ServiceId_SHARED_TEST_CLIENT_SERVICE) + options := []grpc.DialOption{} + options = append(options, grpc.WithDefaultServiceConfig(`{"loadBalancingConfig": [{"round_robin": {}}]}`)) + skycli.Resolve(skylb.NewServiceSpec(skylb.DefaultNameSpace, sid, skylb.DefaultPortName), options...) + skycli.EnableHistogram() + var cli examplepb.EchoServiceClient + var healthCli hpb.HealthClient + skycli.Start(func(spec *skypb.ServiceSpec, conn *grpc.ClientConn) { + cli = examplepb.NewEchoServiceClient(conn) + healthCli = hpb.NewHealthClient(conn) + }) + return skycli, cli, healthCli +} + +func usage() { + fmt.Println(`Skytest gRPC client. + +Usage: + skytest-client [options] + +Options:`) + + flag.PrintDefaults() + os.Exit(2) +} + +func main() { + letsgo.Init(letsgo.FlagUsage(usage)) + + testClient() +} + +func testClient() { + sl, cli, healthCli := startSkylb(vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST) + for { + for i := 0; i < *nBatchRequest; i++ { + req := examplepb.SimpleMessage{ + Id: fmt.Sprintf("John Doe %d", time.Now().Second()), + } + ctx, cancel := context.WithTimeout(context.Background(), *requestTimeout) + _, err := cli.Echo(ctx, &req, grpc.FailFast(false)) + if err != nil { + cancel() + glog.Errorf("Failed to greet service, %v \n", err) + grpcFailCount.Inc() + time.Sleep(*requestTimeout) + continue + } + + // glog.Infof("Greeting resp: %v \n", resp) + + healthCli.Check(context.Background(), &hpb.HealthCheckRequest{}) + time.Sleep(*requestSleep) + } + } + + sl.Shutdown() +} diff --git a/examples/internal/cmd/example-grpc-server/BUILD.bazel b/examples/internal/cmd/example-grpc-server/BUILD.bazel index 2c690d0..9ccd69a 100644 --- a/examples/internal/cmd/example-grpc-server/BUILD.bazel +++ b/examples/internal/cmd/example-grpc-server/BUILD.bazel @@ -12,6 +12,7 @@ go_library( "@com_github_binchencoder_gateway_proto//data:go_default_library", "@com_github_binchencoder_skylb_api//server:go_default_library", "@com_github_golang_glog//:go_default_library", + "@com_github_prometheus_client_golang//prometheus:go_default_library", "@org_golang_google_grpc//:go_default_library", ], ) diff --git a/examples/internal/cmd/example-grpc-server/main.go b/examples/internal/cmd/example-grpc-server/main.go index 1482ee4..633154e 100644 --- a/examples/internal/cmd/example-grpc-server/main.go +++ b/examples/internal/cmd/example-grpc-server/main.go @@ -7,8 +7,11 @@ package main import ( "flag" "fmt" + "log" + "net/http" examplepb "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb" + "github.com/prometheus/client_golang/prometheus" "github.com/binchencoder/gateway-proto/data" skylb "github.com/binchencoder/skylb-api/server" @@ -19,12 +22,20 @@ import ( ) var ( - addr = flag.String("addr", ":9090", "endpoint of the gRPC service") - network = flag.String("network", "tcp", "a valid network type which is consistent to -addr") + addr = flag.String("addr", ":9090", "endpoint of the gRPC service") + network = flag.String("network", "tcp", "a valid network type which is consistent to -addr") + scrapeAddr = flag.String("scrape-addr", "0.0.0.0:18001", "The prometheus scrape port") port = flag.Int("port", 9090, "The gRPC port of the server") ) +func registerPrometheus() { + http.Handle("/_/metrics", prometheus.UninstrumentedHandler()) + if err := http.ListenAndServe(*scrapeAddr, nil); err != nil { + log.Fatal("ListenServerError:", err) + } +} + func main() { flag.Parse() defer glog.Flush() @@ -35,6 +46,8 @@ func main() { // glog.Fatal(err) // } + go registerPrometheus() + skylb.Register(data.ServiceId_CUSTOM_EASE_GATEWAY_TEST, "grpc", *port) skylb.EnableHistogram() skylb.Start(fmt.Sprintf(":%d", *port), func(s *grpc.Server) error { diff --git a/repositories.bzl b/repositories.bzl index 7b65028..4cbd74e 100644 --- a/repositories.bzl +++ b/repositories.bzl @@ -199,29 +199,30 @@ def go_repositories(): sum = "h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g=", version = "v1.2.0", ) + # Prometheus go_repository( name = "com_github_prometheus_client_golang", importpath = "github.com/prometheus/client_golang", - sum = "h1:9iH4JKXLzFbOAdtqv/a+j8aewx2Y8lAjAydhbaScPF8=", - version = "v0.9.3", + sum = "h1:Y8E/JaaPbmFSW2V81Ab/d8yZFYQQGbni1b1jPcG9Y6A=", + version = "v0.9.4", ) go_repository( name = "com_github_prometheus_client_model", importpath = "github.com/prometheus/client_model", - sum = "h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM=", - version = "v0.0.0-20190812154241-14fe0d1b01d4", + sum = "h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=", + version = "v0.2.0", ) go_repository( name = "com_github_prometheus_common", importpath = "github.com/prometheus/common", - sum = "h1:7etb9YClo3a6HjLzfl6rIQaU+FDfi0VSX39io3aQ+DM=", - version = "v0.4.0", + sum = "h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc=", + version = "v0.10.0", ) go_repository( name = "com_github_prometheus_procfs", importpath = "github.com/prometheus/procfs", - sum = "h1:sofwID9zm4tzrgykg80hfFph1mryUeLRsUfoocVVmRY=", - version = "v0.0.0-20190507164030-5867b95ac084", + sum = "h1:F0+tqvhOksq22sc6iCHF5WGlWjdwj92p0udFh1VFBS8=", + version = "v0.1.3", ) go_repository( name = "com_github_prometheus_tsdb", From 098f40df6b4c31e1cb75a8eb0e339909aa9fc2f1 Mon Sep 17 00:00:00 2001 From: binchencoder <15811514091@163.com> Date: Fri, 15 Apr 2022 22:00:58 +0800 Subject: [PATCH 46/56] Add gateway client for test. --- .../cmd/example-grpc-client/BUILD.bazel | 14 +++- .../cmd/example-grpc-client/gatewayclient.go | 83 +++++++++++++++++++ .../{main.go => grpcclient.go} | 2 + 3 files changed, 97 insertions(+), 2 deletions(-) create mode 100644 examples/internal/cmd/example-grpc-client/gatewayclient.go rename examples/internal/cmd/example-grpc-client/{main.go => grpcclient.go} (99%) diff --git a/examples/internal/cmd/example-grpc-client/BUILD.bazel b/examples/internal/cmd/example-grpc-client/BUILD.bazel index 1d2326d..f91e673 100644 --- a/examples/internal/cmd/example-grpc-client/BUILD.bazel +++ b/examples/internal/cmd/example-grpc-client/BUILD.bazel @@ -4,7 +4,7 @@ package(default_visibility = ["//visibility:private"]) go_library( name = "go_default_library", - srcs = ["main.go"], + srcs = ["grpcclient.go"], importpath = "github.com/binchencoder/ease-gateway/examples/internal/cmd/example-grpc-client", deps = [ "//examples/internal/proto/examplepb:go_default_library", @@ -23,7 +23,17 @@ go_library( ) go_binary( - name = "example-grpc-client", + name = "grpc-client", embed = [":go_default_library"], visibility = ["//visibility:public"], +) + +go_binary( + name = "gateway-client", + srcs = ["gatewayclient.go"], + deps = [ + "//examples/internal/proto/examplepb:go_default_library", + "@com_github_binchencoder_letsgo//:go_default_library", + "@com_github_golang_protobuf//jsonpb:go_default_library", + ] ) \ No newline at end of file diff --git a/examples/internal/cmd/example-grpc-client/gatewayclient.go b/examples/internal/cmd/example-grpc-client/gatewayclient.go new file mode 100644 index 0000000..01f3b10 --- /dev/null +++ b/examples/internal/cmd/example-grpc-client/gatewayclient.go @@ -0,0 +1,83 @@ +package main + +import ( + "flag" + "fmt" + "io/ioutil" + "log" + "net/http" + "time" + + "github.com/golang/protobuf/jsonpb" + + examplepb "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb" + "github.com/binchencoder/letsgo" +) + +const urlPattern = "http://%s/v1/example/echo/2211/1" + +var ( + flagServer = flag.String("server", "localhost:8080", "The server host:port") + onceOnly = flag.Bool("send-once", false, "Send the request once only") + clientId = flag.String("client-id", "", "Client ID") + xSource = flag.String("x-source", "web", "X-Source to use") +) + +func main() { + letsgo.Init() + + url := fmt.Sprintf(urlPattern, *flagServer) + + // If specified, send request once and return. + if *onceOnly { + sendRequest(url) + return + } + + for i := 0; i < 10; i++ { + go func() { + for range time.Tick(50 * time.Millisecond) { + sendRequest(url) + } + }() + } + + select {} +} + +func sendRequest(url string) { + req, err := http.NewRequest("GET", url, nil) + if err != nil { + log.Println("NewRequest: ", err) + return + } + req.Header.Set("x-source", *xSource) + req.Header.Set("Content-Type", "application/json") + req.Header.Set("x-Uid", "marlin") + req.Header.Set("X-Cid", "disney") + + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + log.Fatal("Do: ", err) + return + } + defer resp.Body.Close() + + if resp.StatusCode == 200 { + bodyBytes, err := ioutil.ReadAll(resp.Body) + if err != nil { + log.Println(err) + return + } + + record := examplepb.SimpleMessage{} + if err = jsonpb.UnmarshalString(string(bodyBytes), &record); err != nil { + log.Println(err) + return + } + fmt.Printf("%d, resp: %+v.\n", resp.StatusCode, record) + } else { + fmt.Println(resp.StatusCode) + } +} diff --git a/examples/internal/cmd/example-grpc-client/main.go b/examples/internal/cmd/example-grpc-client/grpcclient.go similarity index 99% rename from examples/internal/cmd/example-grpc-client/main.go rename to examples/internal/cmd/example-grpc-client/grpcclient.go index 35d689d..fc4b664 100644 --- a/examples/internal/cmd/example-grpc-client/main.go +++ b/examples/internal/cmd/example-grpc-client/grpcclient.go @@ -38,10 +38,12 @@ var ( func startSkylb(sid vexpb.ServiceId) (skylb.ServiceCli, examplepb.EchoServiceClient, hpb.HealthClient) { skycli := skylb.NewServiceCli(vexpb.ServiceId_SHARED_TEST_CLIENT_SERVICE) + options := []grpc.DialOption{} options = append(options, grpc.WithDefaultServiceConfig(`{"loadBalancingConfig": [{"round_robin": {}}]}`)) skycli.Resolve(skylb.NewServiceSpec(skylb.DefaultNameSpace, sid, skylb.DefaultPortName), options...) skycli.EnableHistogram() + var cli examplepb.EchoServiceClient var healthCli hpb.HealthClient skycli.Start(func(spec *skypb.ServiceSpec, conn *grpc.ClientConn) { From a8cabc5c5c50d32f86101feb659a417651c0d423 Mon Sep 17 00:00:00 2001 From: binchencoder <15811514091@163.com> Date: Fri, 15 Apr 2022 22:37:33 +0800 Subject: [PATCH 47/56] =?UTF-8?q?=E8=A7=A3=E5=86=B3custom=20gateway=20ctrl?= =?UTF-8?q?+c=20=E6=97=A0=E6=B3=95=E5=81=9C=E6=8E=89=E8=BF=9B=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cmd/custom-gateway/BUILD.bazel | 1 + cmd/custom-gateway/main.go | 14 +++++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/cmd/custom-gateway/BUILD.bazel b/cmd/custom-gateway/BUILD.bazel index 2d65430..a7bd2df 100644 --- a/cmd/custom-gateway/BUILD.bazel +++ b/cmd/custom-gateway/BUILD.bazel @@ -18,6 +18,7 @@ go_library( "//examples/internal/proto/examplepb", "//gateway/runtime", "//integrate:go_default_library", + "//util:go_default_library", "@com_github_binchencoder_gateway_proto//data:go_default_library", "@com_github_binchencoder_letsgo//:go_default_library", "@com_github_golang_glog//:go_default_library", diff --git a/cmd/custom-gateway/main.go b/cmd/custom-gateway/main.go index 26f65e5..0da3ac8 100644 --- a/cmd/custom-gateway/main.go +++ b/cmd/custom-gateway/main.go @@ -11,6 +11,7 @@ import ( "github.com/binchencoder/ease-gateway/gateway/runtime" "github.com/binchencoder/ease-gateway/integrate" + "github.com/binchencoder/ease-gateway/util" "github.com/binchencoder/gateway-proto/data" "github.com/binchencoder/letsgo" ) @@ -34,6 +35,8 @@ Options:`) func startHTTPGateway(mux *runtime.ServeMux, hostPort string) { if err := http.ListenAndServe(hostPort, integrate.HttpMux(mux)); err != nil { + glog.Errorf("Start http gateway error: %v", err) + shutdown() panic(err) } } @@ -60,5 +63,14 @@ func main() { signals := make(chan os.Signal, 1) signal.Notify(signals, os.Interrupt, os.Kill) - startHTTPGateway(mux, hostPort) + go startHTTPGateway(mux, hostPort) + + select { + case <-signals: + shutdown() + } +} + +func shutdown() { + util.Flush() } From f721507a6e2daf62546b231e456a60d845a57aa6 Mon Sep 17 00:00:00 2001 From: binchencoder <15811514091@163.com> Date: Sat, 23 Apr 2022 19:34:58 +0800 Subject: [PATCH 48/56] Rename ease-gateway to janus-gateway --- .circleci/README.md | 2 +- .circleci/config.yml | 20 ++-- .gitignore | 2 +- BUILD | 2 +- Issues.md | 8 +- README.md | 16 +-- WORKSPACE | 26 ++--- cmd/custom-gateway/BUILD.bazel | 4 +- cmd/custom-gateway/main.go | 10 +- cmd/custom-gateway/registrydemo.go | 2 +- cmd/gateway/BUILD.bazel | 12 +-- cmd/gateway/main.go | 12 +-- cmd/gateway/registryprod.go | 2 +- docs/design.md | 28 ++--- docs/gateway-validation-rule.md | 16 +-- docs/scripts/start.sh | 6 +- docs/scripts/stop.sh | 4 +- examples/grpc-server/BUILD.bazel | 2 +- examples/grpc-server/echo.go | 2 +- examples/grpc-server/main.go | 2 +- examples/internal/README.md | 12 +-- .../cmd/example-gateway-server/BUILD.bazel | 2 +- .../cmd/example-gateway-server/main.go | 2 +- .../cmd/example-grpc-client/BUILD.bazel | 2 +- .../cmd/example-grpc-client/gatewayclient.go | 2 +- .../cmd/example-grpc-client/grpcclient.go | 2 +- .../cmd/example-grpc-server/BUILD.bazel | 2 +- .../internal/cmd/example-grpc-server/main.go | 4 +- examples/internal/gateway/BUILD.bazel | 2 +- examples/internal/gateway/gateway.go | 4 +- examples/internal/gateway/main.go | 2 +- examples/internal/integration/README.md | 2 +- .../internal/integration/integration_test.go | 4 +- examples/internal/integration/main_test.go | 6 +- examples/internal/proto/examplepb/BUILD.bazel | 4 +- .../proto/examplepb/echo_service.pb.go | 2 +- .../proto/examplepb/echo_service.pb.gw.go | 2 +- .../proto/examplepb/echo_service.proto | 18 ++-- .../proto/examplepb/generated_input.proto | 2 +- .../examplepb/unannotated_echo_service.pb.go | 2 +- .../examplepb/unannotated_echo_service.proto | 4 +- examples/internal/server/BUILD.bazel | 2 +- examples/internal/server/echo.go | 2 +- examples/internal/server/main.go | 4 +- gateway/README.md | 2 +- gateway/internal/BUILD.bazel | 4 +- gateway/internal/casing/BUILD.bazel | 2 +- gateway/internal/descriptor/BUILD.bazel | 2 +- .../internal/descriptor/apiconfig/BUILD.bazel | 4 +- .../descriptor/apiconfig/apiconfig.pb.go | 4 +- .../descriptor/apiconfig/apiconfig.proto | 4 +- .../descriptor/grpc_api_configuration.go | 2 +- .../descriptor/openapi_configuration.go | 2 +- .../descriptor/openapi_configuration_test.go | 2 +- .../descriptor/openapiconfig/BUILD.bazel | 4 +- .../openapiconfig/openapiconfig.pb.go | 2 +- .../openapiconfig/openapiconfig.proto | 2 +- gateway/internal/descriptor/registry.go | 6 +- gateway/internal/descriptor/registry_test.go | 2 +- gateway/internal/descriptor/services.go | 6 +- gateway/internal/descriptor/types.go | 4 +- gateway/internal/generator/BUILD.bazel | 2 +- gateway/internal/generator/generator.go | 2 +- gateway/protoc-gen-grpc-gateway/BUILD.bazel | 2 +- .../internal/gengateway/BUILD.bazel | 2 +- .../internal/gengateway/generator.go | 6 +- .../internal/gengateway/generator_test.go | 2 +- .../internal/gengateway/template.go | 4 +- .../internal/gengateway/template_test.go | 2 +- gateway/protoc-gen-grpc-gateway/main.go | 4 +- gateway/protoc-gen-grpc-gateway/main_test.go | 2 +- gateway/protoc-gen-openapiv2/BUILD.bazel | 2 +- .../internal/genopenapi/BUILD.bazel | 2 +- .../internal/genopenapi/generator.go | 6 +- .../internal/genopenapi/template.go | 8 +- .../internal/genopenapi/types.go | 4 +- gateway/protoc-gen-openapiv2/main.go | 4 +- .../protoc-gen-openapiv2/options/BUILD.bazel | 4 +- .../options/annotations.proto | 2 +- .../options/openapiv2.proto | 2 +- gateway/runtime/BUILD.bazel | 2 +- gateway/runtime/balancer.go | 2 +- gateway/runtime/balancer_test.go | 4 +- gateway/runtime/context_test.go | 2 +- gateway/runtime/convert_test.go | 2 +- gateway/runtime/errors.go | 2 +- gateway/runtime/errors_test.go | 2 +- gateway/runtime/handler_test.go | 4 +- .../runtime/internal/examplepb/BUILD.bazel | 4 +- .../runtime/internal/examplepb/proto3.pb.go | 100 +++++++++--------- .../runtime/internal/examplepb/proto3.proto | 4 +- gateway/runtime/marshal_httpbodyproto_test.go | 2 +- gateway/runtime/marshaler_registry_test.go | 2 +- gateway/runtime/mux_test.go | 2 +- gateway/runtime/service.go | 4 +- go.mod | 2 +- go.sum | 2 +- httpoptions/BUILD.bazel | 4 +- httpoptions/annotations.pb.go | 88 +++++++-------- httpoptions/annotations.proto | 10 +- httpoptions/http.pb.go | 12 +-- httpoptions/http.proto | 6 +- httpoptions/pom.xml | 4 +- integrate/BUILD.bazel | 2 +- integrate/hook.go | 14 +-- integrate/hookexternal.go | 10 +- integrate/metrics/BUILD | 2 +- integrate/metrics/reporter.go | 4 +- integrate/middleware.go | 2 +- proto/examplepb/BUILD.bazel | 4 +- proto/examplepb/echo_service.proto | 14 +-- repositories.bzl | 4 +- util/BUILD.bazel | 2 +- util/glog/BUILD.bazel | 2 +- util/glog/cmd/BUILD.bazel | 2 +- util/glog/cmd/main.go | 2 +- util/log.go | 8 +- 117 files changed, 361 insertions(+), 361 deletions(-) diff --git a/.circleci/README.md b/.circleci/README.md index 70cf33b..bbdcc3b 100644 --- a/.circleci/README.md +++ b/.circleci/README.md @@ -5,4 +5,4 @@ Contained within is the CI test setup for the Gateway. It runs on Circle CI. ### Whats up with the Dockerfile? The `Dockerfile` in this folder is used as the build environment when regenerating the files (see CONTRIBUTING.md). -The canonical repository for this Dockerfile is `docker.pkg.github.com/binchencoder/ease-gateway/build-env`. +The canonical repository for this Dockerfile is `docker.pkg.github.com/binchencoder/janus-gateway/build-env`. diff --git a/.circleci/config.yml b/.circleci/config.yml index 5894410..076541f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -41,7 +41,7 @@ executors: password1: "3ec86b2e5a431be2d72c" GLOG_logtostderr: "1" docker: - - image: docker.pkg.github.com/binchencoder/ease-gateway/build-env:1.15 + - image: docker.pkg.github.com/binchencoder/janus-gateway/build-env:1.15 auth: username: gateway-ci-user password: ${password0}${password1} @@ -49,20 +49,20 @@ executors: jobs: build: executor: build-env - working_directory: /home/vscode/src/ease-gateway + working_directory: /home/vscode/src/janus-gateway steps: - checkout - run: go build ./... test: executor: build-env - working_directory: /home/vscode/src/ease-gateway + working_directory: /home/vscode/src/janus-gateway steps: - checkout - run: go test -race -coverprofile=coverage.txt ./... - run: bash <(curl -s https://codecov.io/bash) node_test: executor: build-env - working_directory: /home/vscode/src/ease-gateway + working_directory: /home/vscode/src/janus-gateway steps: - checkout - run: go mod vendor @@ -73,14 +73,14 @@ jobs: ./node_modules/.bin/gulp generate: executor: build-env - working_directory: /home/vscode/src/ease-gateway + working_directory: /home/vscode/src/janus-gateway steps: - checkout - generate - run: git diff --exit-code bazel: executor: build-env - working_directory: /home/vscode/src/ease-gateway + working_directory: /home/vscode/src/janus-gateway steps: - checkout - restore_cache: @@ -112,7 +112,7 @@ jobs: - /home/vscode/.cache/_ease_gateway_bazel gorelease: executor: build-env - working_directory: /home/vscode/src/ease-gateway + working_directory: /home/vscode/src/janus-gateway steps: - checkout - run: @@ -156,14 +156,14 @@ jobs: - run: BUF_TOKEN="${BUF_API_TOKEN}" buf push --tag "$CIRCLE_SHA1" release: executor: build-env - working_directory: /home/vscode/src/ease-gateway + working_directory: /home/vscode/src/janus-gateway steps: - checkout - run: go mod vendor - run: curl -sL https://git.io/goreleaser | bash update-repositoriesbzl: executor: build-env - working_directory: /home/vscode/src/ease-gateway + working_directory: /home/vscode/src/janus-gateway steps: - checkout - restore_cache: @@ -178,7 +178,7 @@ jobs: - renovate_git_amend_push regenerate: executor: build-env - working_directory: /home/vscode/src/ease-gateway + working_directory: /home/vscode/src/janus-gateway steps: - checkout - generate diff --git a/.gitignore b/.gitignore index 649d93d..82c6465 100644 --- a/.gitignore +++ b/.gitignore @@ -14,7 +14,7 @@ _output/ # Bazel. bazel-bin bazel-genfiles -bazel-ease-gateway +bazel-janus-gateway bazel-out bazel-testlogs *.bin diff --git a/BUILD b/BUILD index cf3996f..581db5d 100644 --- a/BUILD +++ b/BUILD @@ -15,7 +15,7 @@ buildifier( ) # gazelle:exclude _output -# gazelle:prefix github.com/binchencoder/ease-gateway/gateway +# gazelle:prefix github.com/binchencoder/janus-gateway/gateway # gazelle:go_proto_compilers //:go_apiv2 # gazelle:go_grpc_compilers //:go_apiv2, //:go_grpc # gazelle:go_naming_convention import_alias diff --git a/Issues.md b/Issues.md index 249004e..f38b53e 100644 --- a/Issues.md +++ b/Issues.md @@ -24,7 +24,7 @@ org_golang_google_grpc 最新版本已经升级到v1.33.1,编译会出现如下error: ```verilog - chenbin@chenbin-ThinkPad:~/.../github-workspace/ease-gateway$ bazel build gateway/... + chenbin@chenbin-ThinkPad:~/.../github-workspace/janus-gateway$ bazel build gateway/... ERROR: /home/chenbin/.cache/bazel/_bazel_chenbin/95d98bab223e52f58e53a4599e22df3c/external/com_github_binchencoder_skylb_api/balancer/BUILD:5:1: no such package '@org_golang_google_grpc//naming': BUILD file not found in directory 'naming' of external repository @org_golang_google_grpc. Add a BUILD file to a directory to mark it as a package. and referenced by '@com_github_binchencoder_skylb_api//balancer:go_default_library' ERROR: Analysis of target '//gateway/runtime:go_default_test' failed; build aborted: no such package '@org_golang_google_grpc//naming': BUILD file not found in directory 'naming' of external repository @org_golang_google_grpc. Add a BUILD file to a directory to mark it as a package. INFO: Elapsed time: 3.781s @@ -52,16 +52,16 @@ ) ``` - github.com/grpc-ecosystem/grpc-gateway 使用 org_golang_google_grpc_cmd_protoc_gen_go_grpc的版本是v1.0.0,ease-gateway 升级会出现如下error: + github.com/grpc-ecosystem/grpc-gateway 使用 org_golang_google_grpc_cmd_protoc_gen_go_grpc的版本是v1.0.0,janus-gateway 升级会出现如下error: ```verilog - chenbin@chenbin-ThinkPad:~/.../github-workspace/ease-gateway$ bazel build gateway/... + chenbin@chenbin-ThinkPad:~/.../github-workspace/janus-gateway$ bazel build gateway/... INFO: Analyzed 32 targets (103 packages loaded, 1391 targets configured). INFO: Found 32 targets... ERROR: /home/chenbin/.cache/bazel/_bazel_chenbin/95d98bab223e52f58e53a4599e22df3c/external/com_github_grpc_ecosystem_grpc_gateway/runtime/internal/examplepb/BUILD.bazel:39:1: GoCompilePkg external/com_github_grpc_ecosystem_grpc_gateway/runtime/internal/examplepb/go_default_library.a failed (Exit 1) builder failed: error executing command bazel-out/host/bin/external/go_sdk/builder compilepkg -sdk external/go_sdk -installsuffix linux_amd64 -src ... (remaining 67 argument(s) skipped) Use --sandbox_debug to see verbose messages from the sandbox - /home/chenbin/.cache/bazel/_bazel_chenbin/95d98bab223e52f58e53a4599e22df3c/sandbox/linux-sandbox/845/execroot/com_github_binchencoder_ease_gateway/bazel-out/k8-fastbuild/bin/external/com_github_grpc_ecosystem_grpc_gateway/runtime/internal/examplepb/examplepb_go_proto_/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/internal/examplepb/non_standard_names_grpc.pb.go:14:11: undefined: grpc.SupportPackageIsVersion7 + /home/chenbin/.cache/bazel/_bazel_chenbin/95d98bab223e52f58e53a4599e22df3c/sandbox/linux-sandbox/845/execroot/com_github_binchencoder_janus_gateway/bazel-out/k8-fastbuild/bin/external/com_github_grpc_ecosystem_grpc_gateway/runtime/internal/examplepb/examplepb_go_proto_/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/internal/examplepb/non_standard_names_grpc.pb.go:14:11: undefined: grpc.SupportPackageIsVersion7 compilepkg: error running subcommand external/go_sdk/pkg/tool/linux_amd64/compile: exit status 2 INFO: Elapsed time: 11.320s, Critical Path: 1.12s INFO: 5 processes: 5 linux-sandbox. diff --git a/README.md b/README.md index c5236f9..be219a7 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Ease-gateway +# Janus-gateway Gateway service based on [grpc-ecosystem/grpc-gateway](https://github.com/grpc-ecosystem/grpc-gateway). This helps you provide your APIs in both gRPC and RESTful style at the same time. @@ -8,7 +8,7 @@ Gateway service based on [grpc-ecosystem/grpc-gateway](https://github.com/grpc-e **grpc-gateway** 的出现更能引起开发者对使用gRPC的兴趣, 她可以帮你在原有gRPC服务的基础上做少量的改动, 便可以将原gRPC服务同时提供RESTful HTTP API, 了解更多RESTful API的例子可以参考[GitHub REST API](https://developer.github.com/v3/) 、[Google REST API](https://developers.google.com/drive/v2/reference/) -**ease-gateway** 是站在巨人的肩膀上实现的, 增加了更符合企业级应用开发的**Features**: +**janus-gateway** 是站在巨人的肩膀上实现的, 增加了更符合企业级应用开发的**Features**: - 支持自定义的LoadBalancer - 既可以部署单机版模式, 也可注册到注册中心实现集群模式 @@ -21,15 +21,15 @@ Gateway service based on [grpc-ecosystem/grpc-gateway](https://github.com/grpc-e ## Design -[design.md](https://github.com/binchencoder/ease-gateway/tree/master/docs/design.md) +[design.md](https://github.com/binchencoder/janus-gateway/tree/master/docs/design.md) ## Validation Rule -[gateway-validation-rule.md](https://github.com/binchencoder/ease-gateway/tree/master/docs/gateway-validation-rule.md) +[gateway-validation-rule.md](https://github.com/binchencoder/janus-gateway/tree/master/docs/gateway-validation-rule.md) ## Prepared -**ease-gateway** 使用GO MOD来管理Dependencies,clone代码之后直接在本地使用bazel构建 +**janus-gateway** 使用GO MOD来管理Dependencies,clone代码之后直接在本地使用bazel构建 ### Build tools @@ -39,13 +39,13 @@ Gateway service based on [grpc-ecosystem/grpc-gateway](https://github.com/grpc-e ## Clone code ```shell -git clone https://github.com/binchencoder/ease-gateway.git +git clone https://github.com/binchencoder/janus-gateway.git ``` ## Bazel build gateway ``` -cd ease-gateway +cd janus-gateway bazel build cmd/gateway/... ``` @@ -56,4 +56,4 @@ TODO ## Run Examples -See [examples/README.md](https://github.com/binchencoder/ease-gateway/tree/master/examples) +See [examples/README.md](https://github.com/binchencoder/janus-gateway/tree/master/examples) diff --git a/WORKSPACE b/WORKSPACE index bf71513..15bae63 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -1,4 +1,4 @@ -workspace(name = "com_github_binchencoder_ease_gateway") +workspace(name = "com_github_binchencoder_janus_gateway") load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") @@ -109,17 +109,17 @@ load("@com_github_bazelbuild_buildtools//buildifier:deps.bzl", "buildifier_depen buildifier_dependencies() # ---------- local repositories -# local_repository( -# name = "com_github_binchencoder_gateway_proto", -# path = "../gateway-proto", -# ) +local_repository( + name = "com_github_binchencoder_gateway_proto", + path = "../gateway-proto", +) -# local_repository( -# name = "com_github_binchencoder_letsgo", -# path = "../letsgo", -# ) +local_repository( + name = "com_github_binchencoder_letsgo", + path = "../letsgo", +) -# local_repository( -# name = "com_github_binchencoder_skylb_api", -# path = "../skylb-api", -# ) +local_repository( + name = "com_github_binchencoder_skylb_api", + path = "../skylb-api", +) diff --git a/cmd/custom-gateway/BUILD.bazel b/cmd/custom-gateway/BUILD.bazel index a7bd2df..0ae5f8e 100644 --- a/cmd/custom-gateway/BUILD.bazel +++ b/cmd/custom-gateway/BUILD.bazel @@ -3,7 +3,7 @@ package(default_visibility = ["//visibility:public"]) load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library") go_binary( - name = "custom-ease-gateway", + name = "custom-janus-gateway", embed = [":go_default_library"], ) @@ -13,7 +13,7 @@ go_library( "main.go", "registrydemo.go", ], - importpath = "github.com/binchencoder/ease-gateway/cmd/custom-gateway", + importpath = "github.com/binchencoder/janus-gateway/cmd/custom-gateway", deps = [ "//examples/internal/proto/examplepb", "//gateway/runtime", diff --git a/cmd/custom-gateway/main.go b/cmd/custom-gateway/main.go index 0da3ac8..b82b1f3 100644 --- a/cmd/custom-gateway/main.go +++ b/cmd/custom-gateway/main.go @@ -9,9 +9,9 @@ import ( "github.com/golang/glog" - "github.com/binchencoder/ease-gateway/gateway/runtime" - "github.com/binchencoder/ease-gateway/integrate" - "github.com/binchencoder/ease-gateway/util" + "github.com/binchencoder/janus-gateway/gateway/runtime" + "github.com/binchencoder/janus-gateway/integrate" + "github.com/binchencoder/janus-gateway/util" "github.com/binchencoder/gateway-proto/data" "github.com/binchencoder/letsgo" ) @@ -25,7 +25,7 @@ func usage() { fmt.Println(`EaseGateway - Ease Gateway of binchencoder. Usage: - ease-gateway [options] + janus-gateway [options] Options:`) @@ -58,7 +58,7 @@ func main() { mux := runtime.NewServeMux() runtime.SetGatewayServiceHook(integrate.NewGatewayHook(mux, hostPort)) - glog.Infof("***** Starting custom ease-gateway at %s. *****", hostPort) + glog.Infof("***** Starting custom janus-gateway at %s. *****", hostPort) signals := make(chan os.Signal, 1) signal.Notify(signals, os.Interrupt, os.Kill) diff --git a/cmd/custom-gateway/registrydemo.go b/cmd/custom-gateway/registrydemo.go index af7e752..e314c16 100755 --- a/cmd/custom-gateway/registrydemo.go +++ b/cmd/custom-gateway/registrydemo.go @@ -2,5 +2,5 @@ package main // Import so that applications register themselves to gateway. import ( - _ "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb" + _ "github.com/binchencoder/janus-gateway/examples/internal/proto/examplepb" ) diff --git a/cmd/gateway/BUILD.bazel b/cmd/gateway/BUILD.bazel index 494226f..5d20127 100644 --- a/cmd/gateway/BUILD.bazel +++ b/cmd/gateway/BUILD.bazel @@ -2,12 +2,12 @@ load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library") load("@bazel_tools//tools/build_defs/pkg:pkg.bzl", "pkg_tar") go_library( - name = "ease-gateway", + name = "janus-gateway", srcs = [ "main.go", "registryprod.go", ], - importpath = "github.com/binchencoder/ease-gateway/cmd/gateway", + importpath = "github.com/binchencoder/janus-gateway/cmd/gateway", visibility = ["//visibility:public"], deps = [ "//proto/examplepb", @@ -22,15 +22,15 @@ go_library( ) # pkg_tar( -# name = "ease-gateway-tar", +# name = "janus-gateway-tar", # srcs = [ -# ":ease-gateway", +# ":janus-gateway", # ], -# package_dir = "/ease-gateway/bin", +# package_dir = "/janus-gateway/bin", # ) go_binary( name = "gateway", - embed = [":ease-gateway"], + embed = [":janus-gateway"], visibility = ["//visibility:public"], ) diff --git a/cmd/gateway/main.go b/cmd/gateway/main.go index 826ccf3..d76a067 100644 --- a/cmd/gateway/main.go +++ b/cmd/gateway/main.go @@ -9,17 +9,17 @@ import ( "github.com/golang/glog" - "github.com/binchencoder/ease-gateway/gateway/runtime" - "github.com/binchencoder/ease-gateway/integrate" - "github.com/binchencoder/ease-gateway/util" + "github.com/binchencoder/janus-gateway/gateway/runtime" + "github.com/binchencoder/janus-gateway/integrate" + "github.com/binchencoder/janus-gateway/util" "github.com/binchencoder/gateway-proto/data" "github.com/binchencoder/letsgo" "github.com/binchencoder/letsgo/service/naming" ) var ( - host = flag.String("host", "", "The ease-gateway service host ") - port = flag.Int("port", 8080, "The ease-gateway service port") + host = flag.String("host", "", "The janus-gateway service host ") + port = flag.Int("port", 8080, "The janus-gateway service port") enableHTTPS = flag.Bool("enable-https", false, "Whether to enable https.") certFile = flag.String("cert-file", "", "The TLS cert file.") keyFile = flag.String("key-file", "", "The TLS key file.") @@ -29,7 +29,7 @@ func usage() { fmt.Println(`Ease Gateway - Universal Gateway of xxx Inc. Usage: - ease-gateway [options] + janus-gateway [options] Options:`) diff --git a/cmd/gateway/registryprod.go b/cmd/gateway/registryprod.go index bd4c0cf..3bbe031 100755 --- a/cmd/gateway/registryprod.go +++ b/cmd/gateway/registryprod.go @@ -2,5 +2,5 @@ package main // Import so that applications register themselves to gateway. import ( - _ "github.com/binchencoder/ease-gateway/proto/examplepb" + _ "github.com/binchencoder/janus-gateway/proto/examplepb" ) diff --git a/docs/design.md b/docs/design.md index 56e2215..7c73894 100644 --- a/docs/design.md +++ b/docs/design.md @@ -1,26 +1,26 @@ # Ease-gatway - Enterprise Universal Gateway Service -`ease-gateway` is a enterprise universal gateway service for mobile, native, and web apps. +`janus-gateway` is a enterprise universal gateway service for mobile, native, and web apps. It's based on `grpc-gateway` and mobile team's gateway development experience. ## Overview -`ease-gateway` is a thin gateway layer on top of all front-end or APIs services. It's the single entrance for all enterprise internal services except the connection services (such as EIM connection layer, SSO, etc.). All clients access the gateway (through the reverse proxy or load balancer) with RESTful APIs, the gateway translates the requests to gRPC calls to the target services. +`janus-gateway` is a thin gateway layer on top of all front-end or APIs services. It's the single entrance for all enterprise internal services except the connection services (such as EIM connection layer, SSO, etc.). All clients access the gateway (through the reverse proxy or load balancer) with RESTful APIs, the gateway translates the requests to gRPC calls to the target services. ![Architecture](images/Arch.png) > SkyLB is an external load balancer for gRPC which is able to load balance on -> gRPC's long-lived connections. `ease-gateway` instances connect to SkyLB for endpoints +> gRPC's long-lived connections. `janus-gateway` instances connect to SkyLB for endpoints > of the target services, and load balance the end-users' requests to the target > services. -Based on this structure, `ease-gateway` provides foundamental functions to enterprise +Based on this structure, `janus-gateway` provides foundamental functions to enterprise infrastructure such as user identity verification, API management, monitoring, and logging. -## How does Ease-gateway Work? +## How does Janus-gateway Work? -`ease-gateway` is based on the open-sourced `grpc-gateway` framework. The following +`janus-gateway` is based on the open-sourced `grpc-gateway` framework. The following diagram shows how grpc-gateway works: ![grpc-gateway](images/mechanism.png) @@ -40,7 +40,7 @@ gateway and gRPC service stubs in Golang. The generated code can be easily hooked up with a HTTP server, and when HTTP requests arrive, it issues gRPC calls to the target service. -`ease-gateway` is the project to create such a HTTP server to meet enterprise business +`janus-gateway` is the project to create such a HTTP server to meet enterprise business needs. ### Request Interception @@ -83,7 +83,7 @@ translates the proto, it also generates a SkyLB client for each service. The SkyLB clients talk to the SkyLB to fetch service endpoints, and get notified when the service endpoints were changed so that it can do client side load balance properly. A typical SkyLB client example can be found at -[ease-gateway demo](https://github.com/binchencoder/ease-gateway/tree/master/examples/gateway) (it also contains the `grpc-gateway` example). +[janus-gateway demo](https://github.com/binchencoder/janus-gateway/tree/master/examples/gateway) (it also contains the `grpc-gateway` example). The GatewayServiceHook provides a Bootstrap() method for us to do initialization work (triggered by calling runtime.SetGatewayServiceHook() of @@ -136,7 +136,7 @@ In gRPC service proto, engineers need to specify the service ID like this: import "options/extension.proto"; service Demo { - option (ease.api.service_spec) = { + option (janus.api.service_spec) = { service_id: EASE_GATEWAY_DEMO namespace: "default" port_name: "grpc" @@ -162,7 +162,7 @@ import "httpoptions/annotations.proto"; // The request message for greeting. message GreetingRequest { string name = 1 [ - (ease.api.rules) = { + (janus.api.rules) = { rules: { type: STRING, operator: NON_NIL, @@ -196,7 +196,7 @@ We can add Janus customized instrumentation if needed. ## Gateway Rollout Procedure -When a new target service or service update is going to be added to `ease-gateway`, +When a new target service or service update is going to be added to `janus-gateway`, it has to following the following steps: 1. Add a service enum if it's a new service. @@ -206,15 +206,15 @@ it has to following the following steps: 3. Implement the gRPC service and push to production. 4. Link the service to gateway if it's a new service. This can be easily done - by adding an anonymous import in `//ease-gateway/cmd/gateway/registryprod.go ` : + by adding an anonymous import in `//janus-gateway/cmd/gateway/registryprod.go ` : ```go import ( - _ "github.com/binchencoder/ease-gateway/proto/examples" + _ "github.com/binchencoder/janus-gateway/proto/examples" ) ``` -5. Rebuild the `ease-gateway` binary and push to production. +5. Rebuild the `janus-gateway` binary and push to production. ## References diff --git a/docs/gateway-validation-rule.md b/docs/gateway-validation-rule.md index 914691e..20858ed 100644 --- a/docs/gateway-validation-rule.md +++ b/docs/gateway-validation-rule.md @@ -1,10 +1,10 @@ -# Ease-gateway Validation Rule +# Janus-gateway Validation Rule ## Rules Defination Validation Rule定义可以在这里找到: -> ease-gateway/httpoptions/annotations.proto +> janus-gateway/httpoptions/annotations.proto ```protobuf // The opertaion type. @@ -66,7 +66,7 @@ message Payment { PaymentType type = 1; // 100 > paied_amount > 10 int64 paied_amount = 2 [ - (ease.api.rules) = { + (janus.api.rules) = { rules: { type:NUMBER, operator: GT, @@ -84,7 +84,7 @@ message Payment { PaymentType type = 1; // 长度=10 string message_value_len_eq = 3 [ - (ease.api.rules) = { + (janus.api.rules) = { rules: { type:STRING, operator: LEN_EQ, @@ -95,7 +95,7 @@ message Payment { // 长度Trim之后小于21 string message_value_len_gt = 4 [ - (ease.api.rules) = { + (janus.api.rules) = { rules: { type:STRING, operator: LEN_LT, @@ -109,7 +109,7 @@ message Payment { 更多例子可以以下目录找到: -> ease-gateway/proto/examples/... +> janus-gateway/proto/examples/... ## Implemention Details @@ -148,10 +148,10 @@ func Validate__sharedproto_Payment(v *Payment) error { ### Defination -> ease-gateway/httpoptions/annotations.proto +> janus-gateway/httpoptions/annotations.proto ### Implementation Validation Rule -> ease-gateway/gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go +> janus-gateway/gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go 所有Validation Rule的实现都在template.go 文件中, 搜索`validatorTemplate`, 参照现有实现Coding \ No newline at end of file diff --git a/docs/scripts/start.sh b/docs/scripts/start.sh index 2047ede..9734a17 100755 --- a/docs/scripts/start.sh +++ b/docs/scripts/start.sh @@ -29,7 +29,7 @@ fi STDOUT_FILE=$HOMEDIR/std.out set +e -PIDS=`pgrep ^ease-gateway$` +PIDS=`pgrep ^janus-gateway$` if [ $? -eq 0 ]; then echo "ERROR: The service Ease Gateway already started!" echo "PID: $PIDS" @@ -38,7 +38,7 @@ fi set -e echo "Service Ease Gateway start..." -nohup $HOMEDIR/bin/ease-gateway \ +nohup $HOMEDIR/bin/janus-gateway \ -debug-svc-endpoint=vexillary-service=192.168.10.41:4100 \ -debug-svc-endpoint=pay-grpc-service=192.168.32.18:10008 \ -skylb-endpoints=$SKYLB_ENDPOINTS \ @@ -50,7 +50,7 @@ nohup $HOMEDIR/bin/ease-gateway \ sleep 2 -PIDS_COUNT=`pgrep ^ease-gateway$|wc -l` +PIDS_COUNT=`pgrep ^janus-gateway$|wc -l` if [ $PIDS_COUNT -eq 0 ]; then echo "ERROR: The service Ease Gateway does not started!" exit 1 diff --git a/docs/scripts/stop.sh b/docs/scripts/stop.sh index fbf0655..54ff16c 100755 --- a/docs/scripts/stop.sh +++ b/docs/scripts/stop.sh @@ -1,7 +1,7 @@ #!/bin/sh set +e -PIDS=`pgrep ^ease-gateway$` +PIDS=`pgrep ^janus-gateway$` if [ $? -ne 0 ]; then echo "INFO: The service Ease Gateway did not started!" exit 0 @@ -15,7 +15,7 @@ done while [ true ]; do echo -e ".\c" - IDS=`pgrep ^ease-gateway$` + IDS=`pgrep ^janus-gateway$` if [ $? -ne 0 ]; then echo echo "PID: $PIDS" diff --git a/examples/grpc-server/BUILD.bazel b/examples/grpc-server/BUILD.bazel index 4c9fcd7..b55c434 100644 --- a/examples/grpc-server/BUILD.bazel +++ b/examples/grpc-server/BUILD.bazel @@ -8,7 +8,7 @@ go_library( "main.go", "echo.go", ], - importpath = "github.com/binchencoder/ease-gateway/examples/grpc-server", + importpath = "github.com/binchencoder/janus-gateway/examples/grpc-server", deps = [ "//proto/examplepb", "@com_github_binchencoder_gateway_proto//data:go_default_library", diff --git a/examples/grpc-server/echo.go b/examples/grpc-server/echo.go index 181a464..752a723 100644 --- a/examples/grpc-server/echo.go +++ b/examples/grpc-server/echo.go @@ -3,7 +3,7 @@ package main import ( "context" - "github.com/binchencoder/ease-gateway/proto/examplepb" + "github.com/binchencoder/janus-gateway/proto/examplepb" "github.com/golang/glog" "google.golang.org/grpc" "google.golang.org/grpc/metadata" diff --git a/examples/grpc-server/main.go b/examples/grpc-server/main.go index 5b07a39..4a3de71 100644 --- a/examples/grpc-server/main.go +++ b/examples/grpc-server/main.go @@ -8,7 +8,7 @@ import ( "flag" "fmt" - examplepb "github.com/binchencoder/ease-gateway/proto/examplepb" + examplepb "github.com/binchencoder/janus-gateway/proto/examplepb" "github.com/binchencoder/gateway-proto/data" skylb "github.com/binchencoder/skylb-api/server" "github.com/golang/glog" diff --git a/examples/internal/README.md b/examples/internal/README.md index 59660c2..51dc903 100644 --- a/examples/internal/README.md +++ b/examples/internal/README.md @@ -1,6 +1,6 @@ # Overrview -ease-gateway/examples/internal 是使用ease-gateway的一个完整示例,包含gateway-server 和 gRPC-server. 还有Java实现gRPC Server的例子 [https://github.com/binchencoder/spring-boot-grpc/tree/master/spring-boot-grpc-examples] +janus-gateway/examples/internal 是使用ease-gateway的一个完整示例,包含gateway-server 和 gRPC-server. 还有Java实现gRPC Server的例子 [https://github.com/binchencoder/spring-boot-grpc/tree/master/spring-boot-grpc-examples] # Build the example @@ -18,27 +18,27 @@ bazel build examples/internal/cmd/example-grpc-server/... start gateway server ```shell -ease-gateway/bazel-bin/examples/internal/cmd/example-gateway-server/example-gateway-server_/example-gateway-server -skylb-endpoints="127.0.0.1:1900" -debug-svc-endpoint=custom-ease-gateway-test=localhost:9090 +janus-gateway/bazel-bin/examples/internal/cmd/example-gateway-server/example-gateway-server_/example-gateway-server -skylb-endpoints="127.0.0.1:1900" -debug-svc-endpoint=custom-janus-gateway-test=localhost:9090 ``` start custom-gateway server ```shell -ease-gateway/bazel-bin/cmd/custom-gateway/custom-ease-gateway_/custom-ease-gateway -skylb-endpoints="127.0.0.1:1900" -debug-service=custom-ease-gateway-test -debug-svc-endpoint=custom-ease-gateway-test=localhost:9090 +janus-gateway/bazel-bin/cmd/custom-gateway/custom-janus-gateway_/custom-janus-gateway -skylb-endpoints="127.0.0.1:1900" -debug-service=custom-janus-gateway-test -debug-svc-endpoint=custom-janus-gateway-test=localhost:9090 ``` start examples gRPC server for test //examples/internal/cmd/example-grpc-server ```shell -ease-gateway/bazel-bin/examples/internal/cmd/example-grpc-server/example-grpc-server_/example-grpc-server -skylb-endpoints="127.0.0.1:1900,127.0.0.1:1901" +janus-gateway/bazel-bin/examples/internal/cmd/example-grpc-server/example-grpc-server_/example-grpc-server -skylb-endpoints="127.0.0.1:1900,127.0.0.1:1901" ``` start gRPC server for test //cmd/gateway ```shell -ease-gateway/bazel-bin/examples/grpc-server/grpc-server_/grpc-server -skylb-endpoints="127.0.0.1:1900" +janus-gateway/bazel-bin/examples/grpc-server/grpc-server_/grpc-server -skylb-endpoints="127.0.0.1:1900" ``` start //cmd/gateway ```shell -ease-gateway/bazel-bin/cmd/gateway/gateway_/gateway -skylb-endpoints="127.0.0.1:1900" -v=2 -log_dir=. +janus-gateway/bazel-bin/cmd/gateway/gateway_/gateway -skylb-endpoints="127.0.0.1:1900" -v=2 -log_dir=. ``` # Usage diff --git a/examples/internal/cmd/example-gateway-server/BUILD.bazel b/examples/internal/cmd/example-gateway-server/BUILD.bazel index c5df729..39d663d 100644 --- a/examples/internal/cmd/example-gateway-server/BUILD.bazel +++ b/examples/internal/cmd/example-gateway-server/BUILD.bazel @@ -3,7 +3,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library") go_library( name = "go_default_library", srcs = ["main.go"], - importpath = "github.com/binchencoder/ease-gateway/examples/internal/cmd/example-gateway-server", + importpath = "github.com/binchencoder/janus-gateway/examples/internal/cmd/example-gateway-server", visibility = ["//visibility:private"], deps = [ "//examples/internal/gateway:go_default_library", diff --git a/examples/internal/cmd/example-gateway-server/main.go b/examples/internal/cmd/example-gateway-server/main.go index 313bd51..2d34925 100644 --- a/examples/internal/cmd/example-gateway-server/main.go +++ b/examples/internal/cmd/example-gateway-server/main.go @@ -9,7 +9,7 @@ import ( "flag" "github.com/golang/glog" - "github.com/binchencoder/ease-gateway/examples/internal/gateway" + "github.com/binchencoder/janus-gateway/examples/internal/gateway" ) var ( diff --git a/examples/internal/cmd/example-grpc-client/BUILD.bazel b/examples/internal/cmd/example-grpc-client/BUILD.bazel index f91e673..25ddab5 100644 --- a/examples/internal/cmd/example-grpc-client/BUILD.bazel +++ b/examples/internal/cmd/example-grpc-client/BUILD.bazel @@ -5,7 +5,7 @@ package(default_visibility = ["//visibility:private"]) go_library( name = "go_default_library", srcs = ["grpcclient.go"], - importpath = "github.com/binchencoder/ease-gateway/examples/internal/cmd/example-grpc-client", + importpath = "github.com/binchencoder/janus-gateway/examples/internal/cmd/example-grpc-client", deps = [ "//examples/internal/proto/examplepb:go_default_library", "//examples/internal/server:go_default_library", diff --git a/examples/internal/cmd/example-grpc-client/gatewayclient.go b/examples/internal/cmd/example-grpc-client/gatewayclient.go index 01f3b10..818459b 100644 --- a/examples/internal/cmd/example-grpc-client/gatewayclient.go +++ b/examples/internal/cmd/example-grpc-client/gatewayclient.go @@ -10,7 +10,7 @@ import ( "github.com/golang/protobuf/jsonpb" - examplepb "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb" + examplepb "github.com/binchencoder/janus-gateway/examples/internal/proto/examplepb" "github.com/binchencoder/letsgo" ) diff --git a/examples/internal/cmd/example-grpc-client/grpcclient.go b/examples/internal/cmd/example-grpc-client/grpcclient.go index fc4b664..2ea1100 100644 --- a/examples/internal/cmd/example-grpc-client/grpcclient.go +++ b/examples/internal/cmd/example-grpc-client/grpcclient.go @@ -12,7 +12,7 @@ import ( "google.golang.org/grpc" hpb "google.golang.org/grpc/health/grpc_health_v1" - examplepb "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb" + examplepb "github.com/binchencoder/janus-gateway/examples/internal/proto/examplepb" vexpb "github.com/binchencoder/gateway-proto/data" "github.com/binchencoder/letsgo" skylb "github.com/binchencoder/skylb-api/client" diff --git a/examples/internal/cmd/example-grpc-server/BUILD.bazel b/examples/internal/cmd/example-grpc-server/BUILD.bazel index 9ccd69a..eec50ac 100644 --- a/examples/internal/cmd/example-grpc-server/BUILD.bazel +++ b/examples/internal/cmd/example-grpc-server/BUILD.bazel @@ -5,7 +5,7 @@ package(default_visibility = ["//visibility:private"]) go_library( name = "go_default_library", srcs = ["main.go"], - importpath = "github.com/binchencoder/ease-gateway/examples/internal/cmd/example-grpc-server", + importpath = "github.com/binchencoder/janus-gateway/examples/internal/cmd/example-grpc-server", deps = [ "//examples/internal/proto/examplepb:go_default_library", "//examples/internal/server:go_default_library", diff --git a/examples/internal/cmd/example-grpc-server/main.go b/examples/internal/cmd/example-grpc-server/main.go index 633154e..d2752b7 100644 --- a/examples/internal/cmd/example-grpc-server/main.go +++ b/examples/internal/cmd/example-grpc-server/main.go @@ -10,13 +10,13 @@ import ( "log" "net/http" - examplepb "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb" + examplepb "github.com/binchencoder/janus-gateway/examples/internal/proto/examplepb" "github.com/prometheus/client_golang/prometheus" "github.com/binchencoder/gateway-proto/data" skylb "github.com/binchencoder/skylb-api/server" - "github.com/binchencoder/ease-gateway/examples/internal/server" + "github.com/binchencoder/janus-gateway/examples/internal/server" "github.com/golang/glog" "google.golang.org/grpc" ) diff --git a/examples/internal/gateway/BUILD.bazel b/examples/internal/gateway/BUILD.bazel index 5739512..cdc26b2 100644 --- a/examples/internal/gateway/BUILD.bazel +++ b/examples/internal/gateway/BUILD.bazel @@ -8,7 +8,7 @@ go_library( "handlers.go", "main.go", ], - importpath = "github.com/binchencoder/ease-gateway/examples/internal/gateway", + importpath = "github.com/binchencoder/janus-gateway/examples/internal/gateway", visibility = ["//visibility:public"], deps = [ "//examples/internal/proto/examplepb", diff --git a/examples/internal/gateway/gateway.go b/examples/internal/gateway/gateway.go index 65b42ff..87cb3af 100644 --- a/examples/internal/gateway/gateway.go +++ b/examples/internal/gateway/gateway.go @@ -6,8 +6,8 @@ import ( "net" "net/http" - "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb" - gwruntime "github.com/binchencoder/ease-gateway/gateway/runtime" + "github.com/binchencoder/janus-gateway/examples/internal/proto/examplepb" + gwruntime "github.com/binchencoder/janus-gateway/gateway/runtime" "google.golang.org/grpc" ) diff --git a/examples/internal/gateway/main.go b/examples/internal/gateway/main.go index 8d4f3cd..e467b68 100644 --- a/examples/internal/gateway/main.go +++ b/examples/internal/gateway/main.go @@ -5,7 +5,7 @@ import ( "net/http" "github.com/golang/glog" - gwruntime "github.com/binchencoder/ease-gateway/gateway/runtime" + gwruntime "github.com/binchencoder/janus-gateway/gateway/runtime" ) // Endpoint describes a gRPC endpoint diff --git a/examples/internal/integration/README.md b/examples/internal/integration/README.md index 2c55f9e..6b1d01f 100644 --- a/examples/internal/integration/README.md +++ b/examples/internal/integration/README.md @@ -3,7 +3,7 @@ ## Bazel test ```shell -bazel run examples/internal/integration/... --test_arg=--skylb-endpoints="" --test_arg=--debug-svc-endpoint=custom-ease-gateway-test=localhost:9090 +bazel run examples/internal/integration/... --test_arg=--skylb-endpoints="" --test_arg=--debug-svc-endpoint=custom-janus-gateway-test=localhost:9090 ``` > 通过bazel run 执行integration test diff --git a/examples/internal/integration/integration_test.go b/examples/internal/integration/integration_test.go index d43092d..bcae784 100644 --- a/examples/internal/integration/integration_test.go +++ b/examples/internal/integration/integration_test.go @@ -9,8 +9,8 @@ import ( "strings" "testing" - examplepb "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb" - "github.com/binchencoder/ease-gateway/gateway/runtime" + examplepb "github.com/binchencoder/janus-gateway/examples/internal/proto/examplepb" + "github.com/binchencoder/janus-gateway/gateway/runtime" "github.com/google/go-cmp/cmp" fieldmaskpb "google.golang.org/genproto/protobuf/field_mask" diff --git a/examples/internal/integration/main_test.go b/examples/internal/integration/main_test.go index e795158..6c06980 100644 --- a/examples/internal/integration/main_test.go +++ b/examples/internal/integration/main_test.go @@ -10,9 +10,9 @@ import ( "time" "github.com/golang/glog" - "github.com/binchencoder/ease-gateway/examples/internal/gateway" - server "github.com/binchencoder/ease-gateway/examples/internal/server" - gwruntime "github.com/binchencoder/ease-gateway/gateway/runtime" + "github.com/binchencoder/janus-gateway/examples/internal/gateway" + server "github.com/binchencoder/janus-gateway/examples/internal/server" + gwruntime "github.com/binchencoder/janus-gateway/gateway/runtime" ) var ( diff --git a/examples/internal/proto/examplepb/BUILD.bazel b/examples/internal/proto/examplepb/BUILD.bazel index 8084e43..748a4d0 100644 --- a/examples/internal/proto/examplepb/BUILD.bazel +++ b/examples/internal/proto/examplepb/BUILD.bazel @@ -85,7 +85,7 @@ go_proto_library( "//:go_grpc", "//gateway/protoc-gen-grpc-gateway:go_gen_grpc_gateway", ], - importpath = "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb", + importpath = "github.com/binchencoder/janus-gateway/examples/internal/proto/examplepb", proto = ":examplepb_proto", deps = [ "//httpoptions", @@ -105,7 +105,7 @@ go_proto_library( go_library( name = "examplepb", embed = [":examplepb_go_proto"], - importpath = "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb", + importpath = "github.com/binchencoder/janus-gateway/examples/internal/proto/examplepb", deps = [ "//httpoptions", "//gateway/runtime", diff --git a/examples/internal/proto/examplepb/echo_service.pb.go b/examples/internal/proto/examplepb/echo_service.pb.go index c31ddf4..eb22854 100755 --- a/examples/internal/proto/examplepb/echo_service.pb.go +++ b/examples/internal/proto/examplepb/echo_service.pb.go @@ -7,7 +7,7 @@ package examplepb import ( - _ "github.com/binchencoder/ease-gateway/httpoptions" + _ "github.com/binchencoder/janus-gateway/httpoptions" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" fieldmaskpb "google.golang.org/protobuf/types/known/fieldmaskpb" diff --git a/examples/internal/proto/examplepb/echo_service.pb.gw.go b/examples/internal/proto/examplepb/echo_service.pb.gw.go index b4a4cc8..75b4582 100755 --- a/examples/internal/proto/examplepb/echo_service.pb.gw.go +++ b/examples/internal/proto/examplepb/echo_service.pb.gw.go @@ -17,7 +17,7 @@ import ( "sync" "unicode/utf8" - "github.com/binchencoder/ease-gateway/gateway/runtime" + "github.com/binchencoder/janus-gateway/gateway/runtime" vexpb "github.com/binchencoder/gateway-proto/data" fpb "github.com/binchencoder/gateway-proto/frontend" lgr "github.com/binchencoder/letsgo/grpc" diff --git a/examples/internal/proto/examplepb/echo_service.proto b/examples/internal/proto/examplepb/echo_service.proto index 216c78a..589f5cd 100644 --- a/examples/internal/proto/examplepb/echo_service.proto +++ b/examples/internal/proto/examplepb/echo_service.proto @@ -1,5 +1,5 @@ syntax = "proto3"; -option go_package = "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb;examplepb"; +option go_package = "github.com/binchencoder/janus-gateway/examples/internal/proto/examplepb;examplepb"; // Echo Service // @@ -41,7 +41,7 @@ message ValidationRuleTestRequest { // Id represents the message identifier. string id = 1 [ - (ease.api.rules) = { + (janus.api.rules) = { rules: { type: STRING, operator: NON_NIL, @@ -62,7 +62,7 @@ message ValidationRuleTestRequest { ]; int64 num = 2 [ - (ease.api.rules) = { + (janus.api.rules) = { rules: { type: NUMBER, operator: GT, @@ -90,7 +90,7 @@ message DynamicMessageUpdate { // Echo service responds to incoming echo requests. service EchoService { - option (ease.api.service_spec) = { + option (janus.api.service_spec) = { service_id: CUSTOM_EASE_GATEWAY_TEST port_name : "grpc" namespace : "default" @@ -102,7 +102,7 @@ service EchoService { // The message posted as the id parameter will also be // returned. rpc Echo(SimpleMessage) returns (SimpleMessage) { - option (ease.api.http) = { + option (janus.api.http) = { post: "/v1/example/echo/{id}" additional_bindings { get: "/v1/example/echo/{id}/{num}" @@ -120,20 +120,20 @@ service EchoService { } // EchoBody method receives a simple message and returns it. rpc EchoBody(SimpleMessage) returns (SimpleMessage) { - option (ease.api.http) = { + option (janus.api.http) = { post: "/v1/example/echo_body" body: "*" }; } // EchoDelete method receives a simple message and returns it. rpc EchoDelete(SimpleMessage) returns (SimpleMessage) { - option (ease.api.http) = { + option (janus.api.http) = { delete: "/v1/example/echo_delete" }; } // EchoPatch method receives a NonStandardUpdateRequest and returns it. rpc EchoPatch(DynamicMessageUpdate) returns (DynamicMessageUpdate) { - option (ease.api.http) = { + option (janus.api.http) = { patch: "/v1/example/echo_patch" body: "body" }; @@ -141,7 +141,7 @@ service EchoService { // EchoValidationRule method for validation http rules integration test. rpc EchoValidationRule(ValidationRuleTestRequest) returns (ValidationRuleTestResponse) { - option (ease.api.http) = { + option (janus.api.http) = { post: "/v1/example/echo:validationRules" body: "*" }; diff --git a/examples/internal/proto/examplepb/generated_input.proto b/examples/internal/proto/examplepb/generated_input.proto index b2ac0c6..ed6df0f 100644 --- a/examples/internal/proto/examplepb/generated_input.proto +++ b/examples/internal/proto/examplepb/generated_input.proto @@ -1,5 +1,5 @@ syntax = "proto3"; -option go_package = "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb"; +option go_package = "github.com/binchencoder/janus-gateway/examples/internal/proto/examplepb"; package grpc.gateway.examples.internal.proto.examplepb; import "google/api/annotations.proto"; diff --git a/examples/internal/proto/examplepb/unannotated_echo_service.pb.go b/examples/internal/proto/examplepb/unannotated_echo_service.pb.go index 9ef8067..e7b48a7 100755 --- a/examples/internal/proto/examplepb/unannotated_echo_service.pb.go +++ b/examples/internal/proto/examplepb/unannotated_echo_service.pb.go @@ -7,7 +7,7 @@ package examplepb import ( - _ "github.com/binchencoder/ease-gateway/httpoptions" + _ "github.com/binchencoder/janus-gateway/httpoptions" duration "github.com/golang/protobuf/ptypes/duration" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" diff --git a/examples/internal/proto/examplepb/unannotated_echo_service.proto b/examples/internal/proto/examplepb/unannotated_echo_service.proto index 0f48846..ef7161a 100644 --- a/examples/internal/proto/examplepb/unannotated_echo_service.proto +++ b/examples/internal/proto/examplepb/unannotated_echo_service.proto @@ -1,5 +1,5 @@ syntax = "proto3"; -option go_package = "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb;examplepb"; +option go_package = "github.com/binchencoder/janus-gateway/examples/internal/proto/examplepb;examplepb"; // Unannotated Echo Service // Similar to echo_service.proto but without annotations. See @@ -41,7 +41,7 @@ message UnannotatedSimpleMessage { // Echo service responds to incoming echo requests. service UnannotatedEchoService { - option (ease.api.service_spec) = { + option (janus.api.service_spec) = { service_id: CUSTOM_EASE_GATEWAY_TEST port_name : "grpc" namespace : "default" diff --git a/examples/internal/server/BUILD.bazel b/examples/internal/server/BUILD.bazel index 458a608..fc491f1 100644 --- a/examples/internal/server/BUILD.bazel +++ b/examples/internal/server/BUILD.bazel @@ -8,7 +8,7 @@ go_library( "echo.go", "main.go", ], - importpath = "github.com/binchencoder/ease-gateway/examples/internal/server", + importpath = "github.com/binchencoder/janus-gateway/examples/internal/server", deps = [ "//examples/internal/proto/examplepb", "//gateway/runtime", diff --git a/examples/internal/server/echo.go b/examples/internal/server/echo.go index 3721fbf..1a057d3 100644 --- a/examples/internal/server/echo.go +++ b/examples/internal/server/echo.go @@ -3,7 +3,7 @@ package server import ( "context" - examples "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb" + examples "github.com/binchencoder/janus-gateway/examples/internal/proto/examplepb" "github.com/golang/glog" "google.golang.org/grpc" "google.golang.org/grpc/metadata" diff --git a/examples/internal/server/main.go b/examples/internal/server/main.go index 60729e1..dec1cbc 100644 --- a/examples/internal/server/main.go +++ b/examples/internal/server/main.go @@ -5,8 +5,8 @@ import ( "net" "net/http" - examples "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb" - "github.com/binchencoder/ease-gateway/gateway/runtime" + examples "github.com/binchencoder/janus-gateway/examples/internal/proto/examplepb" + "github.com/binchencoder/janus-gateway/gateway/runtime" "github.com/golang/glog" "google.golang.org/grpc" ) diff --git a/gateway/README.md b/gateway/README.md index 961e4e2..7142e1a 100644 --- a/gateway/README.md +++ b/gateway/README.md @@ -2,7 +2,7 @@ grpc-gateway 是一款非常优秀的网关服务器,负责转化和代理转发。让```RESTful API ```和 ```gRPC```可以相互转化,这样可以实现一套```gRPC```接口提供两种接口服务(提供内部的```gRPC```服务和外部```RESTful API```服务),大大提高了开发效率。 -但是官方提供的版本还是单机版的,还不支持集群,所以并不能直接运行在生产环境中。```ease-gateway```就是为了解决这些问题应运而生的,在```grpc-gateway```的基础上增加了新的feature +但是官方提供的版本还是单机版的,还不支持集群,所以并不能直接运行在生产环境中。```janus-gateway```就是为了解决这些问题应运而生的,在```grpc-gateway```的基础上增加了新的feature - 支持自定义的loadbalancer - 支持网关层的parameter validation diff --git a/gateway/internal/BUILD.bazel b/gateway/internal/BUILD.bazel index d1917c5..8d84966 100644 --- a/gateway/internal/BUILD.bazel +++ b/gateway/internal/BUILD.bazel @@ -15,7 +15,7 @@ proto_library( go_proto_library( name = "internal_go_proto", - importpath = "github.com/binchencoder/ease-gateway/gateway/internal", + importpath = "github.com/binchencoder/janus-gateway/gateway/internal", proto = ":internal_proto", deps = [ "@com_github_binchencoder_gateway_proto//frontend:error_go_proto", @@ -25,7 +25,7 @@ go_proto_library( go_library( name = "go_default_library", embed = [":internal_go_proto"], - importpath = "github.com/binchencoder/ease-gateway/gateway/internal", + importpath = "github.com/binchencoder/janus-gateway/gateway/internal", deps = [ "@com_github_binchencoder_gateway_proto//frontend:go_default_library", ] diff --git a/gateway/internal/casing/BUILD.bazel b/gateway/internal/casing/BUILD.bazel index f7ce84c..5876df8 100644 --- a/gateway/internal/casing/BUILD.bazel +++ b/gateway/internal/casing/BUILD.bazel @@ -3,7 +3,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( name = "casing", srcs = ["camel.go"], - importpath = "github.com/binchencoder/ease-gateway/gateway/internal/casing", + importpath = "github.com/binchencoder/janus-gateway/gateway/internal/casing", visibility = ["//:__subpackages__"], ) diff --git a/gateway/internal/descriptor/BUILD.bazel b/gateway/internal/descriptor/BUILD.bazel index 0bff1b9..4f836d9 100644 --- a/gateway/internal/descriptor/BUILD.bazel +++ b/gateway/internal/descriptor/BUILD.bazel @@ -11,7 +11,7 @@ go_library( "services.go", "types.go", ], - importpath = "github.com/binchencoder/ease-gateway/gateway/internal/descriptor", + importpath = "github.com/binchencoder/janus-gateway/gateway/internal/descriptor", deps = [ "//gateway/internal/casing", "@com_github_grpc_ecosystem_grpc_gateway//internal/codegenerator", diff --git a/gateway/internal/descriptor/apiconfig/BUILD.bazel b/gateway/internal/descriptor/apiconfig/BUILD.bazel index 98baaed..2f40350 100644 --- a/gateway/internal/descriptor/apiconfig/BUILD.bazel +++ b/gateway/internal/descriptor/apiconfig/BUILD.bazel @@ -17,7 +17,7 @@ proto_library( go_proto_library( name = "apiconfig_go_proto", compilers = ["//:go_apiv2"], - importpath = "github.com/binchencoder/ease-gateway/gateway/internal/descriptor/apiconfig", + importpath = "github.com/binchencoder/janus-gateway/gateway/internal/descriptor/apiconfig", proto = ":apiconfig_proto", deps = ["//httpoptions"], ) @@ -25,7 +25,7 @@ go_proto_library( go_library( name = "apiconfig", embed = [":apiconfig_go_proto"], - importpath = "github.com/binchencoder/ease-gateway/gateway/internal/descriptor/apiconfig", + importpath = "github.com/binchencoder/janus-gateway/gateway/internal/descriptor/apiconfig", ) alias( diff --git a/gateway/internal/descriptor/apiconfig/apiconfig.pb.go b/gateway/internal/descriptor/apiconfig/apiconfig.pb.go index 1254efb..1abad8b 100644 --- a/gateway/internal/descriptor/apiconfig/apiconfig.pb.go +++ b/gateway/internal/descriptor/apiconfig/apiconfig.pb.go @@ -120,10 +120,10 @@ func file_gateway_internal_descriptor_apiconfig_apiconfig_proto_rawDescGZIP() [] var file_gateway_internal_descriptor_apiconfig_apiconfig_proto_msgTypes = make([]protoimpl.MessageInfo, 1) var file_gateway_internal_descriptor_apiconfig_apiconfig_proto_goTypes = []interface{}{ (*GrpcAPIService)(nil), // 0: grpc.gateway.internal.descriptor.apiconfig.GrpcAPIService - (*httpoptions.Http)(nil), // 1: ease.api.Http + (*httpoptions.Http)(nil), // 1: janus.api.Http } var file_gateway_internal_descriptor_apiconfig_apiconfig_proto_depIdxs = []int32{ - 1, // 0: grpc.gateway.internal.descriptor.apiconfig.GrpcAPIService.http:type_name -> ease.api.Http + 1, // 0: grpc.gateway.internal.descriptor.apiconfig.GrpcAPIService.http:type_name -> janus.api.Http 1, // [1:1] is the sub-list for method output_type 1, // [1:1] is the sub-list for method input_type 1, // [1:1] is the sub-list for extension type_name diff --git a/gateway/internal/descriptor/apiconfig/apiconfig.proto b/gateway/internal/descriptor/apiconfig/apiconfig.proto index ed897c2..2ffc0ed 100644 --- a/gateway/internal/descriptor/apiconfig/apiconfig.proto +++ b/gateway/internal/descriptor/apiconfig/apiconfig.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package grpc.gateway.internal.descriptor.apiconfig; -option go_package = "github.com/binchencoder/ease-gateway/gatewayinternal/descriptor/apiconfig"; +option go_package = "github.com/binchencoder/janus-gateway/gatewayinternal/descriptor/apiconfig"; import "httpoptions/http.proto"; @@ -17,5 +17,5 @@ import "httpoptions/http.proto"; // compatibility guarantees by protobuf it is safe for us to remove the other fields. message GrpcAPIService { // Http Rule. - ease.api.Http http = 1; + janus.api.Http http = 1; } diff --git a/gateway/internal/descriptor/grpc_api_configuration.go b/gateway/internal/descriptor/grpc_api_configuration.go index e125b4c..dd59a30 100644 --- a/gateway/internal/descriptor/grpc_api_configuration.go +++ b/gateway/internal/descriptor/grpc_api_configuration.go @@ -6,7 +6,7 @@ import ( "strings" // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor/apiconfig" - "github.com/binchencoder/ease-gateway/gateway/internal/descriptor/apiconfig" + "github.com/binchencoder/janus-gateway/gateway/internal/descriptor/apiconfig" "google.golang.org/protobuf/encoding/protojson" "sigs.k8s.io/yaml" ) diff --git a/gateway/internal/descriptor/openapi_configuration.go b/gateway/internal/descriptor/openapi_configuration.go index d8d131d..ebbaf6b 100644 --- a/gateway/internal/descriptor/openapi_configuration.go +++ b/gateway/internal/descriptor/openapi_configuration.go @@ -5,7 +5,7 @@ import ( "io/ioutil" // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor/openapiconfig" - "github.com/binchencoder/ease-gateway/gateway/internal/descriptor/openapiconfig" + "github.com/binchencoder/janus-gateway/gateway/internal/descriptor/openapiconfig" "google.golang.org/protobuf/encoding/protojson" "sigs.k8s.io/yaml" ) diff --git a/gateway/internal/descriptor/openapi_configuration_test.go b/gateway/internal/descriptor/openapi_configuration_test.go index 6755b19..6dcec93 100644 --- a/gateway/internal/descriptor/openapi_configuration_test.go +++ b/gateway/internal/descriptor/openapi_configuration_test.go @@ -5,7 +5,7 @@ import ( "testing" // "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options" - "github.com/binchencoder/ease-gateway/gateway/protoc-gen-openapiv2/options" + "github.com/binchencoder/janus-gateway/gateway/protoc-gen-openapiv2/options" ) func TestLoadOpenAPIConfigFromYAMLRejectInvalidYAML(t *testing.T) { diff --git a/gateway/internal/descriptor/openapiconfig/BUILD.bazel b/gateway/internal/descriptor/openapiconfig/BUILD.bazel index c65a584..60d2a9a 100644 --- a/gateway/internal/descriptor/openapiconfig/BUILD.bazel +++ b/gateway/internal/descriptor/openapiconfig/BUILD.bazel @@ -12,7 +12,7 @@ proto_library( go_proto_library( name = "openapiconfig_go_proto", compilers = ["//:go_apiv2"], - importpath = "github.com/binchencoder/ease-gateway/gateway/internal/descriptor/openapiconfig", + importpath = "github.com/binchencoder/janus-gateway/gateway/internal/descriptor/openapiconfig", proto = ":openapiconfig_proto", visibility = ["//:__subpackages__"], deps = ["//gateway/protoc-gen-openapiv2/options"], @@ -21,7 +21,7 @@ go_proto_library( go_library( name = "openapiconfig", embed = [":openapiconfig_go_proto"], - importpath = "github.com/binchencoder/ease-gateway/gateway/internal/descriptor/openapiconfig", + importpath = "github.com/binchencoder/janus-gateway/gateway/internal/descriptor/openapiconfig", visibility = ["//:__subpackages__"], ) diff --git a/gateway/internal/descriptor/openapiconfig/openapiconfig.pb.go b/gateway/internal/descriptor/openapiconfig/openapiconfig.pb.go index e792bd0..405ef9b 100755 --- a/gateway/internal/descriptor/openapiconfig/openapiconfig.pb.go +++ b/gateway/internal/descriptor/openapiconfig/openapiconfig.pb.go @@ -7,7 +7,7 @@ package openapiconfig import ( - options "github.com/binchencoder/ease-gateway/gateway/protoc-gen-openapiv2/options" + options "github.com/binchencoder/janus-gateway/gateway/protoc-gen-openapiv2/options" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" diff --git a/gateway/internal/descriptor/openapiconfig/openapiconfig.proto b/gateway/internal/descriptor/openapiconfig/openapiconfig.proto index 3c194f2..f65a649 100644 --- a/gateway/internal/descriptor/openapiconfig/openapiconfig.proto +++ b/gateway/internal/descriptor/openapiconfig/openapiconfig.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package grpc.gateway.internal.descriptor.openapiconfig; -option go_package = "github.com/binchencoder/ease-gateway/gateway/internal/descriptor/openapiconfig"; +option go_package = "github.com/binchencoder/janus-gateway/gateway/internal/descriptor/openapiconfig"; import "gateway/protoc-gen-openapiv2/options/openapiv2.proto"; diff --git a/gateway/internal/descriptor/registry.go b/gateway/internal/descriptor/registry.go index d4ff801..73a67fe 100644 --- a/gateway/internal/descriptor/registry.go +++ b/gateway/internal/descriptor/registry.go @@ -8,11 +8,11 @@ import ( "github.com/grpc-ecosystem/grpc-gateway/v2/internal/codegenerator" // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor/openapiconfig" - "github.com/binchencoder/ease-gateway/gateway/internal/descriptor/openapiconfig" + "github.com/binchencoder/janus-gateway/gateway/internal/descriptor/openapiconfig" // "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options" - "github.com/binchencoder/ease-gateway/gateway/protoc-gen-openapiv2/options" + "github.com/binchencoder/janus-gateway/gateway/protoc-gen-openapiv2/options" // "google.golang.org/genproto/googleapis/api/annotations" - annotations "github.com/binchencoder/ease-gateway/httpoptions" + annotations "github.com/binchencoder/janus-gateway/httpoptions" "google.golang.org/protobuf/compiler/protogen" "google.golang.org/protobuf/types/descriptorpb" "google.golang.org/protobuf/types/pluginpb" diff --git a/gateway/internal/descriptor/registry_test.go b/gateway/internal/descriptor/registry_test.go index a886063..a87be10 100644 --- a/gateway/internal/descriptor/registry_test.go +++ b/gateway/internal/descriptor/registry_test.go @@ -4,7 +4,7 @@ import ( "testing" // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor/openapiconfig" - "github.com/binchencoder/ease-gateway/gateway/internal/descriptor/openapiconfig" + "github.com/binchencoder/janus-gateway/gateway/internal/descriptor/openapiconfig" "google.golang.org/protobuf/compiler/protogen" "google.golang.org/protobuf/encoding/prototext" "google.golang.org/protobuf/proto" diff --git a/gateway/internal/descriptor/services.go b/gateway/internal/descriptor/services.go index 6e2249e..11c181e 100644 --- a/gateway/internal/descriptor/services.go +++ b/gateway/internal/descriptor/services.go @@ -8,7 +8,7 @@ import ( "github.com/golang/glog" "github.com/grpc-ecosystem/grpc-gateway/v2/internal/httprule" // options "google.golang.org/genproto/googleapis/api/annotations" - options "github.com/binchencoder/ease-gateway/httpoptions" + options "github.com/binchencoder/janus-gateway/httpoptions" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/descriptorpb" ) @@ -243,7 +243,7 @@ func extractServiceSpec(svc *descriptorpb.ServiceDescriptorProto) (*options.Serv return nil, errNoServiceSpec } spec := proto.GetExtension(svc.Options, options.E_ServiceSpec) - // Extract ease gateway service spec options. + // Extract janus gateway service spec options. svcSpec, ok := spec.(*options.ServiceSpec) if !ok { return nil, fmt.Errorf("extension is %T; Want a service spec", spec) @@ -283,7 +283,7 @@ func extractAPIOptions(meth *descriptorpb.MethodDescriptorProto) (*options.HttpR if !proto.HasExtension(meth.Options, options.E_Method) { return opts, mopts, nil } - // Extract ease gateway method options. + // Extract janus gateway method options. m := proto.GetExtension(meth.Options, options.E_Method) mopts, ok = m.(*options.ApiMethod) if !ok { diff --git a/gateway/internal/descriptor/types.go b/gateway/internal/descriptor/types.go index f8b8626..79b20d7 100644 --- a/gateway/internal/descriptor/types.go +++ b/gateway/internal/descriptor/types.go @@ -6,12 +6,12 @@ import ( "unicode" // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/casing" - "github.com/binchencoder/ease-gateway/gateway/internal/casing" + "github.com/binchencoder/janus-gateway/gateway/internal/casing" "github.com/grpc-ecosystem/grpc-gateway/v2/internal/httprule" "google.golang.org/protobuf/types/descriptorpb" "google.golang.org/protobuf/types/pluginpb" - options "github.com/binchencoder/ease-gateway/httpoptions" + options "github.com/binchencoder/janus-gateway/httpoptions" "github.com/binchencoder/gateway-proto/data" ) diff --git a/gateway/internal/generator/BUILD.bazel b/gateway/internal/generator/BUILD.bazel index fec2a2c..225c6a1 100644 --- a/gateway/internal/generator/BUILD.bazel +++ b/gateway/internal/generator/BUILD.bazel @@ -5,7 +5,7 @@ package(default_visibility = ["//visibility:public"]) go_library( name = "generator", srcs = ["generator.go"], - importpath = "github.com/binchencoder/ease-gateway/gateway/internal/generator", + importpath = "github.com/binchencoder/janus-gateway/gateway/internal/generator", deps = ["//gateway/internal/descriptor:go_default_library"], ) diff --git a/gateway/internal/generator/generator.go b/gateway/internal/generator/generator.go index ee5f503..d03c1f7 100644 --- a/gateway/internal/generator/generator.go +++ b/gateway/internal/generator/generator.go @@ -3,7 +3,7 @@ package generator import ( // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor" - "github.com/binchencoder/ease-gateway/gateway/internal/descriptor" + "github.com/binchencoder/janus-gateway/gateway/internal/descriptor" ) // Generator is an abstraction of code generators. diff --git a/gateway/protoc-gen-grpc-gateway/BUILD.bazel b/gateway/protoc-gen-grpc-gateway/BUILD.bazel index 6d60b23..8c39b20 100644 --- a/gateway/protoc-gen-grpc-gateway/BUILD.bazel +++ b/gateway/protoc-gen-grpc-gateway/BUILD.bazel @@ -6,7 +6,7 @@ package(default_visibility = ["//visibility:private"]) go_library( name = "protoc-gen-grpc-gateway_lib", srcs = ["main.go"], - importpath = "github.com/binchencoder/ease-gateway/gateway/protoc-gen-grpc-gateway", + importpath = "github.com/binchencoder/janus-gateway/gateway/protoc-gen-grpc-gateway", deps = [ "@com_github_grpc_ecosystem_grpc_gateway//internal/codegenerator", "//gateway/internal/descriptor:go_default_library", diff --git a/gateway/protoc-gen-grpc-gateway/internal/gengateway/BUILD.bazel b/gateway/protoc-gen-grpc-gateway/internal/gengateway/BUILD.bazel index 555e8fa..880cd64 100644 --- a/gateway/protoc-gen-grpc-gateway/internal/gengateway/BUILD.bazel +++ b/gateway/protoc-gen-grpc-gateway/internal/gengateway/BUILD.bazel @@ -9,7 +9,7 @@ go_library( "generator.go", "template.go", ], - importpath = "github.com/binchencoder/ease-gateway/gateway/protoc-gen-grpc-gateway/internal/gengateway", + importpath = "github.com/binchencoder/janus-gateway/gateway/protoc-gen-grpc-gateway/internal/gengateway", deps = [ "//httpoptions", "//gateway/internal/casing", diff --git a/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator.go b/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator.go index ce62bb0..5b95e48 100644 --- a/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator.go +++ b/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator.go @@ -8,9 +8,9 @@ import ( "github.com/golang/glog" // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor" - "github.com/binchencoder/ease-gateway/gateway/internal/descriptor" + "github.com/binchencoder/janus-gateway/gateway/internal/descriptor" // gen "github.com/grpc-ecosystem/grpc-gateway/v2/internal/generator" - gen "github.com/binchencoder/ease-gateway/gateway/internal/generator" + gen "github.com/binchencoder/janus-gateway/gateway/internal/generator" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/pluginpb" ) @@ -41,7 +41,7 @@ func New(reg *descriptor.Registry, useRequestContext bool, registerFuncSuffix st "sync": "", "unicode/utf8": "", // "github.com/grpc-ecosystem/grpc-gateway/v2/runtime", - "github.com/binchencoder/ease-gateway/gateway/runtime": "", + "github.com/binchencoder/janus-gateway/gateway/runtime": "", "github.com/grpc-ecosystem/grpc-gateway/v2/utilities": "", "google.golang.org/protobuf/proto": "", "github.com/binchencoder/gateway-proto/data": "vexpb", diff --git a/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator_test.go b/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator_test.go index e2d73f3..4ba41e0 100644 --- a/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator_test.go +++ b/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator_test.go @@ -4,7 +4,7 @@ import ( "testing" // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor" - "github.com/binchencoder/ease-gateway/gateway/internal/descriptor" + "github.com/binchencoder/janus-gateway/gateway/internal/descriptor" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/descriptorpb" ) diff --git a/gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go b/gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go index 4bd2bc5..f46ec6b 100644 --- a/gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go +++ b/gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go @@ -10,9 +10,9 @@ import ( "github.com/golang/glog" // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/casing" - "github.com/binchencoder/ease-gateway/gateway/internal/casing" + "github.com/binchencoder/janus-gateway/gateway/internal/casing" // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor" - "github.com/binchencoder/ease-gateway/gateway/internal/descriptor" + "github.com/binchencoder/janus-gateway/gateway/internal/descriptor" "github.com/grpc-ecosystem/grpc-gateway/v2/utilities" ) diff --git a/gateway/protoc-gen-grpc-gateway/internal/gengateway/template_test.go b/gateway/protoc-gen-grpc-gateway/internal/gengateway/template_test.go index b9730a6..7b414a1 100644 --- a/gateway/protoc-gen-grpc-gateway/internal/gengateway/template_test.go +++ b/gateway/protoc-gen-grpc-gateway/internal/gengateway/template_test.go @@ -5,7 +5,7 @@ import ( "testing" // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor" - "github.com/binchencoder/ease-gateway/gateway/internal/descriptor" + "github.com/binchencoder/janus-gateway/gateway/internal/descriptor" "github.com/grpc-ecosystem/grpc-gateway/v2/internal/httprule" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/descriptorpb" diff --git a/gateway/protoc-gen-grpc-gateway/main.go b/gateway/protoc-gen-grpc-gateway/main.go index 5a2c1cb..ff91461 100644 --- a/gateway/protoc-gen-grpc-gateway/main.go +++ b/gateway/protoc-gen-grpc-gateway/main.go @@ -18,9 +18,9 @@ import ( "github.com/grpc-ecosystem/grpc-gateway/v2/internal/codegenerator" // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor" - "github.com/binchencoder/ease-gateway/gateway/internal/descriptor" + "github.com/binchencoder/janus-gateway/gateway/internal/descriptor" // "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway/internal/gengateway" - "github.com/binchencoder/ease-gateway/gateway/protoc-gen-grpc-gateway/internal/gengateway" + "github.com/binchencoder/janus-gateway/gateway/protoc-gen-grpc-gateway/internal/gengateway" "google.golang.org/protobuf/compiler/protogen" ) diff --git a/gateway/protoc-gen-grpc-gateway/main_test.go b/gateway/protoc-gen-grpc-gateway/main_test.go index 7708b12..78068b3 100644 --- a/gateway/protoc-gen-grpc-gateway/main_test.go +++ b/gateway/protoc-gen-grpc-gateway/main_test.go @@ -4,7 +4,7 @@ import ( "testing" // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor" - "github.com/binchencoder/ease-gateway/gateway/internal/descriptor" + "github.com/binchencoder/janus-gateway/gateway/internal/descriptor" ) func TestParseFlagsEmptyNoPanic(t *testing.T) { diff --git a/gateway/protoc-gen-openapiv2/BUILD.bazel b/gateway/protoc-gen-openapiv2/BUILD.bazel index dda91e1..948ef3e 100644 --- a/gateway/protoc-gen-openapiv2/BUILD.bazel +++ b/gateway/protoc-gen-openapiv2/BUILD.bazel @@ -5,7 +5,7 @@ package(default_visibility = ["//visibility:private"]) go_library( name = "protoc-gen-openapiv2_lib", srcs = ["main.go"], - importpath = "github.com/binchencoder/ease-gateway/gateway/protoc-gen-openapiv2", + importpath = "github.com/binchencoder/janus-gateway/gateway/protoc-gen-openapiv2", deps = [ "@com_github_grpc_ecosystem_grpc_gateway//internal/codegenerator", "//gateway/internal/descriptor", diff --git a/gateway/protoc-gen-openapiv2/internal/genopenapi/BUILD.bazel b/gateway/protoc-gen-openapiv2/internal/genopenapi/BUILD.bazel index 90b780b..9285616 100644 --- a/gateway/protoc-gen-openapiv2/internal/genopenapi/BUILD.bazel +++ b/gateway/protoc-gen-openapiv2/internal/genopenapi/BUILD.bazel @@ -14,7 +14,7 @@ go_library( "template.go", "types.go", ], - importpath = "github.com/binchencoder/ease-gateway/gateway/protoc-gen-openapiv2/internal/genopenapi", + importpath = "github.com/binchencoder/janus-gateway/gateway/protoc-gen-openapiv2/internal/genopenapi", deps = [ "//gateway/internal/casing", "//gateway/internal/descriptor", diff --git a/gateway/protoc-gen-openapiv2/internal/genopenapi/generator.go b/gateway/protoc-gen-openapiv2/internal/genopenapi/generator.go index ab67212..06c317d 100644 --- a/gateway/protoc-gen-openapiv2/internal/genopenapi/generator.go +++ b/gateway/protoc-gen-openapiv2/internal/genopenapi/generator.go @@ -12,11 +12,11 @@ import ( "github.com/golang/glog" anypb "github.com/golang/protobuf/ptypes/any" // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor" - "github.com/binchencoder/ease-gateway/gateway/internal/descriptor" + "github.com/binchencoder/janus-gateway/gateway/internal/descriptor" // gen "github.com/grpc-ecosystem/grpc-gateway/v2/internal/generator" - gen "github.com/binchencoder/ease-gateway/gateway/internal/generator" + gen "github.com/binchencoder/janus-gateway/gateway/internal/generator" // openapi_options "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options" - openapi_options "github.com/binchencoder/ease-gateway/gateway/protoc-gen-openapiv2/options" + openapi_options "github.com/binchencoder/janus-gateway/gateway/protoc-gen-openapiv2/options" statuspb "google.golang.org/genproto/googleapis/rpc/status" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/descriptorpb" diff --git a/gateway/protoc-gen-openapiv2/internal/genopenapi/template.go b/gateway/protoc-gen-openapiv2/internal/genopenapi/template.go index 5fccfa2..ca82733 100644 --- a/gateway/protoc-gen-openapiv2/internal/genopenapi/template.go +++ b/gateway/protoc-gen-openapiv2/internal/genopenapi/template.go @@ -20,11 +20,11 @@ import ( "github.com/golang/glog" // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/casing" - "github.com/binchencoder/ease-gateway/gateway/internal/casing" + "github.com/binchencoder/janus-gateway/gateway/internal/casing" // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor" - "github.com/binchencoder/ease-gateway/gateway/internal/descriptor" + "github.com/binchencoder/janus-gateway/gateway/internal/descriptor" // openapi_options "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options" - openapi_options "github.com/binchencoder/ease-gateway/gateway/protoc-gen-openapiv2/options" + openapi_options "github.com/binchencoder/janus-gateway/gateway/protoc-gen-openapiv2/options" "google.golang.org/genproto/googleapis/api/annotations" "google.golang.org/genproto/googleapis/api/visibility" "google.golang.org/protobuf/encoding/protojson" @@ -33,7 +33,7 @@ import ( "google.golang.org/protobuf/types/known/structpb" - options "github.com/binchencoder/ease-gateway/httpoptions" + options "github.com/binchencoder/janus-gateway/httpoptions" ) // The OpenAPI specification does not allow for more than one endpoint with the same HTTP method and path. diff --git a/gateway/protoc-gen-openapiv2/internal/genopenapi/types.go b/gateway/protoc-gen-openapiv2/internal/genopenapi/types.go index 1155b78..3c40929 100644 --- a/gateway/protoc-gen-openapiv2/internal/genopenapi/types.go +++ b/gateway/protoc-gen-openapiv2/internal/genopenapi/types.go @@ -6,8 +6,8 @@ import ( "fmt" // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor" - "github.com/binchencoder/ease-gateway/gateway/internal/descriptor" - options "github.com/binchencoder/ease-gateway/httpoptions" + "github.com/binchencoder/janus-gateway/gateway/internal/descriptor" + options "github.com/binchencoder/janus-gateway/httpoptions" "gopkg.in/yaml.v2" ) diff --git a/gateway/protoc-gen-openapiv2/main.go b/gateway/protoc-gen-openapiv2/main.go index 3e48a20..63cbaf3 100644 --- a/gateway/protoc-gen-openapiv2/main.go +++ b/gateway/protoc-gen-openapiv2/main.go @@ -10,9 +10,9 @@ import ( "github.com/grpc-ecosystem/grpc-gateway/v2/internal/codegenerator" // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor" - "github.com/binchencoder/ease-gateway/gateway/internal/descriptor" + "github.com/binchencoder/janus-gateway/gateway/internal/descriptor" // "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/internal/genopenapi" - genopenapi "github.com/binchencoder/ease-gateway/gateway/protoc-gen-openapiv2/internal/genopenapi" + genopenapi "github.com/binchencoder/janus-gateway/gateway/protoc-gen-openapiv2/internal/genopenapi" "github.com/grpc-ecosystem/grpc-gateway/v2/utilities" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/pluginpb" diff --git a/gateway/protoc-gen-openapiv2/options/BUILD.bazel b/gateway/protoc-gen-openapiv2/options/BUILD.bazel index ecbca2b..5cab09c 100644 --- a/gateway/protoc-gen-openapiv2/options/BUILD.bazel +++ b/gateway/protoc-gen-openapiv2/options/BUILD.bazel @@ -15,7 +15,7 @@ filegroup( go_library( name = "options", embed = [":options_go_proto"], - importpath = "github.com/binchencoder/ease-gateway/gateway/protoc-gen-openapiv2/options", + importpath = "github.com/binchencoder/janus-gateway/gateway/protoc-gen-openapiv2/options", ) proto_library( @@ -33,7 +33,7 @@ proto_library( go_proto_library( name = "options_go_proto", compilers = ["//:go_apiv2"], - importpath = "github.com/binchencoder/ease-gateway/gateway/protoc-gen-openapiv2/options", + importpath = "github.com/binchencoder/janus-gateway/gateway/protoc-gen-openapiv2/options", proto = ":options_proto", ) diff --git a/gateway/protoc-gen-openapiv2/options/annotations.proto b/gateway/protoc-gen-openapiv2/options/annotations.proto index 63dc872..98b03fb 100644 --- a/gateway/protoc-gen-openapiv2/options/annotations.proto +++ b/gateway/protoc-gen-openapiv2/options/annotations.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package grpc.gateway.protoc_gen_openapiv2.options; -option go_package = "github.com/binchencoder/ease-gateway/gateway/protoc-gen-openapiv2/options"; +option go_package = "github.com/binchencoder/janus-gateway/gateway/protoc-gen-openapiv2/options"; import "google/protobuf/descriptor.proto"; import "gateway/protoc-gen-openapiv2/options/openapiv2.proto"; diff --git a/gateway/protoc-gen-openapiv2/options/openapiv2.proto b/gateway/protoc-gen-openapiv2/options/openapiv2.proto index 9d078a5..a2bd206 100644 --- a/gateway/protoc-gen-openapiv2/options/openapiv2.proto +++ b/gateway/protoc-gen-openapiv2/options/openapiv2.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package grpc.gateway.protoc_gen_openapiv2.options; -option go_package = "github.com/binchencoder/ease-gateway/gateway/protoc-gen-openapiv2/options"; +option go_package = "github.com/binchencoder/janus-gateway/gateway/protoc-gen-openapiv2/options"; import "google/protobuf/struct.proto"; diff --git a/gateway/runtime/BUILD.bazel b/gateway/runtime/BUILD.bazel index dab62cc..8365d14 100644 --- a/gateway/runtime/BUILD.bazel +++ b/gateway/runtime/BUILD.bazel @@ -8,7 +8,7 @@ go_library( ["*.go"], exclude = ["*_test.go"], ), - importpath = "github.com/binchencoder/ease-gateway/gateway/runtime", + importpath = "github.com/binchencoder/janus-gateway/gateway/runtime", deps = [ "@com_github_grpc_ecosystem_grpc_gateway//internal/httprule", "@com_github_grpc_ecosystem_grpc_gateway//utilities", diff --git a/gateway/runtime/balancer.go b/gateway/runtime/balancer.go index 0d17ca7..bef183d 100644 --- a/gateway/runtime/balancer.go +++ b/gateway/runtime/balancer.go @@ -6,7 +6,7 @@ import ( "github.com/pborman/uuid" "google.golang.org/protobuf/proto" - options "github.com/binchencoder/ease-gateway/httpoptions" + options "github.com/binchencoder/janus-gateway/httpoptions" "github.com/binchencoder/letsgo/grpc" "github.com/binchencoder/letsgo/hashring" ) diff --git a/gateway/runtime/balancer_test.go b/gateway/runtime/balancer_test.go index 29b50d8..462e64d 100644 --- a/gateway/runtime/balancer_test.go +++ b/gateway/runtime/balancer_test.go @@ -4,10 +4,10 @@ import ( "context" "testing" - pb "github.com/binchencoder/ease-gateway/gateway/runtime/internal/examplepb" + pb "github.com/binchencoder/janus-gateway/gateway/runtime/internal/examplepb" "google.golang.org/protobuf/proto" - options "github.com/binchencoder/ease-gateway/httpoptions" + options "github.com/binchencoder/janus-gateway/httpoptions" "github.com/binchencoder/letsgo/hashring" ) diff --git a/gateway/runtime/context_test.go b/gateway/runtime/context_test.go index 76f79d8..9fa740e 100644 --- a/gateway/runtime/context_test.go +++ b/gateway/runtime/context_test.go @@ -9,7 +9,7 @@ import ( "time" // "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" - "github.com/binchencoder/ease-gateway/gateway/runtime" + "github.com/binchencoder/janus-gateway/gateway/runtime" "google.golang.org/grpc/metadata" ) diff --git a/gateway/runtime/convert_test.go b/gateway/runtime/convert_test.go index 457c0f8..5e971ba 100644 --- a/gateway/runtime/convert_test.go +++ b/gateway/runtime/convert_test.go @@ -4,7 +4,7 @@ import ( "testing" // "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" - "github.com/binchencoder/ease-gateway/gateway/runtime" + "github.com/binchencoder/janus-gateway/gateway/runtime" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/durationpb" "google.golang.org/protobuf/types/known/timestamppb" diff --git a/gateway/runtime/errors.go b/gateway/runtime/errors.go index 0acfcda..1499301 100644 --- a/gateway/runtime/errors.go +++ b/gateway/runtime/errors.go @@ -12,7 +12,7 @@ import ( "google.golang.org/grpc/grpclog" "google.golang.org/grpc/status" - "github.com/binchencoder/ease-gateway/gateway/internal" + "github.com/binchencoder/janus-gateway/gateway/internal" fpb "github.com/binchencoder/gateway-proto/frontend" ) diff --git a/gateway/runtime/errors_test.go b/gateway/runtime/errors_test.go index a761001..498b304 100644 --- a/gateway/runtime/errors_test.go +++ b/gateway/runtime/errors_test.go @@ -10,7 +10,7 @@ import ( "testing" // "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" - "github.com/binchencoder/ease-gateway/gateway/runtime" + "github.com/binchencoder/janus-gateway/gateway/runtime" "google.golang.org/genproto/googleapis/rpc/errdetails" statuspb "google.golang.org/genproto/googleapis/rpc/status" "google.golang.org/grpc/codes" diff --git a/gateway/runtime/handler_test.go b/gateway/runtime/handler_test.go index 13de50d..e3c74a7 100644 --- a/gateway/runtime/handler_test.go +++ b/gateway/runtime/handler_test.go @@ -9,9 +9,9 @@ import ( "testing" // "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" - "github.com/binchencoder/ease-gateway/gateway/runtime" + "github.com/binchencoder/janus-gateway/gateway/runtime" // pb "github.com/grpc-ecosystem/grpc-gateway/v2/runtime/internal/examplepb" - pb "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb" + pb "github.com/binchencoder/janus-gateway/examples/internal/proto/examplepb" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "google.golang.org/protobuf/proto" diff --git a/gateway/runtime/internal/examplepb/BUILD.bazel b/gateway/runtime/internal/examplepb/BUILD.bazel index 2acced4..84ae71c 100644 --- a/gateway/runtime/internal/examplepb/BUILD.bazel +++ b/gateway/runtime/internal/examplepb/BUILD.bazel @@ -29,7 +29,7 @@ go_proto_library( "//:go_apiv2", "//:go_grpc", ], - importpath = "github.com/binchencoder/ease-gateway/gateway/runtime/internal/examplepb", + importpath = "github.com/binchencoder/janus-gateway/gateway/runtime/internal/examplepb", proto = ":examplepb_proto", deps = ["@go_googleapis//google/api:annotations_go_proto"], ) @@ -37,7 +37,7 @@ go_proto_library( go_library( name = "examplepb", embed = [":examplepb_go_proto"], - importpath = "github.com/binchencoder/ease-gateway/gateway/runtime/internal/examplepb", + importpath = "github.com/binchencoder/janus-gateway/gateway/runtime/internal/examplepb", ) alias( diff --git a/gateway/runtime/internal/examplepb/proto3.pb.go b/gateway/runtime/internal/examplepb/proto3.pb.go index faacca3..3aa2d7e 100755 --- a/gateway/runtime/internal/examplepb/proto3.pb.go +++ b/gateway/runtime/internal/examplepb/proto3.pb.go @@ -90,8 +90,8 @@ type Proto3Message struct { BytesValue []byte `protobuf:"bytes,9,opt,name=bytes_value,json=bytesValue,proto3" json:"bytes_value,omitempty"` RepeatedValue []string `protobuf:"bytes,10,rep,name=repeated_value,json=repeatedValue,proto3" json:"repeated_value,omitempty"` RepeatedMessage []*wrapperspb.UInt64Value `protobuf:"bytes,44,rep,name=repeated_message,json=repeatedMessage,proto3" json:"repeated_message,omitempty"` - EnumValue EnumValue `protobuf:"varint,11,opt,name=enum_value,json=enumValue,proto3,enum=ease.gateway.runtime.internal.examplepb.EnumValue" json:"enum_value,omitempty"` - RepeatedEnum []EnumValue `protobuf:"varint,12,rep,packed,name=repeated_enum,json=repeatedEnum,proto3,enum=ease.gateway.runtime.internal.examplepb.EnumValue" json:"repeated_enum,omitempty"` + EnumValue EnumValue `protobuf:"varint,11,opt,name=enum_value,json=enumValue,proto3,enum=janus.gateway.runtime.internal.examplepb.EnumValue" json:"enum_value,omitempty"` + RepeatedEnum []EnumValue `protobuf:"varint,12,rep,packed,name=repeated_enum,json=repeatedEnum,proto3,enum=janus.gateway.runtime.internal.examplepb.EnumValue" json:"repeated_enum,omitempty"` TimestampValue *timestamppb.Timestamp `protobuf:"bytes,13,opt,name=timestamp_value,json=timestampValue,proto3" json:"timestamp_value,omitempty"` DurationValue *durationpb.Duration `protobuf:"bytes,14,opt,name=duration_value,json=durationValue,proto3" json:"duration_value,omitempty"` FieldmaskValue *fieldmaskpb.FieldMask `protobuf:"bytes,15,opt,name=fieldmask_value,json=fieldmaskValue,proto3" json:"fieldmask_value,omitempty"` @@ -803,22 +803,22 @@ func file_gateway_runtime_internal_examplepb_proto3_proto_rawDescGZIP() []byte { var file_gateway_runtime_internal_examplepb_proto3_proto_enumTypes = make([]protoimpl.EnumInfo, 1) var file_gateway_runtime_internal_examplepb_proto3_proto_msgTypes = make([]protoimpl.MessageInfo, 15) var file_gateway_runtime_internal_examplepb_proto3_proto_goTypes = []interface{}{ - (EnumValue)(0), // 0: ease.gateway.runtime.internal.examplepb.EnumValue - (*Proto3Message)(nil), // 1: ease.gateway.runtime.internal.examplepb.Proto3Message - nil, // 2: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValueEntry - nil, // 3: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue2Entry - nil, // 4: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue3Entry - nil, // 5: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue4Entry - nil, // 6: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue5Entry - nil, // 7: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue6Entry - nil, // 8: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue7Entry - nil, // 9: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue8Entry - nil, // 10: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue9Entry - nil, // 11: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue10Entry - nil, // 12: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue12Entry - nil, // 13: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue14Entry - nil, // 14: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue15Entry - nil, // 15: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue16Entry + (EnumValue)(0), // 0: janus.gateway.runtime.internal.examplepb.EnumValue + (*Proto3Message)(nil), // 1: janus.gateway.runtime.internal.examplepb.Proto3Message + nil, // 2: janus.gateway.runtime.internal.examplepb.Proto3Message.MapValueEntry + nil, // 3: janus.gateway.runtime.internal.examplepb.Proto3Message.MapValue2Entry + nil, // 4: janus.gateway.runtime.internal.examplepb.Proto3Message.MapValue3Entry + nil, // 5: janus.gateway.runtime.internal.examplepb.Proto3Message.MapValue4Entry + nil, // 6: janus.gateway.runtime.internal.examplepb.Proto3Message.MapValue5Entry + nil, // 7: janus.gateway.runtime.internal.examplepb.Proto3Message.MapValue6Entry + nil, // 8: janus.gateway.runtime.internal.examplepb.Proto3Message.MapValue7Entry + nil, // 9: janus.gateway.runtime.internal.examplepb.Proto3Message.MapValue8Entry + nil, // 10: janus.gateway.runtime.internal.examplepb.Proto3Message.MapValue9Entry + nil, // 11: janus.gateway.runtime.internal.examplepb.Proto3Message.MapValue10Entry + nil, // 12: janus.gateway.runtime.internal.examplepb.Proto3Message.MapValue12Entry + nil, // 13: janus.gateway.runtime.internal.examplepb.Proto3Message.MapValue14Entry + nil, // 14: janus.gateway.runtime.internal.examplepb.Proto3Message.MapValue15Entry + nil, // 15: janus.gateway.runtime.internal.examplepb.Proto3Message.MapValue16Entry (*wrapperspb.UInt64Value)(nil), // 16: google.protobuf.UInt64Value (*timestamppb.Timestamp)(nil), // 17: google.protobuf.Timestamp (*durationpb.Duration)(nil), // 18: google.protobuf.Duration @@ -833,38 +833,38 @@ var file_gateway_runtime_internal_examplepb_proto3_proto_goTypes = []interface{} (*wrapperspb.BytesValue)(nil), // 27: google.protobuf.BytesValue } var file_gateway_runtime_internal_examplepb_proto3_proto_depIdxs = []int32{ - 1, // 0: ease.gateway.runtime.internal.examplepb.Proto3Message.nested:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message - 16, // 1: ease.gateway.runtime.internal.examplepb.Proto3Message.repeated_message:type_name -> google.protobuf.UInt64Value - 0, // 2: ease.gateway.runtime.internal.examplepb.Proto3Message.enum_value:type_name -> ease.gateway.runtime.internal.examplepb.EnumValue - 0, // 3: ease.gateway.runtime.internal.examplepb.Proto3Message.repeated_enum:type_name -> ease.gateway.runtime.internal.examplepb.EnumValue - 17, // 4: ease.gateway.runtime.internal.examplepb.Proto3Message.timestamp_value:type_name -> google.protobuf.Timestamp - 18, // 5: ease.gateway.runtime.internal.examplepb.Proto3Message.duration_value:type_name -> google.protobuf.Duration - 19, // 6: ease.gateway.runtime.internal.examplepb.Proto3Message.fieldmask_value:type_name -> google.protobuf.FieldMask - 1, // 7: ease.gateway.runtime.internal.examplepb.Proto3Message.nested_oneof_value_one:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message - 20, // 8: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_double_value:type_name -> google.protobuf.DoubleValue - 21, // 9: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_float_value:type_name -> google.protobuf.FloatValue - 22, // 10: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_int64_value:type_name -> google.protobuf.Int64Value - 23, // 11: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_int32_value:type_name -> google.protobuf.Int32Value - 16, // 12: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_u_int64_value:type_name -> google.protobuf.UInt64Value - 24, // 13: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_u_int32_value:type_name -> google.protobuf.UInt32Value - 25, // 14: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_bool_value:type_name -> google.protobuf.BoolValue - 26, // 15: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_string_value:type_name -> google.protobuf.StringValue - 27, // 16: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_bytes_value:type_name -> google.protobuf.BytesValue - 2, // 17: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValueEntry - 3, // 18: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value2:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue2Entry - 4, // 19: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value3:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue3Entry - 5, // 20: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value4:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue4Entry - 6, // 21: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value5:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue5Entry - 7, // 22: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value6:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue6Entry - 8, // 23: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value7:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue7Entry - 9, // 24: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value8:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue8Entry - 10, // 25: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value9:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue9Entry - 11, // 26: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value10:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue10Entry - 12, // 27: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value12:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue12Entry - 13, // 28: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value14:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue14Entry - 14, // 29: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value15:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue15Entry - 15, // 30: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value16:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue16Entry - 16, // 31: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue16Entry.value:type_name -> google.protobuf.UInt64Value + 1, // 0: janus.gateway.runtime.internal.examplepb.Proto3Message.nested:type_name -> janus.gateway.runtime.internal.examplepb.Proto3Message + 16, // 1: janus.gateway.runtime.internal.examplepb.Proto3Message.repeated_message:type_name -> google.protobuf.UInt64Value + 0, // 2: janus.gateway.runtime.internal.examplepb.Proto3Message.enum_value:type_name -> janus.gateway.runtime.internal.examplepb.EnumValue + 0, // 3: janus.gateway.runtime.internal.examplepb.Proto3Message.repeated_enum:type_name -> janus.gateway.runtime.internal.examplepb.EnumValue + 17, // 4: janus.gateway.runtime.internal.examplepb.Proto3Message.timestamp_value:type_name -> google.protobuf.Timestamp + 18, // 5: janus.gateway.runtime.internal.examplepb.Proto3Message.duration_value:type_name -> google.protobuf.Duration + 19, // 6: janus.gateway.runtime.internal.examplepb.Proto3Message.fieldmask_value:type_name -> google.protobuf.FieldMask + 1, // 7: janus.gateway.runtime.internal.examplepb.Proto3Message.nested_oneof_value_one:type_name -> janus.gateway.runtime.internal.examplepb.Proto3Message + 20, // 8: janus.gateway.runtime.internal.examplepb.Proto3Message.wrapper_double_value:type_name -> google.protobuf.DoubleValue + 21, // 9: janus.gateway.runtime.internal.examplepb.Proto3Message.wrapper_float_value:type_name -> google.protobuf.FloatValue + 22, // 10: janus.gateway.runtime.internal.examplepb.Proto3Message.wrapper_int64_value:type_name -> google.protobuf.Int64Value + 23, // 11: janus.gateway.runtime.internal.examplepb.Proto3Message.wrapper_int32_value:type_name -> google.protobuf.Int32Value + 16, // 12: janus.gateway.runtime.internal.examplepb.Proto3Message.wrapper_u_int64_value:type_name -> google.protobuf.UInt64Value + 24, // 13: janus.gateway.runtime.internal.examplepb.Proto3Message.wrapper_u_int32_value:type_name -> google.protobuf.UInt32Value + 25, // 14: janus.gateway.runtime.internal.examplepb.Proto3Message.wrapper_bool_value:type_name -> google.protobuf.BoolValue + 26, // 15: janus.gateway.runtime.internal.examplepb.Proto3Message.wrapper_string_value:type_name -> google.protobuf.StringValue + 27, // 16: janus.gateway.runtime.internal.examplepb.Proto3Message.wrapper_bytes_value:type_name -> google.protobuf.BytesValue + 2, // 17: janus.gateway.runtime.internal.examplepb.Proto3Message.map_value:type_name -> janus.gateway.runtime.internal.examplepb.Proto3Message.MapValueEntry + 3, // 18: janus.gateway.runtime.internal.examplepb.Proto3Message.map_value2:type_name -> janus.gateway.runtime.internal.examplepb.Proto3Message.MapValue2Entry + 4, // 19: janus.gateway.runtime.internal.examplepb.Proto3Message.map_value3:type_name -> janus.gateway.runtime.internal.examplepb.Proto3Message.MapValue3Entry + 5, // 20: janus.gateway.runtime.internal.examplepb.Proto3Message.map_value4:type_name -> janus.gateway.runtime.internal.examplepb.Proto3Message.MapValue4Entry + 6, // 21: janus.gateway.runtime.internal.examplepb.Proto3Message.map_value5:type_name -> janus.gateway.runtime.internal.examplepb.Proto3Message.MapValue5Entry + 7, // 22: janus.gateway.runtime.internal.examplepb.Proto3Message.map_value6:type_name -> janus.gateway.runtime.internal.examplepb.Proto3Message.MapValue6Entry + 8, // 23: janus.gateway.runtime.internal.examplepb.Proto3Message.map_value7:type_name -> janus.gateway.runtime.internal.examplepb.Proto3Message.MapValue7Entry + 9, // 24: janus.gateway.runtime.internal.examplepb.Proto3Message.map_value8:type_name -> janus.gateway.runtime.internal.examplepb.Proto3Message.MapValue8Entry + 10, // 25: janus.gateway.runtime.internal.examplepb.Proto3Message.map_value9:type_name -> janus.gateway.runtime.internal.examplepb.Proto3Message.MapValue9Entry + 11, // 26: janus.gateway.runtime.internal.examplepb.Proto3Message.map_value10:type_name -> janus.gateway.runtime.internal.examplepb.Proto3Message.MapValue10Entry + 12, // 27: janus.gateway.runtime.internal.examplepb.Proto3Message.map_value12:type_name -> janus.gateway.runtime.internal.examplepb.Proto3Message.MapValue12Entry + 13, // 28: janus.gateway.runtime.internal.examplepb.Proto3Message.map_value14:type_name -> janus.gateway.runtime.internal.examplepb.Proto3Message.MapValue14Entry + 14, // 29: janus.gateway.runtime.internal.examplepb.Proto3Message.map_value15:type_name -> janus.gateway.runtime.internal.examplepb.Proto3Message.MapValue15Entry + 15, // 30: janus.gateway.runtime.internal.examplepb.Proto3Message.map_value16:type_name -> janus.gateway.runtime.internal.examplepb.Proto3Message.MapValue16Entry + 16, // 31: janus.gateway.runtime.internal.examplepb.Proto3Message.MapValue16Entry.value:type_name -> google.protobuf.UInt64Value 32, // [32:32] is the sub-list for method output_type 32, // [32:32] is the sub-list for method input_type 32, // [32:32] is the sub-list for extension type_name diff --git a/gateway/runtime/internal/examplepb/proto3.proto b/gateway/runtime/internal/examplepb/proto3.proto index c5b0f10..043b576 100644 --- a/gateway/runtime/internal/examplepb/proto3.proto +++ b/gateway/runtime/internal/examplepb/proto3.proto @@ -1,8 +1,8 @@ syntax = "proto3"; -package ease.gateway.runtime.internal.examplepb; +package janus.gateway.runtime.internal.examplepb; -option go_package = "github.com/binchencoder/ease-gateway/gateway/runtime/internal/examplepb"; +option go_package = "github.com/binchencoder/janus-gateway/gateway/runtime/internal/examplepb"; import "google/protobuf/duration.proto"; import "google/protobuf/field_mask.proto"; diff --git a/gateway/runtime/marshal_httpbodyproto_test.go b/gateway/runtime/marshal_httpbodyproto_test.go index dbfbadb..f7e907a 100644 --- a/gateway/runtime/marshal_httpbodyproto_test.go +++ b/gateway/runtime/marshal_httpbodyproto_test.go @@ -5,7 +5,7 @@ import ( "testing" // "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" - "github.com/binchencoder/ease-gateway/gateway/runtime" + "github.com/binchencoder/janus-gateway/gateway/runtime" "google.golang.org/genproto/googleapis/api/httpbody" "google.golang.org/protobuf/encoding/protojson" ) diff --git a/gateway/runtime/marshaler_registry_test.go b/gateway/runtime/marshaler_registry_test.go index 36028d2..d3854b5 100644 --- a/gateway/runtime/marshaler_registry_test.go +++ b/gateway/runtime/marshaler_registry_test.go @@ -8,7 +8,7 @@ import ( "testing" // "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" - "github.com/binchencoder/ease-gateway/gateway/runtime" + "github.com/binchencoder/janus-gateway/gateway/runtime" ) func TestMarshalerForRequest(t *testing.T) { diff --git a/gateway/runtime/mux_test.go b/gateway/runtime/mux_test.go index 180b7b7..91cba14 100644 --- a/gateway/runtime/mux_test.go +++ b/gateway/runtime/mux_test.go @@ -12,7 +12,7 @@ import ( "testing" // "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" - "github.com/binchencoder/ease-gateway/gateway/runtime" + "github.com/binchencoder/janus-gateway/gateway/runtime" "github.com/grpc-ecosystem/grpc-gateway/v2/utilities" "google.golang.org/grpc" "google.golang.org/grpc/codes" diff --git a/gateway/runtime/service.go b/gateway/runtime/service.go index b048912..8b8846b 100755 --- a/gateway/runtime/service.go +++ b/gateway/runtime/service.go @@ -3,14 +3,14 @@ package runtime import ( "google.golang.org/grpc" - options "github.com/binchencoder/ease-gateway/httpoptions" + options "github.com/binchencoder/janus-gateway/httpoptions" vexpb "github.com/binchencoder/gateway-proto/data" skypb "github.com/binchencoder/skylb-api/proto" ) var ( // CallerServiceId sets the gRPC caller service ID of the gateway. - // For ease-gateway, it's ServiceId_EASE_GATEWAY. + // For janus-gateway, it's ServiceId_EASE_GATEWAY. CallerServiceId = vexpb.ServiceId_EASE_GATEWAY ) diff --git a/go.mod b/go.mod index 8788eaa..79e2544 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/binchencoder/ease-gateway +module github.com/binchencoder/janus-gateway go 1.17 diff --git a/go.sum b/go.sum index 43f6716..7912701 100644 --- a/go.sum +++ b/go.sum @@ -59,7 +59,7 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/binchencoder/ease-gateway v0.0.4/go.mod h1:L8fCaUA1FaYO0ReFNAri15ozAj9NeJ9B+Q6CQAyPFqY= +github.com/binchencoder/janus-gateway v0.0.4/go.mod h1:L8fCaUA1FaYO0ReFNAri15ozAj9NeJ9B+Q6CQAyPFqY= github.com/binchencoder/gateway-proto v0.0.5/go.mod h1:853l4bAOm0Gt8XrDy+9obeKRlBLwP4HAk9tVYbgnSmU= github.com/binchencoder/gateway-proto v0.0.7 h1:+3d1QEBqDxFrTIVrSiao4saXNFNeK/vxsIsa1ClSYBI= github.com/binchencoder/gateway-proto v0.0.7/go.mod h1:DUtwTL1FDBeVIDIHxS8v2YajyWqe444jSvCxexR161A= diff --git a/httpoptions/BUILD.bazel b/httpoptions/BUILD.bazel index 11e15fe..32f020d 100644 --- a/httpoptions/BUILD.bazel +++ b/httpoptions/BUILD.bazel @@ -14,7 +14,7 @@ filegroup( go_library( name = "httpoptions", embed = [":options_go_proto"], - importpath = "github.com/binchencoder/ease-gateway/httpoptions", + importpath = "github.com/binchencoder/janus-gateway/httpoptions", ) proto_library( @@ -34,7 +34,7 @@ proto_library( go_proto_library( name = "options_go_proto", compilers = ["@io_bazel_rules_go//proto:go_grpc"], - importpath = "github.com/binchencoder/ease-gateway/httpoptions", + importpath = "github.com/binchencoder/janus-gateway/httpoptions", proto = ":options_proto", deps = [ "@com_github_binchencoder_gateway_proto//data:go_default_library", diff --git a/httpoptions/annotations.pb.go b/httpoptions/annotations.pb.go index 599940e..ccaa7b5 100755 --- a/httpoptions/annotations.pb.go +++ b/httpoptions/annotations.pb.go @@ -382,9 +382,9 @@ type ApiMethod struct { HashKey string `protobuf:"bytes,3,opt,name=hash_key,json=hashKey,proto3" json:"hash_key,omitempty"` IsThirdParty bool `protobuf:"varint,4,opt,name=is_third_party,json=isThirdParty,proto3" json:"is_third_party,omitempty"` Timeout string `protobuf:"bytes,5,opt,name=timeout,proto3" json:"timeout,omitempty"` - ApiSource ApiSourceType `protobuf:"varint,6,opt,name=api_source,json=apiSource,proto3,enum=ease.api.ApiSourceType" json:"api_source,omitempty"` - TokenType AuthTokenType `protobuf:"varint,7,opt,name=token_type,json=tokenType,proto3,enum=ease.api.AuthTokenType" json:"token_type,omitempty"` - SpecSourceType SpecSourceType `protobuf:"varint,8,opt,name=spec_source_type,json=specSourceType,proto3,enum=ease.api.SpecSourceType" json:"spec_source_type,omitempty"` + ApiSource ApiSourceType `protobuf:"varint,6,opt,name=api_source,json=apiSource,proto3,enum=janus.api.ApiSourceType" json:"api_source,omitempty"` + TokenType AuthTokenType `protobuf:"varint,7,opt,name=token_type,json=tokenType,proto3,enum=janus.api.AuthTokenType" json:"token_type,omitempty"` + SpecSourceType SpecSourceType `protobuf:"varint,8,opt,name=spec_source_type,json=specSourceType,proto3,enum=janus.api.SpecSourceType" json:"spec_source_type,omitempty"` } func (x *ApiMethod) Reset() { @@ -484,7 +484,7 @@ type ServiceSpec struct { PortName string `protobuf:"bytes,2,opt,name=port_name,json=portName,proto3" json:"port_name,omitempty"` Namespace string `protobuf:"bytes,3,opt,name=namespace,proto3" json:"namespace,omitempty"` GenController bool `protobuf:"varint,4,opt,name=gen_controller,json=genController,proto3" json:"gen_controller,omitempty"` - Balancer LoadBalancer `protobuf:"varint,5,opt,name=balancer,proto3,enum=ease.api.LoadBalancer" json:"balancer,omitempty"` + Balancer LoadBalancer `protobuf:"varint,5,opt,name=balancer,proto3,enum=janus.api.LoadBalancer" json:"balancer,omitempty"` } func (x *ServiceSpec) Reset() { @@ -559,10 +559,10 @@ type ValidationRule struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Operator OperatorType `protobuf:"varint,1,opt,name=operator,proto3,enum=ease.api.OperatorType" json:"operator,omitempty"` - Type ValueType `protobuf:"varint,2,opt,name=type,proto3,enum=ease.api.ValueType" json:"type,omitempty"` + Operator OperatorType `protobuf:"varint,1,opt,name=operator,proto3,enum=janus.api.OperatorType" json:"operator,omitempty"` + Type ValueType `protobuf:"varint,2,opt,name=type,proto3,enum=janus.api.ValueType" json:"type,omitempty"` Value string `protobuf:"bytes,3,opt,name=value,proto3" json:"value,omitempty"` - Function FunctionType `protobuf:"varint,4,opt,name=function,proto3,enum=ease.api.FunctionType" json:"function,omitempty"` + Function FunctionType `protobuf:"varint,4,opt,name=function,proto3,enum=janus.api.FunctionType" json:"function,omitempty"` } func (x *ValidationRule) Reset() { @@ -677,7 +677,7 @@ var file_httpoptions_annotations_proto_extTypes = []protoimpl.ExtensionInfo{ ExtendedType: (*descriptorpb.MethodOptions)(nil), ExtensionType: (*HttpRule)(nil), Field: 108345, - Name: "ease.api.http", + Name: "janus.api.http", Tag: "bytes,108345,opt,name=http", Filename: "httpoptions/annotations.proto", }, @@ -685,7 +685,7 @@ var file_httpoptions_annotations_proto_extTypes = []protoimpl.ExtensionInfo{ ExtendedType: (*descriptorpb.MethodOptions)(nil), ExtensionType: (*ApiMethod)(nil), Field: 108361, - Name: "ease.api.method", + Name: "janus.api.method", Tag: "bytes,108361,opt,name=method", Filename: "httpoptions/annotations.proto", }, @@ -693,7 +693,7 @@ var file_httpoptions_annotations_proto_extTypes = []protoimpl.ExtensionInfo{ ExtendedType: (*descriptorpb.ServiceOptions)(nil), ExtensionType: (*ServiceSpec)(nil), Field: 108349, - Name: "ease.api.service_spec", + Name: "janus.api.service_spec", Tag: "bytes,108349,opt,name=service_spec", Filename: "httpoptions/annotations.proto", }, @@ -701,7 +701,7 @@ var file_httpoptions_annotations_proto_extTypes = []protoimpl.ExtensionInfo{ ExtendedType: (*descriptorpb.FieldOptions)(nil), ExtensionType: (*ValidationRules)(nil), Field: 108102, - Name: "ease.api.rules", + Name: "janus.api.rules", Tag: "bytes,108102,opt,name=rules", Filename: "httpoptions/annotations.proto", }, @@ -709,21 +709,21 @@ var file_httpoptions_annotations_proto_extTypes = []protoimpl.ExtensionInfo{ // Extension fields to descriptorpb.MethodOptions. var ( - // optional ease.api.HttpRule http = 108345; + // optional janus.api.HttpRule http = 108345; E_Http = &file_httpoptions_annotations_proto_extTypes[0] - // optional ease.api.ApiMethod method = 108361; + // optional janus.api.ApiMethod method = 108361; E_Method = &file_httpoptions_annotations_proto_extTypes[1] ) // Extension fields to descriptorpb.ServiceOptions. var ( - // optional ease.api.ServiceSpec service_spec = 108349; + // optional janus.api.ServiceSpec service_spec = 108349; E_ServiceSpec = &file_httpoptions_annotations_proto_extTypes[2] ) // Extension fields to descriptorpb.FieldOptions. var ( - // optional ease.api.ValidationRules rules = 108102; + // optional janus.api.ValidationRules rules = 108102; E_Rules = &file_httpoptions_annotations_proto_extTypes[3] ) @@ -865,41 +865,41 @@ func file_httpoptions_annotations_proto_rawDescGZIP() []byte { var file_httpoptions_annotations_proto_enumTypes = make([]protoimpl.EnumInfo, 7) var file_httpoptions_annotations_proto_msgTypes = make([]protoimpl.MessageInfo, 4) var file_httpoptions_annotations_proto_goTypes = []interface{}{ - (ApiSourceType)(0), // 0: ease.api.ApiSourceType - (AuthTokenType)(0), // 1: ease.api.AuthTokenType - (SpecSourceType)(0), // 2: ease.api.SpecSourceType - (LoadBalancer)(0), // 3: ease.api.LoadBalancer - (OperatorType)(0), // 4: ease.api.OperatorType - (FunctionType)(0), // 5: ease.api.FunctionType - (ValueType)(0), // 6: ease.api.ValueType - (*ApiMethod)(nil), // 7: ease.api.ApiMethod - (*ServiceSpec)(nil), // 8: ease.api.ServiceSpec - (*ValidationRule)(nil), // 9: ease.api.ValidationRule - (*ValidationRules)(nil), // 10: ease.api.ValidationRules + (ApiSourceType)(0), // 0: janus.api.ApiSourceType + (AuthTokenType)(0), // 1: janus.api.AuthTokenType + (SpecSourceType)(0), // 2: janus.api.SpecSourceType + (LoadBalancer)(0), // 3: janus.api.LoadBalancer + (OperatorType)(0), // 4: janus.api.OperatorType + (FunctionType)(0), // 5: janus.api.FunctionType + (ValueType)(0), // 6: janus.api.ValueType + (*ApiMethod)(nil), // 7: janus.api.ApiMethod + (*ServiceSpec)(nil), // 8: janus.api.ServiceSpec + (*ValidationRule)(nil), // 9: janus.api.ValidationRule + (*ValidationRules)(nil), // 10: janus.api.ValidationRules (data.ServiceId)(0), // 11: data.ServiceId (*descriptorpb.MethodOptions)(nil), // 12: google.protobuf.MethodOptions (*descriptorpb.ServiceOptions)(nil), // 13: google.protobuf.ServiceOptions (*descriptorpb.FieldOptions)(nil), // 14: google.protobuf.FieldOptions - (*HttpRule)(nil), // 15: ease.api.HttpRule + (*HttpRule)(nil), // 15: janus.api.HttpRule } var file_httpoptions_annotations_proto_depIdxs = []int32{ - 0, // 0: ease.api.ApiMethod.api_source:type_name -> ease.api.ApiSourceType - 1, // 1: ease.api.ApiMethod.token_type:type_name -> ease.api.AuthTokenType - 2, // 2: ease.api.ApiMethod.spec_source_type:type_name -> ease.api.SpecSourceType - 11, // 3: ease.api.ServiceSpec.service_id:type_name -> data.ServiceId - 3, // 4: ease.api.ServiceSpec.balancer:type_name -> ease.api.LoadBalancer - 4, // 5: ease.api.ValidationRule.operator:type_name -> ease.api.OperatorType - 6, // 6: ease.api.ValidationRule.type:type_name -> ease.api.ValueType - 5, // 7: ease.api.ValidationRule.function:type_name -> ease.api.FunctionType - 9, // 8: ease.api.ValidationRules.rules:type_name -> ease.api.ValidationRule - 12, // 9: ease.api.http:extendee -> google.protobuf.MethodOptions - 12, // 10: ease.api.method:extendee -> google.protobuf.MethodOptions - 13, // 11: ease.api.service_spec:extendee -> google.protobuf.ServiceOptions - 14, // 12: ease.api.rules:extendee -> google.protobuf.FieldOptions - 15, // 13: ease.api.http:type_name -> ease.api.HttpRule - 7, // 14: ease.api.method:type_name -> ease.api.ApiMethod - 8, // 15: ease.api.service_spec:type_name -> ease.api.ServiceSpec - 10, // 16: ease.api.rules:type_name -> ease.api.ValidationRules + 0, // 0: janus.api.ApiMethod.api_source:type_name -> janus.api.ApiSourceType + 1, // 1: janus.api.ApiMethod.token_type:type_name -> janus.api.AuthTokenType + 2, // 2: janus.api.ApiMethod.spec_source_type:type_name -> janus.api.SpecSourceType + 11, // 3: janus.api.ServiceSpec.service_id:type_name -> data.ServiceId + 3, // 4: janus.api.ServiceSpec.balancer:type_name -> janus.api.LoadBalancer + 4, // 5: janus.api.ValidationRule.operator:type_name -> janus.api.OperatorType + 6, // 6: janus.api.ValidationRule.type:type_name -> janus.api.ValueType + 5, // 7: janus.api.ValidationRule.function:type_name -> janus.api.FunctionType + 9, // 8: janus.api.ValidationRules.rules:type_name -> janus.api.ValidationRule + 12, // 9: janus.api.http:extendee -> google.protobuf.MethodOptions + 12, // 10: janus.api.method:extendee -> google.protobuf.MethodOptions + 13, // 11: janus.api.service_spec:extendee -> google.protobuf.ServiceOptions + 14, // 12: janus.api.rules:extendee -> google.protobuf.FieldOptions + 15, // 13: janus.api.http:type_name -> janus.api.HttpRule + 7, // 14: janus.api.method:type_name -> janus.api.ApiMethod + 8, // 15: janus.api.service_spec:type_name -> janus.api.ServiceSpec + 10, // 16: janus.api.rules:type_name -> janus.api.ValidationRules 17, // [17:17] is the sub-list for method output_type 17, // [17:17] is the sub-list for method input_type 13, // [13:17] is the sub-list for extension type_name diff --git a/httpoptions/annotations.proto b/httpoptions/annotations.proto index d5c38d8..c1862a8 100644 --- a/httpoptions/annotations.proto +++ b/httpoptions/annotations.proto @@ -15,7 +15,7 @@ // See `https://github.com/googleapis/googleapis/blob/master/google/api/annotations.proto` syntax = "proto3"; -package ease.api; +package janus.api; import "google/protobuf/descriptor.proto"; import "httpoptions/http.proto"; @@ -23,9 +23,9 @@ import "data/data.proto"; import "frontend/error.proto"; option java_multiple_files = true; -option go_package = "github.com/binchencoder/ease-gateway/httpoptions;annotations"; +option go_package = "github.com/binchencoder/janus-gateway/httpoptions;annotations"; option java_outer_classname = "AnnotationsProto"; -option java_package = "com.ease.api"; +option java_package = "com.janus.api"; option objc_class_prefix = "EAPI"; extend google.protobuf.MethodOptions { @@ -66,13 +66,13 @@ message ApiMethod { // Api regist gateway. enum ApiSourceType { - EASE_GATEWAY = 0; // ease-gateway apis. + EASE_GATEWAY = 0; // janus-gateway apis. OPEN_GATEWAY = 1; // open-gateway open apis. } // Auth token type. enum AuthTokenType { - EASE_AUTH_TOKEN = 0; // ease gateway auth type. + EASE_AUTH_TOKEN = 0; // janus gateway auth type. BASE_ACCESS_TOKEN = 1; // open platform baseAccessToken. } diff --git a/httpoptions/http.pb.go b/httpoptions/http.pb.go index 7b6ae47..1bd6d48 100755 --- a/httpoptions/http.pb.go +++ b/httpoptions/http.pb.go @@ -359,14 +359,14 @@ func file_httpoptions_http_proto_rawDescGZIP() []byte { var file_httpoptions_http_proto_msgTypes = make([]protoimpl.MessageInfo, 3) var file_httpoptions_http_proto_goTypes = []interface{}{ - (*Http)(nil), // 0: ease.api.Http - (*HttpRule)(nil), // 1: ease.api.HttpRule - (*CustomHttpPattern)(nil), // 2: ease.api.CustomHttpPattern + (*Http)(nil), // 0: janus.api.Http + (*HttpRule)(nil), // 1: janus.api.HttpRule + (*CustomHttpPattern)(nil), // 2: janus.api.CustomHttpPattern } var file_httpoptions_http_proto_depIdxs = []int32{ - 1, // 0: ease.api.Http.rules:type_name -> ease.api.HttpRule - 2, // 1: ease.api.HttpRule.custom:type_name -> ease.api.CustomHttpPattern - 1, // 2: ease.api.HttpRule.additional_bindings:type_name -> ease.api.HttpRule + 1, // 0: janus.api.Http.rules:type_name -> janus.api.HttpRule + 2, // 1: janus.api.HttpRule.custom:type_name -> janus.api.CustomHttpPattern + 1, // 2: janus.api.HttpRule.additional_bindings:type_name -> janus.api.HttpRule 3, // [3:3] is the sub-list for method output_type 3, // [3:3] is the sub-list for method input_type 3, // [3:3] is the sub-list for extension type_name diff --git a/httpoptions/http.proto b/httpoptions/http.proto index ee1d88b..499627e 100644 --- a/httpoptions/http.proto +++ b/httpoptions/http.proto @@ -14,13 +14,13 @@ // See `https://github.com/googleapis/googleapis/blob/master/google/api/http.proto` syntax = "proto3"; -package ease.api; +package janus.api; option cc_enable_arenas = true; -option go_package = "github.com/binchencoder/ease-gateway/httpoptions;annotations"; +option go_package = "github.com/binchencoder/janus-gateway/httpoptions;annotations"; option java_multiple_files = true; option java_outer_classname = "HttpProto"; -option java_package = "com.ease.api"; +option java_package = "com.janus.api"; option objc_class_prefix = "EAPI"; // Defines the HTTP configuration for an API service. It contains a list of diff --git a/httpoptions/pom.xml b/httpoptions/pom.xml index f91570c..7f72b56 100755 --- a/httpoptions/pom.xml +++ b/httpoptions/pom.xml @@ -2,8 +2,8 @@ 4.0.0 - com.binchencoder.easegw - easegw-options-protos + com.binchencoder.gateway + janus-options-protos jar 1.0-SNAPSHOT diff --git a/integrate/BUILD.bazel b/integrate/BUILD.bazel index f1d2fab..55c5ca2 100755 --- a/integrate/BUILD.bazel +++ b/integrate/BUILD.bazel @@ -8,7 +8,7 @@ go_library( ["*.go"], exclude = ["*_test.go"], ), - importpath = "github.com/binchencoder/ease-gateway/integrate", + importpath = "github.com/binchencoder/janus-gateway/integrate", deps = [ "//httpoptions", "//gateway/runtime", diff --git a/integrate/hook.go b/integrate/hook.go index db7fb0f..31020f1 100755 --- a/integrate/hook.go +++ b/integrate/hook.go @@ -13,10 +13,10 @@ import ( "google.golang.org/grpc/metadata" "google.golang.org/protobuf/proto" - "github.com/binchencoder/ease-gateway/gateway/runtime" - options "github.com/binchencoder/ease-gateway/httpoptions" - "github.com/binchencoder/ease-gateway/integrate/metrics" - "github.com/binchencoder/ease-gateway/util" + "github.com/binchencoder/janus-gateway/gateway/runtime" + options "github.com/binchencoder/janus-gateway/httpoptions" + "github.com/binchencoder/janus-gateway/integrate/metrics" + "github.com/binchencoder/janus-gateway/util" "github.com/binchencoder/letsgo/grpc" "github.com/binchencoder/letsgo/trace" @@ -41,7 +41,7 @@ var ( ) // gatewayHook implements interface GatewayServiceHook in package -// github.com/binchencoder/ease-gateway/gateway/runtime. +// github.com/binchencoder/janus-gateway/gateway/runtime. type gatewayHook struct { mux *runtime.ServeMux host string @@ -149,13 +149,13 @@ func NewGatewayHook(mux *runtime.ServeMux, host string) runtime.GatewayServiceHo } } -// addMetrics add metrics to prometheus for ease-gateway. +// addMetrics add metrics to prometheus for janus-gateway. func addMetrics(ctx context.Context, svc *runtime.Service, m *runtime.Method, code codes.Code, startTime time.Time, clt string) float64 { rp := &metrics.ReporterParam{StartTime: startTime, ServiceName: svc.Spec.GetServiceName(), Url: m.Path, HttpMethod: m.HttpMethod, Code: strconv.FormatUint(uint64(code), 10), Client: clt} return rp.RequestComplete() } -// getClient returns client value who request ease-gateway from Md. +// getClient returns client value who request janus-gateway from Md. func getClientFroMd(md metadata.MD) string { if s, ok := md[XSource]; ok && len(s) > 0 && s[0] != ResourceClient { return s[0] diff --git a/integrate/hookexternal.go b/integrate/hookexternal.go index 1bf12d0..9be3e8a 100644 --- a/integrate/hookexternal.go +++ b/integrate/hookexternal.go @@ -1,4 +1,4 @@ -// Note: this file is for ease-gateway which are exposed to external users. +// Note: this file is for janus-gateway which are exposed to external users. package integrate @@ -12,9 +12,9 @@ import ( gr "google.golang.org/grpc" "google.golang.org/grpc/codes" - "github.com/binchencoder/ease-gateway/gateway/runtime" - options "github.com/binchencoder/ease-gateway/httpoptions" - "github.com/binchencoder/ease-gateway/util" + "github.com/binchencoder/janus-gateway/gateway/runtime" + options "github.com/binchencoder/janus-gateway/httpoptions" + "github.com/binchencoder/janus-gateway/util" vexpb "github.com/binchencoder/gateway-proto/data" fpb "github.com/binchencoder/gateway-proto/frontend" "github.com/binchencoder/letsgo/grpc" @@ -217,7 +217,7 @@ func verifyHeader(ctx context.Context, header http.Header, svc *runtime.Service, return nil } -// getClient returns client value who request ease-gateway from header. +// getClient returns client value who request janus-gateway from header. func getClientFromHeader(header http.Header) string { xs := header.Get(XSource) cl := header.Get(XClient) diff --git a/integrate/metrics/BUILD b/integrate/metrics/BUILD index a068559..dca50df 100755 --- a/integrate/metrics/BUILD +++ b/integrate/metrics/BUILD @@ -5,7 +5,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( name = "go_default_library", srcs = ["reporter.go"], - importpath = "github.com/binchencoder/ease-gateway/integrate/metrics", + importpath = "github.com/binchencoder/janus-gateway/integrate/metrics", deps = [ "@com_github_binchencoder_letsgo//time:go_default_library", "@com_github_prometheus_client_golang//prometheus:go_default_library", diff --git a/integrate/metrics/reporter.go b/integrate/metrics/reporter.go index 5f9f716..9de191e 100755 --- a/integrate/metrics/reporter.go +++ b/integrate/metrics/reporter.go @@ -9,7 +9,7 @@ import ( ) var ( - // Create a histogram for record response latency (milliseconds) of ease-gateway. + // Create a histogram for record response latency (milliseconds) of janus-gateway. // And it will generate additional metric, for example: // gateway_http_response_ms_count, it is the total number of request. gatewayHandledHistogram = prometheus.NewHistogramVec( @@ -23,7 +23,7 @@ var ( []string{"client", "service_name", "url", "http_method", "code"}, ) - // Create a counter for record total system errors of ease-gateway. + // Create a counter for record total system errors of janus-gateway. gatewayErrCounter = prometheus.NewCounterVec( prometheus.CounterOpts{ Namespace: "gateway", diff --git a/integrate/middleware.go b/integrate/middleware.go index 6c3fb21..40db393 100644 --- a/integrate/middleware.go +++ b/integrate/middleware.go @@ -4,7 +4,7 @@ import ( "flag" "net/http" - "github.com/binchencoder/ease-gateway/gateway/runtime" + "github.com/binchencoder/janus-gateway/gateway/runtime" ) var ( diff --git a/proto/examplepb/BUILD.bazel b/proto/examplepb/BUILD.bazel index 7248172..4b2b9fe 100644 --- a/proto/examplepb/BUILD.bazel +++ b/proto/examplepb/BUILD.bazel @@ -30,7 +30,7 @@ go_proto_library( "//:go_grpc", "//gateway/protoc-gen-grpc-gateway:go_gen_grpc_gateway", # keep ], - importpath = "github.com/binchencoder/ease-gateway/proto/examplepb", + importpath = "github.com/binchencoder/janus-gateway/proto/examplepb", proto = ":examplepb_proto", deps = [ "//httpoptions", @@ -45,7 +45,7 @@ go_proto_library( go_library( name = "examplepb", embed = [":examplepb_go_proto"], - importpath = "github.com/binchencoder/ease-gateway/proto/examplepb", + importpath = "github.com/binchencoder/janus-gateway/proto/examplepb", deps = [ "//httpoptions", "//gateway/runtime", diff --git a/proto/examplepb/echo_service.proto b/proto/examplepb/echo_service.proto index 72707da..dbaf516 100644 --- a/proto/examplepb/echo_service.proto +++ b/proto/examplepb/echo_service.proto @@ -1,6 +1,6 @@ syntax = "proto3"; -option go_package = "github.com/binchencoder/ease-gateway/gateway/proto/examplepb"; +option go_package = "github.com/binchencoder/janus-gateway/gateway/proto/examplepb"; package grpc.gateway.proto.examplepb; @@ -23,7 +23,7 @@ message SimpleMessage { // Id represents the message identifier. string id = 1 [ - (ease.api.rules) = { + (janus.api.rules) = { rules: { type: STRING, operator: NON_NIL, @@ -44,7 +44,7 @@ message SimpleMessage { ]; int64 num = 2 [ - (ease.api.rules) = { + (janus.api.rules) = { rules: { type: NUMBER, operator: GT, @@ -65,7 +65,7 @@ message SimpleMessage { // Echo service responds to incoming echo requests. service EchoService { - option (ease.api.service_spec) = { + option (janus.api.service_spec) = { service_id: CUSTOM_EASE_GATEWAY_TEST port_name : "grpc" namespace : "default" @@ -77,7 +77,7 @@ service EchoService { // The message posted as the id parameter will also be // returned. rpc Echo(SimpleMessage) returns (SimpleMessage) { - option (ease.api.http) = { + option (janus.api.http) = { post: "/v1/example/echo/{id}" additional_bindings { get: "/v1/example/echo/{id}/{num}" @@ -95,14 +95,14 @@ service EchoService { } // EchoBody method receives a simple message and returns it. rpc EchoBody(SimpleMessage) returns (SimpleMessage) { - option (ease.api.http) = { + option (janus.api.http) = { post: "/v1/example/echo_body" body: "*" }; } // EchoDelete method receives a simple message and returns it. rpc EchoDelete(SimpleMessage) returns (SimpleMessage) { - option (ease.api.http) = { + option (janus.api.http) = { delete: "/v1/example/echo_delete" }; } diff --git a/repositories.bzl b/repositories.bzl index 4cbd74e..63a42de 100644 --- a/repositories.bzl +++ b/repositories.bzl @@ -2,8 +2,8 @@ load("@bazel_gazelle//:deps.bzl", "go_repository") def go_repositories(): go_repository( - name = "com_github_binchencoder_ease_gateway", - importpath = "github.com/binchencoder/ease-gateway", + name = "com_github_binchencoder_janus_gateway", + importpath = "github.com/binchencoder/janus-gateway", sum = "h1:wYZv8TO4TGO2U8HjEO5Odf8OYWQjfrXS8ddfGZWQfHI=", version = "v1.0.3", ) diff --git a/util/BUILD.bazel b/util/BUILD.bazel index 6de1b86..2a8810e 100755 --- a/util/BUILD.bazel +++ b/util/BUILD.bazel @@ -10,7 +10,7 @@ go_library( ["*.go"], exclude = ["*_test.go"], ), - importpath = "github.com/binchencoder/ease-gateway/util", + importpath = "github.com/binchencoder/janus-gateway/util", deps = [ "//util/glog:go_default_library", "@com_github_fatih_color//:go_default_library", diff --git a/util/glog/BUILD.bazel b/util/glog/BUILD.bazel index d6888fb..56b648e 100755 --- a/util/glog/BUILD.bazel +++ b/util/glog/BUILD.bazel @@ -8,7 +8,7 @@ go_library( ["*.go"], exclude = ["*_test.go"], ), - importpath = "github.com/binchencoder/ease-gateway/util/glog", + importpath = "github.com/binchencoder/janus-gateway/util/glog", deps = [ "@com_github_binchencoder_letsgo//trace:go_default_library", "@org_golang_x_net//context:go_default_library", diff --git a/util/glog/cmd/BUILD.bazel b/util/glog/cmd/BUILD.bazel index 97c7aca..2b3c7f0 100644 --- a/util/glog/cmd/BUILD.bazel +++ b/util/glog/cmd/BUILD.bazel @@ -3,7 +3,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library") go_library( name = "go_default_library", srcs = ["main.go"], - importpath = "github.com/binchencoder/ease-gateway/util/glog/cmd", + importpath = "github.com/binchencoder/janus-gateway/util/glog/cmd", visibility = ["//visibility:private"], deps = ["//util/glog:go_default_library"], ) diff --git a/util/glog/cmd/main.go b/util/glog/cmd/main.go index b0285e2..75c9145 100755 --- a/util/glog/cmd/main.go +++ b/util/glog/cmd/main.go @@ -3,7 +3,7 @@ package main import ( "flag" - "github.com/binchencoder/ease-gateway/util/glog" + "github.com/binchencoder/janus-gateway/util/glog" ) func main() { diff --git a/util/log.go b/util/log.go index 0fc7645..750137e 100755 --- a/util/log.go +++ b/util/log.go @@ -3,7 +3,7 @@ package util import ( col "github.com/fatih/color" - "github.com/binchencoder/ease-gateway/util/glog" + "github.com/binchencoder/janus-gateway/util/glog" ) func init() { @@ -12,7 +12,7 @@ func init() { // gateway-rest日志 var ( - // ease-gateway 请求和响应详情日志. 支持格式包括: + // janus-gateway 请求和响应详情日志. 支持格式包括: // 1. RequestRestFormat // 2. ResponseRestFormat RestLogger = glog.Context(nil, glog.FileName{Name: "gateway-rest"}) @@ -30,13 +30,13 @@ var ( // gateway-config日志 var ( - // ease-gateway 配置操作相关日志. + // janus-gateway 配置操作相关日志. ConfigLogger = glog.Context(nil, glog.FileName{Name: "gateway-config"}) ) // gateway-stat日志 var ( - // ease-gateway 访问统计日志. 支持格式包括: + // janus-gateway 访问统计日志. 支持格式包括: // 1. StatFormat StatLogger = glog.Context(nil, glog.FileName{Name: "gateway-stat"}) From 7ea6e3ab793c65cb09a1a8821b813b27d5161e5e Mon Sep 17 00:00:00 2001 From: binchencoder <15811514091@163.com> Date: Sat, 23 Apr 2022 19:54:15 +0800 Subject: [PATCH 49/56] Rename ease-gateway to janus-gateway --- .circleci/config.yml | 4 +- README.md | 2 +- cmd/custom-gateway/main.go | 6 +- cmd/gateway/main.go | 4 +- docs/design.md | 4 +- ...se-Gateway.drawio => Janus-Gateway.drawio} | 0 .../{Ease-Gateway.png => Janus-Gateway.png} | Bin docs/scripts/start.sh | 8 +- docs/scripts/stop.sh | 6 +- examples/grpc-server/main.go | 2 +- examples/internal/README.md | 2 +- .../cmd/example-grpc-client/grpcclient.go | 4 +- .../internal/cmd/example-grpc-server/main.go | 2 +- examples/internal/gateway/gateway.go | 2 +- .../proto/examplepb/echo_service.pb.gw.go | 192 +++++++++--------- .../proto/examplepb/echo_service.proto | 2 +- .../examplepb/unannotated_echo_service.proto | 2 +- gateway/README.md | 2 +- gateway/runtime/service.go | 4 +- httpoptions/BUILD.bazel | 2 +- httpoptions/annotations.pb.go | 16 +- httpoptions/annotations.proto | 4 +- integrate/hookexternal.go | 8 +- proto/examplepb/echo_service.proto | 4 +- proto/examplepb/pom.xml | 8 +- proto/pom.xml | 8 +- 26 files changed, 149 insertions(+), 149 deletions(-) rename docs/images/{Ease-Gateway.drawio => Janus-Gateway.drawio} (100%) rename docs/images/{Ease-Gateway.png => Janus-Gateway.png} (100%) diff --git a/.circleci/config.yml b/.circleci/config.yml index 076541f..b693f4d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -6,7 +6,7 @@ commands: steps: - run: | cat > .bazelrc \<< EOF - startup --output_base /home/vscode/.cache/_ease_gateway_bazel + startup --output_base /home/vscode/.cache/_janus_gateway_bazel build --test_output errors build --features race # Workaround https://github.com/bazelbuild/bazel/issues/3645 @@ -109,7 +109,7 @@ jobs: - save_cache: key: v3-bazel-cache-{{ checksum "repositories.bzl" }} paths: - - /home/vscode/.cache/_ease_gateway_bazel + - /home/vscode/.cache/_janus_gateway_bazel gorelease: executor: build-env working_directory: /home/vscode/src/janus-gateway diff --git a/README.md b/README.md index be219a7..e08868f 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Gateway service based on [grpc-ecosystem/grpc-gateway](https://github.com/grpc-e ## Architecture -![](./docs/images/Ease-Gateway.png) +![](./docs/images/Janus-Gateway.png) ## Design diff --git a/cmd/custom-gateway/main.go b/cmd/custom-gateway/main.go index b82b1f3..ef9df18 100644 --- a/cmd/custom-gateway/main.go +++ b/cmd/custom-gateway/main.go @@ -22,7 +22,7 @@ var ( ) func usage() { - fmt.Println(`EaseGateway - Ease Gateway of binchencoder. + fmt.Println(`JanusGateway - Janus Gateway of binchencoder. Usage: janus-gateway [options] @@ -48,11 +48,11 @@ func main() { // debugMode := flag.Lookup("debug-mode") // debugMode.Value.Set("true") - runtime.CallerServiceId = data.ServiceId_EASE_GATEWAY + runtime.CallerServiceId = data.ServiceId_JANUS_GATEWAY // integrate.SetAllowCredentials(true) // integrate.SetAllowHostsRegexp([]string{"*"}) - glog.Info("***** Ease gateway init. *****") + glog.Info("***** Janus gateway init. *****") hostPort := fmt.Sprintf("%s:%d", *host, *port) mux := runtime.NewServeMux() diff --git a/cmd/gateway/main.go b/cmd/gateway/main.go index d76a067..e5eab81 100644 --- a/cmd/gateway/main.go +++ b/cmd/gateway/main.go @@ -26,7 +26,7 @@ var ( ) func usage() { - fmt.Println(`Ease Gateway - Universal Gateway of xxx Inc. + fmt.Println(`Janus Gateway - Universal Gateway of xxx Inc. Usage: janus-gateway [options] @@ -72,7 +72,7 @@ func main() { checkFlags() hostPort := fmt.Sprintf("%s:%d", *host, *port) - runtime.CallerServiceId = data.ServiceId_EASE_GATEWAY + runtime.CallerServiceId = data.ServiceId_JANUS_GATEWAY serviceName, err := naming.ServiceIdToName(runtime.CallerServiceId) if err != nil { glog.Errorf("Invalid service id %d", runtime.CallerServiceId) diff --git a/docs/design.md b/docs/design.md index 7c73894..1da7f9c 100644 --- a/docs/design.md +++ b/docs/design.md @@ -1,4 +1,4 @@ -# Ease-gatway - Enterprise Universal Gateway Service +# Janus-gatway - Enterprise Universal Gateway Service `janus-gateway` is a enterprise universal gateway service for mobile, native, and web apps. It's based on `grpc-gateway` and mobile team's gateway development experience. @@ -137,7 +137,7 @@ import "options/extension.proto"; service Demo { option (janus.api.service_spec) = { - service_id: EASE_GATEWAY_DEMO + service_id: JANUS_GATEWAY_DEMO namespace: "default" port_name: "grpc" } diff --git a/docs/images/Ease-Gateway.drawio b/docs/images/Janus-Gateway.drawio similarity index 100% rename from docs/images/Ease-Gateway.drawio rename to docs/images/Janus-Gateway.drawio diff --git a/docs/images/Ease-Gateway.png b/docs/images/Janus-Gateway.png similarity index 100% rename from docs/images/Ease-Gateway.png rename to docs/images/Janus-Gateway.png diff --git a/docs/scripts/start.sh b/docs/scripts/start.sh index 9734a17..6c31e93 100755 --- a/docs/scripts/start.sh +++ b/docs/scripts/start.sh @@ -31,13 +31,13 @@ STDOUT_FILE=$HOMEDIR/std.out set +e PIDS=`pgrep ^janus-gateway$` if [ $? -eq 0 ]; then - echo "ERROR: The service Ease Gateway already started!" + echo "ERROR: The service Janus Gateway already started!" echo "PID: $PIDS" exit 1 fi set -e -echo "Service Ease Gateway start..." +echo "Service Janus Gateway start..." nohup $HOMEDIR/bin/janus-gateway \ -debug-svc-endpoint=vexillary-service=192.168.10.41:4100 \ -debug-svc-endpoint=pay-grpc-service=192.168.32.18:10008 \ @@ -52,8 +52,8 @@ sleep 2 PIDS_COUNT=`pgrep ^janus-gateway$|wc -l` if [ $PIDS_COUNT -eq 0 ]; then - echo "ERROR: The service Ease Gateway does not started!" + echo "ERROR: The service Janus Gateway does not started!" exit 1 fi -echo "Service Ease Gateway start success!" +echo "Service Janus Gateway start success!" diff --git a/docs/scripts/stop.sh b/docs/scripts/stop.sh index 54ff16c..fd54eb6 100755 --- a/docs/scripts/stop.sh +++ b/docs/scripts/stop.sh @@ -3,11 +3,11 @@ set +e PIDS=`pgrep ^janus-gateway$` if [ $? -ne 0 ]; then - echo "INFO: The service Ease Gateway did not started!" + echo "INFO: The service Janus Gateway did not started!" exit 0 fi -echo -e "Stopping the service Ease Gateway ...\c" +echo -e "Stopping the service Janus Gateway ...\c" for PID in $PIDS ; do kill $PID > /dev/null 2>&1 done @@ -19,7 +19,7 @@ while [ true ]; do if [ $? -ne 0 ]; then echo echo "PID: $PIDS" - echo "Service Ease Gateway stopped." + echo "Service Janus Gateway stopped." exit 0 fi diff --git a/examples/grpc-server/main.go b/examples/grpc-server/main.go index 4a3de71..0880604 100644 --- a/examples/grpc-server/main.go +++ b/examples/grpc-server/main.go @@ -26,7 +26,7 @@ func main() { defer glog.Flush() // Regist to skylbserver - skylb.Register(data.ServiceId_CUSTOM_EASE_GATEWAY_TEST, "grpc", *port) + skylb.Register(data.ServiceId_CUSTOM_JANUS_GATEWAY_TEST, "grpc", *port) skylb.EnableHistogram() skylb.Start(fmt.Sprintf(":%d", *port), func(s *grpc.Server) error { examplepb.RegisterEchoServiceServer(s, NewEchoServer()) diff --git a/examples/internal/README.md b/examples/internal/README.md index 51dc903..89cd791 100644 --- a/examples/internal/README.md +++ b/examples/internal/README.md @@ -1,6 +1,6 @@ # Overrview -janus-gateway/examples/internal 是使用ease-gateway的一个完整示例,包含gateway-server 和 gRPC-server. 还有Java实现gRPC Server的例子 [https://github.com/binchencoder/spring-boot-grpc/tree/master/spring-boot-grpc-examples] +janus-gateway/examples/internal 是使用janus-gateway的一个完整示例,包含gateway-server 和 gRPC-server. 还有Java实现gRPC Server的例子 [https://github.com/binchencoder/spring-boot-grpc/tree/master/spring-boot-grpc-examples] # Build the example diff --git a/examples/internal/cmd/example-grpc-client/grpcclient.go b/examples/internal/cmd/example-grpc-client/grpcclient.go index 2ea1100..f75e756 100644 --- a/examples/internal/cmd/example-grpc-client/grpcclient.go +++ b/examples/internal/cmd/example-grpc-client/grpcclient.go @@ -24,7 +24,7 @@ var ( requestSleep = flag.Duration("request-sleep", 100*time.Millisecond, "The sleep time after each request") requestTimeout = flag.Duration("request-timeout", 100*time.Millisecond, "The timeout of each request") - spec = skylb.NewServiceSpec(skylb.DefaultNameSpace, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, skylb.DefaultPortName) + spec = skylb.NewServiceSpec(skylb.DefaultNameSpace, vexpb.ServiceId_CUSTOM_JANUS_GATEWAY_TEST, skylb.DefaultPortName) grpcFailCount = prom.NewCounter( prom.CounterOpts{ @@ -72,7 +72,7 @@ func main() { } func testClient() { - sl, cli, healthCli := startSkylb(vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST) + sl, cli, healthCli := startSkylb(vexpb.ServiceId_CUSTOM_JANUS_GATEWAY_TEST) for { for i := 0; i < *nBatchRequest; i++ { req := examplepb.SimpleMessage{ diff --git a/examples/internal/cmd/example-grpc-server/main.go b/examples/internal/cmd/example-grpc-server/main.go index d2752b7..7df8f7a 100644 --- a/examples/internal/cmd/example-grpc-server/main.go +++ b/examples/internal/cmd/example-grpc-server/main.go @@ -48,7 +48,7 @@ func main() { go registerPrometheus() - skylb.Register(data.ServiceId_CUSTOM_EASE_GATEWAY_TEST, "grpc", *port) + skylb.Register(data.ServiceId_CUSTOM_JANUS_GATEWAY_TEST, "grpc", *port) skylb.EnableHistogram() skylb.Start(fmt.Sprintf(":%d", *port), func(s *grpc.Server) error { examplepb.RegisterEchoServiceServer(s, server.NewEchoServer()) diff --git a/examples/internal/gateway/gateway.go b/examples/internal/gateway/gateway.go index 87cb3af..357cd75 100644 --- a/examples/internal/gateway/gateway.go +++ b/examples/internal/gateway/gateway.go @@ -24,7 +24,7 @@ func newGateway(ctx context.Context, conn *grpc.ClientConn, opts []gwruntime.Ser mux := gwruntime.NewServeMux(opts...) - // examplepb.Enable_CUSTOM_EASE_GATEWAY_TEST__default__grpc_ServiceGroup() + // examplepb.Enable_CUSTOM_JANUS_GATEWAY_TEST__default__grpc_ServiceGroup() for _, f := range []func(context.Context, *gwruntime.ServeMux, *grpc.ClientConn) error{ examplepb.RegisterEchoServiceHandler, } { diff --git a/examples/internal/proto/examplepb/echo_service.pb.gw.go b/examples/internal/proto/examplepb/echo_service.pb.gw.go index 75b4582..bc7235f 100755 --- a/examples/internal/proto/examplepb/echo_service.pb.gw.go +++ b/examples/internal/proto/examplepb/echo_service.pb.gw.go @@ -108,7 +108,7 @@ var ( func request_EchoService_Echo_0(ctx context.Context, marshaler runtime.Marshaler, client EchoServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq SimpleMessage var metadata runtime.ServerMetadata - spec := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec + spec := internal_EchoService_CUSTOM_JANUS_GATEWAY_TEST_spec var ( val string @@ -188,7 +188,7 @@ var ( func request_EchoService_Echo_1(ctx context.Context, marshaler runtime.Marshaler, client EchoServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq SimpleMessage var metadata runtime.ServerMetadata - spec := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec + spec := internal_EchoService_CUSTOM_JANUS_GATEWAY_TEST_spec var ( val string @@ -289,7 +289,7 @@ var ( func request_EchoService_Echo_2(ctx context.Context, marshaler runtime.Marshaler, client EchoServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq SimpleMessage var metadata runtime.ServerMetadata - spec := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec + spec := internal_EchoService_CUSTOM_JANUS_GATEWAY_TEST_spec var ( val string @@ -421,7 +421,7 @@ var ( func request_EchoService_Echo_3(ctx context.Context, marshaler runtime.Marshaler, client EchoServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq SimpleMessage var metadata runtime.ServerMetadata - spec := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec + spec := internal_EchoService_CUSTOM_JANUS_GATEWAY_TEST_spec var ( val string @@ -553,7 +553,7 @@ var ( func request_EchoService_Echo_4(ctx context.Context, marshaler runtime.Marshaler, client EchoServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq SimpleMessage var metadata runtime.ServerMetadata - spec := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec + spec := internal_EchoService_CUSTOM_JANUS_GATEWAY_TEST_spec var ( val string @@ -629,7 +629,7 @@ func local_request_EchoService_Echo_4(ctx context.Context, marshaler runtime.Mar func request_EchoService_EchoBody_0(ctx context.Context, marshaler runtime.Marshaler, client EchoServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq SimpleMessage var metadata runtime.ServerMetadata - spec := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec + spec := internal_EchoService_CUSTOM_JANUS_GATEWAY_TEST_spec newReader, berr := utilities.IOReaderFactory(req.Body) if berr != nil { @@ -677,7 +677,7 @@ var ( func request_EchoService_EchoDelete_0(ctx context.Context, marshaler runtime.Marshaler, client EchoServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq SimpleMessage var metadata runtime.ServerMetadata - spec := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec + spec := internal_EchoService_CUSTOM_JANUS_GATEWAY_TEST_spec if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) @@ -722,7 +722,7 @@ var ( func request_EchoService_EchoPatch_0(ctx context.Context, marshaler runtime.Marshaler, client EchoServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq DynamicMessageUpdate var metadata runtime.ServerMetadata - spec := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec + spec := internal_EchoService_CUSTOM_JANUS_GATEWAY_TEST_spec newReader, berr := utilities.IOReaderFactory(req.Body) if berr != nil { @@ -794,7 +794,7 @@ func local_request_EchoService_EchoPatch_0(ctx context.Context, marshaler runtim func request_EchoService_EchoValidationRule_0(ctx context.Context, marshaler runtime.Marshaler, client EchoServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq ValidationRuleTestRequest var metadata runtime.ServerMetadata - spec := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec + spec := internal_EchoService_CUSTOM_JANUS_GATEWAY_TEST_spec newReader, berr := utilities.IOReaderFactory(req.Body) if berr != nil { @@ -848,7 +848,7 @@ func local_request_EchoService_EchoValidationRule_0(ctx context.Context, marshal // Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterEchoServiceHandlerFromEndpoint instead. func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server EchoServiceServer) error { - mux.Handle("POST", pattern_EchoService_Echo_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("POST", pattern_EchoService_Echo_0, vexpb.ServiceId_CUSTOM_JANUS_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream @@ -872,7 +872,7 @@ func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux }) - mux.Handle("GET", pattern_EchoService_Echo_1, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("GET", pattern_EchoService_Echo_1, vexpb.ServiceId_CUSTOM_JANUS_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream @@ -896,7 +896,7 @@ func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux }) - mux.Handle("GET", pattern_EchoService_Echo_2, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("GET", pattern_EchoService_Echo_2, vexpb.ServiceId_CUSTOM_JANUS_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream @@ -920,7 +920,7 @@ func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux }) - mux.Handle("GET", pattern_EchoService_Echo_3, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("GET", pattern_EchoService_Echo_3, vexpb.ServiceId_CUSTOM_JANUS_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream @@ -944,7 +944,7 @@ func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux }) - mux.Handle("GET", pattern_EchoService_Echo_4, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("GET", pattern_EchoService_Echo_4, vexpb.ServiceId_CUSTOM_JANUS_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream @@ -968,7 +968,7 @@ func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux }) - mux.Handle("POST", pattern_EchoService_EchoBody_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("POST", pattern_EchoService_EchoBody_0, vexpb.ServiceId_CUSTOM_JANUS_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream @@ -992,7 +992,7 @@ func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux }) - mux.Handle("DELETE", pattern_EchoService_EchoDelete_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("DELETE", pattern_EchoService_EchoDelete_0, vexpb.ServiceId_CUSTOM_JANUS_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream @@ -1016,7 +1016,7 @@ func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux }) - mux.Handle("PATCH", pattern_EchoService_EchoPatch_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("PATCH", pattern_EchoService_EchoPatch_0, vexpb.ServiceId_CUSTOM_JANUS_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream @@ -1040,7 +1040,7 @@ func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux }) - mux.Handle("POST", pattern_EchoService_EchoValidationRule_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("POST", pattern_EchoService_EchoValidationRule_0, vexpb.ServiceId_CUSTOM_JANUS_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream @@ -1075,7 +1075,7 @@ func init() { _ = s _ = spec - spec = internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec + spec = internal_EchoService_CUSTOM_JANUS_GATEWAY_TEST_spec s = &runtime.Service{ Spec: *spec, Name: "EchoService", @@ -1084,7 +1084,7 @@ func init() { Disable: DisableEchoService_Service, } - runtime.AddService(s, Enable_CUSTOM_EASE_GATEWAY_TEST__default__grpc_ServiceGroup, Disable_CUSTOM_EASE_GATEWAY_TEST__default__grpc_ServiceGroup) + runtime.AddService(s, Enable_CUSTOM_JANUS_GATEWAY_TEST__default__grpc_ServiceGroup, Disable_CUSTOM_JANUS_GATEWAY_TEST__default__grpc_ServiceGroup) } @@ -1126,14 +1126,14 @@ func RegisterEchoServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn // doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in // "EchoServiceClient" to call the correct interceptors. func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client EchoServiceClient) error { - spec := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec + spec := internal_EchoService_CUSTOM_JANUS_GATEWAY_TEST_spec - runtime.AddMethod(spec, "EchoService", "Echo", "/v1/example/echo/{id}", "POST", true, false, false, "UNSPECIFIED", "EASE_GATEWAY", "EASE_AUTH_TOKEN", "") - mux.Handle("POST", pattern_EchoService_Echo_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + runtime.AddMethod(spec, "EchoService", "Echo", "/v1/example/echo/{id}", "POST", true, false, false, "UNSPECIFIED", "JANUS_GATEWAY", "JANUS_AUTH_TOKEN", "") + mux.Handle("POST", pattern_EchoService_Echo_0, vexpb.ServiceId_CUSTOM_JANUS_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { // TODO(mojz): review all locking/unlocking logic. - // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() - // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() - client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client + // internal_CUSTOM_JANUS_GATEWAY_TEST__default__grpc_lock.RLock() + // defer internal_CUSTOM_JANUS_GATEWAY_TEST__default__grpc_lock.RUnlock() + client := internal_EchoService_CUSTOM_JANUS_GATEWAY_TEST_client inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) if client == nil { err := status.Error(codes.Internal, "service disabled") @@ -1141,7 +1141,7 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux return } - ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) + ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_JANUS_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) if err != nil { grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) @@ -1167,12 +1167,12 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux }) - runtime.AddMethod(spec, "EchoService", "Echo", "/v1/example/echo/{id}/{num}", "GET", true, false, false, "UNSPECIFIED", "EASE_GATEWAY", "EASE_AUTH_TOKEN", "") - mux.Handle("GET", pattern_EchoService_Echo_1, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + runtime.AddMethod(spec, "EchoService", "Echo", "/v1/example/echo/{id}/{num}", "GET", true, false, false, "UNSPECIFIED", "JANUS_GATEWAY", "JANUS_AUTH_TOKEN", "") + mux.Handle("GET", pattern_EchoService_Echo_1, vexpb.ServiceId_CUSTOM_JANUS_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { // TODO(mojz): review all locking/unlocking logic. - // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() - // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() - client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client + // internal_CUSTOM_JANUS_GATEWAY_TEST__default__grpc_lock.RLock() + // defer internal_CUSTOM_JANUS_GATEWAY_TEST__default__grpc_lock.RUnlock() + client := internal_EchoService_CUSTOM_JANUS_GATEWAY_TEST_client inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) if client == nil { err := status.Error(codes.Internal, "service disabled") @@ -1180,7 +1180,7 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux return } - ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) + ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_JANUS_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) if err != nil { grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) @@ -1206,12 +1206,12 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux }) - runtime.AddMethod(spec, "EchoService", "Echo", "/v1/example/echo/{id}/{num}/{lang}", "GET", true, false, false, "UNSPECIFIED", "EASE_GATEWAY", "EASE_AUTH_TOKEN", "") - mux.Handle("GET", pattern_EchoService_Echo_2, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + runtime.AddMethod(spec, "EchoService", "Echo", "/v1/example/echo/{id}/{num}/{lang}", "GET", true, false, false, "UNSPECIFIED", "JANUS_GATEWAY", "JANUS_AUTH_TOKEN", "") + mux.Handle("GET", pattern_EchoService_Echo_2, vexpb.ServiceId_CUSTOM_JANUS_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { // TODO(mojz): review all locking/unlocking logic. - // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() - // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() - client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client + // internal_CUSTOM_JANUS_GATEWAY_TEST__default__grpc_lock.RLock() + // defer internal_CUSTOM_JANUS_GATEWAY_TEST__default__grpc_lock.RUnlock() + client := internal_EchoService_CUSTOM_JANUS_GATEWAY_TEST_client inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) if client == nil { err := status.Error(codes.Internal, "service disabled") @@ -1219,7 +1219,7 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux return } - ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) + ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_JANUS_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) if err != nil { grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) @@ -1245,12 +1245,12 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux }) - runtime.AddMethod(spec, "EchoService", "Echo", "/v1/example/echo1/{id}/{line_num}/{status.note}", "GET", true, false, false, "UNSPECIFIED", "EASE_GATEWAY", "EASE_AUTH_TOKEN", "") - mux.Handle("GET", pattern_EchoService_Echo_3, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + runtime.AddMethod(spec, "EchoService", "Echo", "/v1/example/echo1/{id}/{line_num}/{status.note}", "GET", true, false, false, "UNSPECIFIED", "JANUS_GATEWAY", "JANUS_AUTH_TOKEN", "") + mux.Handle("GET", pattern_EchoService_Echo_3, vexpb.ServiceId_CUSTOM_JANUS_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { // TODO(mojz): review all locking/unlocking logic. - // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() - // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() - client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client + // internal_CUSTOM_JANUS_GATEWAY_TEST__default__grpc_lock.RLock() + // defer internal_CUSTOM_JANUS_GATEWAY_TEST__default__grpc_lock.RUnlock() + client := internal_EchoService_CUSTOM_JANUS_GATEWAY_TEST_client inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) if client == nil { err := status.Error(codes.Internal, "service disabled") @@ -1258,7 +1258,7 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux return } - ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) + ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_JANUS_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) if err != nil { grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) @@ -1284,12 +1284,12 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux }) - runtime.AddMethod(spec, "EchoService", "Echo", "/v1/example/echo2/{no.note}", "GET", true, false, false, "UNSPECIFIED", "EASE_GATEWAY", "EASE_AUTH_TOKEN", "") - mux.Handle("GET", pattern_EchoService_Echo_4, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + runtime.AddMethod(spec, "EchoService", "Echo", "/v1/example/echo2/{no.note}", "GET", true, false, false, "UNSPECIFIED", "JANUS_GATEWAY", "JANUS_AUTH_TOKEN", "") + mux.Handle("GET", pattern_EchoService_Echo_4, vexpb.ServiceId_CUSTOM_JANUS_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { // TODO(mojz): review all locking/unlocking logic. - // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() - // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() - client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client + // internal_CUSTOM_JANUS_GATEWAY_TEST__default__grpc_lock.RLock() + // defer internal_CUSTOM_JANUS_GATEWAY_TEST__default__grpc_lock.RUnlock() + client := internal_EchoService_CUSTOM_JANUS_GATEWAY_TEST_client inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) if client == nil { err := status.Error(codes.Internal, "service disabled") @@ -1297,7 +1297,7 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux return } - ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) + ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_JANUS_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) if err != nil { grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) @@ -1323,12 +1323,12 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux }) - runtime.AddMethod(spec, "EchoService", "EchoBody", "/v1/example/echo_body", "POST", true, false, false, "UNSPECIFIED", "EASE_GATEWAY", "EASE_AUTH_TOKEN", "") - mux.Handle("POST", pattern_EchoService_EchoBody_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + runtime.AddMethod(spec, "EchoService", "EchoBody", "/v1/example/echo_body", "POST", true, false, false, "UNSPECIFIED", "JANUS_GATEWAY", "JANUS_AUTH_TOKEN", "") + mux.Handle("POST", pattern_EchoService_EchoBody_0, vexpb.ServiceId_CUSTOM_JANUS_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { // TODO(mojz): review all locking/unlocking logic. - // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() - // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() - client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client + // internal_CUSTOM_JANUS_GATEWAY_TEST__default__grpc_lock.RLock() + // defer internal_CUSTOM_JANUS_GATEWAY_TEST__default__grpc_lock.RUnlock() + client := internal_EchoService_CUSTOM_JANUS_GATEWAY_TEST_client inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) if client == nil { err := status.Error(codes.Internal, "service disabled") @@ -1336,7 +1336,7 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux return } - ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "EchoBody", w, req) + ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_JANUS_GATEWAY_TEST_spec, "EchoService", "EchoBody", w, req) if err != nil { grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) @@ -1362,12 +1362,12 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux }) - runtime.AddMethod(spec, "EchoService", "EchoDelete", "/v1/example/echo_delete", "DELETE", true, false, false, "UNSPECIFIED", "EASE_GATEWAY", "EASE_AUTH_TOKEN", "") - mux.Handle("DELETE", pattern_EchoService_EchoDelete_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + runtime.AddMethod(spec, "EchoService", "EchoDelete", "/v1/example/echo_delete", "DELETE", true, false, false, "UNSPECIFIED", "JANUS_GATEWAY", "JANUS_AUTH_TOKEN", "") + mux.Handle("DELETE", pattern_EchoService_EchoDelete_0, vexpb.ServiceId_CUSTOM_JANUS_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { // TODO(mojz): review all locking/unlocking logic. - // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() - // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() - client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client + // internal_CUSTOM_JANUS_GATEWAY_TEST__default__grpc_lock.RLock() + // defer internal_CUSTOM_JANUS_GATEWAY_TEST__default__grpc_lock.RUnlock() + client := internal_EchoService_CUSTOM_JANUS_GATEWAY_TEST_client inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) if client == nil { err := status.Error(codes.Internal, "service disabled") @@ -1375,7 +1375,7 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux return } - ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "EchoDelete", w, req) + ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_JANUS_GATEWAY_TEST_spec, "EchoService", "EchoDelete", w, req) if err != nil { grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) @@ -1401,12 +1401,12 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux }) - runtime.AddMethod(spec, "EchoService", "EchoPatch", "/v1/example/echo_patch", "PATCH", true, false, false, "UNSPECIFIED", "EASE_GATEWAY", "EASE_AUTH_TOKEN", "") - mux.Handle("PATCH", pattern_EchoService_EchoPatch_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + runtime.AddMethod(spec, "EchoService", "EchoPatch", "/v1/example/echo_patch", "PATCH", true, false, false, "UNSPECIFIED", "JANUS_GATEWAY", "JANUS_AUTH_TOKEN", "") + mux.Handle("PATCH", pattern_EchoService_EchoPatch_0, vexpb.ServiceId_CUSTOM_JANUS_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { // TODO(mojz): review all locking/unlocking logic. - // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() - // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() - client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client + // internal_CUSTOM_JANUS_GATEWAY_TEST__default__grpc_lock.RLock() + // defer internal_CUSTOM_JANUS_GATEWAY_TEST__default__grpc_lock.RUnlock() + client := internal_EchoService_CUSTOM_JANUS_GATEWAY_TEST_client inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) if client == nil { err := status.Error(codes.Internal, "service disabled") @@ -1414,7 +1414,7 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux return } - ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "EchoPatch", w, req) + ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_JANUS_GATEWAY_TEST_spec, "EchoService", "EchoPatch", w, req) if err != nil { grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) @@ -1440,12 +1440,12 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux }) - runtime.AddMethod(spec, "EchoService", "EchoValidationRule", "/v1/example/echo:validationRules", "POST", true, false, false, "UNSPECIFIED", "EASE_GATEWAY", "EASE_AUTH_TOKEN", "") - mux.Handle("POST", pattern_EchoService_EchoValidationRule_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + runtime.AddMethod(spec, "EchoService", "EchoValidationRule", "/v1/example/echo:validationRules", "POST", true, false, false, "UNSPECIFIED", "JANUS_GATEWAY", "JANUS_AUTH_TOKEN", "") + mux.Handle("POST", pattern_EchoService_EchoValidationRule_0, vexpb.ServiceId_CUSTOM_JANUS_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { // TODO(mojz): review all locking/unlocking logic. - // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() - // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() - client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client + // internal_CUSTOM_JANUS_GATEWAY_TEST__default__grpc_lock.RLock() + // defer internal_CUSTOM_JANUS_GATEWAY_TEST__default__grpc_lock.RUnlock() + client := internal_EchoService_CUSTOM_JANUS_GATEWAY_TEST_client inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) if client == nil { err := status.Error(codes.Internal, "service disabled") @@ -1453,7 +1453,7 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux return } - ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "EchoValidationRule", w, req) + ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_JANUS_GATEWAY_TEST_spec, "EchoService", "EchoValidationRule", w, req) if err != nil { grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) @@ -1482,34 +1482,34 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux return nil } -func Disable_CUSTOM_EASE_GATEWAY_TEST__default__grpc_ServiceGroup() { - // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.Lock() - // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.Unlock() - if internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_skycli != nil { - spec := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec +func Disable_CUSTOM_JANUS_GATEWAY_TEST__default__grpc_ServiceGroup() { + // internal_CUSTOM_JANUS_GATEWAY_TEST__default__grpc_lock.Lock() + // defer internal_CUSTOM_JANUS_GATEWAY_TEST__default__grpc_lock.Unlock() + if internal_CUSTOM_JANUS_GATEWAY_TEST__default__grpc_skycli != nil { + spec := internal_EchoService_CUSTOM_JANUS_GATEWAY_TEST_spec sg := runtime.GetServiceGroup(spec) for _, svc := range sg.Services { svc.Disable() } - internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client = nil - internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_skycli.Shutdown() - internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_skycli = nil + internal_EchoService_CUSTOM_JANUS_GATEWAY_TEST_client = nil + internal_CUSTOM_JANUS_GATEWAY_TEST__default__grpc_skycli.Shutdown() + internal_CUSTOM_JANUS_GATEWAY_TEST__default__grpc_skycli = nil } } -func Enable_CUSTOM_EASE_GATEWAY_TEST__default__grpc_ServiceGroup() { - // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.Lock() - // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.Unlock() +func Enable_CUSTOM_JANUS_GATEWAY_TEST__default__grpc_ServiceGroup() { + // internal_CUSTOM_JANUS_GATEWAY_TEST__default__grpc_lock.Lock() + // defer internal_CUSTOM_JANUS_GATEWAY_TEST__default__grpc_lock.Unlock() - internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_skycli = client.NewServiceCli(runtime.CallerServiceId) + internal_CUSTOM_JANUS_GATEWAY_TEST__default__grpc_skycli = client.NewServiceCli(runtime.CallerServiceId) // Resolve service - spec := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec + spec := internal_EchoService_CUSTOM_JANUS_GATEWAY_TEST_spec - internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_skycli.Resolve(spec) + internal_CUSTOM_JANUS_GATEWAY_TEST__default__grpc_skycli.Resolve(spec) - internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_skycli.Start(func(spec *skypb.ServiceSpec, conn *grpc.ClientConn) { + internal_CUSTOM_JANUS_GATEWAY_TEST__default__grpc_skycli.Start(func(spec *skypb.ServiceSpec, conn *grpc.ClientConn) { sg := runtime.GetServiceGroup(spec) for _, svc := range sg.Services { svc.Enable(spec, conn) @@ -1518,11 +1518,11 @@ func Enable_CUSTOM_EASE_GATEWAY_TEST__default__grpc_ServiceGroup() { } func EnableEchoService_Service(spec *skypb.ServiceSpec, conn *grpc.ClientConn) { - internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client = NewEchoServiceClient(conn) + internal_EchoService_CUSTOM_JANUS_GATEWAY_TEST_client = NewEchoServiceClient(conn) } func DisableEchoService_Service() { - internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client = nil + internal_EchoService_CUSTOM_JANUS_GATEWAY_TEST_client = nil } var ( @@ -1566,10 +1566,10 @@ var ( ) var ( - internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec = client.NewServiceSpec("default", vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, "grpc") - internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client EchoServiceClient + internal_EchoService_CUSTOM_JANUS_GATEWAY_TEST_spec = client.NewServiceSpec("default", vexpb.ServiceId_CUSTOM_JANUS_GATEWAY_TEST, "grpc") + internal_EchoService_CUSTOM_JANUS_GATEWAY_TEST_client EchoServiceClient - internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_skycli client.ServiceCli + internal_CUSTOM_JANUS_GATEWAY_TEST__default__grpc_skycli client.ServiceCli - internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock = sync.RWMutex{} + internal_CUSTOM_JANUS_GATEWAY_TEST__default__grpc_lock = sync.RWMutex{} ) diff --git a/examples/internal/proto/examplepb/echo_service.proto b/examples/internal/proto/examplepb/echo_service.proto index 589f5cd..0f18f38 100644 --- a/examples/internal/proto/examplepb/echo_service.proto +++ b/examples/internal/proto/examplepb/echo_service.proto @@ -91,7 +91,7 @@ message DynamicMessageUpdate { // Echo service responds to incoming echo requests. service EchoService { option (janus.api.service_spec) = { - service_id: CUSTOM_EASE_GATEWAY_TEST + service_id: CUSTOM_JANUS_GATEWAY_TEST port_name : "grpc" namespace : "default" gen_controller: true diff --git a/examples/internal/proto/examplepb/unannotated_echo_service.proto b/examples/internal/proto/examplepb/unannotated_echo_service.proto index ef7161a..add92fe 100644 --- a/examples/internal/proto/examplepb/unannotated_echo_service.proto +++ b/examples/internal/proto/examplepb/unannotated_echo_service.proto @@ -42,7 +42,7 @@ message UnannotatedSimpleMessage { // Echo service responds to incoming echo requests. service UnannotatedEchoService { option (janus.api.service_spec) = { - service_id: CUSTOM_EASE_GATEWAY_TEST + service_id: CUSTOM_JANUS_GATEWAY_TEST port_name : "grpc" namespace : "default" }; diff --git a/gateway/README.md b/gateway/README.md index 7142e1a..0318594 100644 --- a/gateway/README.md +++ b/gateway/README.md @@ -8,7 +8,7 @@ grpc-gateway 是一款非常优秀的网关服务器,负责转化和代理转 - 支持网关层的parameter validation - 支持自定义的annotaion -为了支持这些新feature,我不得不将grpc-gateway的源码拷贝到ease-gateway中并进行大量的修改,```//gateway``` 目录下就是从grpc-gateway中拷贝的部分源码 +为了支持这些新feature,我不得不将grpc-gateway的源码拷贝到janus-gateway中并进行大量的修改,```//gateway``` 目录下就是从grpc-gateway中拷贝的部分源码 # Changed History diff --git a/gateway/runtime/service.go b/gateway/runtime/service.go index 8b8846b..5b37ec2 100755 --- a/gateway/runtime/service.go +++ b/gateway/runtime/service.go @@ -10,8 +10,8 @@ import ( var ( // CallerServiceId sets the gRPC caller service ID of the gateway. - // For janus-gateway, it's ServiceId_EASE_GATEWAY. - CallerServiceId = vexpb.ServiceId_EASE_GATEWAY + // For janus-gateway, it's ServiceId_JANUS_GATEWAY. + CallerServiceId = vexpb.ServiceId_JANUS_GATEWAY ) // Method represents a gRPC service method. diff --git a/httpoptions/BUILD.bazel b/httpoptions/BUILD.bazel index 32f020d..5bf5ff1 100644 --- a/httpoptions/BUILD.bazel +++ b/httpoptions/BUILD.bazel @@ -43,7 +43,7 @@ go_proto_library( ) # proto_library( -# name = "ease_api_proto", +# name = "janus_api_proto", # srcs = [ # "annotations.proto", # "http.proto", diff --git a/httpoptions/annotations.pb.go b/httpoptions/annotations.pb.go index ccaa7b5..575c928 100755 --- a/httpoptions/annotations.pb.go +++ b/httpoptions/annotations.pb.go @@ -26,18 +26,18 @@ const ( type ApiSourceType int32 const ( - ApiSourceType_EASE_GATEWAY ApiSourceType = 0 + ApiSourceType_JANUS_GATEWAY ApiSourceType = 0 ApiSourceType_OPEN_GATEWAY ApiSourceType = 1 ) // Enum value maps for ApiSourceType. var ( ApiSourceType_name = map[int32]string{ - 0: "EASE_GATEWAY", + 0: "JANUS_GATEWAY", 1: "OPEN_GATEWAY", } ApiSourceType_value = map[string]int32{ - "EASE_GATEWAY": 0, + "JANUS_GATEWAY": 0, "OPEN_GATEWAY": 1, } ) @@ -72,18 +72,18 @@ func (ApiSourceType) EnumDescriptor() ([]byte, []int) { type AuthTokenType int32 const ( - AuthTokenType_EASE_AUTH_TOKEN AuthTokenType = 0 + AuthTokenType_JANUS_AUTH_TOKEN AuthTokenType = 0 AuthTokenType_BASE_ACCESS_TOKEN AuthTokenType = 1 ) // Enum value maps for AuthTokenType. var ( AuthTokenType_name = map[int32]string{ - 0: "EASE_AUTH_TOKEN", + 0: "JANUS_AUTH_TOKEN", 1: "BASE_ACCESS_TOKEN", } AuthTokenType_value = map[string]int32{ - "EASE_AUTH_TOKEN": 0, + "JANUS_AUTH_TOKEN": 0, "BASE_ACCESS_TOKEN": 1, } ) @@ -458,14 +458,14 @@ func (x *ApiMethod) GetApiSource() ApiSourceType { if x != nil { return x.ApiSource } - return ApiSourceType_EASE_GATEWAY + return ApiSourceType_JANUS_GATEWAY } func (x *ApiMethod) GetTokenType() AuthTokenType { if x != nil { return x.TokenType } - return AuthTokenType_EASE_AUTH_TOKEN + return AuthTokenType_JANUS_AUTH_TOKEN } func (x *ApiMethod) GetSpecSourceType() SpecSourceType { diff --git a/httpoptions/annotations.proto b/httpoptions/annotations.proto index c1862a8..01a27cf 100644 --- a/httpoptions/annotations.proto +++ b/httpoptions/annotations.proto @@ -66,13 +66,13 @@ message ApiMethod { // Api regist gateway. enum ApiSourceType { - EASE_GATEWAY = 0; // janus-gateway apis. + JANUS_GATEWAY = 0; // janus-gateway apis. OPEN_GATEWAY = 1; // open-gateway open apis. } // Auth token type. enum AuthTokenType { - EASE_AUTH_TOKEN = 0; // janus gateway auth type. + JANUS_AUTH_TOKEN = 0; // janus gateway auth type. BASE_ACCESS_TOKEN = 1; // open platform baseAccessToken. } diff --git a/integrate/hookexternal.go b/integrate/hookexternal.go index 9be3e8a..a51ed42 100644 --- a/integrate/hookexternal.go +++ b/integrate/hookexternal.go @@ -326,11 +326,11 @@ func getHeader(h http.Header, key string) string { } func isGatewayApi(api *runtime.Method) bool { - if runtime.CallerServiceId == vexpb.ServiceId_EASE_GATEWAY { - return api.ApiSource == options.ApiSourceType_EASE_GATEWAY + if runtime.CallerServiceId == vexpb.ServiceId_JANUS_GATEWAY { + return api.ApiSource == options.ApiSourceType_JANUS_GATEWAY } - // else if runtime.CallerServiceId == vexpb.ServiceId_EASE_OPEN_GATEWAY { - // return api.ApiSource == options.ApiSourceType_EASE_OPEN_GATEWAY || + // else if runtime.CallerServiceId == vexpb.ServiceId_JANUS_OPEN_GATEWAY { + // return api.ApiSource == options.ApiSourceType_JANUS_OPEN_GATEWAY || // api.ApiSource == options.ApiSourceType_OPEN_GATEWAY_PRIVATE // } return false diff --git a/proto/examplepb/echo_service.proto b/proto/examplepb/echo_service.proto index dbaf516..ebb4c08 100644 --- a/proto/examplepb/echo_service.proto +++ b/proto/examplepb/echo_service.proto @@ -4,7 +4,7 @@ option go_package = "github.com/binchencoder/janus-gateway/gateway/proto/example package grpc.gateway.proto.examplepb; -option java_package = "com.binchencoder.easegw.examplepb"; +option java_package = "com.binchencoder.janusgw.examplepb"; option java_outer_classname = "ExamplesProto"; // import "google/api/annotations.proto"; @@ -66,7 +66,7 @@ message SimpleMessage { // Echo service responds to incoming echo requests. service EchoService { option (janus.api.service_spec) = { - service_id: CUSTOM_EASE_GATEWAY_TEST + service_id: CUSTOM_JANUS_GATEWAY_TEST port_name : "grpc" namespace : "default" gen_controller: true diff --git a/proto/examplepb/pom.xml b/proto/examplepb/pom.xml index 68446a2..18f6c78 100755 --- a/proto/examplepb/pom.xml +++ b/proto/examplepb/pom.xml @@ -8,16 +8,16 @@ - com.binchencoder.easegw - easegw-proto + com.binchencoder.gateway + janus-proto 1.0-SNAPSHOT ../pom.xml - com.binchencoder.easegw - easegw-options-protos + com.binchencoder.gateway + janus-options-protos com.binchencoder.gateway diff --git a/proto/pom.xml b/proto/pom.xml index 8da16f4..9724b50 100755 --- a/proto/pom.xml +++ b/proto/pom.xml @@ -2,8 +2,8 @@ 4.0.0 - com.binchencoder.easegw - easegw-proto + com.binchencoder.gateway + janus-proto pom 1.0-SNAPSHOT @@ -45,8 +45,8 @@ 1.0-SNAPSHOT - com.binchencoder.easegw - easegw-options-protos + com.binchencoder.gateway + janus-options-protos 1.0-SNAPSHOT provided From d4f627fcdf24040485f476f2956bf7e5c4b82a94 Mon Sep 17 00:00:00 2001 From: binchencoder <15811514091@163.com> Date: Sat, 23 Apr 2022 20:51:32 +0800 Subject: [PATCH 50/56] Not use local repository --- WORKSPACE | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/WORKSPACE b/WORKSPACE index 15bae63..a4bb804 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -109,17 +109,17 @@ load("@com_github_bazelbuild_buildtools//buildifier:deps.bzl", "buildifier_depen buildifier_dependencies() # ---------- local repositories -local_repository( - name = "com_github_binchencoder_gateway_proto", - path = "../gateway-proto", -) +# local_repository( +# name = "com_github_binchencoder_gateway_proto", +# path = "../gateway-proto", +# ) -local_repository( - name = "com_github_binchencoder_letsgo", - path = "../letsgo", -) +# local_repository( +# name = "com_github_binchencoder_letsgo", +# path = "../letsgo", +# ) -local_repository( - name = "com_github_binchencoder_skylb_api", - path = "../skylb-api", -) +# local_repository( +# name = "com_github_binchencoder_skylb_api", +# path = "../skylb-api", +# ) From 7902387203f2ff0d3531b59d579afd2aeb1f5315 Mon Sep 17 00:00:00 2001 From: chenbin1314 Date: Sat, 23 Apr 2022 21:21:50 +0800 Subject: [PATCH 51/56] Format --- WORKSPACE | 1 + 1 file changed, 1 insertion(+) diff --git a/WORKSPACE b/WORKSPACE index a4bb804..4068380 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -123,3 +123,4 @@ buildifier_dependencies() # name = "com_github_binchencoder_skylb_api", # path = "../skylb-api", # ) + From 7c09a04ad4a7036723da79f2aaa3a67d2666d3b8 Mon Sep 17 00:00:00 2001 From: chenbin1314 Date: Sat, 23 Apr 2022 21:30:55 +0800 Subject: [PATCH 52/56] Format WORKSPACE --- WORKSPACE | 1 - 1 file changed, 1 deletion(-) diff --git a/WORKSPACE b/WORKSPACE index 4068380..a4bb804 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -123,4 +123,3 @@ buildifier_dependencies() # name = "com_github_binchencoder_skylb_api", # path = "../skylb-api", # ) - From ab14c231b1bc8c76845fbdee5018b48cfcf2fb07 Mon Sep 17 00:00:00 2001 From: chenbin1314 Date: Sat, 23 Apr 2022 22:01:41 +0800 Subject: [PATCH 53/56] Upgrade gateway-proto versiont v0.0.9 --- cmd/gateway/main.go | 2 +- proto/examplepb/pom.xml | 14 +++++++------- repositories.bzl | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/cmd/gateway/main.go b/cmd/gateway/main.go index e5eab81..19ece71 100644 --- a/cmd/gateway/main.go +++ b/cmd/gateway/main.go @@ -9,10 +9,10 @@ import ( "github.com/golang/glog" + "github.com/binchencoder/gateway-proto/data" "github.com/binchencoder/janus-gateway/gateway/runtime" "github.com/binchencoder/janus-gateway/integrate" "github.com/binchencoder/janus-gateway/util" - "github.com/binchencoder/gateway-proto/data" "github.com/binchencoder/letsgo" "github.com/binchencoder/letsgo/service/naming" ) diff --git a/proto/examplepb/pom.xml b/proto/examplepb/pom.xml index 18f6c78..95d132e 100755 --- a/proto/examplepb/pom.xml +++ b/proto/examplepb/pom.xml @@ -15,13 +15,13 @@ - - com.binchencoder.gateway - janus-options-protos - - - com.binchencoder.gateway - data-proto + + com.binchencoder.gateway + janus-options-protos + + + com.binchencoder.gateway + data-proto diff --git a/repositories.bzl b/repositories.bzl index 63a42de..aa043bc 100644 --- a/repositories.bzl +++ b/repositories.bzl @@ -23,7 +23,7 @@ def go_repositories(): name = "com_github_binchencoder_gateway_proto", importpath = "github.com/binchencoder/gateway-proto", sum = "h1:ZvjzhU0CR93EdhqGtQj0Wkwd76D+KsvMuNEMAS1XVos=", - version = "v0.0.8", + version = "v0.0.9", ) go_repository( name = "com_github_armon_circbuf", From c4f6b1364e7cd20a5ad43fc62f4249bbef595573 Mon Sep 17 00:00:00 2001 From: chenbin1314 Date: Sat, 23 Apr 2022 22:10:53 +0800 Subject: [PATCH 54/56] Upgrade gateway-proto versiont v0.0.9 --- repositories.bzl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/repositories.bzl b/repositories.bzl index aa043bc..299ddda 100644 --- a/repositories.bzl +++ b/repositories.bzl @@ -22,7 +22,7 @@ def go_repositories(): go_repository( name = "com_github_binchencoder_gateway_proto", importpath = "github.com/binchencoder/gateway-proto", - sum = "h1:ZvjzhU0CR93EdhqGtQj0Wkwd76D+KsvMuNEMAS1XVos=", + sum = "h1:+B4hxnqdYOP2DErADRLNpP0tTxEqYxAugQ0EDMpPxZc=", version = "v0.0.9", ) go_repository( From 2e4dbae04ec28c9c23f6e4e51d254c8dfe027be0 Mon Sep 17 00:00:00 2001 From: chenbin1314 Date: Mon, 25 Apr 2022 22:48:58 +0800 Subject: [PATCH 55/56] Update: examples/internal/proto/examplepb/BUILD.bazel --- examples/internal/proto/examplepb/BUILD.bazel | 5 +- .../examplepb/unannotated_echo_service.pb.go | 143 ++++++++---------- .../examplepb/unannotated_echo_service.proto | 73 ++++----- 3 files changed, 103 insertions(+), 118 deletions(-) diff --git a/examples/internal/proto/examplepb/BUILD.bazel b/examples/internal/proto/examplepb/BUILD.bazel index 748a4d0..bd69aa4 100644 --- a/examples/internal/proto/examplepb/BUILD.bazel +++ b/examples/internal/proto/examplepb/BUILD.bazel @@ -1,7 +1,7 @@ load("@rules_proto//proto:defs.bzl", "proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library") load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") -load("//gateway/protoc-gen-openapiv2:defs.bzl", "protoc_gen_openapiv2") +load("@com_github_binchencoder_janus_gateway//gateway/protoc-gen-openapiv2:defs.bzl", "protoc_gen_openapiv2") package(default_visibility = ["//visibility:public"]) @@ -45,7 +45,7 @@ proto_library( name = "examplepb_proto", srcs = [ "echo_service.proto", - # "unannotated_echo_service.proto", + "unannotated_echo_service.proto", ], deps = [ "//httpoptions:options_proto", @@ -112,6 +112,7 @@ go_library( "@com_github_grpc_ecosystem_grpc_gateway//utilities", "@com_github_binchencoder_gateway_proto//frontend:go_default_library", "@com_github_binchencoder_skylb_api//client:go_default_library", + "@go_googleapis//google/api:annotations_go_proto", "@org_golang_google_grpc//:go_default_library", "@org_golang_google_grpc//codes", "@org_golang_google_grpc//grpclog", diff --git a/examples/internal/proto/examplepb/unannotated_echo_service.pb.go b/examples/internal/proto/examplepb/unannotated_echo_service.pb.go index e7b48a7..238ef7a 100755 --- a/examples/internal/proto/examplepb/unannotated_echo_service.pb.go +++ b/examples/internal/proto/examplepb/unannotated_echo_service.pb.go @@ -1,14 +1,13 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.27.1 -// protoc v3.19.4 +// protoc v3.20.0--rc2 // source: examples/internal/proto/examplepb/unannotated_echo_service.proto package examplepb import ( _ "github.com/binchencoder/janus-gateway/httpoptions" - duration "github.com/golang/protobuf/ptypes/duration" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" @@ -107,9 +106,8 @@ type UnannotatedSimpleMessage struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Num int64 `protobuf:"varint,2,opt,name=num,proto3" json:"num,omitempty"` - Duration *duration.Duration `protobuf:"bytes,3,opt,name=duration,proto3" json:"duration,omitempty"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Num int64 `protobuf:"varint,2,opt,name=num,proto3" json:"num,omitempty"` // Types that are assignable to Code: // *UnannotatedSimpleMessage_LineNum // *UnannotatedSimpleMessage_Lang @@ -167,13 +165,6 @@ func (x *UnannotatedSimpleMessage) GetNum() int64 { return 0 } -func (x *UnannotatedSimpleMessage) GetDuration() *duration.Duration { - if x != nil { - return x.Duration - } - return nil -} - func (m *UnannotatedSimpleMessage) GetCode() isUnannotatedSimpleMessage_Code { if m != nil { return m.Code @@ -267,77 +258,71 @@ var file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDes 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x1a, 0x1d, 0x68, 0x74, 0x74, 0x70, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x51, 0x0a, 0x13, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x12, 0x1c, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x14, 0x0a, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x42, 0x06, 0x0a, 0x04, - 0x6d, 0x61, 0x72, 0x6b, 0x22, 0xfb, 0x02, 0x0a, 0x18, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, + 0x6d, 0x61, 0x72, 0x6b, 0x22, 0xc4, 0x02, 0x0a, 0x18, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x6e, 0x75, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, - 0x6e, 0x75, 0x6d, 0x12, 0x35, 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x08, 0x6c, 0x69, - 0x6e, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x07, - 0x6c, 0x69, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x12, 0x14, 0x0a, 0x04, 0x6c, 0x61, 0x6e, 0x67, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x6c, 0x61, 0x6e, 0x67, 0x12, 0x5b, 0x0a, - 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x43, 0x2e, - 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, - 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x55, - 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, - 0x65, 0x64, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x10, 0x0a, 0x02, 0x65, 0x6e, - 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x48, 0x01, 0x52, 0x02, 0x65, 0x6e, 0x12, 0x55, 0x0a, 0x02, - 0x6e, 0x6f, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x43, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, - 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, - 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, - 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, - 0x74, 0x61, 0x74, 0x65, 0x64, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x48, 0x01, 0x52, - 0x02, 0x6e, 0x6f, 0x42, 0x06, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x42, 0x05, 0x0a, 0x03, 0x65, - 0x78, 0x74, 0x32, 0x94, 0x04, 0x0a, 0x16, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, - 0x65, 0x64, 0x45, 0x63, 0x68, 0x6f, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x9a, 0x01, - 0x0a, 0x04, 0x45, 0x63, 0x68, 0x6f, 0x12, 0x48, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, + 0x6e, 0x75, 0x6d, 0x12, 0x1b, 0x0a, 0x08, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x07, 0x6c, 0x69, 0x6e, 0x65, 0x4e, 0x75, 0x6d, + 0x12, 0x14, 0x0a, 0x04, 0x6c, 0x61, 0x6e, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, + 0x52, 0x04, 0x6c, 0x61, 0x6e, 0x67, 0x12, 0x5b, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x43, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, - 0x74, 0x65, 0x64, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x1a, 0x48, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, + 0x74, 0x65, 0x64, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x52, 0x06, 0x73, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x12, 0x10, 0x0a, 0x02, 0x65, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x48, + 0x01, 0x52, 0x02, 0x65, 0x6e, 0x12, 0x55, 0x0a, 0x02, 0x6e, 0x6f, 0x18, 0x08, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x43, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, + 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, + 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, + 0x70, 0x62, 0x2e, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x45, 0x6d, + 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x48, 0x01, 0x52, 0x02, 0x6e, 0x6f, 0x42, 0x06, 0x0a, 0x04, + 0x63, 0x6f, 0x64, 0x65, 0x42, 0x05, 0x0a, 0x03, 0x65, 0x78, 0x74, 0x32, 0x94, 0x04, 0x0a, 0x16, + 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x45, 0x63, 0x68, 0x6f, 0x53, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x9a, 0x01, 0x0a, 0x04, 0x45, 0x63, 0x68, 0x6f, 0x12, + 0x48, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, + 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, + 0x2e, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x53, 0x69, 0x6d, 0x70, + 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x48, 0x2e, 0x67, 0x72, 0x70, 0x63, + 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, + 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x55, 0x6e, 0x61, 0x6e, 0x6e, + 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x9e, 0x01, 0x0a, 0x08, 0x45, 0x63, 0x68, 0x6f, 0x42, 0x6f, 0x64, 0x79, + 0x12, 0x48, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x53, 0x69, 0x6d, - 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x9e, 0x01, 0x0a, 0x08, 0x45, - 0x63, 0x68, 0x6f, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x48, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, - 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, - 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, - 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, - 0x61, 0x74, 0x65, 0x64, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x1a, 0x48, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, - 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, - 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, - 0x70, 0x62, 0x2e, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x53, 0x69, - 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0xa0, 0x01, 0x0a, 0x0a, - 0x45, 0x63, 0x68, 0x6f, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x48, 0x2e, 0x67, 0x72, 0x70, + 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x48, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x1a, 0x48, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, - 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, - 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, - 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, - 0x64, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x19, - 0xea, 0xf3, 0x34, 0x15, 0x08, 0xb6, 0x95, 0xff, 0xff, 0x07, 0x12, 0x04, 0x67, 0x72, 0x70, 0x63, - 0x1a, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x42, 0x52, 0x5a, 0x50, 0x67, 0x69, 0x74, - 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x69, 0x6e, 0x63, 0x68, 0x65, 0x6e, 0x63, - 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x65, 0x61, 0x73, 0x65, 0x2d, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, - 0x79, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, - 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, - 0x65, 0x70, 0x62, 0x3b, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x73, 0x61, 0x67, 0x65, 0x12, 0xa0, 0x01, 0x0a, 0x0a, 0x45, 0x63, 0x68, 0x6f, 0x44, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x12, 0x48, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, + 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, + 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, + 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, + 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x48, 0x2e, + 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, + 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x55, + 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x19, 0xea, 0xf3, 0x34, 0x15, 0x08, 0xb6, 0x95, + 0xff, 0xff, 0x07, 0x12, 0x04, 0x67, 0x72, 0x70, 0x63, 0x1a, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, + 0x6c, 0x74, 0x42, 0x53, 0x5a, 0x51, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x62, 0x69, 0x6e, 0x63, 0x68, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x6a, 0x61, + 0x6e, 0x75, 0x73, 0x2d, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2f, 0x65, 0x78, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x3b, 0x65, 0x78, + 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -356,23 +341,21 @@ var file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTyp var file_examples_internal_proto_examplepb_unannotated_echo_service_proto_goTypes = []interface{}{ (*UnannotatedEmbedded)(nil), // 0: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEmbedded (*UnannotatedSimpleMessage)(nil), // 1: grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage - (*duration.Duration)(nil), // 2: google.protobuf.Duration } var file_examples_internal_proto_examplepb_unannotated_echo_service_proto_depIdxs = []int32{ - 2, // 0: grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage.duration:type_name -> google.protobuf.Duration - 0, // 1: grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage.status:type_name -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedEmbedded - 0, // 2: grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage.no:type_name -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedEmbedded - 1, // 3: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.Echo:input_type -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage - 1, // 4: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.EchoBody:input_type -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage - 1, // 5: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.EchoDelete:input_type -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage - 1, // 6: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.Echo:output_type -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage - 1, // 7: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.EchoBody:output_type -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage - 1, // 8: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.EchoDelete:output_type -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage - 6, // [6:9] is the sub-list for method output_type - 3, // [3:6] is the sub-list for method input_type - 3, // [3:3] is the sub-list for extension type_name - 3, // [3:3] is the sub-list for extension extendee - 0, // [0:3] is the sub-list for field type_name + 0, // 0: grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage.status:type_name -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedEmbedded + 0, // 1: grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage.no:type_name -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedEmbedded + 1, // 2: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.Echo:input_type -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage + 1, // 3: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.EchoBody:input_type -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage + 1, // 4: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.EchoDelete:input_type -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage + 1, // 5: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.Echo:output_type -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage + 1, // 6: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.EchoBody:output_type -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage + 1, // 7: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.EchoDelete:output_type -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage + 5, // [5:8] is the sub-list for method output_type + 2, // [2:5] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name } func init() { file_examples_internal_proto_examplepb_unannotated_echo_service_proto_init() } diff --git a/examples/internal/proto/examplepb/unannotated_echo_service.proto b/examples/internal/proto/examplepb/unannotated_echo_service.proto index add92fe..3454400 100644 --- a/examples/internal/proto/examplepb/unannotated_echo_service.proto +++ b/examples/internal/proto/examplepb/unannotated_echo_service.proto @@ -1,5 +1,4 @@ syntax = "proto3"; -option go_package = "github.com/binchencoder/janus-gateway/examples/internal/proto/examplepb;examplepb"; // Unannotated Echo Service // Similar to echo_service.proto but without annotations. See @@ -12,50 +11,52 @@ package grpc.gateway.examples.internal.proto.examplepb; import "httpoptions/annotations.proto"; // Do not need annotations.proto, can still use well known types as usual -import "google/protobuf/duration.proto"; +// import "google/protobuf/duration.proto"; + +option go_package = "github.com/binchencoder/janus-gateway/examples/internal/proto/examplepb;examplepb"; // Embedded represents a message embedded in SimpleMessage. message UnannotatedEmbedded { - oneof mark { - int64 progress = 1; - string note = 2; - } + oneof mark { + int64 progress = 1; + string note = 2; + } } // UnannotatedSimpleMessage represents a simple message sent to the unannotated Echo service. message UnannotatedSimpleMessage { - // Id represents the message identifier. - string id = 1; - int64 num = 2; - google.protobuf.Duration duration = 3; - oneof code { - int64 line_num = 4; - string lang = 5; - } - UnannotatedEmbedded status = 6; - oneof ext { - int64 en = 7; - UnannotatedEmbedded no = 8; - } + // Id represents the message identifier. + string id = 1; + int64 num = 2; + // google.protobuf.Duration duration = 3; + oneof code { + int64 line_num = 4; + string lang = 5; + } + UnannotatedEmbedded status = 6; + oneof ext { + int64 en = 7; + UnannotatedEmbedded no = 8; + } } // Echo service responds to incoming echo requests. service UnannotatedEchoService { - option (janus.api.service_spec) = { - service_id: CUSTOM_JANUS_GATEWAY_TEST - port_name : "grpc" - namespace : "default" - }; - - // Echo method receives a simple message and returns it. - // - // The message posted as the id parameter will also be - // returned. - rpc Echo(UnannotatedSimpleMessage) returns (UnannotatedSimpleMessage); - - // EchoBody method receives a simple message and returns it. - rpc EchoBody(UnannotatedSimpleMessage) returns (UnannotatedSimpleMessage); - - // EchoDelete method receives a simple message and returns it. - rpc EchoDelete(UnannotatedSimpleMessage) returns (UnannotatedSimpleMessage); + option (janus.api.service_spec) = { + service_id: CUSTOM_JANUS_GATEWAY_TEST + port_name : "grpc" + namespace : "default" + }; + + // Echo method receives a simple message and returns it. + // + // The message posted as the id parameter will also be + // returned. + rpc Echo(UnannotatedSimpleMessage) returns (UnannotatedSimpleMessage); + + // EchoBody method receives a simple message and returns it. + rpc EchoBody(UnannotatedSimpleMessage) returns (UnannotatedSimpleMessage); + + // EchoDelete method receives a simple message and returns it. + rpc EchoDelete(UnannotatedSimpleMessage) returns (UnannotatedSimpleMessage); } From ef7498d75fcf647583abbb2ef1cd67147c49e069 Mon Sep 17 00:00:00 2001 From: chenbin1314 Date: Tue, 26 Apr 2022 22:21:17 +0800 Subject: [PATCH 56/56] Success: bazel build ... --- examples/internal/integration/BUILD.bazel | 2 +- examples/internal/server/BUILD.bazel | 4 +- examples/internal/server/echo.go | 15 ++++---- examples/internal/server/main.go | 5 +++ examples/internal/server/unannotatedecho.go | 41 +++++++++++++++++++++ 5 files changed, 57 insertions(+), 10 deletions(-) create mode 100644 examples/internal/server/unannotatedecho.go diff --git a/examples/internal/integration/BUILD.bazel b/examples/internal/integration/BUILD.bazel index 03c89f4..173b989 100644 --- a/examples/internal/integration/BUILD.bazel +++ b/examples/internal/integration/BUILD.bazel @@ -3,7 +3,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_test") go_test( name = "integration_test", srcs = [ - "integration_test.go", + # "integration_test.go", "main_test.go", ], deps = [ diff --git a/examples/internal/server/BUILD.bazel b/examples/internal/server/BUILD.bazel index fc491f1..8f21e56 100644 --- a/examples/internal/server/BUILD.bazel +++ b/examples/internal/server/BUILD.bazel @@ -7,11 +7,13 @@ go_library( srcs = [ "echo.go", "main.go", + "unannotatedecho.go", ], importpath = "github.com/binchencoder/janus-gateway/examples/internal/server", deps = [ "//examples/internal/proto/examplepb", - "//gateway/runtime", + # "//examples/internal/proto/standalone", + "//gateway/runtime", "@com_github_golang_glog//:glog", "@com_github_rogpeppe_fastuuid//:fastuuid", "@go_googleapis//google/api:httpbody_go_proto", diff --git a/examples/internal/server/echo.go b/examples/internal/server/echo.go index 1a057d3..d2f6d38 100644 --- a/examples/internal/server/echo.go +++ b/examples/internal/server/echo.go @@ -6,7 +6,9 @@ import ( examples "github.com/binchencoder/janus-gateway/examples/internal/proto/examplepb" "github.com/golang/glog" "google.golang.org/grpc" + "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" ) // Implements of EchoServiceServer @@ -19,14 +21,6 @@ func NewEchoServer() examples.EchoServiceServer { func (s *echoServer) Echo(ctx context.Context, msg *examples.SimpleMessage) (*examples.SimpleMessage, error) { glog.Info(msg) - grpc.SendHeader(ctx, metadata.New(map[string]string{ - "foo": "foo1", - "bar": "bar1", - })) - grpc.SetTrailer(ctx, metadata.New(map[string]string{ - "foo": "foo2", - "bar": "bar2", - })) return msg, nil } @@ -53,6 +47,11 @@ func (s *echoServer) EchoPatch(ctx context.Context, msg *examples.DynamicMessage return msg, nil } +func (s *echoServer) EchoUnauthorized(ctx context.Context, msg *examples.SimpleMessage) (*examples.SimpleMessage, error) { + glog.Info(msg) + return nil, status.Error(codes.Unauthenticated, "unauthorized err") +} + func (s *echoServer) EchoValidationRule(ctx context.Context, msg *examples.ValidationRuleTestRequest) (*examples.ValidationRuleTestResponse, error) { glog.Info(msg) return &examples.ValidationRuleTestResponse{}, nil diff --git a/examples/internal/server/main.go b/examples/internal/server/main.go index dec1cbc..ca95cfc 100644 --- a/examples/internal/server/main.go +++ b/examples/internal/server/main.go @@ -8,6 +8,8 @@ import ( examples "github.com/binchencoder/janus-gateway/examples/internal/proto/examplepb" "github.com/binchencoder/janus-gateway/gateway/runtime" "github.com/golang/glog" + + // standalone "github.com/binchencoder/janus-gateway/examples/internal/proto/standalone" "google.golang.org/grpc" ) @@ -26,6 +28,7 @@ func Run(ctx context.Context, network, address string) error { s := grpc.NewServer() examples.RegisterEchoServiceServer(s, NewEchoServer()) + examples.RegisterUnannotatedEchoServiceServer(s, newUnannotatedEchoServer()) go func() { defer s.GracefulStop() @@ -39,6 +42,8 @@ func RunInProcessGateway(ctx context.Context, addr string, opts ...runtime.Serve mux := runtime.NewServeMux(opts...) examples.RegisterEchoServiceHandlerServer(ctx, mux, NewEchoServer()) + // examples.RegisterNonStandardServiceHandlerServer(ctx, mux, newNonStandardServer()) + // standalone.RegisterUnannotatedEchoServiceHandlerServer(ctx, mux, newUnannotatedEchoServer()) s := &http.Server{ Addr: addr, Handler: mux, diff --git a/examples/internal/server/unannotatedecho.go b/examples/internal/server/unannotatedecho.go new file mode 100644 index 0000000..2b446b2 --- /dev/null +++ b/examples/internal/server/unannotatedecho.go @@ -0,0 +1,41 @@ +package server + +import ( + "context" + + "github.com/golang/glog" + examples "github.com/binchencoder/janus-gateway/examples/internal/proto/examplepb" + "google.golang.org/grpc" + "google.golang.org/grpc/metadata" +) + +// Implements of UnannotatedEchoServiceServer + +type unannotatedEchoServer struct{} + +func newUnannotatedEchoServer() examples.UnannotatedEchoServiceServer { + return new(unannotatedEchoServer) +} + +func (s *unannotatedEchoServer) Echo(ctx context.Context, msg *examples.UnannotatedSimpleMessage) (*examples.UnannotatedSimpleMessage, error) { + glog.Info(msg) + return msg, nil +} + +func (s *unannotatedEchoServer) EchoBody(ctx context.Context, msg *examples.UnannotatedSimpleMessage) (*examples.UnannotatedSimpleMessage, error) { + glog.Info(msg) + grpc.SendHeader(ctx, metadata.New(map[string]string{ + "foo": "foo1", + "bar": "bar1", + })) + grpc.SetTrailer(ctx, metadata.New(map[string]string{ + "foo": "foo2", + "bar": "bar2", + })) + return msg, nil +} + +func (s *unannotatedEchoServer) EchoDelete(ctx context.Context, msg *examples.UnannotatedSimpleMessage) (*examples.UnannotatedSimpleMessage, error) { + glog.Info(msg) + return msg, nil +}