|
|
|
@ -30,6 +30,7 @@ |
|
|
|
|
|
|
|
|
|
namespace grpc { |
|
|
|
|
|
|
|
|
|
namespace internal { |
|
|
|
|
/// Common interface for all synchronous client side streaming.
|
|
|
|
|
class ClientStreamingInterface { |
|
|
|
|
public: |
|
|
|
@ -141,10 +142,12 @@ class WriterInterface { |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
} // namespace internal
|
|
|
|
|
|
|
|
|
|
/// Client-side interface for streaming reads of message of type \a R.
|
|
|
|
|
template <class R> |
|
|
|
|
class ClientReaderInterface : public ClientStreamingInterface, |
|
|
|
|
public ReaderInterface<R> { |
|
|
|
|
class ClientReaderInterface : public internal::ClientStreamingInterface, |
|
|
|
|
public internal::ReaderInterface<R> { |
|
|
|
|
public: |
|
|
|
|
/// Block to wait for initial metadata from server. The received metadata
|
|
|
|
|
/// can only be accessed after this call returns. Should only be called before
|
|
|
|
@ -153,35 +156,25 @@ class ClientReaderInterface : public ClientStreamingInterface, |
|
|
|
|
virtual void WaitForInitialMetadata() = 0; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
namespace internal { |
|
|
|
|
template <class R> |
|
|
|
|
class ClientReaderFactory { |
|
|
|
|
public: |
|
|
|
|
template <class W> |
|
|
|
|
static ClientReader<R>* Create(ChannelInterface* channel, |
|
|
|
|
const ::grpc::internal::RpcMethod& method, |
|
|
|
|
ClientContext* context, const W& request) { |
|
|
|
|
return new ClientReader<R>(channel, method, context, request); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
} // namespace internal
|
|
|
|
|
|
|
|
|
|
/// Synchronous (blocking) client-side API for doing server-streaming RPCs,
|
|
|
|
|
/// where the stream of messages coming from the server has messages
|
|
|
|
|
/// of type \a R.
|
|
|
|
|
template <class R> |
|
|
|
|
class ClientReader final : public ClientReaderInterface<R> { |
|
|
|
|
public: |
|
|
|
|
/// Block to create a stream and write the initial metadata and \a request
|
|
|
|
|
/// out. Note that \a context will be used to fill in custom initial
|
|
|
|
|
/// metadata used to send to the server when starting the call.
|
|
|
|
|
template <class W> |
|
|
|
|
ClientReader(ChannelInterface* channel, const RpcMethod& method, |
|
|
|
|
ClientContext* context, const W& request) |
|
|
|
|
: context_(context), |
|
|
|
|
cq_(grpc_completion_queue_attributes{ |
|
|
|
|
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, |
|
|
|
|
GRPC_CQ_DEFAULT_POLLING}), // Pluckable cq
|
|
|
|
|
call_(channel->CreateCall(method, context, &cq_)) { |
|
|
|
|
CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage, |
|
|
|
|
CallOpClientSendClose> |
|
|
|
|
ops; |
|
|
|
|
ops.SendInitialMetadata(context->send_initial_metadata_, |
|
|
|
|
context->initial_metadata_flags()); |
|
|
|
|
// TODO(ctiller): don't assert
|
|
|
|
|
GPR_CODEGEN_ASSERT(ops.SendMessage(request).ok()); |
|
|
|
|
ops.ClientSendClose(); |
|
|
|
|
call_.PerformOps(&ops); |
|
|
|
|
cq_.Pluck(&ops); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// See the \a ClientStreamingInterface.WaitForInitialMetadata method for
|
|
|
|
|
/// semantics.
|
|
|
|
|
///
|
|
|
|
@ -192,7 +185,8 @@ class ClientReader final : public ClientReaderInterface<R> { |
|
|
|
|
void WaitForInitialMetadata() override { |
|
|
|
|
GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_); |
|
|
|
|
|
|
|
|
|
CallOpSet<CallOpRecvInitialMetadata> ops; |
|
|
|
|
::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata> |
|
|
|
|
ops; |
|
|
|
|
ops.RecvInitialMetadata(context_); |
|
|
|
|
call_.PerformOps(&ops); |
|
|
|
|
cq_.Pluck(&ops); /// status ignored
|
|
|
|
@ -209,7 +203,9 @@ class ClientReader final : public ClientReaderInterface<R> { |
|
|
|
|
/// already received (if initial metadata is received, it can be then
|
|
|
|
|
/// accessed through the \a ClientContext associated with this call).
|
|
|
|
|
bool Read(R* msg) override { |
|
|
|
|
CallOpSet<CallOpRecvInitialMetadata, CallOpRecvMessage<R>> ops; |
|
|
|
|
::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, |
|
|
|
|
::grpc::internal::CallOpRecvMessage<R>> |
|
|
|
|
ops; |
|
|
|
|
if (!context_->initial_metadata_received_) { |
|
|
|
|
ops.RecvInitialMetadata(context_); |
|
|
|
|
} |
|
|
|
@ -224,7 +220,7 @@ class ClientReader final : public ClientReaderInterface<R> { |
|
|
|
|
/// The \a ClientContext associated with this call is updated with
|
|
|
|
|
/// possible metadata received from the server.
|
|
|
|
|
Status Finish() override { |
|
|
|
|
CallOpSet<CallOpClientRecvStatus> ops; |
|
|
|
|
::grpc::internal::CallOpSet<::grpc::internal::CallOpClientRecvStatus> ops; |
|
|
|
|
Status status; |
|
|
|
|
ops.ClientRecvStatus(context_, &status); |
|
|
|
|
call_.PerformOps(&ops); |
|
|
|
@ -233,15 +229,41 @@ class ClientReader final : public ClientReaderInterface<R> { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
friend class internal::ClientReaderFactory<R>; |
|
|
|
|
ClientContext* context_; |
|
|
|
|
CompletionQueue cq_; |
|
|
|
|
Call call_; |
|
|
|
|
::grpc::internal::Call call_; |
|
|
|
|
|
|
|
|
|
/// Block to create a stream and write the initial metadata and \a request
|
|
|
|
|
/// out. Note that \a context will be used to fill in custom initial
|
|
|
|
|
/// metadata used to send to the server when starting the call.
|
|
|
|
|
template <class W> |
|
|
|
|
ClientReader(::grpc::ChannelInterface* channel, |
|
|
|
|
const ::grpc::internal::RpcMethod& method, |
|
|
|
|
ClientContext* context, const W& request) |
|
|
|
|
: context_(context), |
|
|
|
|
cq_(grpc_completion_queue_attributes{ |
|
|
|
|
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, |
|
|
|
|
GRPC_CQ_DEFAULT_POLLING}), // Pluckable cq
|
|
|
|
|
call_(channel->CreateCall(method, context, &cq_)) { |
|
|
|
|
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, |
|
|
|
|
::grpc::internal::CallOpSendMessage, |
|
|
|
|
::grpc::internal::CallOpClientSendClose> |
|
|
|
|
ops; |
|
|
|
|
ops.SendInitialMetadata(context->send_initial_metadata_, |
|
|
|
|
context->initial_metadata_flags()); |
|
|
|
|
// TODO(ctiller): don't assert
|
|
|
|
|
GPR_CODEGEN_ASSERT(ops.SendMessage(request).ok()); |
|
|
|
|
ops.ClientSendClose(); |
|
|
|
|
call_.PerformOps(&ops); |
|
|
|
|
cq_.Pluck(&ops); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
/// Client-side interface for streaming writes of message type \a W.
|
|
|
|
|
template <class W> |
|
|
|
|
class ClientWriterInterface : public ClientStreamingInterface, |
|
|
|
|
public WriterInterface<W> { |
|
|
|
|
class ClientWriterInterface : public internal::ClientStreamingInterface, |
|
|
|
|
public internal::WriterInterface<W> { |
|
|
|
|
public: |
|
|
|
|
/// Half close writing from the client. (signal that the stream of messages
|
|
|
|
|
/// coming from the client is complete).
|
|
|
|
@ -252,37 +274,25 @@ class ClientWriterInterface : public ClientStreamingInterface, |
|
|
|
|
virtual bool WritesDone() = 0; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
namespace internal { |
|
|
|
|
template <class W> |
|
|
|
|
class ClientWriterFactory { |
|
|
|
|
public: |
|
|
|
|
template <class R> |
|
|
|
|
static ClientWriter<W>* Create(::grpc::ChannelInterface* channel, |
|
|
|
|
const ::grpc::internal::RpcMethod& method, |
|
|
|
|
ClientContext* context, R* response) { |
|
|
|
|
return new ClientWriter<W>(channel, method, context, response); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
} // namespace internal
|
|
|
|
|
|
|
|
|
|
/// Synchronous (blocking) client-side API for doing client-streaming RPCs,
|
|
|
|
|
/// where the outgoing message stream coming from the client has messages of
|
|
|
|
|
/// type \a W.
|
|
|
|
|
template <class W> |
|
|
|
|
class ClientWriter : public ClientWriterInterface<W> { |
|
|
|
|
public: |
|
|
|
|
/// Block to create a stream (i.e. send request headers and other initial
|
|
|
|
|
/// metadata to the server). Note that \a context will be used to fill
|
|
|
|
|
/// in custom initial metadata. \a response will be filled in with the
|
|
|
|
|
/// single expected response message from the server upon a successful
|
|
|
|
|
/// call to the \a Finish method of this instance.
|
|
|
|
|
template <class R> |
|
|
|
|
ClientWriter(ChannelInterface* channel, const RpcMethod& method, |
|
|
|
|
ClientContext* context, R* response) |
|
|
|
|
: context_(context), |
|
|
|
|
cq_(grpc_completion_queue_attributes{ |
|
|
|
|
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, |
|
|
|
|
GRPC_CQ_DEFAULT_POLLING}), // Pluckable cq
|
|
|
|
|
call_(channel->CreateCall(method, context, &cq_)) { |
|
|
|
|
finish_ops_.RecvMessage(response); |
|
|
|
|
finish_ops_.AllowNoMessage(); |
|
|
|
|
|
|
|
|
|
if (!context_->initial_metadata_corked_) { |
|
|
|
|
CallOpSet<CallOpSendInitialMetadata> ops; |
|
|
|
|
ops.SendInitialMetadata(context->send_initial_metadata_, |
|
|
|
|
context->initial_metadata_flags()); |
|
|
|
|
call_.PerformOps(&ops); |
|
|
|
|
cq_.Pluck(&ops); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// See the \a ClientStreamingInterface.WaitForInitialMetadata method for
|
|
|
|
|
/// semantics.
|
|
|
|
|
///
|
|
|
|
@ -292,7 +302,8 @@ class ClientWriter : public ClientWriterInterface<W> { |
|
|
|
|
void WaitForInitialMetadata() { |
|
|
|
|
GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_); |
|
|
|
|
|
|
|
|
|
CallOpSet<CallOpRecvInitialMetadata> ops; |
|
|
|
|
::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata> |
|
|
|
|
ops; |
|
|
|
|
ops.RecvInitialMetadata(context_); |
|
|
|
|
call_.PerformOps(&ops); |
|
|
|
|
cq_.Pluck(&ops); // status ignored
|
|
|
|
@ -304,10 +315,11 @@ class ClientWriter : public ClientWriterInterface<W> { |
|
|
|
|
/// Side effect:
|
|
|
|
|
/// Also sends initial metadata if not already sent (using the
|
|
|
|
|
/// \a ClientContext associated with this call).
|
|
|
|
|
using WriterInterface<W>::Write; |
|
|
|
|
using ::grpc::internal::WriterInterface<W>::Write; |
|
|
|
|
bool Write(const W& msg, WriteOptions options) override { |
|
|
|
|
CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage, |
|
|
|
|
CallOpClientSendClose> |
|
|
|
|
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, |
|
|
|
|
::grpc::internal::CallOpSendMessage, |
|
|
|
|
::grpc::internal::CallOpClientSendClose> |
|
|
|
|
ops; |
|
|
|
|
|
|
|
|
|
if (options.is_last_message()) { |
|
|
|
@ -328,7 +340,7 @@ class ClientWriter : public ClientWriterInterface<W> { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool WritesDone() override { |
|
|
|
|
CallOpSet<CallOpClientSendClose> ops; |
|
|
|
|
::grpc::internal::CallOpSet<::grpc::internal::CallOpClientSendClose> ops; |
|
|
|
|
ops.ClientSendClose(); |
|
|
|
|
call_.PerformOps(&ops); |
|
|
|
|
return cq_.Pluck(&ops); |
|
|
|
@ -352,21 +364,51 @@ class ClientWriter : public ClientWriterInterface<W> { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
friend class internal::ClientWriterFactory<W>; |
|
|
|
|
|
|
|
|
|
/// Block to create a stream (i.e. send request headers and other initial
|
|
|
|
|
/// metadata to the server). Note that \a context will be used to fill
|
|
|
|
|
/// in custom initial metadata. \a response will be filled in with the
|
|
|
|
|
/// single expected response message from the server upon a successful
|
|
|
|
|
/// call to the \a Finish method of this instance.
|
|
|
|
|
template <class R> |
|
|
|
|
ClientWriter(ChannelInterface* channel, |
|
|
|
|
const ::grpc::internal::RpcMethod& method, |
|
|
|
|
ClientContext* context, R* response) |
|
|
|
|
: context_(context), |
|
|
|
|
cq_(grpc_completion_queue_attributes{ |
|
|
|
|
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, |
|
|
|
|
GRPC_CQ_DEFAULT_POLLING}), // Pluckable cq
|
|
|
|
|
call_(channel->CreateCall(method, context, &cq_)) { |
|
|
|
|
finish_ops_.RecvMessage(response); |
|
|
|
|
finish_ops_.AllowNoMessage(); |
|
|
|
|
|
|
|
|
|
if (!context_->initial_metadata_corked_) { |
|
|
|
|
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata> |
|
|
|
|
ops; |
|
|
|
|
ops.SendInitialMetadata(context->send_initial_metadata_, |
|
|
|
|
context->initial_metadata_flags()); |
|
|
|
|
call_.PerformOps(&ops); |
|
|
|
|
cq_.Pluck(&ops); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ClientContext* context_; |
|
|
|
|
CallOpSet<CallOpRecvInitialMetadata, CallOpGenericRecvMessage, |
|
|
|
|
CallOpClientRecvStatus> |
|
|
|
|
::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, |
|
|
|
|
::grpc::internal::CallOpGenericRecvMessage, |
|
|
|
|
::grpc::internal::CallOpClientRecvStatus> |
|
|
|
|
finish_ops_; |
|
|
|
|
CompletionQueue cq_; |
|
|
|
|
Call call_; |
|
|
|
|
::grpc::internal::Call call_; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
/// Client-side interface for bi-directional streaming with
|
|
|
|
|
/// client-to-server stream messages of type \a W and
|
|
|
|
|
/// server-to-client stream messages of type \a R.
|
|
|
|
|
template <class W, class R> |
|
|
|
|
class ClientReaderWriterInterface : public ClientStreamingInterface, |
|
|
|
|
public WriterInterface<W>, |
|
|
|
|
public ReaderInterface<R> { |
|
|
|
|
class ClientReaderWriterInterface : public internal::ClientStreamingInterface, |
|
|
|
|
public internal::WriterInterface<W>, |
|
|
|
|
public internal::ReaderInterface<R> { |
|
|
|
|
public: |
|
|
|
|
/// Block to wait for initial metadata from server. The received metadata
|
|
|
|
|
/// can only be accessed after this call returns. Should only be called before
|
|
|
|
@ -375,7 +417,7 @@ class ClientReaderWriterInterface : public ClientStreamingInterface, |
|
|
|
|
virtual void WaitForInitialMetadata() = 0; |
|
|
|
|
|
|
|
|
|
/// Half close writing from the client. (signal that the stream of messages
|
|
|
|
|
/// coming from the client is complete).
|
|
|
|
|
/// coming from the clinet is complete).
|
|
|
|
|
/// Blocks until currently-pending writes are completed.
|
|
|
|
|
/// Thread-safe with respect to \a ReaderInterface::Read
|
|
|
|
|
///
|
|
|
|
@ -383,6 +425,18 @@ class ClientReaderWriterInterface : public ClientStreamingInterface, |
|
|
|
|
virtual bool WritesDone() = 0; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
namespace internal { |
|
|
|
|
template <class W, class R> |
|
|
|
|
class ClientReaderWriterFactory { |
|
|
|
|
public: |
|
|
|
|
static ClientReaderWriter<W, R>* Create( |
|
|
|
|
::grpc::ChannelInterface* channel, |
|
|
|
|
const ::grpc::internal::RpcMethod& method, ClientContext* context) { |
|
|
|
|
return new ClientReaderWriter<W, R>(channel, method, context); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
} // namespace internal
|
|
|
|
|
|
|
|
|
|
/// Synchronous (blocking) client-side API for bi-directional streaming RPCs,
|
|
|
|
|
/// where the outgoing message stream coming from the client has messages of
|
|
|
|
|
/// type \a W, and the incoming messages stream coming from the server has
|
|
|
|
@ -390,25 +444,6 @@ class ClientReaderWriterInterface : public ClientStreamingInterface, |
|
|
|
|
template <class W, class R> |
|
|
|
|
class ClientReaderWriter final : public ClientReaderWriterInterface<W, R> { |
|
|
|
|
public: |
|
|
|
|
/// Block to create a stream and write the initial metadata and \a request
|
|
|
|
|
/// out. Note that \a context will be used to fill in custom initial metadata
|
|
|
|
|
/// used to send to the server when starting the call.
|
|
|
|
|
ClientReaderWriter(ChannelInterface* channel, const RpcMethod& method, |
|
|
|
|
ClientContext* context) |
|
|
|
|
: context_(context), |
|
|
|
|
cq_(grpc_completion_queue_attributes{ |
|
|
|
|
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, |
|
|
|
|
GRPC_CQ_DEFAULT_POLLING}), // Pluckable cq
|
|
|
|
|
call_(channel->CreateCall(method, context, &cq_)) { |
|
|
|
|
if (!context_->initial_metadata_corked_) { |
|
|
|
|
CallOpSet<CallOpSendInitialMetadata> ops; |
|
|
|
|
ops.SendInitialMetadata(context->send_initial_metadata_, |
|
|
|
|
context->initial_metadata_flags()); |
|
|
|
|
call_.PerformOps(&ops); |
|
|
|
|
cq_.Pluck(&ops); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Block waiting to read initial metadata from the server.
|
|
|
|
|
/// This call is optional, but if it is used, it cannot be used concurrently
|
|
|
|
|
/// with or after the \a Finish method.
|
|
|
|
@ -418,7 +453,8 @@ class ClientReaderWriter final : public ClientReaderWriterInterface<W, R> { |
|
|
|
|
void WaitForInitialMetadata() override { |
|
|
|
|
GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_); |
|
|
|
|
|
|
|
|
|
CallOpSet<CallOpRecvInitialMetadata> ops; |
|
|
|
|
::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata> |
|
|
|
|
ops; |
|
|
|
|
ops.RecvInitialMetadata(context_); |
|
|
|
|
call_.PerformOps(&ops); |
|
|
|
|
cq_.Pluck(&ops); // status ignored
|
|
|
|
@ -434,7 +470,9 @@ class ClientReaderWriter final : public ClientReaderWriterInterface<W, R> { |
|
|
|
|
/// Also receives initial metadata if not already received (updates the \a
|
|
|
|
|
/// ClientContext associated with this call in that case).
|
|
|
|
|
bool Read(R* msg) override { |
|
|
|
|
CallOpSet<CallOpRecvInitialMetadata, CallOpRecvMessage<R>> ops; |
|
|
|
|
::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, |
|
|
|
|
::grpc::internal::CallOpRecvMessage<R>> |
|
|
|
|
ops; |
|
|
|
|
if (!context_->initial_metadata_received_) { |
|
|
|
|
ops.RecvInitialMetadata(context_); |
|
|
|
|
} |
|
|
|
@ -448,10 +486,11 @@ class ClientReaderWriter final : public ClientReaderWriterInterface<W, R> { |
|
|
|
|
/// Side effect:
|
|
|
|
|
/// Also sends initial metadata if not already sent (using the
|
|
|
|
|
/// \a ClientContext associated with this call to fill in values).
|
|
|
|
|
using WriterInterface<W>::Write; |
|
|
|
|
using ::grpc::internal::WriterInterface<W>::Write; |
|
|
|
|
bool Write(const W& msg, WriteOptions options) override { |
|
|
|
|
CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage, |
|
|
|
|
CallOpClientSendClose> |
|
|
|
|
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, |
|
|
|
|
::grpc::internal::CallOpSendMessage, |
|
|
|
|
::grpc::internal::CallOpClientSendClose> |
|
|
|
|
ops; |
|
|
|
|
|
|
|
|
|
if (options.is_last_message()) { |
|
|
|
@ -472,7 +511,7 @@ class ClientReaderWriter final : public ClientReaderWriterInterface<W, R> { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool WritesDone() override { |
|
|
|
|
CallOpSet<CallOpClientSendClose> ops; |
|
|
|
|
::grpc::internal::CallOpSet<::grpc::internal::CallOpClientSendClose> ops; |
|
|
|
|
ops.ClientSendClose(); |
|
|
|
|
call_.PerformOps(&ops); |
|
|
|
|
return cq_.Pluck(&ops); |
|
|
|
@ -484,7 +523,9 @@ class ClientReaderWriter final : public ClientReaderWriterInterface<W, R> { |
|
|
|
|
/// - the \a ClientContext associated with this call is updated with
|
|
|
|
|
/// possible trailing metadata sent from the server.
|
|
|
|
|
Status Finish() override { |
|
|
|
|
CallOpSet<CallOpRecvInitialMetadata, CallOpClientRecvStatus> ops; |
|
|
|
|
::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, |
|
|
|
|
::grpc::internal::CallOpClientRecvStatus> |
|
|
|
|
ops; |
|
|
|
|
if (!context_->initial_metadata_received_) { |
|
|
|
|
ops.RecvInitialMetadata(context_); |
|
|
|
|
} |
|
|
|
@ -496,15 +537,38 @@ class ClientReaderWriter final : public ClientReaderWriterInterface<W, R> { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
friend class internal::ClientReaderWriterFactory<W, R>; |
|
|
|
|
|
|
|
|
|
ClientContext* context_; |
|
|
|
|
CompletionQueue cq_; |
|
|
|
|
Call call_; |
|
|
|
|
::grpc::internal::Call call_; |
|
|
|
|
|
|
|
|
|
/// Block to create a stream and write the initial metadata and \a request
|
|
|
|
|
/// out. Note that \a context will be used to fill in custom initial metadata
|
|
|
|
|
/// used to send to the server when starting the call.
|
|
|
|
|
ClientReaderWriter(::grpc::ChannelInterface* channel, |
|
|
|
|
const ::grpc::internal::RpcMethod& method, |
|
|
|
|
ClientContext* context) |
|
|
|
|
: context_(context), |
|
|
|
|
cq_(grpc_completion_queue_attributes{ |
|
|
|
|
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, |
|
|
|
|
GRPC_CQ_DEFAULT_POLLING}), // Pluckable cq
|
|
|
|
|
call_(channel->CreateCall(method, context, &cq_)) { |
|
|
|
|
if (!context_->initial_metadata_corked_) { |
|
|
|
|
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata> |
|
|
|
|
ops; |
|
|
|
|
ops.SendInitialMetadata(context->send_initial_metadata_, |
|
|
|
|
context->initial_metadata_flags()); |
|
|
|
|
call_.PerformOps(&ops); |
|
|
|
|
cq_.Pluck(&ops); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
/// Server-side interface for streaming reads of message of type \a R.
|
|
|
|
|
template <class R> |
|
|
|
|
class ServerReaderInterface : public ServerStreamingInterface, |
|
|
|
|
public ReaderInterface<R> {}; |
|
|
|
|
class ServerReaderInterface : public internal::ServerStreamingInterface, |
|
|
|
|
public internal::ReaderInterface<R> {}; |
|
|
|
|
|
|
|
|
|
/// Synchronous (blocking) server-side API for doing client-streaming RPCs,
|
|
|
|
|
/// where the incoming message stream coming from the client has messages of
|
|
|
|
@ -512,15 +576,13 @@ class ServerReaderInterface : public ServerStreamingInterface, |
|
|
|
|
template <class R> |
|
|
|
|
class ServerReader final : public ServerReaderInterface<R> { |
|
|
|
|
public: |
|
|
|
|
ServerReader(Call* call, ServerContext* ctx) : call_(call), ctx_(ctx) {} |
|
|
|
|
|
|
|
|
|
/// See the \a ServerStreamingInterface.SendInitialMetadata method
|
|
|
|
|
/// for semantics. Note that initial metadata will be affected by the
|
|
|
|
|
/// \a ServerContext associated with this call.
|
|
|
|
|
void SendInitialMetadata() override { |
|
|
|
|
GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); |
|
|
|
|
|
|
|
|
|
CallOpSet<CallOpSendInitialMetadata> ops; |
|
|
|
|
internal::CallOpSet<internal::CallOpSendInitialMetadata> ops; |
|
|
|
|
ops.SendInitialMetadata(ctx_->initial_metadata_, |
|
|
|
|
ctx_->initial_metadata_flags()); |
|
|
|
|
if (ctx_->compression_level_set()) { |
|
|
|
@ -537,21 +599,27 @@ class ServerReader final : public ServerReaderInterface<R> { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool Read(R* msg) override { |
|
|
|
|
CallOpSet<CallOpRecvMessage<R>> ops; |
|
|
|
|
internal::CallOpSet<internal::CallOpRecvMessage<R>> ops; |
|
|
|
|
ops.RecvMessage(msg); |
|
|
|
|
call_->PerformOps(&ops); |
|
|
|
|
return call_->cq()->Pluck(&ops) && ops.got_message; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
Call* const call_; |
|
|
|
|
internal::Call* const call_; |
|
|
|
|
ServerContext* const ctx_; |
|
|
|
|
|
|
|
|
|
template <class ServiceType, class RequestType, class ResponseType> |
|
|
|
|
friend class internal::ClientStreamingHandler; |
|
|
|
|
|
|
|
|
|
ServerReader(internal::Call* call, ServerContext* ctx) |
|
|
|
|
: call_(call), ctx_(ctx) {} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
/// Server-side interface for streaming writes of message of type \a W.
|
|
|
|
|
template <class W> |
|
|
|
|
class ServerWriterInterface : public ServerStreamingInterface, |
|
|
|
|
public WriterInterface<W> {}; |
|
|
|
|
class ServerWriterInterface : public internal::ServerStreamingInterface, |
|
|
|
|
public internal::WriterInterface<W> {}; |
|
|
|
|
|
|
|
|
|
/// Synchronous (blocking) server-side API for doing for doing a
|
|
|
|
|
/// server-streaming RPCs, where the outgoing message stream coming from the
|
|
|
|
@ -559,8 +627,6 @@ class ServerWriterInterface : public ServerStreamingInterface, |
|
|
|
|
template <class W> |
|
|
|
|
class ServerWriter final : public ServerWriterInterface<W> { |
|
|
|
|
public: |
|
|
|
|
ServerWriter(Call* call, ServerContext* ctx) : call_(call), ctx_(ctx) {} |
|
|
|
|
|
|
|
|
|
/// See the \a ServerStreamingInterface.SendInitialMetadata method
|
|
|
|
|
/// for semantics.
|
|
|
|
|
/// Note that initial metadata will be affected by the
|
|
|
|
@ -568,7 +634,7 @@ class ServerWriter final : public ServerWriterInterface<W> { |
|
|
|
|
void SendInitialMetadata() override { |
|
|
|
|
GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); |
|
|
|
|
|
|
|
|
|
CallOpSet<CallOpSendInitialMetadata> ops; |
|
|
|
|
internal::CallOpSet<internal::CallOpSendInitialMetadata> ops; |
|
|
|
|
ops.SendInitialMetadata(ctx_->initial_metadata_, |
|
|
|
|
ctx_->initial_metadata_flags()); |
|
|
|
|
if (ctx_->compression_level_set()) { |
|
|
|
@ -584,11 +650,12 @@ class ServerWriter final : public ServerWriterInterface<W> { |
|
|
|
|
/// Side effect:
|
|
|
|
|
/// Also sends initial metadata if not already sent (using the
|
|
|
|
|
/// \a ClientContext associated with this call to fill in values).
|
|
|
|
|
using WriterInterface<W>::Write; |
|
|
|
|
using internal::WriterInterface<W>::Write; |
|
|
|
|
bool Write(const W& msg, WriteOptions options) override { |
|
|
|
|
if (options.is_last_message()) { |
|
|
|
|
options.set_buffer_hint(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!ctx_->pending_ops_.SendMessage(msg, options).ok()) { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
@ -613,15 +680,21 @@ class ServerWriter final : public ServerWriterInterface<W> { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
Call* const call_; |
|
|
|
|
internal::Call* const call_; |
|
|
|
|
ServerContext* const ctx_; |
|
|
|
|
|
|
|
|
|
template <class ServiceType, class RequestType, class ResponseType> |
|
|
|
|
friend class internal::ServerStreamingHandler; |
|
|
|
|
|
|
|
|
|
ServerWriter(internal::Call* call, ServerContext* ctx) |
|
|
|
|
: call_(call), ctx_(ctx) {} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
/// Server-side interface for bi-directional streaming.
|
|
|
|
|
template <class W, class R> |
|
|
|
|
class ServerReaderWriterInterface : public ServerStreamingInterface, |
|
|
|
|
public WriterInterface<W>, |
|
|
|
|
public ReaderInterface<R> {}; |
|
|
|
|
class ServerReaderWriterInterface : public internal::ServerStreamingInterface, |
|
|
|
|
public internal::WriterInterface<W>, |
|
|
|
|
public internal::ReaderInterface<R> {}; |
|
|
|
|
|
|
|
|
|
/// Actual implementation of bi-directional streaming
|
|
|
|
|
namespace internal { |
|
|
|
@ -688,6 +761,7 @@ class ServerReaderWriterBody final { |
|
|
|
|
Call* const call_; |
|
|
|
|
ServerContext* const ctx_; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
} // namespace internal
|
|
|
|
|
|
|
|
|
|
/// Synchronous (blocking) server-side API for a bidirectional
|
|
|
|
@ -697,8 +771,6 @@ class ServerReaderWriterBody final { |
|
|
|
|
template <class W, class R> |
|
|
|
|
class ServerReaderWriter final : public ServerReaderWriterInterface<W, R> { |
|
|
|
|
public: |
|
|
|
|
ServerReaderWriter(Call* call, ServerContext* ctx) : body_(call, ctx) {} |
|
|
|
|
|
|
|
|
|
/// See the \a ServerStreamingInterface.SendInitialMetadata method
|
|
|
|
|
/// for semantics. Note that initial metadata will be affected by the
|
|
|
|
|
/// \a ServerContext associated with this call.
|
|
|
|
@ -715,13 +787,18 @@ class ServerReaderWriter final : public ServerReaderWriterInterface<W, R> { |
|
|
|
|
/// Side effect:
|
|
|
|
|
/// Also sends initial metadata if not already sent (using the \a
|
|
|
|
|
/// ServerContext associated with this call).
|
|
|
|
|
using WriterInterface<W>::Write; |
|
|
|
|
using internal::WriterInterface<W>::Write; |
|
|
|
|
bool Write(const W& msg, WriteOptions options) override { |
|
|
|
|
return body_.Write(msg, options); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
internal::ServerReaderWriterBody<W, R> body_; |
|
|
|
|
|
|
|
|
|
friend class internal::TemplatedBidiStreamingHandler<ServerReaderWriter<W, R>, |
|
|
|
|
false>; |
|
|
|
|
ServerReaderWriter(internal::Call* call, ServerContext* ctx) |
|
|
|
|
: body_(call, ctx) {} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
/// A class to represent a flow-controlled unary call. This is something
|
|
|
|
@ -736,9 +813,6 @@ template <class RequestType, class ResponseType> |
|
|
|
|
class ServerUnaryStreamer final |
|
|
|
|
: public ServerReaderWriterInterface<ResponseType, RequestType> { |
|
|
|
|
public: |
|
|
|
|
ServerUnaryStreamer(Call* call, ServerContext* ctx) |
|
|
|
|
: body_(call, ctx), read_done_(false), write_done_(false) {} |
|
|
|
|
|
|
|
|
|
/// Block to send initial metadata to client.
|
|
|
|
|
/// Implicit input parameter:
|
|
|
|
|
/// - the \a ServerContext associated with this call will be used for
|
|
|
|
@ -775,7 +849,7 @@ class ServerUnaryStreamer final |
|
|
|
|
/// \param options The WriteOptions affecting the write operation.
|
|
|
|
|
///
|
|
|
|
|
/// \return \a true on success, \a false when the stream has been closed.
|
|
|
|
|
using WriterInterface<ResponseType>::Write; |
|
|
|
|
using internal::WriterInterface<ResponseType>::Write; |
|
|
|
|
bool Write(const ResponseType& response, WriteOptions options) override { |
|
|
|
|
if (write_done_ || !read_done_) { |
|
|
|
|
return false; |
|
|
|
@ -788,6 +862,11 @@ class ServerUnaryStreamer final |
|
|
|
|
internal::ServerReaderWriterBody<ResponseType, RequestType> body_; |
|
|
|
|
bool read_done_; |
|
|
|
|
bool write_done_; |
|
|
|
|
|
|
|
|
|
friend class internal::TemplatedBidiStreamingHandler< |
|
|
|
|
ServerUnaryStreamer<RequestType, ResponseType>, true>; |
|
|
|
|
ServerUnaryStreamer(internal::Call* call, ServerContext* ctx) |
|
|
|
|
: body_(call, ctx), read_done_(false), write_done_(false) {} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
/// A class to represent a flow-controlled server-side streaming call.
|
|
|
|
@ -799,9 +878,6 @@ template <class RequestType, class ResponseType> |
|
|
|
|
class ServerSplitStreamer final |
|
|
|
|
: public ServerReaderWriterInterface<ResponseType, RequestType> { |
|
|
|
|
public: |
|
|
|
|
ServerSplitStreamer(Call* call, ServerContext* ctx) |
|
|
|
|
: body_(call, ctx), read_done_(false) {} |
|
|
|
|
|
|
|
|
|
/// Block to send initial metadata to client.
|
|
|
|
|
/// Implicit input parameter:
|
|
|
|
|
/// - the \a ServerContext associated with this call will be used for
|
|
|
|
@ -838,7 +914,7 @@ class ServerSplitStreamer final |
|
|
|
|
/// \param options The WriteOptions affecting the write operation.
|
|
|
|
|
///
|
|
|
|
|
/// \return \a true on success, \a false when the stream has been closed.
|
|
|
|
|
using WriterInterface<ResponseType>::Write; |
|
|
|
|
using internal::WriterInterface<ResponseType>::Write; |
|
|
|
|
bool Write(const ResponseType& response, WriteOptions options) override { |
|
|
|
|
return read_done_ && body_.Write(response, options); |
|
|
|
|
} |
|
|
|
@ -846,6 +922,11 @@ class ServerSplitStreamer final |
|
|
|
|
private: |
|
|
|
|
internal::ServerReaderWriterBody<ResponseType, RequestType> body_; |
|
|
|
|
bool read_done_; |
|
|
|
|
|
|
|
|
|
friend class internal::TemplatedBidiStreamingHandler< |
|
|
|
|
ServerSplitStreamer<RequestType, ResponseType>, false>; |
|
|
|
|
ServerSplitStreamer(internal::Call* call, ServerContext* ctx) |
|
|
|
|
: body_(call, ctx), read_done_(false) {} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
} // namespace grpc
|
|
|
|
|