From 34e698a49a40fd587f9169397b1edc9f5a380bb9 Mon Sep 17 00:00:00 2001 From: Steve Ayers Date: Fri, 13 Oct 2023 13:42:29 -0400 Subject: [PATCH 01/13] Initial server implementation --- cmd/server/main.go | 226 +--- internal/app/server/impl.go | 360 +++++++ internal/app/server/server.go | 126 +++ .../service.connect.go | 96 +- .../conformance/v1alpha1/service.pb.go | 977 +++++++++++++----- internal/server/server.go | 107 -- 6 files changed, 1257 insertions(+), 635 deletions(-) create mode 100644 internal/app/server/impl.go create mode 100644 internal/app/server/server.go delete mode 100644 internal/server/server.go diff --git a/cmd/server/main.go b/cmd/server/main.go index 72e2ae2c..bebf53d0 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -12,226 +12,46 @@ // See the License for the specific language governing permissions and // limitations under the License. +// Copyright 2022-2023 The Connect Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package main import ( "context" - "crypto/tls" - "crypto/x509" - "errors" - "log" - "net/http" - "os" - "os/signal" - "syscall" - "time" + "flag" + "fmt" - "connectrpc.com/conformance/internal/gen/proto/connect/connectrpc/conformance/v1alpha1/conformancev1alpha1connect" - "connectrpc.com/conformance/internal/server" - "github.com/quic-go/quic-go/http3" - "github.com/rs/cors" - "github.com/spf13/cobra" - "golang.org/x/net/http2" - "golang.org/x/net/http2/h2c" + "connectrpc.com/conformance/internal/app/server" ) const ( h1PortFlagName = "h1port" h2PortFlagName = "h2port" - h3PortFlagName = "h3port" - certFlagName = "cert" - keyFlagName = "key" insecureFlagName = "insecure" ) -type flags struct { - h1Port string - h2Port string - h3Port string - certFile string - keyFile string - insecure bool -} - func main() { - flagset := &flags{} - rootCmd := &cobra.Command{ - Use: "server", - Short: "Starts a Connect Go server", - PreRunE: func(cmd *cobra.Command, args []string) error { - insecure, _ := cmd.Flags().GetBool(insecureFlagName) - certFile, _ := cmd.Flags().GetString(certFlagName) - keyFile, _ := cmd.Flags().GetString(keyFlagName) - h3Port, _ := cmd.Flags().GetString(h3PortFlagName) - if !insecure && (certFile == "" || keyFile == "") { - return errors.New("either a 'cert' and 'key' combination or 'insecure' must be specified") - } - if h3Port != "" && (certFile == "" || keyFile == "") { - return errors.New("a 'cert' and 'key' combination is required when an HTTP/3 port is specified") - } - return nil - }, - Run: func(cmd *cobra.Command, args []string) { - run(flagset) - }, - } - if err := bind(rootCmd, flagset); err != nil { - os.Exit(1) - } - _ = rootCmd.Execute() -} - -func bind(cmd *cobra.Command, flagset *flags) error { - cmd.Flags().StringVar(&flagset.h1Port, h1PortFlagName, "", "port for HTTP/1.1 traffic") - cmd.Flags().StringVar(&flagset.h2Port, h2PortFlagName, "", "port for HTTP/2 traffic") - cmd.Flags().StringVar(&flagset.h3Port, h3PortFlagName, "", "port for HTTP/3 traffic") - cmd.Flags().StringVar(&flagset.certFile, certFlagName, "", "path to the TLS cert file") - cmd.Flags().StringVar(&flagset.keyFile, keyFlagName, "", "path to the TLS key file") - cmd.Flags().BoolVar(&flagset.insecure, insecureFlagName, false, "whether to serve cleartext or TLS. HTTP/3 requires TLS.") - for _, requiredFlag := range []string{h1PortFlagName, h2PortFlagName} { - if err := cmd.MarkFlagRequired(requiredFlag); err != nil { - return err - } - } - return nil -} + h1Port := flag.String("h1Port", "8080", "port for HTTP/1.1 traffic") + h2Port := flag.String("h2Port", "8081", "port for HTTP/2 traffic") -func run(flags *flags) { - mux := http.NewServeMux() - mux.Handle(conformancev1alpha1connect.NewConformanceServiceHandler( - server.NewConformanceServiceHandler(), - )) - corsHandler := cors.New(cors.Options{ - AllowedMethods: []string{ - http.MethodHead, - http.MethodGet, - http.MethodPost, - http.MethodPut, - http.MethodPatch, - http.MethodDelete, - }, - // Mirror the `Origin` header value in the `Access-Control-Allow-Origin` - // preflight response header. - // This is equivalent to `Access-Control-Allow-Origin: *`, but allows - // for requests with credentials. - // Note that this effectively disables CORS and is not safe for use in - // production environments. - AllowOriginFunc: func(origin string) bool { - return true - }, - // Note that rs/cors does not return `Access-Control-Allow-Headers: *` - // in response to preflight requests with the following configuration. - // It simply mirrors all headers listed in the `Access-Control-Request-Headers` - // preflight request header. - AllowedHeaders: []string{"*"}, - // We explicitly set the exposed header names instead of using the wildcard *, - // because in requests with credentials, it is treated as the literal header - // name "*" without special semantics. - ExposedHeaders: []string{ - "Grpc-Status", "Grpc-Message", "Grpc-Status-Details-Bin", "X-Grpc-Test-Echo-Initial", - "Trailer-X-Grpc-Test-Echo-Trailing-Bin", "Request-Protocol", "Get-Request"}, - }).Handler(mux) + flag.Parse() - // Create servers - h1Server := newH1Server(flags, corsHandler) - h2Server := newH2Server(flags, mux) - var h3Server http3.Server - if flags.h3Port != "" { - h3Server = newH3Server(flags, mux) - } - done := make(chan os.Signal, 1) - signal.Notify(done, os.Interrupt, syscall.SIGINT, syscall.SIGTERM) - go func() { - var err error - if flags.insecure { - err = h1Server.ListenAndServe() - } else { - err = h1Server.ListenAndServeTLS(flags.certFile, flags.keyFile) - } - if err != nil && !errors.Is(err, http.ErrServerClosed) { - log.Fatalln(err) - } - }() - go func() { - var err error - if flags.insecure { - err = h2Server.ListenAndServe() - } else { - err = h2Server.ListenAndServeTLS(flags.certFile, flags.keyFile) - } - if err != nil && !errors.Is(err, http.ErrServerClosed) { - log.Fatalln(err) - } - }() - if flags.h3Port != "" { - go func() { - if err := h3Server.ListenAndServeTLS(flags.certFile, flags.keyFile); err != nil && !errors.Is(err, http.ErrServerClosed) { - log.Fatalln(err) - } - }() - } - <-done - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() - if err := h1Server.Shutdown(ctx); err != nil { - log.Fatalln(err) - } - if err := h2Server.Shutdown(ctx); err != nil { - log.Fatalln(err) - } - if flags.h3Port != "" { - if err := h3Server.Close(); err != nil { - log.Fatalln(err) - } - } -} - -func newH1Server(flags *flags, handler http.Handler) *http.Server { - h1Server := &http.Server{ - Addr: ":" + flags.h1Port, - Handler: handler, - } - if !flags.insecure { - h1Server.TLSConfig = newTLSConfig(flags.certFile, flags.keyFile) - } - return h1Server -} + args := []string{*h1Port, *h2Port} -func newH2Server(flags *flags, handler http.Handler) *http.Server { - h2Server := &http.Server{ - Addr: ":" + flags.h2Port, - } - if !flags.insecure { - h2Server.TLSConfig = newTLSConfig(flags.certFile, flags.keyFile) - h2Server.Handler = handler - } else { - h2Server.Handler = h2c.NewHandler(handler, &http2.Server{}) - } - return h2Server -} - -func newH3Server(flags *flags, handler http.Handler) http3.Server { - return http3.Server{ - Addr: ":" + flags.h3Port, - Handler: handler, - TLSConfig: newTLSConfig(flags.certFile, flags.keyFile), - } -} - -func newTLSConfig(certFile, keyFile string) *tls.Config { - cert, err := tls.LoadX509KeyPair(certFile, keyFile) + err := server.Run(context.Background(), args, nil, nil, nil) if err != nil { - log.Fatalf("Error creating x509 keypair from client cert file %s and client key file %s", certFile, keyFile) - } - caCert, err := os.ReadFile("cert/ConformanceCA.crt") - if err != nil { - log.Fatalf("Error opening cert file") - } - caCertPool := x509.NewCertPool() - caCertPool.AppendCertsFromPEM(caCert) - return &tls.Config{ - MinVersion: tls.VersionTLS12, - Certificates: []tls.Certificate{cert}, - RootCAs: caCertPool, + fmt.Println("an error occurred running the server ", err) } } diff --git a/internal/app/server/impl.go b/internal/app/server/impl.go new file mode 100644 index 00000000..95364cd3 --- /dev/null +++ b/internal/app/server/impl.go @@ -0,0 +1,360 @@ +// Copyright 2022-2023 The Connect Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package server + +import ( + "context" + "errors" + "fmt" + "io" + "net/http" + "time" + + "connectrpc.com/conformance/internal/gen/proto/connect/connectrpc/conformance/v1alpha1/conformancev1alpha1connect" + v1alpha1 "connectrpc.com/conformance/internal/gen/proto/go/connectrpc/conformance/v1alpha1" + connect "connectrpc.com/connect" + proto "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/anypb" +) + +// ConformanceRequest is a general interface for all conformance requests (UnaryRequest, ServerStreamRequest, etc.) +type ConformanceRequest interface { + GetResponseHeaders() []*v1alpha1.Header + GetResponseTrailers() []*v1alpha1.Header +} + +type Stream[T any] interface { + ResponseHeader() http.Header + ResponseTrailer() http.Header + Send(*T) error +} + +type conformanceServer struct{} + +func (s *conformanceServer) Unary( + ctx context.Context, + req *connect.Request[v1alpha1.UnaryRequest], +) (*connect.Response[v1alpha1.UnaryResponse], error) { + msgAsAny, err := asAny(req.Msg) + if err != nil { + return nil, err + } + payload, err := parseUnaryResponseDefinition(req.Msg.ResponseDefinition, req.Header(), []*anypb.Any{msgAsAny}) + if err != nil { + return nil, err + } + + resp := connect.NewResponse(&v1alpha1.UnaryResponse{ + Payload: payload, + }) + + if req.Msg.ResponseDefinition != nil { + setResponseHeadersAndTrailers(req.Msg.ResponseDefinition, resp) + } + + return resp, nil +} + +func (s *conformanceServer) ClientStream( + ctx context.Context, + stream *connect.ClientStream[v1alpha1.ClientStreamRequest], +) (*connect.Response[v1alpha1.ClientStreamResponse], error) { + var responseDefinition *v1alpha1.UnaryResponseDefinition + firstRecv := true + var reqs []*anypb.Any + for stream.Receive() { + if err := ctx.Err(); err != nil { + return nil, err + } + msg := stream.Msg() + // If this is the first message received on the stream, save off the response definition we need to send + if firstRecv { + responseDefinition = msg.ResponseDefinition + firstRecv = false + } + // Record all the requests received + msgAsAny, err := asAny(msg) + if err != nil { + return nil, err + } + reqs = append(reqs, msgAsAny) + } + if err := stream.Err(); err != nil { + return nil, err + } + + payload, err := parseUnaryResponseDefinition(responseDefinition, stream.RequestHeader(), reqs) + + resp := connect.NewResponse(&v1alpha1.ClientStreamResponse{ + Payload: payload, + }) + + if responseDefinition != nil { + setResponseHeadersAndTrailers(responseDefinition, resp) + } + + return resp, err +} + +func (s *conformanceServer) ServerStream( + ctx context.Context, + req *connect.Request[v1alpha1.ServerStreamRequest], + stream *connect.ServerStream[v1alpha1.ServerStreamResponse], +) error { + responseDefinition := req.Msg.ResponseDefinition + if responseDefinition != nil { + // Set all requested response headers on the response + for _, header := range responseDefinition.ResponseHeaders { + for _, val := range header.Value { + stream.ResponseHeader().Add(header.Name, val) + } + } + // Set all requested response trailers on the response + for _, trailer := range responseDefinition.ResponseTrailers { + for _, val := range trailer.Value { + stream.ResponseTrailer().Add(trailer.Name, val) + } + } + } + + // Convert the request to an Any so that it can be recorded in the payload + msgAsAny, err := asAny(req.Msg) + if err != nil { + return err + } + payload := initPayload(req.Header(), []*anypb.Any{msgAsAny}) + + for _, data := range responseDefinition.ResponseData { + payload.Data = data + + resp := &v1alpha1.ServerStreamResponse{ + Payload: payload, + } + + if err := sendOnStream[v1alpha1.ServerStreamResponse](ctx, stream, responseDefinition, resp); err != nil { + return err + } + + } + if responseDefinition.Error != nil { + return createError(responseDefinition.Error) + } + return nil +} + +func (s *conformanceServer) BidiStream( + ctx context.Context, + stream *connect.BidiStream[v1alpha1.BidiStreamRequest, v1alpha1.BidiStreamResponse], +) error { + var responseDefinition *v1alpha1.StreamResponseDefinition + fullDuplex := false + firstRecv := true + respNum := 0 + var reqs []*anypb.Any + for { + if err := ctx.Err(); err != nil { + return err + } + req, err := stream.Receive() + if err != nil { + if errors.Is(err, io.EOF) { + // Reads are done, break the receive loop and send any remaining responses + break + } + return fmt.Errorf("receive request: %w", err) + } + + // Record all requests received + msgAsAny, err := asAny(req) + if err != nil { + return err + } + reqs = append(reqs, msgAsAny) + + // If this is the first message in the stream, save off the total responses we need to send + // plus whether this should be full or half duplex + if firstRecv { + responseDefinition = req.ResponseDefinition + fullDuplex = req.FullDuplex + firstRecv = false + } + + // If fullDuplex, then send one of the desired responses each time we get a message on the stream + if fullDuplex { + if respNum >= len(responseDefinition.ResponseData) { + return connect.NewError( + connect.CodeAborted, + errors.New("received more requests than desired responses on a full duplex stream"), + ) + } + payload := initPayload(stream.RequestHeader(), reqs) + payload.Data = responseDefinition.ResponseData[respNum] + resp := &v1alpha1.BidiStreamResponse{ + Payload: payload, + } + err := sendOnStream[v1alpha1.BidiStreamResponse](ctx, stream, responseDefinition, resp) + if err != nil { + return err + } + respNum++ + reqs = nil + } + } + + // If this is a half duplex call, then send all the responses now. + // If this is a full deplex call, then flush any remaining responses. It is possible + // that the initial request specifying the desired response definitions contained more + // definitions than requests sent on the stream. In that case, if we interleave for + // full duplex, we should have some responses left over to send. + if respNum < len(responseDefinition.ResponseData) { + for i := respNum; i < len(responseDefinition.ResponseData); i++ { + payload := initPayload(stream.RequestHeader(), reqs) + payload.Data = responseDefinition.ResponseData[i] + resp := &v1alpha1.BidiStreamResponse{ + Payload: payload, + } + err := sendOnStream[v1alpha1.BidiStreamResponse](ctx, stream, responseDefinition, resp) + if err != nil { + return err + } + + } + } + + if responseDefinition.Error != nil { + return createError(responseDefinition.Error) + } + return nil +} + +// NewConformanceServiceHandler returns a new ConformanceServiceHandler. +func NewConformanceServiceHandler() conformancev1alpha1connect.ConformanceServiceHandler { + return &conformanceServer{} +} + +// Sends a response T on the given stream, setting response headers and trailers +// according to the provided response definition. +func sendOnStream[T any]( + ctx context.Context, + stream Stream[T], + def *v1alpha1.StreamResponseDefinition, + resp *T, +) error { + var ticker *time.Ticker + if def.ResponseDelayMs > 0 { + ticker = time.NewTicker(time.Duration(def.ResponseDelayMs) * time.Millisecond) + defer ticker.Stop() + } + if ticker != nil { + select { + case <-ctx.Done(): + return ctx.Err() + case <-ticker.C: + } + } + + if err := stream.Send(resp); err != nil { + return fmt.Errorf("error sending on stream: %w", err) + } + return nil +} + +// Parses the given unary response definition and returns either +// a built payload or a connect error based on the definition. +func parseUnaryResponseDefinition( + def *v1alpha1.UnaryResponseDefinition, + headers http.Header, + reqs []*anypb.Any, +) (*v1alpha1.ConformancePayload, error) { + if def != nil { + switch rt := def.Response.(type) { + case *v1alpha1.UnaryResponseDefinition_Error: + return nil, createError(rt.Error) + case *v1alpha1.UnaryResponseDefinition_ResponseData, nil: + payload := initPayload(headers, reqs) + + // If response data was provided, set that in the payload response + if rt, ok := rt.(*v1alpha1.UnaryResponseDefinition_ResponseData); ok { + payload.Data = rt.ResponseData + } + return payload, nil + default: + return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("provided UnaryRequest.Response has an unexpected type %T", rt)) + } + } + return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("no response definition provided")) +} + +// Initializes a conformance payload +func initPayload(headers http.Header, reqs []*anypb.Any) *v1alpha1.ConformancePayload { + payload := &v1alpha1.ConformancePayload{} + + headerInfo := []*v1alpha1.Header{} + for key, value := range headers { + hdr := &v1alpha1.Header{ + Name: key, + Value: value, + } + headerInfo = append(headerInfo, hdr) + } + + // Set all observed request headers and requests in the response payload + payload.RequestInfo = &v1alpha1.ConformancePayload_RequestInfo{ + RequestHeaders: headerInfo, + Requests: reqs, + } + return payload +} + +// Sets all response headers and trailers onto the given response +func setResponseHeadersAndTrailers[T any](def ConformanceRequest, resp *connect.Response[T]) { + // Set all requested response headers on the response + for _, header := range def.GetResponseHeaders() { + for _, val := range header.Value { + resp.Header().Add(header.Name, val) + } + } + // Set all requested response trailers on the response + for _, trailer := range def.GetResponseTrailers() { + for _, val := range trailer.Value { + resp.Trailer().Add(trailer.Name, val) + } + } +} + +// Creates a Connect error from the given Error message +func createError(err *v1alpha1.Error) *connect.Error { + connectErr := connect.NewError(connect.Code(err.Code), errors.New(err.Message)) + for _, detail := range err.Details { + connectDetail, err := connect.NewErrorDetail(detail) + if err != nil { + return connect.NewError(connect.CodeInvalidArgument, err) + } + connectErr.AddDetail(connectDetail) + } + return connectErr +} + +// Converts the given message to an Any +func asAny(msg proto.Message) (*anypb.Any, error) { + msgAsAny, err := anypb.New(msg) + if err != nil { + return nil, connect.NewError( + connect.CodeInternal, + fmt.Errorf("unable to convert message: %w", err), + ) + } + return msgAsAny, nil +} diff --git a/internal/app/server/server.go b/internal/app/server/server.go new file mode 100644 index 00000000..368727f8 --- /dev/null +++ b/internal/app/server/server.go @@ -0,0 +1,126 @@ +// Copyright 2022-2023 The Connect Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package server + +import ( + "context" + "errors" + "fmt" + "io" + "net/http" + "os" + "os/signal" + "syscall" + "time" + + "connectrpc.com/conformance/internal/gen/proto/connect/connectrpc/conformance/v1alpha1/conformancev1alpha1connect" + "github.com/rs/cors" + "golang.org/x/net/http2" + "golang.org/x/net/http2/h2c" +) + +func Run(ctx context.Context, args []string, in io.ReadCloser, out, err io.WriteCloser) error { + h1Port := args[0] + h2Port := args[1] + + mux := http.NewServeMux() + mux.Handle(conformancev1alpha1connect.NewConformanceServiceHandler( + NewConformanceServiceHandler(), + )) + corsHandler := cors.New(cors.Options{ + AllowedMethods: []string{ + http.MethodHead, + http.MethodGet, + http.MethodPost, + http.MethodPut, + http.MethodPatch, + http.MethodDelete, + }, + // Mirror the `Origin` header value in the `Access-Control-Allow-Origin` + // preflight response header. + // This is equivalent to `Access-Control-Allow-Origin: *`, but allows + // for requests with credentials. + // Note that this effectively disables CORS and is not safe for use in + // production environments. + AllowOriginFunc: func(origin string) bool { + return true + }, + // Note that rs/cors does not return `Access-Control-Allow-Headers: *` + // in response to preflight requests with the following configuration. + // It simply mirrors all headers listed in the `Access-Control-Request-Headers` + // preflight request header. + AllowedHeaders: []string{"*"}, + // We explicitly set the exposed header names instead of using the wildcard *, + // because in requests with credentials, it is treated as the literal header + // name "*" without special semantics. + ExposedHeaders: []string{ + "Grpc-Status", "Grpc-Message", "Grpc-Status-Details-Bin", "X-Grpc-Test-Echo-Initial", + "Trailer-X-Grpc-Test-Echo-Trailing-Bin", "Request-Protocol", "Get-Request"}, + }).Handler(mux) + + // Create servers + h1Server := newH1Server(h1Port, corsHandler) + h2Server := newH2Server(h2Port, mux) + done := make(chan os.Signal, 1) + errs := make(chan error, 2) + signal.Notify(done, os.Interrupt, syscall.SIGINT, syscall.SIGTERM) + go func() { + err := h1Server.ListenAndServe() + if err != nil && !errors.Is(err, http.ErrServerClosed) { + errs <- err + } + }() + go func() { + err := h2Server.ListenAndServe() + if err != nil && !errors.Is(err, http.ErrServerClosed) { + errs <- err + } + }() + + fmt.Printf("HTTP/1.1 server listening on port %s\nHTTP/2 server listening on port %s", h1Port, h2Port) + + select { + case err := <-errs: + return err + case <-done: + } + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + if err := h1Server.Shutdown(ctx); err != nil { + return err + } + if err := h2Server.Shutdown(ctx); err != nil { + return err + } + + return nil +} + +func newH1Server(h1Port string, handler http.Handler) *http.Server { + h1Server := &http.Server{ + Addr: ":" + h1Port, + Handler: handler, + } + return h1Server +} + +func newH2Server(h2Port string, handler http.Handler) *http.Server { + h2Server := &http.Server{ + Addr: ":" + h2Port, + } + h2Server.Handler = h2c.NewHandler(handler, &http2.Server{}) + return h2Server +} diff --git a/internal/gen/proto/connect/connectrpc/conformance/v1alpha1/conformancev1alpha1connect/service.connect.go b/internal/gen/proto/connect/connectrpc/conformance/v1alpha1/conformancev1alpha1connect/service.connect.go index d9715fd8..e6ff1a97 100644 --- a/internal/gen/proto/connect/connectrpc/conformance/v1alpha1/conformancev1alpha1connect/service.connect.go +++ b/internal/gen/proto/connect/connectrpc/conformance/v1alpha1/conformancev1alpha1connect/service.connect.go @@ -56,7 +56,10 @@ type ConformanceServiceClient interface { // Response message data is specified as bytes. The service should echo back // request properties in the ConformancePayload and then include the message // data in the data field. - Unary(context.Context, *connect.Request[v1alpha1.UnaryRequest]) (*connect.Response[v1alpha1.ConformancePayload], error) + // + // Servers should allow the response definition to be unset in the request and + // if it is, set no response headers or trailers and send back an empty response. + Unary(context.Context, *connect.Request[v1alpha1.UnaryRequest]) (*connect.Response[v1alpha1.UnaryResponse], error) // A server-streaming operation. The request indicates the response headers, // response messages, trailers, and an optional error to send back. The // response data should be sent in the order indicated, and the server should @@ -66,27 +69,22 @@ type ConformanceServiceClient interface { // request properties in the first ConformancePayload, and then include the // message data in the data field. Subsequent messages after the first one // should contain only the data field. - ServerStream(context.Context, *connect.Request[v1alpha1.ServerStreamRequest]) (*connect.ServerStreamForClient[v1alpha1.ConformancePayload], error) - // A client-streaming operation. The first request indicates the response - // headers and trailers and also indicates either a response message or an - // error to send back. - // - // Response message data is specified as bytes. The service should echo back - // request properties, including all request messages in the order they were - // received, in the ConformancePayload and then include the message data in - // the data field. // - // If the input stream is empty, the server's response will include no data, - // only the request properties (headers, timeout). - ClientStream(context.Context) *connect.ClientStreamForClient[v1alpha1.ClientStreamRequest, v1alpha1.ConformancePayload] + // Servers should allow the response definition to be unset in the request and + // if so, all responses should contain no response headers or trailers and + // contain empty response data. + ServerStream(context.Context, *connect.Request[v1alpha1.ServerStreamRequest]) (*connect.ServerStreamForClient[v1alpha1.ServerStreamResponse], error) + // Servers should allow the response definition to be unset in the request and + // if it is, set no response headers or trailers and send back empty response data. + ClientStream(context.Context) *connect.ClientStreamForClient[v1alpha1.ClientStreamRequest, v1alpha1.ClientStreamResponse] // A bidirectional-streaming operation. The first request indicates the response // headers, response messages, trailers, and an optional error to send back. // The response data should be sent in the order indicated, and the server // should wait between sending response messages as indicated. If the - // wait_for_each request field is true, the handler should read one request + // full_duplex field is true, the handler should read one request // and then send back one response, and then alternate, reading another - // request and then sending back another response, etc. If the wait duration - // is specified, the server should wait that long in between sending each + // request and then sending back another response, etc. If the response_delay_ms + // duration is specified, the server should wait that long in between sending each // response message. If both are specified, the server should wait the given // duration after reading the request before sending the corresponding // response. @@ -100,7 +98,7 @@ type ConformanceServiceClient interface { // If the input stream is empty, the server should send a single response // message that includes no data and only the request properties (headers, // timeout). - BidiStream(context.Context) *connect.BidiStreamForClient[v1alpha1.BidiStreamRequest, v1alpha1.ConformancePayload] + BidiStream(context.Context) *connect.BidiStreamForClient[v1alpha1.BidiStreamRequest, v1alpha1.BidiStreamResponse] } // NewConformanceServiceClient constructs a client for the @@ -114,22 +112,22 @@ type ConformanceServiceClient interface { func NewConformanceServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) ConformanceServiceClient { baseURL = strings.TrimRight(baseURL, "/") return &conformanceServiceClient{ - unary: connect.NewClient[v1alpha1.UnaryRequest, v1alpha1.ConformancePayload]( + unary: connect.NewClient[v1alpha1.UnaryRequest, v1alpha1.UnaryResponse]( httpClient, baseURL+ConformanceServiceUnaryProcedure, opts..., ), - serverStream: connect.NewClient[v1alpha1.ServerStreamRequest, v1alpha1.ConformancePayload]( + serverStream: connect.NewClient[v1alpha1.ServerStreamRequest, v1alpha1.ServerStreamResponse]( httpClient, baseURL+ConformanceServiceServerStreamProcedure, opts..., ), - clientStream: connect.NewClient[v1alpha1.ClientStreamRequest, v1alpha1.ConformancePayload]( + clientStream: connect.NewClient[v1alpha1.ClientStreamRequest, v1alpha1.ClientStreamResponse]( httpClient, baseURL+ConformanceServiceClientStreamProcedure, opts..., ), - bidiStream: connect.NewClient[v1alpha1.BidiStreamRequest, v1alpha1.ConformancePayload]( + bidiStream: connect.NewClient[v1alpha1.BidiStreamRequest, v1alpha1.BidiStreamResponse]( httpClient, baseURL+ConformanceServiceBidiStreamProcedure, opts..., @@ -139,29 +137,29 @@ func NewConformanceServiceClient(httpClient connect.HTTPClient, baseURL string, // conformanceServiceClient implements ConformanceServiceClient. type conformanceServiceClient struct { - unary *connect.Client[v1alpha1.UnaryRequest, v1alpha1.ConformancePayload] - serverStream *connect.Client[v1alpha1.ServerStreamRequest, v1alpha1.ConformancePayload] - clientStream *connect.Client[v1alpha1.ClientStreamRequest, v1alpha1.ConformancePayload] - bidiStream *connect.Client[v1alpha1.BidiStreamRequest, v1alpha1.ConformancePayload] + unary *connect.Client[v1alpha1.UnaryRequest, v1alpha1.UnaryResponse] + serverStream *connect.Client[v1alpha1.ServerStreamRequest, v1alpha1.ServerStreamResponse] + clientStream *connect.Client[v1alpha1.ClientStreamRequest, v1alpha1.ClientStreamResponse] + bidiStream *connect.Client[v1alpha1.BidiStreamRequest, v1alpha1.BidiStreamResponse] } // Unary calls connectrpc.conformance.v1alpha1.ConformanceService.Unary. -func (c *conformanceServiceClient) Unary(ctx context.Context, req *connect.Request[v1alpha1.UnaryRequest]) (*connect.Response[v1alpha1.ConformancePayload], error) { +func (c *conformanceServiceClient) Unary(ctx context.Context, req *connect.Request[v1alpha1.UnaryRequest]) (*connect.Response[v1alpha1.UnaryResponse], error) { return c.unary.CallUnary(ctx, req) } // ServerStream calls connectrpc.conformance.v1alpha1.ConformanceService.ServerStream. -func (c *conformanceServiceClient) ServerStream(ctx context.Context, req *connect.Request[v1alpha1.ServerStreamRequest]) (*connect.ServerStreamForClient[v1alpha1.ConformancePayload], error) { +func (c *conformanceServiceClient) ServerStream(ctx context.Context, req *connect.Request[v1alpha1.ServerStreamRequest]) (*connect.ServerStreamForClient[v1alpha1.ServerStreamResponse], error) { return c.serverStream.CallServerStream(ctx, req) } // ClientStream calls connectrpc.conformance.v1alpha1.ConformanceService.ClientStream. -func (c *conformanceServiceClient) ClientStream(ctx context.Context) *connect.ClientStreamForClient[v1alpha1.ClientStreamRequest, v1alpha1.ConformancePayload] { +func (c *conformanceServiceClient) ClientStream(ctx context.Context) *connect.ClientStreamForClient[v1alpha1.ClientStreamRequest, v1alpha1.ClientStreamResponse] { return c.clientStream.CallClientStream(ctx) } // BidiStream calls connectrpc.conformance.v1alpha1.ConformanceService.BidiStream. -func (c *conformanceServiceClient) BidiStream(ctx context.Context) *connect.BidiStreamForClient[v1alpha1.BidiStreamRequest, v1alpha1.ConformancePayload] { +func (c *conformanceServiceClient) BidiStream(ctx context.Context) *connect.BidiStreamForClient[v1alpha1.BidiStreamRequest, v1alpha1.BidiStreamResponse] { return c.bidiStream.CallBidiStream(ctx) } @@ -174,7 +172,10 @@ type ConformanceServiceHandler interface { // Response message data is specified as bytes. The service should echo back // request properties in the ConformancePayload and then include the message // data in the data field. - Unary(context.Context, *connect.Request[v1alpha1.UnaryRequest]) (*connect.Response[v1alpha1.ConformancePayload], error) + // + // Servers should allow the response definition to be unset in the request and + // if it is, set no response headers or trailers and send back an empty response. + Unary(context.Context, *connect.Request[v1alpha1.UnaryRequest]) (*connect.Response[v1alpha1.UnaryResponse], error) // A server-streaming operation. The request indicates the response headers, // response messages, trailers, and an optional error to send back. The // response data should be sent in the order indicated, and the server should @@ -184,27 +185,22 @@ type ConformanceServiceHandler interface { // request properties in the first ConformancePayload, and then include the // message data in the data field. Subsequent messages after the first one // should contain only the data field. - ServerStream(context.Context, *connect.Request[v1alpha1.ServerStreamRequest], *connect.ServerStream[v1alpha1.ConformancePayload]) error - // A client-streaming operation. The first request indicates the response - // headers and trailers and also indicates either a response message or an - // error to send back. - // - // Response message data is specified as bytes. The service should echo back - // request properties, including all request messages in the order they were - // received, in the ConformancePayload and then include the message data in - // the data field. // - // If the input stream is empty, the server's response will include no data, - // only the request properties (headers, timeout). - ClientStream(context.Context, *connect.ClientStream[v1alpha1.ClientStreamRequest]) (*connect.Response[v1alpha1.ConformancePayload], error) + // Servers should allow the response definition to be unset in the request and + // if so, all responses should contain no response headers or trailers and + // contain empty response data. + ServerStream(context.Context, *connect.Request[v1alpha1.ServerStreamRequest], *connect.ServerStream[v1alpha1.ServerStreamResponse]) error + // Servers should allow the response definition to be unset in the request and + // if it is, set no response headers or trailers and send back empty response data. + ClientStream(context.Context, *connect.ClientStream[v1alpha1.ClientStreamRequest]) (*connect.Response[v1alpha1.ClientStreamResponse], error) // A bidirectional-streaming operation. The first request indicates the response // headers, response messages, trailers, and an optional error to send back. // The response data should be sent in the order indicated, and the server // should wait between sending response messages as indicated. If the - // wait_for_each request field is true, the handler should read one request + // full_duplex field is true, the handler should read one request // and then send back one response, and then alternate, reading another - // request and then sending back another response, etc. If the wait duration - // is specified, the server should wait that long in between sending each + // request and then sending back another response, etc. If the response_delay_ms + // duration is specified, the server should wait that long in between sending each // response message. If both are specified, the server should wait the given // duration after reading the request before sending the corresponding // response. @@ -218,7 +214,7 @@ type ConformanceServiceHandler interface { // If the input stream is empty, the server should send a single response // message that includes no data and only the request properties (headers, // timeout). - BidiStream(context.Context, *connect.BidiStream[v1alpha1.BidiStreamRequest, v1alpha1.ConformancePayload]) error + BidiStream(context.Context, *connect.BidiStream[v1alpha1.BidiStreamRequest, v1alpha1.BidiStreamResponse]) error } // NewConformanceServiceHandler builds an HTTP handler from the service implementation. It returns @@ -266,18 +262,18 @@ func NewConformanceServiceHandler(svc ConformanceServiceHandler, opts ...connect // UnimplementedConformanceServiceHandler returns CodeUnimplemented from all methods. type UnimplementedConformanceServiceHandler struct{} -func (UnimplementedConformanceServiceHandler) Unary(context.Context, *connect.Request[v1alpha1.UnaryRequest]) (*connect.Response[v1alpha1.ConformancePayload], error) { +func (UnimplementedConformanceServiceHandler) Unary(context.Context, *connect.Request[v1alpha1.UnaryRequest]) (*connect.Response[v1alpha1.UnaryResponse], error) { return nil, connect.NewError(connect.CodeUnimplemented, errors.New("connectrpc.conformance.v1alpha1.ConformanceService.Unary is not implemented")) } -func (UnimplementedConformanceServiceHandler) ServerStream(context.Context, *connect.Request[v1alpha1.ServerStreamRequest], *connect.ServerStream[v1alpha1.ConformancePayload]) error { +func (UnimplementedConformanceServiceHandler) ServerStream(context.Context, *connect.Request[v1alpha1.ServerStreamRequest], *connect.ServerStream[v1alpha1.ServerStreamResponse]) error { return connect.NewError(connect.CodeUnimplemented, errors.New("connectrpc.conformance.v1alpha1.ConformanceService.ServerStream is not implemented")) } -func (UnimplementedConformanceServiceHandler) ClientStream(context.Context, *connect.ClientStream[v1alpha1.ClientStreamRequest]) (*connect.Response[v1alpha1.ConformancePayload], error) { +func (UnimplementedConformanceServiceHandler) ClientStream(context.Context, *connect.ClientStream[v1alpha1.ClientStreamRequest]) (*connect.Response[v1alpha1.ClientStreamResponse], error) { return nil, connect.NewError(connect.CodeUnimplemented, errors.New("connectrpc.conformance.v1alpha1.ConformanceService.ClientStream is not implemented")) } -func (UnimplementedConformanceServiceHandler) BidiStream(context.Context, *connect.BidiStream[v1alpha1.BidiStreamRequest, v1alpha1.ConformancePayload]) error { +func (UnimplementedConformanceServiceHandler) BidiStream(context.Context, *connect.BidiStream[v1alpha1.BidiStreamRequest, v1alpha1.BidiStreamResponse]) error { return connect.NewError(connect.CodeUnimplemented, errors.New("connectrpc.conformance.v1alpha1.ConformanceService.BidiStream is not implemented")) } diff --git a/internal/gen/proto/go/connectrpc/conformance/v1alpha1/service.pb.go b/internal/gen/proto/go/connectrpc/conformance/v1alpha1/service.pb.go index 08e7ebc5..220c2a0c 100644 --- a/internal/gen/proto/go/connectrpc/conformance/v1alpha1/service.pb.go +++ b/internal/gen/proto/go/connectrpc/conformance/v1alpha1/service.pb.go @@ -21,23 +21,25 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -type UnaryRequest struct { +// A definition of a response to be sent from a single-response endpoint. +// Can be used to define a response for unary or client-streaming calls. +type UnaryResponseDefinition struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // response headers to send + // Response headers to send ResponseHeaders []*Header `protobuf:"bytes,1,rep,name=response_headers,json=responseHeaders,proto3" json:"response_headers,omitempty"` // Types that are assignable to Response: - // *UnaryRequest_ResponseData - // *UnaryRequest_Error - Response isUnaryRequest_Response `protobuf_oneof:"response"` - // response trailers to send - together with the error if present + // *UnaryResponseDefinition_ResponseData + // *UnaryResponseDefinition_Error + Response isUnaryResponseDefinition_Response `protobuf_oneof:"response"` + // Response trailers to send - together with the error if present ResponseTrailers []*Header `protobuf:"bytes,4,rep,name=response_trailers,json=responseTrailers,proto3" json:"response_trailers,omitempty"` } -func (x *UnaryRequest) Reset() { - *x = UnaryRequest{} +func (x *UnaryResponseDefinition) Reset() { + *x = UnaryResponseDefinition{} if protoimpl.UnsafeEnabled { mi := &file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -45,13 +47,13 @@ func (x *UnaryRequest) Reset() { } } -func (x *UnaryRequest) String() string { +func (x *UnaryResponseDefinition) String() string { return protoimpl.X.MessageStringOf(x) } -func (*UnaryRequest) ProtoMessage() {} +func (*UnaryResponseDefinition) ProtoMessage() {} -func (x *UnaryRequest) ProtoReflect() protoreflect.Message { +func (x *UnaryResponseDefinition) ProtoReflect() protoreflect.Message { mi := &file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -63,83 +65,85 @@ func (x *UnaryRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use UnaryRequest.ProtoReflect.Descriptor instead. -func (*UnaryRequest) Descriptor() ([]byte, []int) { +// Deprecated: Use UnaryResponseDefinition.ProtoReflect.Descriptor instead. +func (*UnaryResponseDefinition) Descriptor() ([]byte, []int) { return file_connectrpc_conformance_v1alpha1_service_proto_rawDescGZIP(), []int{0} } -func (x *UnaryRequest) GetResponseHeaders() []*Header { +func (x *UnaryResponseDefinition) GetResponseHeaders() []*Header { if x != nil { return x.ResponseHeaders } return nil } -func (m *UnaryRequest) GetResponse() isUnaryRequest_Response { +func (m *UnaryResponseDefinition) GetResponse() isUnaryResponseDefinition_Response { if m != nil { return m.Response } return nil } -func (x *UnaryRequest) GetResponseData() []byte { - if x, ok := x.GetResponse().(*UnaryRequest_ResponseData); ok { +func (x *UnaryResponseDefinition) GetResponseData() []byte { + if x, ok := x.GetResponse().(*UnaryResponseDefinition_ResponseData); ok { return x.ResponseData } return nil } -func (x *UnaryRequest) GetError() *Error { - if x, ok := x.GetResponse().(*UnaryRequest_Error); ok { +func (x *UnaryResponseDefinition) GetError() *Error { + if x, ok := x.GetResponse().(*UnaryResponseDefinition_Error); ok { return x.Error } return nil } -func (x *UnaryRequest) GetResponseTrailers() []*Header { +func (x *UnaryResponseDefinition) GetResponseTrailers() []*Header { if x != nil { return x.ResponseTrailers } return nil } -type isUnaryRequest_Response interface { - isUnaryRequest_Response() +type isUnaryResponseDefinition_Response interface { + isUnaryResponseDefinition_Response() } -type UnaryRequest_ResponseData struct { - // response message to send +type UnaryResponseDefinition_ResponseData struct { + // Response message to send ResponseData []byte `protobuf:"bytes,2,opt,name=response_data,json=responseData,proto3,oneof"` } -type UnaryRequest_Error struct { - // error to raise instead of response message +type UnaryResponseDefinition_Error struct { + // Error to raise instead of response message Error *Error `protobuf:"bytes,3,opt,name=error,proto3,oneof"` } -func (*UnaryRequest_ResponseData) isUnaryRequest_Response() {} +func (*UnaryResponseDefinition_ResponseData) isUnaryResponseDefinition_Response() {} -func (*UnaryRequest_Error) isUnaryRequest_Response() {} +func (*UnaryResponseDefinition_Error) isUnaryResponseDefinition_Response() {} -type ServerStreamRequest struct { +// A definition of responses to be sent from a streaming endpoint. +// Can be used to define responses for server-streaming or bidi-streaming calls. +type StreamResponseDefinition struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // response headers to send + // Response headers to send ResponseHeaders []*Header `protobuf:"bytes,1,rep,name=response_headers,json=responseHeaders,proto3" json:"response_headers,omitempty"` - // response messages to send + // Response messages to send ResponseData [][]byte `protobuf:"bytes,2,rep,name=response_data,json=responseData,proto3" json:"response_data,omitempty"` - // wait this many milliseconds before sending each response message - WaitBeforeEachMessageMillis uint32 `protobuf:"varint,3,opt,name=wait_before_each_message_millis,json=waitBeforeEachMessageMillis,proto3" json:"wait_before_each_message_millis,omitempty"` - // optional error to raise, but only after sending the response messages + // Wait this many milliseconds before sending each response message + ResponseDelayMs uint32 `protobuf:"varint,3,opt,name=response_delay_ms,json=responseDelayMs,proto3" json:"response_delay_ms,omitempty"` + // Optional error to raise, but only after sending the response messages Error *Error `protobuf:"bytes,4,opt,name=error,proto3" json:"error,omitempty"` - // response trailers to send - together with the error if present + // Response trailers to send - together with the error if present ResponseTrailers []*Header `protobuf:"bytes,5,rep,name=response_trailers,json=responseTrailers,proto3" json:"response_trailers,omitempty"` } -func (x *ServerStreamRequest) Reset() { - *x = ServerStreamRequest{} +func (x *StreamResponseDefinition) Reset() { + *x = StreamResponseDefinition{} if protoimpl.UnsafeEnabled { mi := &file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -147,13 +151,13 @@ func (x *ServerStreamRequest) Reset() { } } -func (x *ServerStreamRequest) String() string { +func (x *StreamResponseDefinition) String() string { return protoimpl.X.MessageStringOf(x) } -func (*ServerStreamRequest) ProtoMessage() {} +func (*StreamResponseDefinition) ProtoMessage() {} -func (x *ServerStreamRequest) ProtoReflect() protoreflect.Message { +func (x *StreamResponseDefinition) ProtoReflect() protoreflect.Message { mi := &file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[1] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -165,54 +169,247 @@ func (x *ServerStreamRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use ServerStreamRequest.ProtoReflect.Descriptor instead. -func (*ServerStreamRequest) Descriptor() ([]byte, []int) { +// Deprecated: Use StreamResponseDefinition.ProtoReflect.Descriptor instead. +func (*StreamResponseDefinition) Descriptor() ([]byte, []int) { return file_connectrpc_conformance_v1alpha1_service_proto_rawDescGZIP(), []int{1} } -func (x *ServerStreamRequest) GetResponseHeaders() []*Header { +func (x *StreamResponseDefinition) GetResponseHeaders() []*Header { if x != nil { return x.ResponseHeaders } return nil } -func (x *ServerStreamRequest) GetResponseData() [][]byte { +func (x *StreamResponseDefinition) GetResponseData() [][]byte { if x != nil { return x.ResponseData } return nil } -func (x *ServerStreamRequest) GetWaitBeforeEachMessageMillis() uint32 { +func (x *StreamResponseDefinition) GetResponseDelayMs() uint32 { if x != nil { - return x.WaitBeforeEachMessageMillis + return x.ResponseDelayMs } return 0 } -func (x *ServerStreamRequest) GetError() *Error { +func (x *StreamResponseDefinition) GetError() *Error { if x != nil { return x.Error } return nil } -func (x *ServerStreamRequest) GetResponseTrailers() []*Header { +func (x *StreamResponseDefinition) GetResponseTrailers() []*Header { if x != nil { return x.ResponseTrailers } return nil } +type UnaryRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The response definition which should be returned in the conformance payload + ResponseDefinition *UnaryResponseDefinition `protobuf:"bytes,1,opt,name=response_definition,json=responseDefinition,proto3" json:"response_definition,omitempty"` +} + +func (x *UnaryRequest) Reset() { + *x = UnaryRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UnaryRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UnaryRequest) ProtoMessage() {} + +func (x *UnaryRequest) ProtoReflect() protoreflect.Message { + mi := &file_connectrpc_conformance_v1alpha1_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 UnaryRequest.ProtoReflect.Descriptor instead. +func (*UnaryRequest) Descriptor() ([]byte, []int) { + return file_connectrpc_conformance_v1alpha1_service_proto_rawDescGZIP(), []int{2} +} + +func (x *UnaryRequest) GetResponseDefinition() *UnaryResponseDefinition { + if x != nil { + return x.ResponseDefinition + } + return nil +} + +type UnaryResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The conformance payload to respond with. + Payload *ConformancePayload `protobuf:"bytes,1,opt,name=payload,proto3" json:"payload,omitempty"` +} + +func (x *UnaryResponse) Reset() { + *x = UnaryResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UnaryResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UnaryResponse) ProtoMessage() {} + +func (x *UnaryResponse) ProtoReflect() protoreflect.Message { + mi := &file_connectrpc_conformance_v1alpha1_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 UnaryResponse.ProtoReflect.Descriptor instead. +func (*UnaryResponse) Descriptor() ([]byte, []int) { + return file_connectrpc_conformance_v1alpha1_service_proto_rawDescGZIP(), []int{3} +} + +func (x *UnaryResponse) GetPayload() *ConformancePayload { + if x != nil { + return x.Payload + } + return nil +} + +type ServerStreamRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The response definition which should be returned in the conformance payload. + ResponseDefinition *StreamResponseDefinition `protobuf:"bytes,1,opt,name=response_definition,json=responseDefinition,proto3" json:"response_definition,omitempty"` +} + +func (x *ServerStreamRequest) Reset() { + *x = ServerStreamRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ServerStreamRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ServerStreamRequest) ProtoMessage() {} + +func (x *ServerStreamRequest) ProtoReflect() protoreflect.Message { + mi := &file_connectrpc_conformance_v1alpha1_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 ServerStreamRequest.ProtoReflect.Descriptor instead. +func (*ServerStreamRequest) Descriptor() ([]byte, []int) { + return file_connectrpc_conformance_v1alpha1_service_proto_rawDescGZIP(), []int{4} +} + +func (x *ServerStreamRequest) GetResponseDefinition() *StreamResponseDefinition { + if x != nil { + return x.ResponseDefinition + } + return nil +} + +type ServerStreamResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The conformance payload to respond with + Payload *ConformancePayload `protobuf:"bytes,1,opt,name=payload,proto3" json:"payload,omitempty"` +} + +func (x *ServerStreamResponse) Reset() { + *x = ServerStreamResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ServerStreamResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ServerStreamResponse) ProtoMessage() {} + +func (x *ServerStreamResponse) ProtoReflect() protoreflect.Message { + mi := &file_connectrpc_conformance_v1alpha1_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 ServerStreamResponse.ProtoReflect.Descriptor instead. +func (*ServerStreamResponse) Descriptor() ([]byte, []int) { + return file_connectrpc_conformance_v1alpha1_service_proto_rawDescGZIP(), []int{5} +} + +func (x *ServerStreamResponse) GetPayload() *ConformancePayload { + if x != nil { + return x.Payload + } + return nil +} + type ClientStreamRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // Tells the server how to reply at the end; required in the first message - // in the stream. Should not be present in subsequent messages. - ResponseDefinition *UnaryRequest `protobuf:"bytes,1,opt,name=response_definition,json=responseDefinition,proto3" json:"response_definition,omitempty"` + // Tells the server how to reply once all client messages are + // complete. Required in the first message in the stream, but + // should be ignored in subsequent messages. + ResponseDefinition *UnaryResponseDefinition `protobuf:"bytes,1,opt,name=response_definition,json=responseDefinition,proto3" json:"response_definition,omitempty"` // Additional data for subsequent messages in the stream. Extra []byte `protobuf:"bytes,2,opt,name=extra,proto3" json:"extra,omitempty"` } @@ -220,7 +417,7 @@ type ClientStreamRequest struct { func (x *ClientStreamRequest) Reset() { *x = ClientStreamRequest{} if protoimpl.UnsafeEnabled { - mi := &file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[2] + mi := &file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -233,7 +430,7 @@ func (x *ClientStreamRequest) String() string { func (*ClientStreamRequest) ProtoMessage() {} func (x *ClientStreamRequest) ProtoReflect() protoreflect.Message { - mi := &file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[2] + mi := &file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -246,10 +443,10 @@ func (x *ClientStreamRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ClientStreamRequest.ProtoReflect.Descriptor instead. func (*ClientStreamRequest) Descriptor() ([]byte, []int) { - return file_connectrpc_conformance_v1alpha1_service_proto_rawDescGZIP(), []int{2} + return file_connectrpc_conformance_v1alpha1_service_proto_rawDescGZIP(), []int{6} } -func (x *ClientStreamRequest) GetResponseDefinition() *UnaryRequest { +func (x *ClientStreamRequest) GetResponseDefinition() *UnaryResponseDefinition { if x != nil { return x.ResponseDefinition } @@ -263,31 +460,81 @@ func (x *ClientStreamRequest) GetExtra() []byte { return nil } +type ClientStreamResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The conformance payload to respond with + Payload *ConformancePayload `protobuf:"bytes,1,opt,name=payload,proto3" json:"payload,omitempty"` +} + +func (x *ClientStreamResponse) Reset() { + *x = ClientStreamResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ClientStreamResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ClientStreamResponse) ProtoMessage() {} + +func (x *ClientStreamResponse) ProtoReflect() protoreflect.Message { + mi := &file_connectrpc_conformance_v1alpha1_service_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 ClientStreamResponse.ProtoReflect.Descriptor instead. +func (*ClientStreamResponse) Descriptor() ([]byte, []int) { + return file_connectrpc_conformance_v1alpha1_service_proto_rawDescGZIP(), []int{7} +} + +func (x *ClientStreamResponse) GetPayload() *ConformancePayload { + if x != nil { + return x.Payload + } + return nil +} + type BidiStreamRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields // Tells the server how to reply; required in the first message - // in the stream. Should not be present in subsequent messages. - ResponseDefinition *ServerStreamRequest `protobuf:"bytes,1,opt,name=response_definition,json=responseDefinition,proto3" json:"response_definition,omitempty"` - // Tells the server to wait for each request before sending a - // response, to effectively interleave the stream so messages - // always are sent in request->response pairs. If false, then - // the response stream will be sent immediately with the only - // delays between messages being a optional fixed milliseconds - // in the above field. This field is only present in the first - // message in the stream and should not appear in subsequent - // messages. - WaitForEachRequest bool `protobuf:"varint,2,opt,name=wait_for_each_request,json=waitForEachRequest,proto3" json:"wait_for_each_request,omitempty"` + // in the stream. Should be ignored in subsequent messages. + ResponseDefinition *StreamResponseDefinition `protobuf:"bytes,1,opt,name=response_definition,json=responseDefinition,proto3" json:"response_definition,omitempty"` + // Tells the server whether it should wait for each request + // before sending a response. + // If true, it indicates the server should effectively interleave the + // stream so messages are sent in request->response pairs. + // If false, then the response stream will be sent once all request messages + // are finished sending with the only delays between messages + // being the optional fixed milliseconds defined in the response + // definition. + // This field is only relevant in the first message in the stream + // and should be ignored in subsequent messages. + FullDuplex bool `protobuf:"varint,2,opt,name=full_duplex,json=fullDuplex,proto3" json:"full_duplex,omitempty"` // Additional data for subsequent messages in the stream. - Extra []byte `protobuf:"bytes,3,opt,name=extra,proto3" json:"extra,omitempty"` + RequestData []byte `protobuf:"bytes,3,opt,name=request_data,json=requestData,proto3" json:"request_data,omitempty"` } func (x *BidiStreamRequest) Reset() { *x = BidiStreamRequest{} if protoimpl.UnsafeEnabled { - mi := &file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[3] + mi := &file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -300,7 +547,7 @@ func (x *BidiStreamRequest) String() string { func (*BidiStreamRequest) ProtoMessage() {} func (x *BidiStreamRequest) ProtoReflect() protoreflect.Message { - mi := &file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[3] + mi := &file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -313,26 +560,74 @@ func (x *BidiStreamRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use BidiStreamRequest.ProtoReflect.Descriptor instead. func (*BidiStreamRequest) Descriptor() ([]byte, []int) { - return file_connectrpc_conformance_v1alpha1_service_proto_rawDescGZIP(), []int{3} + return file_connectrpc_conformance_v1alpha1_service_proto_rawDescGZIP(), []int{8} } -func (x *BidiStreamRequest) GetResponseDefinition() *ServerStreamRequest { +func (x *BidiStreamRequest) GetResponseDefinition() *StreamResponseDefinition { if x != nil { return x.ResponseDefinition } return nil } -func (x *BidiStreamRequest) GetWaitForEachRequest() bool { +func (x *BidiStreamRequest) GetFullDuplex() bool { if x != nil { - return x.WaitForEachRequest + return x.FullDuplex } return false } -func (x *BidiStreamRequest) GetExtra() []byte { +func (x *BidiStreamRequest) GetRequestData() []byte { if x != nil { - return x.Extra + return x.RequestData + } + return nil +} + +type BidiStreamResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The conformance payload to respond with + Payload *ConformancePayload `protobuf:"bytes,1,opt,name=payload,proto3" json:"payload,omitempty"` +} + +func (x *BidiStreamResponse) Reset() { + *x = BidiStreamResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BidiStreamResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BidiStreamResponse) ProtoMessage() {} + +func (x *BidiStreamResponse) ProtoReflect() protoreflect.Message { + mi := &file_connectrpc_conformance_v1alpha1_service_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 BidiStreamResponse.ProtoReflect.Descriptor instead. +func (*BidiStreamResponse) Descriptor() ([]byte, []int) { + return file_connectrpc_conformance_v1alpha1_service_proto_rawDescGZIP(), []int{9} +} + +func (x *BidiStreamResponse) GetPayload() *ConformancePayload { + if x != nil { + return x.Payload } return nil } @@ -350,7 +645,7 @@ type ConformancePayload struct { func (x *ConformancePayload) Reset() { *x = ConformancePayload{} if protoimpl.UnsafeEnabled { - mi := &file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[4] + mi := &file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -363,7 +658,7 @@ func (x *ConformancePayload) String() string { func (*ConformancePayload) ProtoMessage() {} func (x *ConformancePayload) ProtoReflect() protoreflect.Message { - mi := &file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[4] + mi := &file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -376,7 +671,7 @@ func (x *ConformancePayload) ProtoReflect() protoreflect.Message { // Deprecated: Use ConformancePayload.ProtoReflect.Descriptor instead. func (*ConformancePayload) Descriptor() ([]byte, []int) { - return file_connectrpc_conformance_v1alpha1_service_proto_rawDescGZIP(), []int{4} + return file_connectrpc_conformance_v1alpha1_service_proto_rawDescGZIP(), []int{10} } func (x *ConformancePayload) GetData() []byte { @@ -393,20 +688,21 @@ func (x *ConformancePayload) GetRequestInfo() *ConformancePayload_RequestInfo { return nil } +// An error definition used for specifying a desired error response type Error struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Code int32 `protobuf:"varint,3,opt,name=code,proto3" json:"code,omitempty"` - Message string `protobuf:"bytes,4,opt,name=message,proto3" json:"message,omitempty"` - Details []*anypb.Any `protobuf:"bytes,5,rep,name=details,proto3" json:"details,omitempty"` + Code int32 `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"` + Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"` + Details []*anypb.Any `protobuf:"bytes,3,rep,name=details,proto3" json:"details,omitempty"` } func (x *Error) Reset() { *x = Error{} if protoimpl.UnsafeEnabled { - mi := &file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[5] + mi := &file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -419,7 +715,7 @@ func (x *Error) String() string { func (*Error) ProtoMessage() {} func (x *Error) ProtoReflect() protoreflect.Message { - mi := &file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[5] + mi := &file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -432,7 +728,7 @@ func (x *Error) ProtoReflect() protoreflect.Message { // Deprecated: Use Error.ProtoReflect.Descriptor instead. func (*Error) Descriptor() ([]byte, []int) { - return file_connectrpc_conformance_v1alpha1_service_proto_rawDescGZIP(), []int{5} + return file_connectrpc_conformance_v1alpha1_service_proto_rawDescGZIP(), []int{11} } func (x *Error) GetCode() int32 { @@ -469,7 +765,7 @@ type Header struct { func (x *Header) Reset() { *x = Header{} if protoimpl.UnsafeEnabled { - mi := &file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[6] + mi := &file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -482,7 +778,7 @@ func (x *Header) String() string { func (*Header) ProtoMessage() {} func (x *Header) ProtoReflect() protoreflect.Message { - mi := &file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[6] + mi := &file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -495,7 +791,7 @@ func (x *Header) ProtoReflect() protoreflect.Message { // Deprecated: Use Header.ProtoReflect.Descriptor instead. func (*Header) Descriptor() ([]byte, []int) { - return file_connectrpc_conformance_v1alpha1_service_proto_rawDescGZIP(), []int{6} + return file_connectrpc_conformance_v1alpha1_service_proto_rawDescGZIP(), []int{12} } func (x *Header) GetName() string { @@ -520,14 +816,20 @@ type ConformancePayload_RequestInfo struct { // The server echos back the request headers it observed here. RequestHeaders []*Header `protobuf:"bytes,1,rep,name=request_headers,json=requestHeaders,proto3" json:"request_headers,omitempty"` // The timeout observed that was included in the request. - TimeoutMillis *uint32 `protobuf:"varint,2,opt,name=timeout_millis,json=timeoutMillis,proto3,oneof" json:"timeout_millis,omitempty"` - Requests []*anypb.Any `protobuf:"bytes,3,rep,name=requests,proto3" json:"requests,omitempty"` + TimeoutMs *uint32 `protobuf:"varint,2,opt,name=timeout_ms,json=timeoutMs,proto3,oneof" json:"timeout_ms,omitempty"` + // The server should echo back all requests received. + // For unary and server-streaming requests, this should always contain a single request + // For client-streaming and half-duplex bidi-streaming, this should contain + // all client requests in the order received and be present in each response. + // For full-duplex bidirectional-streaming, this should contain all requests in the order + // they were received since the last sent response. + Requests []*anypb.Any `protobuf:"bytes,3,rep,name=requests,proto3" json:"requests,omitempty"` } func (x *ConformancePayload_RequestInfo) Reset() { *x = ConformancePayload_RequestInfo{} if protoimpl.UnsafeEnabled { - mi := &file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[7] + mi := &file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -540,7 +842,7 @@ func (x *ConformancePayload_RequestInfo) String() string { func (*ConformancePayload_RequestInfo) ProtoMessage() {} func (x *ConformancePayload_RequestInfo) ProtoReflect() protoreflect.Message { - mi := &file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[7] + mi := &file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -553,7 +855,7 @@ func (x *ConformancePayload_RequestInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use ConformancePayload_RequestInfo.ProtoReflect.Descriptor instead. func (*ConformancePayload_RequestInfo) Descriptor() ([]byte, []int) { - return file_connectrpc_conformance_v1alpha1_service_proto_rawDescGZIP(), []int{4, 0} + return file_connectrpc_conformance_v1alpha1_service_proto_rawDescGZIP(), []int{10, 0} } func (x *ConformancePayload_RequestInfo) GetRequestHeaders() []*Header { @@ -563,9 +865,9 @@ func (x *ConformancePayload_RequestInfo) GetRequestHeaders() []*Header { return nil } -func (x *ConformancePayload_RequestInfo) GetTimeoutMillis() uint32 { - if x != nil && x.TimeoutMillis != nil { - return *x.TimeoutMillis +func (x *ConformancePayload_RequestInfo) GetTimeoutMs() uint32 { + if x != nil && x.TimeoutMs != nil { + return *x.TimeoutMs } return 0 } @@ -586,153 +888,194 @@ var file_connectrpc_conformance_v1alpha1_service_proto_rawDesc = []byte{ 0x1f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 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, 0x22, 0xab, 0x02, 0x0a, 0x0c, - 0x55, 0x6e, 0x61, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x52, 0x0a, 0x10, - 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, - 0x72, 0x70, 0x63, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x2e, - 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, - 0x0f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, - 0x12, 0x25, 0x0a, 0x0d, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x64, 0x61, 0x74, - 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x0c, 0x72, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x3e, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, - 0x72, 0x70, 0x63, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x2e, - 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x48, 0x00, - 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x54, 0x0a, 0x11, 0x72, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x5f, 0x74, 0x72, 0x61, 0x69, 0x6c, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, - 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x61, 0x6c, - 0x70, 0x68, 0x61, 0x31, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x10, 0x72, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x54, 0x72, 0x61, 0x69, 0x6c, 0x65, 0x72, 0x73, 0x42, 0x0a, 0x0a, - 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xe8, 0x02, 0x0a, 0x13, 0x53, 0x65, - 0x72, 0x76, 0x65, 0x72, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x52, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x68, 0x65, + 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb6, 0x02, 0x0a, 0x17, + 0x55, 0x6e, 0x61, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x44, 0x65, 0x66, + 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x52, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x27, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x63, + 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, + 0x68, 0x61, 0x31, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x25, 0x0a, 0x0d, 0x72, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0c, 0x48, 0x00, 0x52, 0x0c, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x44, 0x61, + 0x74, 0x61, 0x12, 0x3e, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x26, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x63, + 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, + 0x68, 0x61, 0x31, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x48, 0x00, 0x52, 0x05, 0x65, 0x72, 0x72, + 0x6f, 0x72, 0x12, 0x54, 0x0a, 0x11, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x74, + 0x72, 0x61, 0x69, 0x6c, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, + 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x6f, + 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, + 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x10, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x54, 0x72, 0x61, 0x69, 0x6c, 0x65, 0x72, 0x73, 0x42, 0x0a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xd3, 0x02, 0x0a, 0x18, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x52, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0c, 0x72, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x44, 0x0a, 0x1f, 0x77, 0x61, - 0x69, 0x74, 0x5f, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x5f, 0x65, 0x61, 0x63, 0x68, 0x5f, 0x6d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x6d, 0x69, 0x6c, 0x6c, 0x69, 0x73, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x0d, 0x52, 0x1b, 0x77, 0x61, 0x69, 0x74, 0x42, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x45, - 0x61, 0x63, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4d, 0x69, 0x6c, 0x6c, 0x69, 0x73, - 0x12, 0x3c, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x26, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x63, 0x6f, 0x6e, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x2a, 0x0a, 0x11, 0x72, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x6d, 0x73, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x44, + 0x65, 0x6c, 0x61, 0x79, 0x4d, 0x73, 0x12, 0x3c, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x72, + 0x70, 0x63, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, + 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, + 0x72, 0x72, 0x6f, 0x72, 0x12, 0x54, 0x0a, 0x11, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x5f, 0x74, 0x72, 0x61, 0x69, 0x6c, 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x27, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, - 0x31, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x54, - 0x0a, 0x11, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x74, 0x72, 0x61, 0x69, 0x6c, - 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, - 0x65, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, - 0x63, 0x65, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x48, 0x65, 0x61, 0x64, - 0x65, 0x72, 0x52, 0x10, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x54, 0x72, 0x61, 0x69, - 0x6c, 0x65, 0x72, 0x73, 0x22, 0x8b, 0x01, 0x0a, 0x13, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, - 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x5e, 0x0a, 0x13, - 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, - 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, - 0x65, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, - 0x63, 0x65, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x55, 0x6e, 0x61, 0x72, - 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x12, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, - 0x65, 0x78, 0x74, 0x72, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x65, 0x78, 0x74, - 0x72, 0x61, 0x22, 0xc3, 0x01, 0x0a, 0x11, 0x42, 0x69, 0x64, 0x69, 0x53, 0x74, 0x72, 0x65, 0x61, - 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x65, 0x0a, 0x13, 0x72, 0x65, 0x73, 0x70, + 0x31, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x10, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x54, 0x72, 0x61, 0x69, 0x6c, 0x65, 0x72, 0x73, 0x22, 0x79, 0x0a, 0x0c, 0x55, 0x6e, + 0x61, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x69, 0x0a, 0x13, 0x72, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, + 0x74, 0x72, 0x70, 0x63, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, + 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x55, 0x6e, 0x61, 0x72, 0x79, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x12, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x44, 0x65, 0x66, 0x69, 0x6e, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x5e, 0x0a, 0x0d, 0x55, 0x6e, 0x61, 0x72, 0x79, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4d, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, + 0x74, 0x72, 0x70, 0x63, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, + 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x6f, 0x72, + 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x07, 0x70, 0x61, + 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x81, 0x01, 0x0a, 0x13, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6a, 0x0a, + 0x13, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, + 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x63, 0x6f, 0x6e, + 0x6e, 0x65, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, + 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x53, 0x74, 0x72, + 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x44, 0x65, 0x66, 0x69, 0x6e, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x12, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x44, + 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x65, 0x0a, 0x14, 0x53, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x4d, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, + 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x61, 0x6c, + 0x70, 0x68, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, + 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, + 0x22, 0x96, 0x01, 0x0a, 0x13, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, + 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x69, 0x0a, 0x13, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x72, - 0x70, 0x63, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, - 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x53, 0x74, - 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x12, 0x72, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, - 0x31, 0x0a, 0x15, 0x77, 0x61, 0x69, 0x74, 0x5f, 0x66, 0x6f, 0x72, 0x5f, 0x65, 0x61, 0x63, 0x68, - 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, - 0x77, 0x61, 0x69, 0x74, 0x46, 0x6f, 0x72, 0x45, 0x61, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x78, 0x74, 0x72, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x05, 0x65, 0x78, 0x74, 0x72, 0x61, 0x22, 0xdf, 0x02, 0x0a, 0x12, 0x43, 0x6f, 0x6e, - 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, - 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, - 0x61, 0x74, 0x61, 0x12, 0x62, 0x0a, 0x0c, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, - 0x6e, 0x66, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, - 0x65, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, - 0x63, 0x65, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x66, - 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x2e, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0b, 0x72, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x1a, 0xd0, 0x01, 0x0a, 0x0b, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x50, 0x0a, 0x0f, 0x72, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x27, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x63, 0x6f, - 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, - 0x61, 0x31, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x0e, 0x72, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x2a, 0x0a, 0x0e, 0x74, 0x69, 0x6d, - 0x65, 0x6f, 0x75, 0x74, 0x5f, 0x6d, 0x69, 0x6c, 0x6c, 0x69, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0d, 0x48, 0x00, 0x52, 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x4d, 0x69, 0x6c, 0x6c, - 0x69, 0x73, 0x88, 0x01, 0x01, 0x12, 0x30, 0x0a, 0x08, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x73, 0x18, 0x03, 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, 0x08, 0x72, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x42, 0x11, 0x0a, 0x0f, 0x5f, 0x74, 0x69, 0x6d, 0x65, - 0x6f, 0x75, 0x74, 0x5f, 0x6d, 0x69, 0x6c, 0x6c, 0x69, 0x73, 0x22, 0x65, 0x0a, 0x05, 0x45, 0x72, - 0x72, 0x6f, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x05, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x18, 0x04, 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, 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, 0x22, 0x32, 0x0a, 0x06, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, - 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, - 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x32, 0xf6, 0x03, 0x0a, 0x12, 0x43, 0x6f, 0x6e, 0x66, 0x6f, 0x72, - 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x6b, 0x0a, 0x05, - 0x55, 0x6e, 0x61, 0x72, 0x79, 0x12, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x72, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, - 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x55, 0x6e, 0x61, 0x72, 0x79, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x72, 0x70, - 0x63, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, - 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, - 0x63, 0x65, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x7b, 0x0a, 0x0c, 0x53, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x34, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, - 0x65, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, - 0x63, 0x65, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x33, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x63, 0x6f, 0x6e, - 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, - 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x50, 0x61, 0x79, - 0x6c, 0x6f, 0x61, 0x64, 0x30, 0x01, 0x12, 0x7b, 0x0a, 0x0c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, - 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x34, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, - 0x72, 0x70, 0x63, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x2e, - 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, - 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e, 0x63, + 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x55, 0x6e, 0x61, 0x72, 0x79, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x12, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x78, 0x74, 0x72, 0x61, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x05, 0x65, 0x78, 0x74, 0x72, 0x61, 0x22, 0x65, 0x0a, 0x14, 0x43, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x4d, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, + 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x61, 0x6c, + 0x70, 0x68, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, + 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, + 0x22, 0xc3, 0x01, 0x0a, 0x11, 0x42, 0x69, 0x64, 0x69, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6a, 0x0a, 0x13, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x5f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x72, 0x70, 0x63, + 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x61, + 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x12, + 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x66, 0x75, 0x6c, 0x6c, 0x5f, 0x64, 0x75, 0x70, 0x6c, 0x65, + 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x66, 0x75, 0x6c, 0x6c, 0x44, 0x75, 0x70, + 0x6c, 0x65, 0x78, 0x12, 0x21, 0x0a, 0x0c, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x64, + 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x72, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x22, 0x63, 0x0a, 0x12, 0x42, 0x69, 0x64, 0x69, 0x53, 0x74, + 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4d, 0x0a, 0x07, + 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, + 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x6f, + 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, + 0x43, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x50, 0x61, 0x79, 0x6c, 0x6f, + 0x61, 0x64, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0xd3, 0x02, 0x0a, 0x12, + 0x43, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x50, 0x61, 0x79, 0x6c, 0x6f, + 0x61, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x62, 0x0a, 0x0c, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, - 0x64, 0x28, 0x01, 0x12, 0x79, 0x0a, 0x0a, 0x42, 0x69, 0x64, 0x69, 0x53, 0x74, 0x72, 0x65, 0x61, - 0x6d, 0x12, 0x32, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x63, + 0x64, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0b, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x1a, 0xc4, 0x01, 0x0a, 0x0b, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x50, 0x0a, 0x0f, 0x72, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x72, 0x70, 0x63, + 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x61, + 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x0e, 0x72, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x22, 0x0a, 0x0a, + 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, + 0x48, 0x00, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x4d, 0x73, 0x88, 0x01, 0x01, + 0x12, 0x30, 0x0a, 0x08, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x18, 0x03, 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, 0x08, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x73, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x5f, 0x6d, + 0x73, 0x22, 0x65, 0x0a, 0x05, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, + 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x18, + 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 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, 0x03, 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, 0x32, 0x0a, 0x06, 0x48, 0x65, 0x61, 0x64, + 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x32, 0xf5, 0x03, 0x0a, + 0x12, 0x43, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x12, 0x66, 0x0a, 0x05, 0x55, 0x6e, 0x61, 0x72, 0x79, 0x12, 0x2d, 0x2e, 0x63, + 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72, + 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x55, + 0x6e, 0x61, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x63, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, + 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x55, 0x6e, + 0x61, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7d, 0x0a, 0x0c, 0x53, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x34, 0x2e, 0x63, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, + 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x53, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x35, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, - 0x68, 0x61, 0x31, 0x2e, 0x42, 0x69, 0x64, 0x69, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x72, - 0x70, 0x63, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, - 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, - 0x6e, 0x63, 0x65, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x28, 0x01, 0x30, 0x01, 0x42, 0xb7, - 0x02, 0x0a, 0x23, 0x63, 0x6f, 0x6d, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x72, 0x70, - 0x63, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, - 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x42, 0x0c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, - 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x64, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x72, - 0x70, 0x63, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, - 0x63, 0x65, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x67, 0x65, 0x6e, 0x2f, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x2f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, - 0x72, 0x70, 0x63, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x2f, - 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x3b, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, - 0x61, 0x6e, 0x63, 0x65, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0xa2, 0x02, 0x03, 0x43, - 0x43, 0x58, 0xaa, 0x02, 0x1f, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, - 0x43, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x56, 0x31, 0x61, 0x6c, - 0x70, 0x68, 0x61, 0x31, 0xca, 0x02, 0x1f, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x72, 0x70, - 0x63, 0x5c, 0x43, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x5c, 0x56, 0x31, - 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0xe2, 0x02, 0x2b, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, - 0x72, 0x70, 0x63, 0x5c, 0x43, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x5c, - 0x56, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x21, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x72, 0x70, - 0x63, 0x3a, 0x3a, 0x43, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x3a, 0x3a, - 0x56, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x68, 0x61, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x7d, 0x0a, 0x0c, 0x43, 0x6c, + 0x69, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x34, 0x2e, 0x63, 0x6f, 0x6e, + 0x6e, 0x65, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, + 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x43, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x35, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x63, 0x6f, + 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, + 0x61, 0x31, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x12, 0x79, 0x0a, 0x0a, 0x42, 0x69, 0x64, + 0x69, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x32, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, + 0x74, 0x72, 0x70, 0x63, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, + 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x42, 0x69, 0x64, 0x69, 0x53, 0x74, + 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e, 0x63, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, + 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x42, 0x69, + 0x64, 0x69, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x28, 0x01, 0x30, 0x01, 0x42, 0xb7, 0x02, 0x0a, 0x23, 0x63, 0x6f, 0x6d, 0x2e, 0x63, 0x6f, 0x6e, + 0x6e, 0x65, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, + 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x42, 0x0c, 0x53, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x64, 0x63, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, + 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, + 0x6c, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x2f, 0x63, + 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72, + 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x3b, 0x63, + 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, + 0x61, 0x31, 0xa2, 0x02, 0x03, 0x43, 0x43, 0x58, 0xaa, 0x02, 0x1f, 0x43, 0x6f, 0x6e, 0x6e, 0x65, + 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, + 0x65, 0x2e, 0x56, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0xca, 0x02, 0x1f, 0x43, 0x6f, 0x6e, + 0x6e, 0x65, 0x63, 0x74, 0x72, 0x70, 0x63, 0x5c, 0x43, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, + 0x6e, 0x63, 0x65, 0x5c, 0x56, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0xe2, 0x02, 0x2b, 0x43, + 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x72, 0x70, 0x63, 0x5c, 0x43, 0x6f, 0x6e, 0x66, 0x6f, 0x72, + 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x5c, 0x56, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x5c, 0x47, + 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x21, 0x43, 0x6f, 0x6e, + 0x6e, 0x65, 0x63, 0x74, 0x72, 0x70, 0x63, 0x3a, 0x3a, 0x43, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, + 0x61, 0x6e, 0x63, 0x65, 0x3a, 0x3a, 0x56, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -747,44 +1090,56 @@ func file_connectrpc_conformance_v1alpha1_service_proto_rawDescGZIP() []byte { return file_connectrpc_conformance_v1alpha1_service_proto_rawDescData } -var file_connectrpc_conformance_v1alpha1_service_proto_msgTypes = make([]protoimpl.MessageInfo, 8) +var file_connectrpc_conformance_v1alpha1_service_proto_msgTypes = make([]protoimpl.MessageInfo, 14) var file_connectrpc_conformance_v1alpha1_service_proto_goTypes = []interface{}{ - (*UnaryRequest)(nil), // 0: connectrpc.conformance.v1alpha1.UnaryRequest - (*ServerStreamRequest)(nil), // 1: connectrpc.conformance.v1alpha1.ServerStreamRequest - (*ClientStreamRequest)(nil), // 2: connectrpc.conformance.v1alpha1.ClientStreamRequest - (*BidiStreamRequest)(nil), // 3: connectrpc.conformance.v1alpha1.BidiStreamRequest - (*ConformancePayload)(nil), // 4: connectrpc.conformance.v1alpha1.ConformancePayload - (*Error)(nil), // 5: connectrpc.conformance.v1alpha1.Error - (*Header)(nil), // 6: connectrpc.conformance.v1alpha1.Header - (*ConformancePayload_RequestInfo)(nil), // 7: connectrpc.conformance.v1alpha1.ConformancePayload.RequestInfo - (*anypb.Any)(nil), // 8: google.protobuf.Any + (*UnaryResponseDefinition)(nil), // 0: connectrpc.conformance.v1alpha1.UnaryResponseDefinition + (*StreamResponseDefinition)(nil), // 1: connectrpc.conformance.v1alpha1.StreamResponseDefinition + (*UnaryRequest)(nil), // 2: connectrpc.conformance.v1alpha1.UnaryRequest + (*UnaryResponse)(nil), // 3: connectrpc.conformance.v1alpha1.UnaryResponse + (*ServerStreamRequest)(nil), // 4: connectrpc.conformance.v1alpha1.ServerStreamRequest + (*ServerStreamResponse)(nil), // 5: connectrpc.conformance.v1alpha1.ServerStreamResponse + (*ClientStreamRequest)(nil), // 6: connectrpc.conformance.v1alpha1.ClientStreamRequest + (*ClientStreamResponse)(nil), // 7: connectrpc.conformance.v1alpha1.ClientStreamResponse + (*BidiStreamRequest)(nil), // 8: connectrpc.conformance.v1alpha1.BidiStreamRequest + (*BidiStreamResponse)(nil), // 9: connectrpc.conformance.v1alpha1.BidiStreamResponse + (*ConformancePayload)(nil), // 10: connectrpc.conformance.v1alpha1.ConformancePayload + (*Error)(nil), // 11: connectrpc.conformance.v1alpha1.Error + (*Header)(nil), // 12: connectrpc.conformance.v1alpha1.Header + (*ConformancePayload_RequestInfo)(nil), // 13: connectrpc.conformance.v1alpha1.ConformancePayload.RequestInfo + (*anypb.Any)(nil), // 14: google.protobuf.Any } var file_connectrpc_conformance_v1alpha1_service_proto_depIdxs = []int32{ - 6, // 0: connectrpc.conformance.v1alpha1.UnaryRequest.response_headers:type_name -> connectrpc.conformance.v1alpha1.Header - 5, // 1: connectrpc.conformance.v1alpha1.UnaryRequest.error:type_name -> connectrpc.conformance.v1alpha1.Error - 6, // 2: connectrpc.conformance.v1alpha1.UnaryRequest.response_trailers:type_name -> connectrpc.conformance.v1alpha1.Header - 6, // 3: connectrpc.conformance.v1alpha1.ServerStreamRequest.response_headers:type_name -> connectrpc.conformance.v1alpha1.Header - 5, // 4: connectrpc.conformance.v1alpha1.ServerStreamRequest.error:type_name -> connectrpc.conformance.v1alpha1.Error - 6, // 5: connectrpc.conformance.v1alpha1.ServerStreamRequest.response_trailers:type_name -> connectrpc.conformance.v1alpha1.Header - 0, // 6: connectrpc.conformance.v1alpha1.ClientStreamRequest.response_definition:type_name -> connectrpc.conformance.v1alpha1.UnaryRequest - 1, // 7: connectrpc.conformance.v1alpha1.BidiStreamRequest.response_definition:type_name -> connectrpc.conformance.v1alpha1.ServerStreamRequest - 7, // 8: connectrpc.conformance.v1alpha1.ConformancePayload.request_info:type_name -> connectrpc.conformance.v1alpha1.ConformancePayload.RequestInfo - 8, // 9: connectrpc.conformance.v1alpha1.Error.details:type_name -> google.protobuf.Any - 6, // 10: connectrpc.conformance.v1alpha1.ConformancePayload.RequestInfo.request_headers:type_name -> connectrpc.conformance.v1alpha1.Header - 8, // 11: connectrpc.conformance.v1alpha1.ConformancePayload.RequestInfo.requests:type_name -> google.protobuf.Any - 0, // 12: connectrpc.conformance.v1alpha1.ConformanceService.Unary:input_type -> connectrpc.conformance.v1alpha1.UnaryRequest - 1, // 13: connectrpc.conformance.v1alpha1.ConformanceService.ServerStream:input_type -> connectrpc.conformance.v1alpha1.ServerStreamRequest - 2, // 14: connectrpc.conformance.v1alpha1.ConformanceService.ClientStream:input_type -> connectrpc.conformance.v1alpha1.ClientStreamRequest - 3, // 15: connectrpc.conformance.v1alpha1.ConformanceService.BidiStream:input_type -> connectrpc.conformance.v1alpha1.BidiStreamRequest - 4, // 16: connectrpc.conformance.v1alpha1.ConformanceService.Unary:output_type -> connectrpc.conformance.v1alpha1.ConformancePayload - 4, // 17: connectrpc.conformance.v1alpha1.ConformanceService.ServerStream:output_type -> connectrpc.conformance.v1alpha1.ConformancePayload - 4, // 18: connectrpc.conformance.v1alpha1.ConformanceService.ClientStream:output_type -> connectrpc.conformance.v1alpha1.ConformancePayload - 4, // 19: connectrpc.conformance.v1alpha1.ConformanceService.BidiStream:output_type -> connectrpc.conformance.v1alpha1.ConformancePayload - 16, // [16:20] is the sub-list for method output_type - 12, // [12:16] is the sub-list for method input_type - 12, // [12:12] is the sub-list for extension type_name - 12, // [12:12] is the sub-list for extension extendee - 0, // [0:12] is the sub-list for field type_name + 12, // 0: connectrpc.conformance.v1alpha1.UnaryResponseDefinition.response_headers:type_name -> connectrpc.conformance.v1alpha1.Header + 11, // 1: connectrpc.conformance.v1alpha1.UnaryResponseDefinition.error:type_name -> connectrpc.conformance.v1alpha1.Error + 12, // 2: connectrpc.conformance.v1alpha1.UnaryResponseDefinition.response_trailers:type_name -> connectrpc.conformance.v1alpha1.Header + 12, // 3: connectrpc.conformance.v1alpha1.StreamResponseDefinition.response_headers:type_name -> connectrpc.conformance.v1alpha1.Header + 11, // 4: connectrpc.conformance.v1alpha1.StreamResponseDefinition.error:type_name -> connectrpc.conformance.v1alpha1.Error + 12, // 5: connectrpc.conformance.v1alpha1.StreamResponseDefinition.response_trailers:type_name -> connectrpc.conformance.v1alpha1.Header + 0, // 6: connectrpc.conformance.v1alpha1.UnaryRequest.response_definition:type_name -> connectrpc.conformance.v1alpha1.UnaryResponseDefinition + 10, // 7: connectrpc.conformance.v1alpha1.UnaryResponse.payload:type_name -> connectrpc.conformance.v1alpha1.ConformancePayload + 1, // 8: connectrpc.conformance.v1alpha1.ServerStreamRequest.response_definition:type_name -> connectrpc.conformance.v1alpha1.StreamResponseDefinition + 10, // 9: connectrpc.conformance.v1alpha1.ServerStreamResponse.payload:type_name -> connectrpc.conformance.v1alpha1.ConformancePayload + 0, // 10: connectrpc.conformance.v1alpha1.ClientStreamRequest.response_definition:type_name -> connectrpc.conformance.v1alpha1.UnaryResponseDefinition + 10, // 11: connectrpc.conformance.v1alpha1.ClientStreamResponse.payload:type_name -> connectrpc.conformance.v1alpha1.ConformancePayload + 1, // 12: connectrpc.conformance.v1alpha1.BidiStreamRequest.response_definition:type_name -> connectrpc.conformance.v1alpha1.StreamResponseDefinition + 10, // 13: connectrpc.conformance.v1alpha1.BidiStreamResponse.payload:type_name -> connectrpc.conformance.v1alpha1.ConformancePayload + 13, // 14: connectrpc.conformance.v1alpha1.ConformancePayload.request_info:type_name -> connectrpc.conformance.v1alpha1.ConformancePayload.RequestInfo + 14, // 15: connectrpc.conformance.v1alpha1.Error.details:type_name -> google.protobuf.Any + 12, // 16: connectrpc.conformance.v1alpha1.ConformancePayload.RequestInfo.request_headers:type_name -> connectrpc.conformance.v1alpha1.Header + 14, // 17: connectrpc.conformance.v1alpha1.ConformancePayload.RequestInfo.requests:type_name -> google.protobuf.Any + 2, // 18: connectrpc.conformance.v1alpha1.ConformanceService.Unary:input_type -> connectrpc.conformance.v1alpha1.UnaryRequest + 4, // 19: connectrpc.conformance.v1alpha1.ConformanceService.ServerStream:input_type -> connectrpc.conformance.v1alpha1.ServerStreamRequest + 6, // 20: connectrpc.conformance.v1alpha1.ConformanceService.ClientStream:input_type -> connectrpc.conformance.v1alpha1.ClientStreamRequest + 8, // 21: connectrpc.conformance.v1alpha1.ConformanceService.BidiStream:input_type -> connectrpc.conformance.v1alpha1.BidiStreamRequest + 3, // 22: connectrpc.conformance.v1alpha1.ConformanceService.Unary:output_type -> connectrpc.conformance.v1alpha1.UnaryResponse + 5, // 23: connectrpc.conformance.v1alpha1.ConformanceService.ServerStream:output_type -> connectrpc.conformance.v1alpha1.ServerStreamResponse + 7, // 24: connectrpc.conformance.v1alpha1.ConformanceService.ClientStream:output_type -> connectrpc.conformance.v1alpha1.ClientStreamResponse + 9, // 25: connectrpc.conformance.v1alpha1.ConformanceService.BidiStream:output_type -> connectrpc.conformance.v1alpha1.BidiStreamResponse + 22, // [22:26] is the sub-list for method output_type + 18, // [18:22] is the sub-list for method input_type + 18, // [18:18] is the sub-list for extension type_name + 18, // [18:18] is the sub-list for extension extendee + 0, // [0:18] is the sub-list for field type_name } func init() { file_connectrpc_conformance_v1alpha1_service_proto_init() } @@ -794,7 +1149,7 @@ func file_connectrpc_conformance_v1alpha1_service_proto_init() { } if !protoimpl.UnsafeEnabled { file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UnaryRequest); i { + switch v := v.(*UnaryResponseDefinition); i { case 0: return &v.state case 1: @@ -806,7 +1161,7 @@ func file_connectrpc_conformance_v1alpha1_service_proto_init() { } } file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ServerStreamRequest); i { + switch v := v.(*StreamResponseDefinition); i { case 0: return &v.state case 1: @@ -818,7 +1173,7 @@ func file_connectrpc_conformance_v1alpha1_service_proto_init() { } } file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ClientStreamRequest); i { + switch v := v.(*UnaryRequest); i { case 0: return &v.state case 1: @@ -830,7 +1185,7 @@ func file_connectrpc_conformance_v1alpha1_service_proto_init() { } } file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BidiStreamRequest); i { + switch v := v.(*UnaryResponse); i { case 0: return &v.state case 1: @@ -842,7 +1197,7 @@ func file_connectrpc_conformance_v1alpha1_service_proto_init() { } } file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ConformancePayload); i { + switch v := v.(*ServerStreamRequest); i { case 0: return &v.state case 1: @@ -854,7 +1209,7 @@ func file_connectrpc_conformance_v1alpha1_service_proto_init() { } } file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Error); i { + switch v := v.(*ServerStreamResponse); i { case 0: return &v.state case 1: @@ -866,7 +1221,7 @@ func file_connectrpc_conformance_v1alpha1_service_proto_init() { } } file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Header); i { + switch v := v.(*ClientStreamRequest); i { case 0: return &v.state case 1: @@ -878,6 +1233,78 @@ func file_connectrpc_conformance_v1alpha1_service_proto_init() { } } file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ClientStreamResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BidiStreamRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BidiStreamResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ConformancePayload); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[11].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_connectrpc_conformance_v1alpha1_service_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Header); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ConformancePayload_RequestInfo); i { case 0: return &v.state @@ -891,17 +1318,17 @@ func file_connectrpc_conformance_v1alpha1_service_proto_init() { } } file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[0].OneofWrappers = []interface{}{ - (*UnaryRequest_ResponseData)(nil), - (*UnaryRequest_Error)(nil), + (*UnaryResponseDefinition_ResponseData)(nil), + (*UnaryResponseDefinition_Error)(nil), } - file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[7].OneofWrappers = []interface{}{} + file_connectrpc_conformance_v1alpha1_service_proto_msgTypes[13].OneofWrappers = []interface{}{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_connectrpc_conformance_v1alpha1_service_proto_rawDesc, NumEnums: 0, - NumMessages: 8, + NumMessages: 14, NumExtensions: 0, NumServices: 1, }, diff --git a/internal/server/server.go b/internal/server/server.go deleted file mode 100644 index 13e5c73b..00000000 --- a/internal/server/server.go +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright 2022-2023 The Connect Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package server - -import ( - "context" - "errors" - "fmt" - - "connectrpc.com/conformance/internal/gen/proto/connect/connectrpc/conformance/v1alpha1/conformancev1alpha1connect" - v1alpha1 "connectrpc.com/conformance/internal/gen/proto/go/connectrpc/conformance/v1alpha1" - connect "connectrpc.com/connect" -) - -// NewConformanceServiceHandler returns a new ConformanceServiceHandler. -func NewConformanceServiceHandler() conformancev1alpha1connect.ConformanceServiceHandler { - return &conformanceServer{} -} - -type conformanceServer struct{} - -func (s *conformanceServer) Unary(ctx context.Context, req *connect.Request[v1alpha1.UnaryRequest]) (*connect.Response[v1alpha1.ConformancePayload], error) { - res := connect.NewResponse(&v1alpha1.ConformancePayload{}) - - // Set all requested response headers on the response - for _, header := range req.Msg.ResponseHeaders { - for _, val := range header.Value { - res.Header().Add(header.Name, val) - } - } - - // Set all requested response trailers on the response - for _, trailer := range req.Msg.ResponseTrailers { - for _, val := range trailer.Value { - res.Trailer().Add(trailer.Name, val) - } - } - - // Set all observed request headers in the response payload - headerInfo := []*v1alpha1.Header{} - for key, value := range req.Header() { - hdr := &v1alpha1.Header{ - Name: key, - Value: value, - } - headerInfo = append(headerInfo, hdr) - } - res.Msg.RequestInfo = &v1alpha1.ConformancePayload_RequestInfo{ - RequestHeaders: headerInfo, - } - - switch rt := req.Msg.Response.(type) { - case *v1alpha1.UnaryRequest_ResponseData: - res.Msg.Data = rt.ResponseData - case *v1alpha1.UnaryRequest_Error: - connectErr := connect.NewError(connect.Code(rt.Error.Code), errors.New(rt.Error.Message)) - for _, reqDetail := range rt.Error.Details { - connectDetail, err := connect.NewErrorDetail(reqDetail) - if err != nil { - return nil, err - } - connectErr.AddDetail(connectDetail) - } - - return nil, connectErr - case nil: - // TODO - Which error should we raise here? Invalid Argument? - return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("A desired response data or response error is required")) - default: - return nil, fmt.Errorf("UnaryRequest.Response has an unexpected type %T", rt) - } - - return res, nil -} - -func (s *conformanceServer) ClientStream(context.Context, *connect.ClientStream[v1alpha1.ClientStreamRequest]) (*connect.Response[v1alpha1.ConformancePayload], error) { - return nil, connect.NewError( - connect.CodeUnimplemented, - errors.New("ClientStream is not yet implemented"), - ) -} - -func (s *conformanceServer) ServerStream(context.Context, *connect.Request[v1alpha1.ServerStreamRequest], *connect.ServerStream[v1alpha1.ConformancePayload]) error { - return connect.NewError( - connect.CodeUnimplemented, - errors.New("ServerStream is not yet implemented"), - ) -} - -func (s *conformanceServer) BidiStream(context.Context, *connect.BidiStream[v1alpha1.BidiStreamRequest, v1alpha1.ConformancePayload]) error { - return connect.NewError( - connect.CodeUnimplemented, - errors.New("BidiStream is not yet implemented"), - ) -} From 3a7590160e57bad96f5c70aaa14507e0be451ab3 Mon Sep 17 00:00:00 2001 From: Steve Ayers Date: Fri, 13 Oct 2023 13:44:34 -0400 Subject: [PATCH 02/13] Docs --- internal/app/server/impl.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/app/server/impl.go b/internal/app/server/impl.go index 95364cd3..7ca6a3bb 100644 --- a/internal/app/server/impl.go +++ b/internal/app/server/impl.go @@ -35,6 +35,7 @@ type ConformanceRequest interface { GetResponseTrailers() []*v1alpha1.Header } +// Stream represents a stream with the ability to set headers and trailers and send a message T type Stream[T any] interface { ResponseHeader() http.Header ResponseTrailer() http.Header From 829dcd65481b2756f9bff5876bed8722cfef99a9 Mon Sep 17 00:00:00 2001 From: Steve Ayers Date: Fri, 13 Oct 2023 15:56:24 -0400 Subject: [PATCH 03/13] Generate --- internal/app/server/impl.go | 2 +- internal/app/server/server.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/app/server/impl.go b/internal/app/server/impl.go index 7ca6a3bb..9fdec36b 100644 --- a/internal/app/server/impl.go +++ b/internal/app/server/impl.go @@ -1,4 +1,4 @@ -// Copyright 2022-2023 The Connect Authors +// Copyright 2023 The Connect Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/internal/app/server/server.go b/internal/app/server/server.go index 368727f8..e90b039e 100644 --- a/internal/app/server/server.go +++ b/internal/app/server/server.go @@ -1,4 +1,4 @@ -// Copyright 2022-2023 The Connect Authors +// Copyright 2023 The Connect Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. From 3576e355346bdfbc42ddbf385c300e332a673f59 Mon Sep 17 00:00:00 2001 From: Steve Ayers Date: Fri, 13 Oct 2023 15:58:06 -0400 Subject: [PATCH 04/13] Fix header --- cmd/server/main.go | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/cmd/server/main.go b/cmd/server/main.go index 94d2425c..295731c5 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -12,20 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Copyright 2022-2023 The Connect Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - package main import ( From 23a633344159f9ee0343e54bee06777a676cd4aa Mon Sep 17 00:00:00 2001 From: Steve Ayers Date: Sun, 15 Oct 2023 21:40:20 -0400 Subject: [PATCH 05/13] Fix docs --- internal/app/server/impl.go | 39 ++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/internal/app/server/impl.go b/internal/app/server/impl.go index 9fdec36b..bc287baa 100644 --- a/internal/app/server/impl.go +++ b/internal/app/server/impl.go @@ -144,7 +144,12 @@ func (s *conformanceServer) ServerStream( Payload: payload, } - if err := sendOnStream[v1alpha1.ServerStreamResponse](ctx, stream, responseDefinition, resp); err != nil { + if err := sendOnStream[v1alpha1.ServerStreamResponse]( + ctx, + stream, + resp, + responseDefinition.ResponseDelayMs, + ); err != nil { return err } @@ -205,7 +210,12 @@ func (s *conformanceServer) BidiStream( resp := &v1alpha1.BidiStreamResponse{ Payload: payload, } - err := sendOnStream[v1alpha1.BidiStreamResponse](ctx, stream, responseDefinition, resp) + err := sendOnStream[v1alpha1.BidiStreamResponse]( + ctx, + stream, + resp, + responseDefinition.ResponseDelayMs, + ) if err != nil { return err } @@ -214,11 +224,9 @@ func (s *conformanceServer) BidiStream( } } - // If this is a half duplex call, then send all the responses now. - // If this is a full deplex call, then flush any remaining responses. It is possible - // that the initial request specifying the desired response definitions contained more - // definitions than requests sent on the stream. In that case, if we interleave for - // full duplex, we should have some responses left over to send. + // If we still have responses left to send, flush them now. This accommodates + // both scenarios of half duplex (we haven't sent any responses yet) or full duplex + // where the requested responses are greater than the total requests. if respNum < len(responseDefinition.ResponseData) { for i := respNum; i < len(responseDefinition.ResponseData); i++ { payload := initPayload(stream.RequestHeader(), reqs) @@ -226,7 +234,12 @@ func (s *conformanceServer) BidiStream( resp := &v1alpha1.BidiStreamResponse{ Payload: payload, } - err := sendOnStream[v1alpha1.BidiStreamResponse](ctx, stream, responseDefinition, resp) + err := sendOnStream[v1alpha1.BidiStreamResponse]( + ctx, + stream, + resp, + responseDefinition.ResponseDelayMs, + ) if err != nil { return err } @@ -245,17 +258,17 @@ func NewConformanceServiceHandler() conformancev1alpha1connect.ConformanceServic return &conformanceServer{} } -// Sends a response T on the given stream, setting response headers and trailers -// according to the provided response definition. +// Sends a response T on the given stream. If delayMs is > 0, the function +// will wait that many milliseconds before sending the message. func sendOnStream[T any]( ctx context.Context, stream Stream[T], - def *v1alpha1.StreamResponseDefinition, resp *T, + delayMs uint32, ) error { var ticker *time.Ticker - if def.ResponseDelayMs > 0 { - ticker = time.NewTicker(time.Duration(def.ResponseDelayMs) * time.Millisecond) + if delayMs > 0 { + ticker = time.NewTicker(time.Duration(delayMs) * time.Millisecond) defer ticker.Stop() } if ticker != nil { From f63a43476e2c9ec0a473ba372b9af2ab9e0cb393 Mon Sep 17 00:00:00 2001 From: Steve Ayers Date: Tue, 17 Oct 2023 10:47:19 -0400 Subject: [PATCH 06/13] Update internal/app/server/impl.go Co-authored-by: Joshua Humphries <2035234+jhump@users.noreply.github.com> --- internal/app/server/impl.go | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/internal/app/server/impl.go b/internal/app/server/impl.go index bc287baa..bec3ea4b 100644 --- a/internal/app/server/impl.go +++ b/internal/app/server/impl.go @@ -313,9 +313,7 @@ func parseUnaryResponseDefinition( // Initializes a conformance payload func initPayload(headers http.Header, reqs []*anypb.Any) *v1alpha1.ConformancePayload { - payload := &v1alpha1.ConformancePayload{} - - headerInfo := []*v1alpha1.Header{} + headerInfo := make([]*v1alpha1.Header{}, 0, len(headers)) for key, value := range headers { hdr := &v1alpha1.Header{ Name: key, @@ -325,11 +323,12 @@ func initPayload(headers http.Header, reqs []*anypb.Any) *v1alpha1.ConformancePa } // Set all observed request headers and requests in the response payload - payload.RequestInfo = &v1alpha1.ConformancePayload_RequestInfo{ - RequestHeaders: headerInfo, - Requests: reqs, + return &v1alpha1.ConformancePayload{ + RequestInfo: &v1alpha1.ConformancePayload_RequestInfo{ + RequestHeaders: headerInfo, + Requests: reqs, + } } - return payload } // Sets all response headers and trailers onto the given response From 6078d78e6e62b4dc443671f90306b3972e0a9daa Mon Sep 17 00:00:00 2001 From: Steve Ayers Date: Tue, 17 Oct 2023 10:48:17 -0400 Subject: [PATCH 07/13] Update internal/app/server/impl.go Co-authored-by: Joshua Humphries <2035234+jhump@users.noreply.github.com> --- internal/app/server/impl.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/internal/app/server/impl.go b/internal/app/server/impl.go index bec3ea4b..af741a0f 100644 --- a/internal/app/server/impl.go +++ b/internal/app/server/impl.go @@ -331,8 +331,11 @@ func initPayload(headers http.Header, reqs []*anypb.Any) *v1alpha1.ConformancePa } } -// Sets all response headers and trailers onto the given response -func setResponseHeadersAndTrailers[T any](def ConformanceRequest, resp *connect.Response[T]) { +// Adds all header values in src to dest. +func addHeaders( + src []*v1alpha1.Header, + dest http.Header, +) { // Set all requested response headers on the response for _, header := range def.GetResponseHeaders() { for _, val := range header.Value { From cce79626b2f77d3d591815360f643597f2cfb247 Mon Sep 17 00:00:00 2001 From: Steve Ayers Date: Tue, 17 Oct 2023 10:49:03 -0400 Subject: [PATCH 08/13] Feedback --- internal/app/server/impl.go | 77 ++++++----------------------------- internal/app/server/server.go | 9 ++-- 2 files changed, 18 insertions(+), 68 deletions(-) diff --git a/internal/app/server/impl.go b/internal/app/server/impl.go index af741a0f..75268039 100644 --- a/internal/app/server/impl.go +++ b/internal/app/server/impl.go @@ -22,7 +22,6 @@ import ( "net/http" "time" - "connectrpc.com/conformance/internal/gen/proto/connect/connectrpc/conformance/v1alpha1/conformancev1alpha1connect" v1alpha1 "connectrpc.com/conformance/internal/gen/proto/go/connectrpc/conformance/v1alpha1" connect "connectrpc.com/connect" proto "google.golang.org/protobuf/proto" @@ -35,13 +34,6 @@ type ConformanceRequest interface { GetResponseTrailers() []*v1alpha1.Header } -// Stream represents a stream with the ability to set headers and trailers and send a message T -type Stream[T any] interface { - ResponseHeader() http.Header - ResponseTrailer() http.Header - Send(*T) error -} - type conformanceServer struct{} func (s *conformanceServer) Unary( @@ -144,15 +136,11 @@ func (s *conformanceServer) ServerStream( Payload: payload, } - if err := sendOnStream[v1alpha1.ServerStreamResponse]( - ctx, - stream, - resp, - responseDefinition.ResponseDelayMs, - ); err != nil { - return err - } + time.Sleep((time.Duration(responseDefinition.ResponseDelayMs) * time.Millisecond)) + if err := stream.Send(resp); err != nil { + return connect.NewError(connect.CodeInternal, fmt.Errorf("error sending on stream: %w", err)) + } } if responseDefinition.Error != nil { return createError(responseDefinition.Error) @@ -210,14 +198,10 @@ func (s *conformanceServer) BidiStream( resp := &v1alpha1.BidiStreamResponse{ Payload: payload, } - err := sendOnStream[v1alpha1.BidiStreamResponse]( - ctx, - stream, - resp, - responseDefinition.ResponseDelayMs, - ) - if err != nil { - return err + time.Sleep((time.Duration(responseDefinition.ResponseDelayMs) * time.Millisecond)) + + if err := stream.Send(resp); err != nil { + return connect.NewError(connect.CodeInternal, fmt.Errorf("error sending on stream: %w", err)) } respNum++ reqs = nil @@ -234,16 +218,11 @@ func (s *conformanceServer) BidiStream( resp := &v1alpha1.BidiStreamResponse{ Payload: payload, } - err := sendOnStream[v1alpha1.BidiStreamResponse]( - ctx, - stream, - resp, - responseDefinition.ResponseDelayMs, - ) - if err != nil { - return err - } + time.Sleep((time.Duration(responseDefinition.ResponseDelayMs) * time.Millisecond)) + if err := stream.Send(resp); err != nil { + return connect.NewError(connect.CodeInternal, fmt.Errorf("error sending on stream: %w", err)) + } } } @@ -253,38 +232,6 @@ func (s *conformanceServer) BidiStream( return nil } -// NewConformanceServiceHandler returns a new ConformanceServiceHandler. -func NewConformanceServiceHandler() conformancev1alpha1connect.ConformanceServiceHandler { - return &conformanceServer{} -} - -// Sends a response T on the given stream. If delayMs is > 0, the function -// will wait that many milliseconds before sending the message. -func sendOnStream[T any]( - ctx context.Context, - stream Stream[T], - resp *T, - delayMs uint32, -) error { - var ticker *time.Ticker - if delayMs > 0 { - ticker = time.NewTicker(time.Duration(delayMs) * time.Millisecond) - defer ticker.Stop() - } - if ticker != nil { - select { - case <-ctx.Done(): - return ctx.Err() - case <-ticker.C: - } - } - - if err := stream.Send(resp); err != nil { - return fmt.Errorf("error sending on stream: %w", err) - } - return nil -} - // Parses the given unary response definition and returns either // a built payload or a connect error based on the definition. func parseUnaryResponseDefinition( diff --git a/internal/app/server/server.go b/internal/app/server/server.go index e90b039e..575b4f75 100644 --- a/internal/app/server/server.go +++ b/internal/app/server/server.go @@ -37,7 +37,7 @@ func Run(ctx context.Context, args []string, in io.ReadCloser, out, err io.Write mux := http.NewServeMux() mux.Handle(conformancev1alpha1connect.NewConformanceServiceHandler( - NewConformanceServiceHandler(), + &conformanceServer{}, )) corsHandler := cors.New(cors.Options{ AllowedMethods: []string{ @@ -75,6 +75,9 @@ func Run(ctx context.Context, args []string, in io.ReadCloser, out, err io.Write h2Server := newH2Server(h2Port, mux) done := make(chan os.Signal, 1) errs := make(chan error, 2) + // TODO - This graceful shutdown sophistication may not be needed. + // The test scaffolding won't send the signal until after all requests are complete + // (or until it decides to abort, in which it's okay to have non-graceful termination of requests in progress) signal.Notify(done, os.Interrupt, syscall.SIGINT, syscall.SIGTERM) go func() { err := h1Server.ListenAndServe() @@ -111,7 +114,7 @@ func Run(ctx context.Context, args []string, in io.ReadCloser, out, err io.Write func newH1Server(h1Port string, handler http.Handler) *http.Server { h1Server := &http.Server{ - Addr: ":" + h1Port, + Addr: "127.0.0.1:" + h1Port, Handler: handler, } return h1Server @@ -119,7 +122,7 @@ func newH1Server(h1Port string, handler http.Handler) *http.Server { func newH2Server(h2Port string, handler http.Handler) *http.Server { h2Server := &http.Server{ - Addr: ":" + h2Port, + Addr: "127.0.0.1:" + h2Port, } h2Server.Handler = h2c.NewHandler(handler, &http2.Server{}) return h2Server From ee5dc64fe7cf0314f816916392cb58db5f7762b3 Mon Sep 17 00:00:00 2001 From: Steve Ayers Date: Tue, 17 Oct 2023 11:18:24 -0400 Subject: [PATCH 09/13] Feedback --- internal/app/server/impl.go | 94 ++++++++++++++++++++----------------- 1 file changed, 50 insertions(+), 44 deletions(-) diff --git a/internal/app/server/impl.go b/internal/app/server/impl.go index 75268039..1567bbc4 100644 --- a/internal/app/server/impl.go +++ b/internal/app/server/impl.go @@ -44,18 +44,23 @@ func (s *conformanceServer) Unary( if err != nil { return nil, err } - payload, err := parseUnaryResponseDefinition(req.Msg.ResponseDefinition, req.Header(), []*anypb.Any{msgAsAny}) - if err != nil { - return nil, err + payload, connectErr := parseUnaryResponseDefinition( + req.Msg.ResponseDefinition, + req.Header(), + []*anypb.Any{msgAsAny}, + ) + if connectErr != nil { + addHeaders(req.Msg.ResponseDefinition.ResponseHeaders, connectErr.Meta()) + addHeaders(req.Msg.ResponseDefinition.ResponseTrailers, connectErr.Meta()) + return nil, connectErr } resp := connect.NewResponse(&v1alpha1.UnaryResponse{ Payload: payload, }) - if req.Msg.ResponseDefinition != nil { - setResponseHeadersAndTrailers(req.Msg.ResponseDefinition, resp) - } + addHeaders(req.Msg.ResponseDefinition.ResponseHeaders, resp.Header()) + addHeaders(req.Msg.ResponseDefinition.ResponseTrailers, resp.Trailer()) return resp, nil } @@ -94,9 +99,8 @@ func (s *conformanceServer) ClientStream( Payload: payload, }) - if responseDefinition != nil { - setResponseHeadersAndTrailers(responseDefinition, resp) - } + addHeaders(responseDefinition.ResponseHeaders, resp.Header()) + addHeaders(responseDefinition.ResponseTrailers, resp.Trailer()) return resp, err } @@ -127,7 +131,10 @@ func (s *conformanceServer) ServerStream( if err != nil { return err } - payload := initPayload(req.Header(), []*anypb.Any{msgAsAny}) + requestInfo := createRequestInfo(req.Header(), []*anypb.Any{msgAsAny}) + payload := &v1alpha1.ConformancePayload{ + RequestInfo: requestInfo, + } for _, data := range responseDefinition.ResponseData { payload.Data = data @@ -141,6 +148,8 @@ func (s *conformanceServer) ServerStream( if err := stream.Send(resp); err != nil { return connect.NewError(connect.CodeInternal, fmt.Errorf("error sending on stream: %w", err)) } + // Only echo back the request info in the first response + payload.RequestInfo = nil } if responseDefinition.Error != nil { return createError(responseDefinition.Error) @@ -193,10 +202,12 @@ func (s *conformanceServer) BidiStream( errors.New("received more requests than desired responses on a full duplex stream"), ) } - payload := initPayload(stream.RequestHeader(), reqs) - payload.Data = responseDefinition.ResponseData[respNum] + requestInfo := createRequestInfo(stream.RequestHeader(), reqs) resp := &v1alpha1.BidiStreamResponse{ - Payload: payload, + Payload: &v1alpha1.ConformancePayload{ + RequestInfo: requestInfo, + Data: responseDefinition.ResponseData[respNum], + }, } time.Sleep((time.Duration(responseDefinition.ResponseDelayMs) * time.Millisecond)) @@ -211,18 +222,18 @@ func (s *conformanceServer) BidiStream( // If we still have responses left to send, flush them now. This accommodates // both scenarios of half duplex (we haven't sent any responses yet) or full duplex // where the requested responses are greater than the total requests. - if respNum < len(responseDefinition.ResponseData) { - for i := respNum; i < len(responseDefinition.ResponseData); i++ { - payload := initPayload(stream.RequestHeader(), reqs) - payload.Data = responseDefinition.ResponseData[i] - resp := &v1alpha1.BidiStreamResponse{ - Payload: payload, - } - time.Sleep((time.Duration(responseDefinition.ResponseDelayMs) * time.Millisecond)) + for ; respNum < len(responseDefinition.ResponseData); respNum++ { + requestInfo := createRequestInfo(stream.RequestHeader(), reqs) + resp := &v1alpha1.BidiStreamResponse{ + Payload: &v1alpha1.ConformancePayload{ + RequestInfo: requestInfo, + Data: responseDefinition.ResponseData[respNum], + }, + } + time.Sleep((time.Duration(responseDefinition.ResponseDelayMs) * time.Millisecond)) - if err := stream.Send(resp); err != nil { - return connect.NewError(connect.CodeInternal, fmt.Errorf("error sending on stream: %w", err)) - } + if err := stream.Send(resp); err != nil { + return connect.NewError(connect.CodeInternal, fmt.Errorf("error sending on stream: %w", err)) } } @@ -238,13 +249,16 @@ func parseUnaryResponseDefinition( def *v1alpha1.UnaryResponseDefinition, headers http.Header, reqs []*anypb.Any, -) (*v1alpha1.ConformancePayload, error) { +) (*v1alpha1.ConformancePayload, *connect.Error) { if def != nil { switch rt := def.Response.(type) { case *v1alpha1.UnaryResponseDefinition_Error: return nil, createError(rt.Error) case *v1alpha1.UnaryResponseDefinition_ResponseData, nil: - payload := initPayload(headers, reqs) + requestInfo := createRequestInfo(headers, reqs) + payload := &v1alpha1.ConformancePayload{ + RequestInfo: requestInfo, + } // If response data was provided, set that in the payload response if rt, ok := rt.(*v1alpha1.UnaryResponseDefinition_ResponseData); ok { @@ -258,9 +272,9 @@ func parseUnaryResponseDefinition( return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("no response definition provided")) } -// Initializes a conformance payload -func initPayload(headers http.Header, reqs []*anypb.Any) *v1alpha1.ConformancePayload { - headerInfo := make([]*v1alpha1.Header{}, 0, len(headers)) +// Creates request info for a conformance payload +func createRequestInfo(headers http.Header, reqs []*anypb.Any) *v1alpha1.ConformancePayload_RequestInfo { + headerInfo := make([]*v1alpha1.Header, 0, len(headers)) for key, value := range headers { hdr := &v1alpha1.Header{ Name: key, @@ -270,29 +284,21 @@ func initPayload(headers http.Header, reqs []*anypb.Any) *v1alpha1.ConformancePa } // Set all observed request headers and requests in the response payload - return &v1alpha1.ConformancePayload{ - RequestInfo: &v1alpha1.ConformancePayload_RequestInfo{ - RequestHeaders: headerInfo, - Requests: reqs, - } + return &v1alpha1.ConformancePayload_RequestInfo{ + RequestHeaders: headerInfo, + Requests: reqs, } } // Adds all header values in src to dest. func addHeaders( - src []*v1alpha1.Header, - dest http.Header, + src []*v1alpha1.Header, + dest http.Header, ) { // Set all requested response headers on the response - for _, header := range def.GetResponseHeaders() { + for _, header := range src { for _, val := range header.Value { - resp.Header().Add(header.Name, val) - } - } - // Set all requested response trailers on the response - for _, trailer := range def.GetResponseTrailers() { - for _, val := range trailer.Value { - resp.Trailer().Add(trailer.Name, val) + dest.Add(header.Name, val) } } } From 643f76068f6d273db7845d6dc59dfca3c2717fcf Mon Sep 17 00:00:00 2001 From: Steve Ayers Date: Tue, 17 Oct 2023 12:01:15 -0400 Subject: [PATCH 10/13] Feedback --- cmd/server/main.go | 31 ++++++++++++++-------------- internal/app/server/server.go | 39 ++++++++++++----------------------- 2 files changed, 29 insertions(+), 41 deletions(-) diff --git a/cmd/server/main.go b/cmd/server/main.go index 295731c5..508387c4 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -12,31 +12,32 @@ // See the License for the specific language governing permissions and // limitations under the License. +// Copyright 2022-2023 The Connect Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package main import ( "context" - "flag" "fmt" + "os" "connectrpc.com/conformance/internal/app/server" ) -const ( - h1PortFlagName = "h1port" - h2PortFlagName = "h2port" - insecureFlagName = "insecure" -) - func main() { - h1Port := flag.String("h1Port", "8080", "port for HTTP/1.1 traffic") - h2Port := flag.String("h2Port", "8081", "port for HTTP/2 traffic") - - flag.Parse() - - args := []string{*h1Port, *h2Port} - - err := server.Run(context.Background(), args, nil, nil, nil) + err := server.Run(context.Background(), os.Args, os.Stdin, os.Stdout, os.Stderr) if err != nil { fmt.Println("an error occurred running the server ", err) } diff --git a/internal/app/server/server.go b/internal/app/server/server.go index 575b4f75..8feacf05 100644 --- a/internal/app/server/server.go +++ b/internal/app/server/server.go @@ -1,4 +1,4 @@ -// Copyright 2023 The Connect Authors +// Copyright 2022-2023 The Connect Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ package server import ( "context" "errors" + "flag" "fmt" "io" "net/http" @@ -32,8 +33,10 @@ import ( ) func Run(ctx context.Context, args []string, in io.ReadCloser, out, err io.WriteCloser) error { - h1Port := args[0] - h2Port := args[1] + h1Port := flag.String("h1Port", "8080", "port for HTTP/1.1 traffic") + h2Port := flag.String("h2Port", "8081", "port for HTTP/2 traffic") + + flag.Parse() mux := http.NewServeMux() mux.Handle(conformancev1alpha1connect.NewConformanceServiceHandler( @@ -48,36 +51,20 @@ func Run(ctx context.Context, args []string, in io.ReadCloser, out, err io.Write http.MethodPatch, http.MethodDelete, }, - // Mirror the `Origin` header value in the `Access-Control-Allow-Origin` - // preflight response header. - // This is equivalent to `Access-Control-Allow-Origin: *`, but allows - // for requests with credentials. - // Note that this effectively disables CORS and is not safe for use in - // production environments. - AllowOriginFunc: func(origin string) bool { - return true - }, // Note that rs/cors does not return `Access-Control-Allow-Headers: *` // in response to preflight requests with the following configuration. // It simply mirrors all headers listed in the `Access-Control-Request-Headers` // preflight request header. AllowedHeaders: []string{"*"}, - // We explicitly set the exposed header names instead of using the wildcard *, - // because in requests with credentials, it is treated as the literal header - // name "*" without special semantics. - ExposedHeaders: []string{ - "Grpc-Status", "Grpc-Message", "Grpc-Status-Details-Bin", "X-Grpc-Test-Echo-Initial", - "Trailer-X-Grpc-Test-Echo-Trailing-Bin", "Request-Protocol", "Get-Request"}, + // Expose all headers + ExposedHeaders: []string{"*"}, }).Handler(mux) // Create servers - h1Server := newH1Server(h1Port, corsHandler) - h2Server := newH2Server(h2Port, mux) + h1Server := newH1Server(*h1Port, corsHandler) + h2Server := newH2Server(*h2Port, mux) done := make(chan os.Signal, 1) errs := make(chan error, 2) - // TODO - This graceful shutdown sophistication may not be needed. - // The test scaffolding won't send the signal until after all requests are complete - // (or until it decides to abort, in which it's okay to have non-graceful termination of requests in progress) signal.Notify(done, os.Interrupt, syscall.SIGINT, syscall.SIGTERM) go func() { err := h1Server.ListenAndServe() @@ -92,7 +79,7 @@ func Run(ctx context.Context, args []string, in io.ReadCloser, out, err io.Write } }() - fmt.Printf("HTTP/1.1 server listening on port %s\nHTTP/2 server listening on port %s", h1Port, h2Port) + fmt.Printf("HTTP/1.1 server listening on port %s\nHTTP/2 server listening on port %s", *h1Port, *h2Port) select { case err := <-errs: @@ -114,7 +101,7 @@ func Run(ctx context.Context, args []string, in io.ReadCloser, out, err io.Write func newH1Server(h1Port string, handler http.Handler) *http.Server { h1Server := &http.Server{ - Addr: "127.0.0.1:" + h1Port, + Addr: ":" + h1Port, Handler: handler, } return h1Server @@ -122,7 +109,7 @@ func newH1Server(h1Port string, handler http.Handler) *http.Server { func newH2Server(h2Port string, handler http.Handler) *http.Server { h2Server := &http.Server{ - Addr: "127.0.0.1:" + h2Port, + Addr: ":" + h2Port, } h2Server.Handler = h2c.NewHandler(handler, &http2.Server{}) return h2Server From da0474bf7a2e24e327c0196a6be2586488247016 Mon Sep 17 00:00:00 2001 From: Steve Ayers Date: Tue, 17 Oct 2023 12:43:50 -0400 Subject: [PATCH 11/13] Feedback --- internal/app/server/impl.go | 19 +++++++------------ .../conformance/v1alpha1/service.proto | 2 +- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/internal/app/server/impl.go b/internal/app/server/impl.go index 1567bbc4..47b1c6db 100644 --- a/internal/app/server/impl.go +++ b/internal/app/server/impl.go @@ -94,6 +94,11 @@ func (s *conformanceServer) ClientStream( } payload, err := parseUnaryResponseDefinition(responseDefinition, stream.RequestHeader(), reqs) + if err != nil { + addHeaders(responseDefinition.ResponseHeaders, err.Meta()) + addHeaders(responseDefinition.ResponseTrailers, err.Meta()) + return nil, err + } resp := connect.NewResponse(&v1alpha1.ClientStreamResponse{ Payload: payload, @@ -112,18 +117,8 @@ func (s *conformanceServer) ServerStream( ) error { responseDefinition := req.Msg.ResponseDefinition if responseDefinition != nil { - // Set all requested response headers on the response - for _, header := range responseDefinition.ResponseHeaders { - for _, val := range header.Value { - stream.ResponseHeader().Add(header.Name, val) - } - } - // Set all requested response trailers on the response - for _, trailer := range responseDefinition.ResponseTrailers { - for _, val := range trailer.Value { - stream.ResponseTrailer().Add(trailer.Name, val) - } - } + addHeaders(responseDefinition.ResponseHeaders, stream.ResponseHeader()) + addHeaders(responseDefinition.ResponseTrailers, stream.ResponseTrailer()) } // Convert the request to an Any so that it can be recorded in the payload diff --git a/proto/connectrpc/conformance/v1alpha1/service.proto b/proto/connectrpc/conformance/v1alpha1/service.proto index 62632c9e..6dd24328 100644 --- a/proto/connectrpc/conformance/v1alpha1/service.proto +++ b/proto/connectrpc/conformance/v1alpha1/service.proto @@ -153,7 +153,7 @@ message ClientStreamRequest { UnaryResponseDefinition response_definition = 1; // Additional data for subsequent messages in the stream. - bytes extra = 2; + bytes request_data = 2; } message ClientStreamResponse { From 08ccef3b9ea1734601d409d002d4b5bfa4c3602e Mon Sep 17 00:00:00 2001 From: Steve Ayers Date: Tue, 17 Oct 2023 12:47:31 -0400 Subject: [PATCH 12/13] Better comment --- internal/app/server/server.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/internal/app/server/server.go b/internal/app/server/server.go index 8feacf05..8d2efb33 100644 --- a/internal/app/server/server.go +++ b/internal/app/server/server.go @@ -42,6 +42,8 @@ func Run(ctx context.Context, args []string, in io.ReadCloser, out, err io.Write mux.Handle(conformancev1alpha1connect.NewConformanceServiceHandler( &conformanceServer{}, )) + // The server needs a lenient cors setup so that it can handle testing + // browser clients. corsHandler := cors.New(cors.Options{ AllowedMethods: []string{ http.MethodHead, From 0cb037d4de2026b48e8f18f419411b21781dc7d8 Mon Sep 17 00:00:00 2001 From: Steve Ayers Date: Wed, 18 Oct 2023 11:22:23 -0400 Subject: [PATCH 13/13] Added TODO --- internal/app/server/server.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/internal/app/server/server.go b/internal/app/server/server.go index 8d2efb33..5a318167 100644 --- a/internal/app/server/server.go +++ b/internal/app/server/server.go @@ -33,6 +33,9 @@ import ( ) func Run(ctx context.Context, args []string, in io.ReadCloser, out, err io.WriteCloser) error { + // TODO - The ports should not be given to the run call. Instead the server should read a + // ServerCompatRequest and start itself. It should then return the port numbers back on stdout + // as a ServerCompatResponse h1Port := flag.String("h1Port", "8080", "port for HTTP/1.1 traffic") h2Port := flag.String("h2Port", "8081", "port for HTTP/2 traffic")