open-vault/vendor/google.golang.org/grpc/stream.go

686 lines
19 KiB
Go
Raw Normal View History

2016-08-19 15:03:53 +00:00
/*
*
2017-06-16 15:14:18 +00:00
* Copyright 2014 gRPC authors.
2016-08-19 15:03:53 +00:00
*
2017-06-16 15:14:18 +00:00
* 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
2016-08-19 15:03:53 +00:00
*
2017-06-16 15:14:18 +00:00
* http://www.apache.org/licenses/LICENSE-2.0
2016-08-19 15:03:53 +00:00
*
2017-06-16 15:14:18 +00:00
* 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.
2016-08-19 15:03:53 +00:00
*
*/
package grpc
import (
"errors"
"io"
"sync"
"time"
"golang.org/x/net/context"
"golang.org/x/net/trace"
2017-09-05 22:06:47 +00:00
"google.golang.org/grpc/balancer"
2016-08-19 15:03:53 +00:00
"google.golang.org/grpc/codes"
2017-11-07 16:57:05 +00:00
"google.golang.org/grpc/encoding"
2016-08-19 15:03:53 +00:00
"google.golang.org/grpc/metadata"
2017-07-18 14:15:54 +00:00
"google.golang.org/grpc/peer"
2016-11-16 23:22:54 +00:00
"google.golang.org/grpc/stats"
2017-04-17 15:17:06 +00:00
"google.golang.org/grpc/status"
2016-08-19 15:03:53 +00:00
"google.golang.org/grpc/transport"
)
// StreamHandler defines the handler called by gRPC server to complete the
// execution of a streaming RPC.
type StreamHandler func(srv interface{}, stream ServerStream) error
// StreamDesc represents a streaming RPC service's method specification.
type StreamDesc struct {
StreamName string
Handler StreamHandler
// At least one of these is true.
ServerStreams bool
ClientStreams bool
}
// Stream defines the common interface a client or server stream has to satisfy.
type Stream interface {
// Context returns the context for this stream.
Context() context.Context
// SendMsg blocks until it sends m, the stream is done or the stream
// breaks.
// On error, it aborts the stream and returns an RPC status on client
// side. On server side, it simply returns the error to the caller.
// SendMsg is called by generated code. Also Users can call SendMsg
// directly when it is really needed in their use cases.
2017-06-16 15:14:18 +00:00
// It's safe to have a goroutine calling SendMsg and another goroutine calling
// recvMsg on the same stream at the same time.
// But it is not safe to call SendMsg on the same stream in different goroutines.
2016-08-19 15:03:53 +00:00
SendMsg(m interface{}) error
// RecvMsg blocks until it receives a message or the stream is
// done. On client side, it returns io.EOF when the stream is done. On
// any other error, it aborts the stream and returns an RPC status. On
// server side, it simply returns the error to the caller.
2017-06-16 15:14:18 +00:00
// It's safe to have a goroutine calling SendMsg and another goroutine calling
// recvMsg on the same stream at the same time.
// But it is not safe to call RecvMsg on the same stream in different goroutines.
2016-08-19 15:03:53 +00:00
RecvMsg(m interface{}) error
}
// ClientStream defines the interface a client stream has to satisfy.
type ClientStream interface {
// Header returns the header metadata received from the server if there
// is any. It blocks if the metadata is not ready to read.
Header() (metadata.MD, error)
// Trailer returns the trailer metadata from the server, if there is any.
// It must only be called after stream.CloseAndRecv has returned, or
// stream.Recv has returned a non-nil error (including io.EOF).
Trailer() metadata.MD
// CloseSend closes the send direction of the stream. It closes the stream
// when non-nil error is met.
CloseSend() error
2017-07-18 14:15:54 +00:00
// Stream.SendMsg() may return a non-nil error when something wrong happens sending
// the request. The returned error indicates the status of this sending, not the final
// status of the RPC.
// Always call Stream.RecvMsg() to get the final status if you care about the status of
// the RPC.
2016-08-19 15:03:53 +00:00
Stream
}
2017-10-27 19:06:04 +00:00
// NewStream creates a new Stream for the client side. This is typically
// called by generated code.
func (cc *ClientConn) NewStream(ctx context.Context, desc *StreamDesc, method string, opts ...CallOption) (ClientStream, error) {
2016-09-12 19:16:55 +00:00
if cc.dopts.streamInt != nil {
return cc.dopts.streamInt(ctx, desc, cc, method, newClientStream, opts...)
}
return newClientStream(ctx, desc, cc, method, opts...)
}
2017-10-27 19:06:04 +00:00
// NewClientStream creates a new Stream for the client side. This is typically
// called by generated code.
//
// DEPRECATED: Use ClientConn.NewStream instead.
func NewClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, method string, opts ...CallOption) (ClientStream, error) {
return cc.NewStream(ctx, desc, method, opts...)
}
2016-09-12 19:16:55 +00:00
func newClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, method string, opts ...CallOption) (_ ClientStream, err error) {
2016-08-19 15:03:53 +00:00
var (
2017-01-04 21:47:38 +00:00
t transport.ClientTransport
s *transport.Stream
2017-10-27 19:06:04 +00:00
done func(balancer.DoneInfo)
2017-01-04 21:47:38 +00:00
cancel context.CancelFunc
2016-08-19 15:03:53 +00:00
)
2017-09-05 22:06:47 +00:00
c := defaultCallInfo()
2017-05-24 13:34:59 +00:00
mc := cc.GetMethodConfig(method)
if mc.WaitForReady != nil {
c.failFast = !*mc.WaitForReady
}
if mc.Timeout != nil {
ctx, cancel = context.WithTimeout(ctx, *mc.Timeout)
2017-09-05 22:06:47 +00:00
defer func() {
if err != nil {
cancel()
}
}()
2017-01-04 21:47:38 +00:00
}
2017-05-24 13:34:59 +00:00
opts = append(cc.dopts.callOptions, opts...)
2016-08-19 15:03:53 +00:00
for _, o := range opts {
2017-09-05 22:06:47 +00:00
if err := o.before(c); err != nil {
2016-08-19 15:03:53 +00:00
return nil, toRPCErr(err)
}
}
2017-05-24 13:34:59 +00:00
c.maxSendMessageSize = getMaxSize(mc.MaxReqSize, c.maxSendMessageSize, defaultClientMaxSendMessageSize)
c.maxReceiveMessageSize = getMaxSize(mc.MaxRespSize, c.maxReceiveMessageSize, defaultClientMaxReceiveMessageSize)
2016-08-19 15:03:53 +00:00
callHdr := &transport.CallHdr{
Host: cc.authority,
Method: method,
2017-07-18 14:15:54 +00:00
// If it's not client streaming, we should already have the request to be sent,
// so we don't flush the header.
// If it's client streaming, the user may never send a request or send it any
// time soon, so we ask the transport to flush the header.
Flush: desc.ClientStreams,
2016-08-19 15:03:53 +00:00
}
2017-11-07 16:57:05 +00:00
if c.compressorType != "" {
callHdr.SendCompress = c.compressorType
} else if cc.dopts.cp != nil {
2016-08-19 15:03:53 +00:00
callHdr.SendCompress = cc.dopts.cp.Type()
}
2017-05-24 13:34:59 +00:00
if c.creds != nil {
callHdr.Creds = c.creds
}
2016-08-19 15:03:53 +00:00
var trInfo traceInfo
if EnableTracing {
trInfo.tr = trace.New("grpc.Sent."+methodFamily(method), method)
trInfo.firstLine.client = true
if deadline, ok := ctx.Deadline(); ok {
trInfo.firstLine.deadline = deadline.Sub(time.Now())
}
trInfo.tr.LazyLog(&trInfo.firstLine, false)
ctx = trace.NewContext(ctx, trInfo.tr)
defer func() {
if err != nil {
// Need to call tr.finish() if error is returned.
// Because tr will not be returned to caller.
trInfo.tr.LazyPrintf("RPC: [%v]", err)
trInfo.tr.SetError()
trInfo.tr.Finish()
}
}()
}
2017-09-05 22:06:47 +00:00
ctx = newContextWithRPCInfo(ctx, c.failFast)
2017-01-13 14:06:34 +00:00
sh := cc.dopts.copts.StatsHandler
if sh != nil {
2017-05-24 13:34:59 +00:00
ctx = sh.TagRPC(ctx, &stats.RPCTagInfo{FullMethodName: method, FailFast: c.failFast})
2016-11-16 23:22:54 +00:00
begin := &stats.Begin{
Client: true,
BeginTime: time.Now(),
FailFast: c.failFast,
}
2017-01-13 14:06:34 +00:00
sh.HandleRPC(ctx, begin)
2017-05-24 13:34:59 +00:00
defer func() {
if err != nil {
// Only handle end stats if err != nil.
end := &stats.End{
Client: true,
Error: err,
}
sh.HandleRPC(ctx, end)
2016-11-16 23:22:54 +00:00
}
2017-05-24 13:34:59 +00:00
}()
}
2017-11-07 16:57:05 +00:00
2016-08-19 15:03:53 +00:00
for {
2017-11-07 16:57:05 +00:00
// Check to make sure the context has expired. This will prevent us from
// looping forever if an error occurs for wait-for-ready RPCs where no data
// is sent on the wire.
select {
case <-ctx.Done():
return nil, toRPCErr(ctx.Err())
default:
}
2017-10-27 19:06:04 +00:00
t, done, err = cc.getTransport(ctx, c.failFast)
2016-08-19 15:03:53 +00:00
if err != nil {
2017-11-07 16:57:05 +00:00
return nil, err
2016-08-19 15:03:53 +00:00
}
s, err = t.NewStream(ctx, callHdr)
if err != nil {
2017-10-27 19:06:04 +00:00
if done != nil {
done(balancer.DoneInfo{Err: err})
done = nil
2016-08-19 15:03:53 +00:00
}
2017-11-07 16:57:05 +00:00
// In the event of any error from NewStream, we never attempted to write
// anything to the wire, so we can retry indefinitely for non-fail-fast
// RPCs.
if !c.failFast {
2016-08-19 15:03:53 +00:00
continue
}
return nil, toRPCErr(err)
}
break
}
2017-11-07 16:57:05 +00:00
2017-07-18 14:15:54 +00:00
// Set callInfo.peer object from stream's context.
if peer, ok := peer.FromContext(s.Context()); ok {
c.peer = peer
}
2016-08-19 15:03:53 +00:00
cs := &clientStream{
2017-05-24 13:34:59 +00:00
opts: opts,
c: c,
desc: desc,
codec: cc.dopts.codec,
2017-11-07 16:57:05 +00:00
cpType: c.compressorType,
2017-05-24 13:34:59 +00:00
cp: cc.dopts.cp,
dc: cc.dopts.dc,
cancel: cancel,
2016-08-19 15:03:53 +00:00
2017-10-27 19:06:04 +00:00
done: done,
t: t,
s: s,
p: &parser{r: s},
2016-08-19 15:03:53 +00:00
tracing: EnableTracing,
trInfo: trInfo,
2016-11-16 23:22:54 +00:00
2017-01-13 14:06:34 +00:00
statsCtx: ctx,
statsHandler: cc.dopts.copts.StatsHandler,
2016-08-19 15:03:53 +00:00
}
2017-11-07 16:57:05 +00:00
// Listen on s.Context().Done() to detect cancellation and s.Done() to detect
// normal termination when there is no pending I/O operations on this stream.
2016-08-19 15:03:53 +00:00
go func() {
select {
case <-t.Error():
// Incur transport error, simply exit.
2017-05-24 13:34:59 +00:00
case <-cc.ctx.Done():
cs.finish(ErrClientConnClosing)
cs.closeTransportStream(ErrClientConnClosing)
2016-08-19 15:03:53 +00:00
case <-s.Done():
// TODO: The trace of the RPC is terminated here when there is no pending
// I/O, which is probably not the optimal solution.
2017-04-17 15:17:06 +00:00
cs.finish(s.Status().Err())
2016-08-19 15:03:53 +00:00
cs.closeTransportStream(nil)
case <-s.GoAway():
cs.finish(errConnDrain)
cs.closeTransportStream(errConnDrain)
case <-s.Context().Done():
err := s.Context().Err()
cs.finish(err)
cs.closeTransportStream(transport.ContextErr(err))
}
}()
return cs, nil
}
// clientStream implements a client side Stream.
type clientStream struct {
2017-05-24 13:34:59 +00:00
opts []CallOption
2017-09-05 22:06:47 +00:00
c *callInfo
2017-05-24 13:34:59 +00:00
t transport.ClientTransport
s *transport.Stream
p *parser
desc *StreamDesc
codec Codec
2017-11-07 16:57:05 +00:00
cpType string
2017-05-24 13:34:59 +00:00
cp Compressor
dc Decompressor
cancel context.CancelFunc
2016-08-19 15:03:53 +00:00
tracing bool // set to EnableTracing when the clientStream is created.
2017-04-17 15:17:06 +00:00
mu sync.Mutex
2017-10-27 19:06:04 +00:00
done func(balancer.DoneInfo)
2017-04-17 15:17:06 +00:00
closed bool
finished bool
2016-08-19 15:03:53 +00:00
// trInfo.tr is set when the clientStream is created (if EnableTracing is true),
// and is set to nil when the clientStream's finish method is called.
trInfo traceInfo
2016-11-16 23:22:54 +00:00
// statsCtx keeps the user context for stats handling.
// All stats collection should use the statsCtx (instead of the stream context)
// so that all the generated stats for a particular RPC can be associated in the processing phase.
2017-01-13 14:06:34 +00:00
statsCtx context.Context
statsHandler stats.Handler
2016-08-19 15:03:53 +00:00
}
func (cs *clientStream) Context() context.Context {
return cs.s.Context()
}
func (cs *clientStream) Header() (metadata.MD, error) {
m, err := cs.s.Header()
if err != nil {
if _, ok := err.(transport.ConnectionError); !ok {
cs.closeTransportStream(err)
}
}
return m, err
}
func (cs *clientStream) Trailer() metadata.MD {
return cs.s.Trailer()
}
func (cs *clientStream) SendMsg(m interface{}) (err error) {
if cs.tracing {
cs.mu.Lock()
if cs.trInfo.tr != nil {
cs.trInfo.tr.LazyLog(&payload{sent: true, msg: m}, true)
}
cs.mu.Unlock()
}
2016-11-16 23:22:54 +00:00
// TODO Investigate how to signal the stats handling party.
// generate error stats if err != nil && err != io.EOF?
2016-08-19 15:03:53 +00:00
defer func() {
if err != nil {
cs.finish(err)
}
if err == nil {
return
}
if err == io.EOF {
2017-09-05 22:06:47 +00:00
// Specialize the process for server streaming. SendMsg is only called
2016-08-19 15:03:53 +00:00
// once when creating the stream object. io.EOF needs to be skipped when
// the rpc is early finished (before the stream object is created.).
// TODO: It is probably better to move this into the generated code.
if !cs.desc.ClientStreams && cs.desc.ServerStreams {
err = nil
}
return
}
if _, ok := err.(transport.ConnectionError); !ok {
cs.closeTransportStream(err)
}
err = toRPCErr(err)
}()
2016-11-16 23:22:54 +00:00
var outPayload *stats.OutPayload
2017-01-13 14:06:34 +00:00
if cs.statsHandler != nil {
2016-11-16 23:22:54 +00:00
outPayload = &stats.OutPayload{
Client: true,
}
}
2017-11-07 16:57:05 +00:00
if cs.cpType != "" && encoding.GetCompressor(cs.cpType) == nil {
return Errorf(codes.Internal, "grpc: Compressor is not installed for grpc-encoding %q", cs.cpType)
}
hdr, data, err := encode(cs.codec, m, cs.cp, outPayload, encoding.GetCompressor(cs.cpType))
2016-08-19 15:03:53 +00:00
if err != nil {
2017-06-05 14:50:46 +00:00
return err
2016-08-19 15:03:53 +00:00
}
2017-05-24 13:34:59 +00:00
if cs.c.maxSendMessageSize == nil {
return Errorf(codes.Internal, "callInfo maxSendMessageSize field uninitialized(nil)")
}
2017-09-05 22:06:47 +00:00
if len(data) > *cs.c.maxSendMessageSize {
return Errorf(codes.ResourceExhausted, "trying to send message larger than max (%d vs. %d)", len(data), *cs.c.maxSendMessageSize)
2017-05-24 13:34:59 +00:00
}
2017-09-05 22:06:47 +00:00
err = cs.t.Write(cs.s, hdr, data, &transport.Options{Last: false})
2016-11-16 23:22:54 +00:00
if err == nil && outPayload != nil {
outPayload.SentTime = time.Now()
2017-01-13 14:06:34 +00:00
cs.statsHandler.HandleRPC(cs.statsCtx, outPayload)
2016-11-16 23:22:54 +00:00
}
return err
2016-08-19 15:03:53 +00:00
}
func (cs *clientStream) RecvMsg(m interface{}) (err error) {
2016-11-16 23:22:54 +00:00
var inPayload *stats.InPayload
2017-01-13 14:06:34 +00:00
if cs.statsHandler != nil {
2016-11-16 23:22:54 +00:00
inPayload = &stats.InPayload{
Client: true,
}
}
2017-05-24 13:34:59 +00:00
if cs.c.maxReceiveMessageSize == nil {
return Errorf(codes.Internal, "callInfo maxReceiveMessageSize field uninitialized(nil)")
}
2017-11-07 16:57:05 +00:00
err = recv(cs.p, cs.codec, cs.s, cs.dc, m, *cs.c.maxReceiveMessageSize, inPayload, encoding.GetCompressor(cs.cpType))
2016-08-19 15:03:53 +00:00
defer func() {
// err != nil indicates the termination of the stream.
if err != nil {
cs.finish(err)
}
}()
if err == nil {
if cs.tracing {
cs.mu.Lock()
if cs.trInfo.tr != nil {
cs.trInfo.tr.LazyLog(&payload{sent: false, msg: m}, true)
}
cs.mu.Unlock()
}
2016-11-16 23:22:54 +00:00
if inPayload != nil {
2017-01-13 14:06:34 +00:00
cs.statsHandler.HandleRPC(cs.statsCtx, inPayload)
2016-11-16 23:22:54 +00:00
}
2016-08-19 15:03:53 +00:00
if !cs.desc.ClientStreams || cs.desc.ServerStreams {
return
}
// Special handling for client streaming rpc.
2016-11-16 23:22:54 +00:00
// This recv expects EOF or errors, so we don't collect inPayload.
2017-05-24 13:34:59 +00:00
if cs.c.maxReceiveMessageSize == nil {
return Errorf(codes.Internal, "callInfo maxReceiveMessageSize field uninitialized(nil)")
}
2017-11-07 16:57:05 +00:00
err = recv(cs.p, cs.codec, cs.s, cs.dc, m, *cs.c.maxReceiveMessageSize, nil, encoding.GetCompressor(cs.cpType))
2016-08-19 15:03:53 +00:00
cs.closeTransportStream(err)
if err == nil {
return toRPCErr(errors.New("grpc: client streaming protocol violation: get <nil>, want <EOF>"))
}
if err == io.EOF {
2017-04-17 15:17:06 +00:00
if se := cs.s.Status().Err(); se != nil {
return se
2016-08-19 15:03:53 +00:00
}
2017-04-17 15:17:06 +00:00
cs.finish(err)
return nil
2016-08-19 15:03:53 +00:00
}
return toRPCErr(err)
}
if _, ok := err.(transport.ConnectionError); !ok {
cs.closeTransportStream(err)
}
if err == io.EOF {
2017-04-17 15:17:06 +00:00
if statusErr := cs.s.Status().Err(); statusErr != nil {
return statusErr
2016-08-19 15:03:53 +00:00
}
2017-04-17 15:17:06 +00:00
// Returns io.EOF to indicate the end of the stream.
return
2016-08-19 15:03:53 +00:00
}
return toRPCErr(err)
}
func (cs *clientStream) CloseSend() (err error) {
2017-09-05 22:06:47 +00:00
err = cs.t.Write(cs.s, nil, nil, &transport.Options{Last: true})
2016-08-19 15:03:53 +00:00
defer func() {
if err != nil {
cs.finish(err)
}
}()
if err == nil || err == io.EOF {
return nil
}
if _, ok := err.(transport.ConnectionError); !ok {
cs.closeTransportStream(err)
}
err = toRPCErr(err)
return
}
func (cs *clientStream) closeTransportStream(err error) {
cs.mu.Lock()
if cs.closed {
cs.mu.Unlock()
return
}
cs.closed = true
cs.mu.Unlock()
cs.t.CloseStream(cs.s, err)
}
func (cs *clientStream) finish(err error) {
2017-04-17 15:17:06 +00:00
cs.mu.Lock()
defer cs.mu.Unlock()
if cs.finished {
return
}
cs.finished = true
2017-01-04 21:47:38 +00:00
defer func() {
if cs.cancel != nil {
cs.cancel()
}
}()
2016-08-19 15:03:53 +00:00
for _, o := range cs.opts {
2017-09-05 22:06:47 +00:00
o.after(cs.c)
2016-08-19 15:03:53 +00:00
}
2017-10-27 19:06:04 +00:00
if cs.done != nil {
2017-05-24 13:34:59 +00:00
updateRPCInfoInContext(cs.s.Context(), rpcInfo{
2017-11-07 16:57:05 +00:00
bytesSent: true,
2017-05-24 13:34:59 +00:00
bytesReceived: cs.s.BytesReceived(),
})
2017-10-27 19:06:04 +00:00
cs.done(balancer.DoneInfo{Err: err})
cs.done = nil
2016-08-19 15:03:53 +00:00
}
2017-04-17 15:17:06 +00:00
if cs.statsHandler != nil {
end := &stats.End{
Client: true,
EndTime: time.Now(),
}
if err != io.EOF {
// end.Error is nil if the RPC finished successfully.
end.Error = toRPCErr(err)
}
cs.statsHandler.HandleRPC(cs.statsCtx, end)
}
2016-08-19 15:03:53 +00:00
if !cs.tracing {
return
}
if cs.trInfo.tr != nil {
if err == nil || err == io.EOF {
cs.trInfo.tr.LazyPrintf("RPC: [OK]")
} else {
cs.trInfo.tr.LazyPrintf("RPC: [%v]", err)
cs.trInfo.tr.SetError()
}
cs.trInfo.tr.Finish()
cs.trInfo.tr = nil
}
}
// ServerStream defines the interface a server stream has to satisfy.
type ServerStream interface {
2016-11-02 19:34:30 +00:00
// SetHeader sets the header metadata. It may be called multiple times.
// When call multiple times, all the provided metadata will be merged.
// All the metadata will be sent out when one of the following happens:
// - ServerStream.SendHeader() is called;
// - The first response is sent out;
// - An RPC status is sent out (error or success).
SetHeader(metadata.MD) error
// SendHeader sends the header metadata.
// The provided md and headers set by SetHeader() will be sent.
// It fails if called multiple times.
2016-08-19 15:03:53 +00:00
SendHeader(metadata.MD) error
2016-09-30 13:50:46 +00:00
// SetTrailer sets the trailer metadata which will be sent with the RPC status.
// When called more than once, all the provided metadata will be merged.
2016-08-19 15:03:53 +00:00
SetTrailer(metadata.MD)
Stream
}
// serverStream implements a server side Stream.
type serverStream struct {
2017-05-24 13:34:59 +00:00
t transport.ServerTransport
s *transport.Stream
p *parser
codec Codec
2017-11-07 16:57:05 +00:00
cpType string
2017-05-24 13:34:59 +00:00
cp Compressor
dc Decompressor
maxReceiveMessageSize int
maxSendMessageSize int
trInfo *traceInfo
2016-08-19 15:03:53 +00:00
2017-01-13 14:06:34 +00:00
statsHandler stats.Handler
2016-08-19 15:03:53 +00:00
mu sync.Mutex // protects trInfo.tr after the service handler runs.
}
func (ss *serverStream) Context() context.Context {
return ss.s.Context()
}
2016-11-02 19:34:30 +00:00
func (ss *serverStream) SetHeader(md metadata.MD) error {
if md.Len() == 0 {
return nil
}
return ss.s.SetHeader(md)
}
2016-08-19 15:03:53 +00:00
func (ss *serverStream) SendHeader(md metadata.MD) error {
return ss.t.WriteHeader(ss.s, md)
}
func (ss *serverStream) SetTrailer(md metadata.MD) {
if md.Len() == 0 {
return
}
ss.s.SetTrailer(md)
return
}
func (ss *serverStream) SendMsg(m interface{}) (err error) {
defer func() {
if ss.trInfo != nil {
ss.mu.Lock()
if ss.trInfo.tr != nil {
if err == nil {
ss.trInfo.tr.LazyLog(&payload{sent: true, msg: m}, true)
} else {
ss.trInfo.tr.LazyLog(&fmtStringer{"%v", []interface{}{err}}, true)
ss.trInfo.tr.SetError()
}
}
ss.mu.Unlock()
}
2017-09-05 22:06:47 +00:00
if err != nil && err != io.EOF {
st, _ := status.FromError(toRPCErr(err))
ss.t.WriteStatus(ss.s, st)
}
2016-08-19 15:03:53 +00:00
}()
2016-11-16 23:22:54 +00:00
var outPayload *stats.OutPayload
2017-01-13 14:06:34 +00:00
if ss.statsHandler != nil {
2016-11-16 23:22:54 +00:00
outPayload = &stats.OutPayload{}
}
2017-11-07 16:57:05 +00:00
if ss.cpType != "" {
if encoding.GetCompressor(ss.cpType) == nil && (ss.cp == nil || ss.cp != nil && ss.cp.Type() != ss.cpType) {
return Errorf(codes.Internal, "grpc: Compressor is not installed for grpc-encoding %q", ss.cpType)
}
}
hdr, data, err := encode(ss.codec, m, ss.cp, outPayload, encoding.GetCompressor(ss.cpType))
2016-08-19 15:03:53 +00:00
if err != nil {
return err
}
2017-09-05 22:06:47 +00:00
if len(data) > ss.maxSendMessageSize {
return Errorf(codes.ResourceExhausted, "trying to send message larger than max (%d vs. %d)", len(data), ss.maxSendMessageSize)
2017-05-24 13:34:59 +00:00
}
2017-09-05 22:06:47 +00:00
if err := ss.t.Write(ss.s, hdr, data, &transport.Options{Last: false}); err != nil {
2016-09-02 22:05:09 +00:00
return toRPCErr(err)
}
2016-11-16 23:22:54 +00:00
if outPayload != nil {
outPayload.SentTime = time.Now()
2017-01-13 14:06:34 +00:00
ss.statsHandler.HandleRPC(ss.s.Context(), outPayload)
2016-11-16 23:22:54 +00:00
}
2016-09-02 22:05:09 +00:00
return nil
2016-08-19 15:03:53 +00:00
}
func (ss *serverStream) RecvMsg(m interface{}) (err error) {
defer func() {
if ss.trInfo != nil {
ss.mu.Lock()
if ss.trInfo.tr != nil {
if err == nil {
ss.trInfo.tr.LazyLog(&payload{sent: false, msg: m}, true)
} else if err != io.EOF {
ss.trInfo.tr.LazyLog(&fmtStringer{"%v", []interface{}{err}}, true)
ss.trInfo.tr.SetError()
}
}
ss.mu.Unlock()
}
2017-09-05 22:06:47 +00:00
if err != nil && err != io.EOF {
st, _ := status.FromError(toRPCErr(err))
ss.t.WriteStatus(ss.s, st)
}
2016-08-19 15:03:53 +00:00
}()
2016-11-16 23:22:54 +00:00
var inPayload *stats.InPayload
2017-01-13 14:06:34 +00:00
if ss.statsHandler != nil {
2016-11-16 23:22:54 +00:00
inPayload = &stats.InPayload{}
}
2017-11-07 16:57:05 +00:00
if err := recv(ss.p, ss.codec, ss.s, ss.dc, m, ss.maxReceiveMessageSize, inPayload, encoding.GetCompressor(ss.cpType)); err != nil {
2016-09-02 22:05:09 +00:00
if err == io.EOF {
return err
}
if err == io.ErrUnexpectedEOF {
err = Errorf(codes.Internal, io.ErrUnexpectedEOF.Error())
}
return toRPCErr(err)
}
2016-11-16 23:22:54 +00:00
if inPayload != nil {
2017-01-13 14:06:34 +00:00
ss.statsHandler.HandleRPC(ss.s.Context(), inPayload)
2016-11-16 23:22:54 +00:00
}
2016-09-02 22:05:09 +00:00
return nil
2016-08-19 15:03:53 +00:00
}
2017-10-27 19:06:04 +00:00
// MethodFromServerStream returns the method string for the input stream.
// The returned string is in the format of "/service/method".
func MethodFromServerStream(stream ServerStream) (string, bool) {
s, ok := transport.StreamFromContext(stream.Context())
if !ok {
return "", ok
}
return s.Method(), ok
}