go.uber.org/yarpc@v1.72.1/api/transport/stream.go (about)

     1  // Copyright (c) 2022 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package transport
    22  
    23  import (
    24  	"context"
    25  	"io"
    26  
    27  	"go.uber.org/yarpc/yarpcerrors"
    28  )
    29  
    30  // StreamRequest represents a streaming request.  It contains basic stream
    31  // metadata.
    32  type StreamRequest struct {
    33  	Meta *RequestMeta
    34  }
    35  
    36  // ServerStreamOption are options to configure a ServerStream.
    37  // There are no current ServerStreamOptions implemented.
    38  type ServerStreamOption interface {
    39  	unimplemented()
    40  }
    41  
    42  // NewServerStream will create a new ServerStream.
    43  // The Stream can implement StreamHeadersSender if the underlying transport
    44  // supports stream headers.
    45  func NewServerStream(s Stream, options ...ServerStreamOption) (*ServerStream, error) {
    46  	if s == nil {
    47  		return nil, yarpcerrors.InvalidArgumentErrorf("non-nil stream is required")
    48  	}
    49  	return &ServerStream{stream: s}, nil
    50  }
    51  
    52  // ServerStream represents the Server API of interacting with a Stream.
    53  type ServerStream struct {
    54  	stream Stream
    55  }
    56  
    57  // StreamHeadersSender is the interface for sending stream headers.
    58  type StreamHeadersSender interface {
    59  	SendHeaders(headers Headers) error
    60  }
    61  
    62  // SendStreamHeaders conditionally type asserts a Stream to a StreamHeadersSender to send the provided headers.
    63  func SendStreamHeaders(s Stream, headers Headers) error {
    64  	if w, ok := s.(StreamHeadersSender); ok {
    65  		return w.SendHeaders(headers)
    66  	}
    67  	return yarpcerrors.UnimplementedErrorf("stream does not support sending headers")
    68  }
    69  
    70  // Context returns the context for the stream.
    71  func (s *ServerStream) Context() context.Context {
    72  	return s.stream.Context()
    73  }
    74  
    75  // Request contains all the metadata about the request.
    76  func (s *ServerStream) Request() *StreamRequest {
    77  	return s.stream.Request()
    78  }
    79  
    80  // SendMessage sends a request over the stream. It blocks until the message
    81  // has been sent.  In certain implementations, the timeout on the context
    82  // will be used to timeout the request.
    83  func (s *ServerStream) SendMessage(ctx context.Context, msg *StreamMessage) error {
    84  	return s.stream.SendMessage(ctx, msg)
    85  }
    86  
    87  // ReceiveMessage blocks until a message is received from the connection. It
    88  // returns an io.Reader with the contents of the message.
    89  func (s *ServerStream) ReceiveMessage(ctx context.Context) (*StreamMessage, error) {
    90  	return s.stream.ReceiveMessage(ctx)
    91  }
    92  
    93  // SendHeaders sends the one-time response headers to an initial stream connect.
    94  // It fails if called multiple times.
    95  func (s *ServerStream) SendHeaders(headers Headers) error {
    96  	return SendStreamHeaders(s.stream, headers)
    97  }
    98  
    99  // ClientStreamOption is an option for configuring a client stream.
   100  // There are no current ClientStreamOptions implemented.
   101  type ClientStreamOption interface {
   102  	unimplemented()
   103  }
   104  
   105  // NewClientStream will create a new ClientStream.
   106  // The StreamCloser can implement StreamMessageReader if the underlying stream
   107  // supports stream headers.
   108  func NewClientStream(s StreamCloser, options ...ClientStreamOption) (*ClientStream, error) {
   109  	if s == nil {
   110  		return nil, yarpcerrors.InvalidArgumentErrorf("non-nil stream with close is required")
   111  	}
   112  	return &ClientStream{stream: s}, nil
   113  }
   114  
   115  // ClientStream represents the Client API of interacting with a Stream.
   116  type ClientStream struct {
   117  	stream StreamCloser
   118  }
   119  
   120  // StreamHeadersReader is the interface for reading stream headers.
   121  type StreamHeadersReader interface {
   122  	Headers() (Headers, error)
   123  }
   124  
   125  // ReadStreamHeaders conditionally type asserts a Stream to a StreamHeadersReader to read the received headers.
   126  func ReadStreamHeaders(s Stream) (Headers, error) {
   127  	if r, ok := s.(StreamHeadersReader); ok {
   128  		return r.Headers()
   129  	}
   130  	return NewHeaders(), yarpcerrors.UnimplementedErrorf("stream does not support reading headers")
   131  }
   132  
   133  // Context returns the context for the stream.
   134  func (s *ClientStream) Context() context.Context {
   135  	return s.stream.Context()
   136  }
   137  
   138  // Request contains all the metadata about the request.
   139  func (s *ClientStream) Request() *StreamRequest {
   140  	return s.stream.Request()
   141  }
   142  
   143  // SendMessage sends a request over the stream. It blocks until the message
   144  // has been sent.  In certain implementations, the timeout on the context
   145  // will be used to timeout the request.
   146  func (s *ClientStream) SendMessage(ctx context.Context, msg *StreamMessage) error {
   147  	return s.stream.SendMessage(ctx, msg)
   148  }
   149  
   150  // ReceiveMessage blocks until a message is received from the connection. It
   151  // returns an io.Reader with the contents of the message.
   152  func (s *ClientStream) ReceiveMessage(ctx context.Context) (*StreamMessage, error) {
   153  	return s.stream.ReceiveMessage(ctx)
   154  }
   155  
   156  // Close will close the connection. It blocks until the server has
   157  // acknowledged the close. In certain implementations, the timeout on the
   158  // context will be used to timeout the request. If the server timed out the
   159  // connection will be forced closed by the client.
   160  func (s *ClientStream) Close(ctx context.Context) error {
   161  	return s.stream.Close(ctx)
   162  }
   163  
   164  // Headers returns the initial stream response headers received from the server if there
   165  // are any. It blocks if the headers are not available.
   166  func (s *ClientStream) Headers() (Headers, error) {
   167  	return ReadStreamHeaders(s.stream)
   168  }
   169  
   170  // StreamCloser represents an API of interacting with a Stream that is
   171  // closable.
   172  type StreamCloser interface {
   173  	Stream
   174  
   175  	// Close will close the connection. It blocks until the server has
   176  	// acknowledged the close. The provided context controls the timeout for
   177  	// this operation if the implementation supports it. If the server timed out
   178  	// the connection will be forced closed by the client.
   179  	Close(context.Context) error
   180  }
   181  
   182  // Stream is an interface for interacting with a stream.
   183  type Stream interface {
   184  	// Context returns the context for the stream.
   185  	Context() context.Context
   186  
   187  	// Request contains all the metadata about the request.
   188  	Request() *StreamRequest
   189  
   190  	// SendMessage sends a request over the stream. It blocks until the message
   191  	// has been sent.  In certain implementations, the timeout on the context
   192  	// will be used to timeout the request.
   193  	SendMessage(context.Context, *StreamMessage) error
   194  
   195  	// ReceiveMessage blocks until a message is received from the connection. It
   196  	// returns an io.Reader with the contents of the message.
   197  	ReceiveMessage(context.Context) (*StreamMessage, error)
   198  }
   199  
   200  // StreamMessage represents information that can be read off of an individual
   201  // message in the stream.
   202  type StreamMessage struct {
   203  	Body     io.ReadCloser
   204  	BodySize int
   205  }