package client import ( "context" "time" "google.golang.org/grpc" "google.golang.org/protobuf/proto" ) type streamWrapper struct { grpc.ClientStream timeout time.Duration cancel context.CancelFunc } func (w streamWrapper) ReadMessage(m proto.Message) error { return w.withTimeout(func() error { return w.ClientStream.RecvMsg(m) }) } func (w streamWrapper) WriteMessage(m proto.Message) error { return w.withTimeout(func() error { return w.ClientStream.SendMsg(m) }) } func (w *streamWrapper) Close() error { return w.withTimeout(w.ClientStream.CloseSend) } func (w *streamWrapper) withTimeout(closure func() error) error { ch := make(chan error, 1) go func() { ch <- closure() close(ch) }() tt := time.NewTimer(w.timeout) select { case err := <-ch: tt.Stop() return err case <-tt.C: w.cancel() return context.DeadlineExceeded } }