create
This commit is contained in:
1133
Pods/gRPC-C++/include/grpcpp/support/async_stream.h
generated
Normal file
1133
Pods/gRPC-C++/include/grpcpp/support/async_stream.h
generated
Normal file
@@ -0,0 +1,1133 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2015 gRPC 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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef GRPCPP_SUPPORT_ASYNC_STREAM_H
|
||||
#define GRPCPP_SUPPORT_ASYNC_STREAM_H
|
||||
|
||||
#include <grpc/grpc.h>
|
||||
#include <grpc/support/log.h>
|
||||
#include <grpcpp/impl/call.h>
|
||||
#include <grpcpp/impl/channel_interface.h>
|
||||
#include <grpcpp/impl/service_type.h>
|
||||
#include <grpcpp/server_context.h>
|
||||
#include <grpcpp/support/status.h>
|
||||
|
||||
namespace grpc {
|
||||
|
||||
namespace internal {
|
||||
/// Common interface for all client side asynchronous streaming.
|
||||
class ClientAsyncStreamingInterface {
|
||||
public:
|
||||
virtual ~ClientAsyncStreamingInterface() {}
|
||||
|
||||
/// Start the call that was set up by the constructor, but only if the
|
||||
/// constructor was invoked through the "Prepare" API which doesn't actually
|
||||
/// start the call
|
||||
virtual void StartCall(void* tag) = 0;
|
||||
|
||||
/// Request notification of the reading of the initial metadata. Completion
|
||||
/// will be notified by \a tag on the associated completion queue.
|
||||
/// This call is optional, but if it is used, it cannot be used concurrently
|
||||
/// with or after the \a AsyncReaderInterface::Read method.
|
||||
///
|
||||
/// \param[in] tag Tag identifying this request.
|
||||
virtual void ReadInitialMetadata(void* tag) = 0;
|
||||
|
||||
/// Indicate that the stream is to be finished and request notification for
|
||||
/// when the call has been ended.
|
||||
/// Should not be used concurrently with other operations.
|
||||
///
|
||||
/// It is appropriate to call this method exactly once when both:
|
||||
/// * the client side has no more message to send
|
||||
/// (this can be declared implicitly by calling this method, or
|
||||
/// explicitly through an earlier call to the <i>WritesDone</i> method
|
||||
/// of the class in use, e.g. \a ClientAsyncWriterInterface::WritesDone or
|
||||
/// \a ClientAsyncReaderWriterInterface::WritesDone).
|
||||
/// * there are no more messages to be received from the server (this can
|
||||
/// be known implicitly by the calling code, or explicitly from an
|
||||
/// earlier call to \a AsyncReaderInterface::Read that yielded a failed
|
||||
/// result, e.g. cq->Next(&read_tag, &ok) filled in 'ok' with 'false').
|
||||
///
|
||||
/// The tag will be returned when either:
|
||||
/// - all incoming messages have been read and the server has returned
|
||||
/// a status.
|
||||
/// - the server has returned a non-OK status.
|
||||
/// - the call failed for some reason and the library generated a
|
||||
/// status.
|
||||
///
|
||||
/// Note that implementations of this method attempt to receive initial
|
||||
/// metadata from the server if initial metadata hasn't yet been received.
|
||||
///
|
||||
/// \param[in] tag Tag identifying this request.
|
||||
/// \param[out] status To be updated with the operation status.
|
||||
virtual void Finish(grpc::Status* status, void* tag) = 0;
|
||||
};
|
||||
|
||||
/// An interface that yields a sequence of messages of type \a R.
|
||||
template <class R>
|
||||
class AsyncReaderInterface {
|
||||
public:
|
||||
virtual ~AsyncReaderInterface() {}
|
||||
|
||||
/// Read a message of type \a R into \a msg. Completion will be notified by \a
|
||||
/// tag on the associated completion queue.
|
||||
/// This is thread-safe with respect to \a Write or \a WritesDone methods. It
|
||||
/// should not be called concurrently with other streaming APIs
|
||||
/// on the same stream. It is not meaningful to call it concurrently
|
||||
/// with another \a AsyncReaderInterface::Read on the same stream since reads
|
||||
/// on the same stream are delivered in order.
|
||||
///
|
||||
/// \param[out] msg Where to eventually store the read message.
|
||||
/// \param[in] tag The tag identifying the operation.
|
||||
///
|
||||
/// Side effect: note that this method attempt to receive initial metadata for
|
||||
/// a stream if it hasn't yet been received.
|
||||
virtual void Read(R* msg, void* tag) = 0;
|
||||
};
|
||||
|
||||
/// An interface that can be fed a sequence of messages of type \a W.
|
||||
template <class W>
|
||||
class AsyncWriterInterface {
|
||||
public:
|
||||
virtual ~AsyncWriterInterface() {}
|
||||
|
||||
/// Request the writing of \a msg with identifying tag \a tag.
|
||||
///
|
||||
/// Only one write may be outstanding at any given time. This means that
|
||||
/// after calling Write, one must wait to receive \a tag from the completion
|
||||
/// queue BEFORE calling Write again.
|
||||
/// This is thread-safe with respect to \a AsyncReaderInterface::Read
|
||||
///
|
||||
/// gRPC doesn't take ownership or a reference to \a msg, so it is safe to
|
||||
/// to deallocate once Write returns.
|
||||
///
|
||||
/// \param[in] msg The message to be written.
|
||||
/// \param[in] tag The tag identifying the operation.
|
||||
virtual void Write(const W& msg, void* tag) = 0;
|
||||
|
||||
/// Request the writing of \a msg using WriteOptions \a options with
|
||||
/// identifying tag \a tag.
|
||||
///
|
||||
/// Only one write may be outstanding at any given time. This means that
|
||||
/// after calling Write, one must wait to receive \a tag from the completion
|
||||
/// queue BEFORE calling Write again.
|
||||
/// WriteOptions \a options is used to set the write options of this message.
|
||||
/// This is thread-safe with respect to \a AsyncReaderInterface::Read
|
||||
///
|
||||
/// gRPC doesn't take ownership or a reference to \a msg, so it is safe to
|
||||
/// to deallocate once Write returns.
|
||||
///
|
||||
/// \param[in] msg The message to be written.
|
||||
/// \param[in] options The WriteOptions to be used to write this message.
|
||||
/// \param[in] tag The tag identifying the operation.
|
||||
virtual void Write(const W& msg, grpc::WriteOptions options, void* tag) = 0;
|
||||
|
||||
/// Request the writing of \a msg and coalesce it with the writing
|
||||
/// of trailing metadata, using WriteOptions \a options with
|
||||
/// identifying tag \a tag.
|
||||
///
|
||||
/// For client, WriteLast is equivalent of performing Write and
|
||||
/// WritesDone in a single step.
|
||||
/// For server, WriteLast buffers the \a msg. The writing of \a msg is held
|
||||
/// until Finish is called, where \a msg and trailing metadata are coalesced
|
||||
/// and write is initiated. Note that WriteLast can only buffer \a msg up to
|
||||
/// the flow control window size. If \a msg size is larger than the window
|
||||
/// size, it will be sent on wire without buffering.
|
||||
///
|
||||
/// gRPC doesn't take ownership or a reference to \a msg, so it is safe to
|
||||
/// to deallocate once Write returns.
|
||||
///
|
||||
/// \param[in] msg The message to be written.
|
||||
/// \param[in] options The WriteOptions to be used to write this message.
|
||||
/// \param[in] tag The tag identifying the operation.
|
||||
void WriteLast(const W& msg, grpc::WriteOptions options, void* tag) {
|
||||
Write(msg, options.set_last_message(), tag);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template <class R>
|
||||
class ClientAsyncReaderInterface
|
||||
: public internal::ClientAsyncStreamingInterface,
|
||||
public internal::AsyncReaderInterface<R> {};
|
||||
|
||||
namespace internal {
|
||||
template <class R>
|
||||
class ClientAsyncReaderFactory {
|
||||
public:
|
||||
/// Create a stream object.
|
||||
/// Write the first request out if \a start is set.
|
||||
/// \a tag will be notified on \a cq when the call has been started and
|
||||
/// \a request has been written out. If \a start is not set, \a tag must be
|
||||
/// nullptr and the actual call must be initiated by StartCall
|
||||
/// 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>
|
||||
static ClientAsyncReader<R>* Create(grpc::ChannelInterface* channel,
|
||||
grpc::CompletionQueue* cq,
|
||||
const grpc::internal::RpcMethod& method,
|
||||
grpc::ClientContext* context,
|
||||
const W& request, bool start, void* tag) {
|
||||
grpc::internal::Call call = channel->CreateCall(method, context, cq);
|
||||
return new (
|
||||
grpc_call_arena_alloc(call.call(), sizeof(ClientAsyncReader<R>)))
|
||||
ClientAsyncReader<R>(call, context, request, start, tag);
|
||||
}
|
||||
};
|
||||
} // namespace internal
|
||||
|
||||
/// Async client-side API for doing server-streaming RPCs,
|
||||
/// where the incoming message stream coming from the server has
|
||||
/// messages of type \a R.
|
||||
template <class R>
|
||||
class ClientAsyncReader final : public ClientAsyncReaderInterface<R> {
|
||||
public:
|
||||
// always allocated against a call arena, no memory free required
|
||||
static void operator delete(void* /*ptr*/, std::size_t size) {
|
||||
GPR_ASSERT(size == sizeof(ClientAsyncReader));
|
||||
}
|
||||
|
||||
// This operator should never be called as the memory should be freed as part
|
||||
// of the arena destruction. It only exists to provide a matching operator
|
||||
// delete to the operator new so that some compilers will not complain (see
|
||||
// https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
|
||||
// there are no tests catching the compiler warning.
|
||||
static void operator delete(void*, void*) { GPR_ASSERT(false); }
|
||||
|
||||
void StartCall(void* tag) override {
|
||||
GPR_ASSERT(!started_);
|
||||
started_ = true;
|
||||
StartCallInternal(tag);
|
||||
}
|
||||
|
||||
/// See the \a ClientAsyncStreamingInterface.ReadInitialMetadata
|
||||
/// method for semantics.
|
||||
///
|
||||
/// Side effect:
|
||||
/// - upon receiving initial metadata from the server,
|
||||
/// the \a ClientContext associated with this call is updated, and the
|
||||
/// calling code can access the received metadata through the
|
||||
/// \a ClientContext.
|
||||
void ReadInitialMetadata(void* tag) override {
|
||||
GPR_ASSERT(started_);
|
||||
GPR_ASSERT(!context_->initial_metadata_received_);
|
||||
|
||||
meta_ops_.set_output_tag(tag);
|
||||
meta_ops_.RecvInitialMetadata(context_);
|
||||
call_.PerformOps(&meta_ops_);
|
||||
}
|
||||
|
||||
void Read(R* msg, void* tag) override {
|
||||
GPR_ASSERT(started_);
|
||||
read_ops_.set_output_tag(tag);
|
||||
if (!context_->initial_metadata_received_) {
|
||||
read_ops_.RecvInitialMetadata(context_);
|
||||
}
|
||||
read_ops_.RecvMessage(msg);
|
||||
call_.PerformOps(&read_ops_);
|
||||
}
|
||||
|
||||
/// See the \a ClientAsyncStreamingInterface.Finish method for semantics.
|
||||
///
|
||||
/// Side effect:
|
||||
/// - the \a ClientContext associated with this call is updated with
|
||||
/// possible initial and trailing metadata received from the server.
|
||||
void Finish(grpc::Status* status, void* tag) override {
|
||||
GPR_ASSERT(started_);
|
||||
finish_ops_.set_output_tag(tag);
|
||||
if (!context_->initial_metadata_received_) {
|
||||
finish_ops_.RecvInitialMetadata(context_);
|
||||
}
|
||||
finish_ops_.ClientRecvStatus(context_, status);
|
||||
call_.PerformOps(&finish_ops_);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class internal::ClientAsyncReaderFactory<R>;
|
||||
template <class W>
|
||||
ClientAsyncReader(grpc::internal::Call call, grpc::ClientContext* context,
|
||||
const W& request, bool start, void* tag)
|
||||
: context_(context), call_(call), started_(start) {
|
||||
// TODO(ctiller): don't assert
|
||||
GPR_ASSERT(init_ops_.SendMessage(request).ok());
|
||||
init_ops_.ClientSendClose();
|
||||
if (start) {
|
||||
StartCallInternal(tag);
|
||||
} else {
|
||||
GPR_ASSERT(tag == nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void StartCallInternal(void* tag) {
|
||||
init_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
|
||||
context_->initial_metadata_flags());
|
||||
init_ops_.set_output_tag(tag);
|
||||
call_.PerformOps(&init_ops_);
|
||||
}
|
||||
|
||||
grpc::ClientContext* context_;
|
||||
grpc::internal::Call call_;
|
||||
bool started_;
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,
|
||||
grpc::internal::CallOpSendMessage,
|
||||
grpc::internal::CallOpClientSendClose>
|
||||
init_ops_;
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpRecvInitialMetadata>
|
||||
meta_ops_;
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpRecvInitialMetadata,
|
||||
grpc::internal::CallOpRecvMessage<R>>
|
||||
read_ops_;
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpRecvInitialMetadata,
|
||||
grpc::internal::CallOpClientRecvStatus>
|
||||
finish_ops_;
|
||||
};
|
||||
|
||||
/// Common interface for client side asynchronous writing.
|
||||
template <class W>
|
||||
class ClientAsyncWriterInterface
|
||||
: public internal::ClientAsyncStreamingInterface,
|
||||
public internal::AsyncWriterInterface<W> {
|
||||
public:
|
||||
/// Signal the client is done with the writes (half-close the client stream).
|
||||
/// Thread-safe with respect to \a AsyncReaderInterface::Read
|
||||
///
|
||||
/// \param[in] tag The tag identifying the operation.
|
||||
virtual void WritesDone(void* tag) = 0;
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
template <class W>
|
||||
class ClientAsyncWriterFactory {
|
||||
public:
|
||||
/// Create a stream object.
|
||||
/// Start the RPC if \a start is set
|
||||
/// \a tag will be notified on \a cq when the call has been started (i.e.
|
||||
/// initial metadata sent) and \a request has been written out.
|
||||
/// If \a start is not set, \a tag must be nullptr and the actual call
|
||||
/// must be initiated by StartCall
|
||||
/// Note that \a context will be used to fill in custom initial metadata
|
||||
/// used to send to the server when starting the call.
|
||||
/// \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>
|
||||
static ClientAsyncWriter<W>* Create(grpc::ChannelInterface* channel,
|
||||
grpc::CompletionQueue* cq,
|
||||
const grpc::internal::RpcMethod& method,
|
||||
grpc::ClientContext* context, R* response,
|
||||
bool start, void* tag) {
|
||||
grpc::internal::Call call = channel->CreateCall(method, context, cq);
|
||||
return new (
|
||||
grpc_call_arena_alloc(call.call(), sizeof(ClientAsyncWriter<W>)))
|
||||
ClientAsyncWriter<W>(call, context, response, start, tag);
|
||||
}
|
||||
};
|
||||
} // namespace internal
|
||||
|
||||
/// Async API on the client side for doing client-streaming RPCs,
|
||||
/// where the outgoing message stream going to the server contains
|
||||
/// messages of type \a W.
|
||||
template <class W>
|
||||
class ClientAsyncWriter final : public ClientAsyncWriterInterface<W> {
|
||||
public:
|
||||
// always allocated against a call arena, no memory free required
|
||||
static void operator delete(void* /*ptr*/, std::size_t size) {
|
||||
GPR_ASSERT(size == sizeof(ClientAsyncWriter));
|
||||
}
|
||||
|
||||
// This operator should never be called as the memory should be freed as part
|
||||
// of the arena destruction. It only exists to provide a matching operator
|
||||
// delete to the operator new so that some compilers will not complain (see
|
||||
// https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
|
||||
// there are no tests catching the compiler warning.
|
||||
static void operator delete(void*, void*) { GPR_ASSERT(false); }
|
||||
|
||||
void StartCall(void* tag) override {
|
||||
GPR_ASSERT(!started_);
|
||||
started_ = true;
|
||||
StartCallInternal(tag);
|
||||
}
|
||||
|
||||
/// See the \a ClientAsyncStreamingInterface.ReadInitialMetadata method for
|
||||
/// semantics.
|
||||
///
|
||||
/// Side effect:
|
||||
/// - upon receiving initial metadata from the server, the \a ClientContext
|
||||
/// associated with this call is updated, and the calling code can access
|
||||
/// the received metadata through the \a ClientContext.
|
||||
void ReadInitialMetadata(void* tag) override {
|
||||
GPR_ASSERT(started_);
|
||||
GPR_ASSERT(!context_->initial_metadata_received_);
|
||||
|
||||
meta_ops_.set_output_tag(tag);
|
||||
meta_ops_.RecvInitialMetadata(context_);
|
||||
call_.PerformOps(&meta_ops_);
|
||||
}
|
||||
|
||||
void Write(const W& msg, void* tag) override {
|
||||
GPR_ASSERT(started_);
|
||||
write_ops_.set_output_tag(tag);
|
||||
// TODO(ctiller): don't assert
|
||||
GPR_ASSERT(write_ops_.SendMessage(msg).ok());
|
||||
call_.PerformOps(&write_ops_);
|
||||
}
|
||||
|
||||
void Write(const W& msg, grpc::WriteOptions options, void* tag) override {
|
||||
GPR_ASSERT(started_);
|
||||
write_ops_.set_output_tag(tag);
|
||||
if (options.is_last_message()) {
|
||||
options.set_buffer_hint();
|
||||
write_ops_.ClientSendClose();
|
||||
}
|
||||
// TODO(ctiller): don't assert
|
||||
GPR_ASSERT(write_ops_.SendMessage(msg, options).ok());
|
||||
call_.PerformOps(&write_ops_);
|
||||
}
|
||||
|
||||
void WritesDone(void* tag) override {
|
||||
GPR_ASSERT(started_);
|
||||
write_ops_.set_output_tag(tag);
|
||||
write_ops_.ClientSendClose();
|
||||
call_.PerformOps(&write_ops_);
|
||||
}
|
||||
|
||||
/// See the \a ClientAsyncStreamingInterface.Finish method for semantics.
|
||||
///
|
||||
/// Side effect:
|
||||
/// - the \a ClientContext associated with this call is updated with
|
||||
/// possible initial and trailing metadata received from the server.
|
||||
/// - attempts to fill in the \a response parameter passed to this class's
|
||||
/// constructor with the server's response message.
|
||||
void Finish(grpc::Status* status, void* tag) override {
|
||||
GPR_ASSERT(started_);
|
||||
finish_ops_.set_output_tag(tag);
|
||||
if (!context_->initial_metadata_received_) {
|
||||
finish_ops_.RecvInitialMetadata(context_);
|
||||
}
|
||||
finish_ops_.ClientRecvStatus(context_, status);
|
||||
call_.PerformOps(&finish_ops_);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class internal::ClientAsyncWriterFactory<W>;
|
||||
template <class R>
|
||||
ClientAsyncWriter(grpc::internal::Call call, grpc::ClientContext* context,
|
||||
R* response, bool start, void* tag)
|
||||
: context_(context), call_(call), started_(start) {
|
||||
finish_ops_.RecvMessage(response);
|
||||
finish_ops_.AllowNoMessage();
|
||||
if (start) {
|
||||
StartCallInternal(tag);
|
||||
} else {
|
||||
GPR_ASSERT(tag == nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void StartCallInternal(void* tag) {
|
||||
write_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
|
||||
context_->initial_metadata_flags());
|
||||
// if corked bit is set in context, we just keep the initial metadata
|
||||
// buffered up to coalesce with later message send. No op is performed.
|
||||
if (!context_->initial_metadata_corked_) {
|
||||
write_ops_.set_output_tag(tag);
|
||||
call_.PerformOps(&write_ops_);
|
||||
}
|
||||
}
|
||||
|
||||
grpc::ClientContext* context_;
|
||||
grpc::internal::Call call_;
|
||||
bool started_;
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpRecvInitialMetadata>
|
||||
meta_ops_;
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,
|
||||
grpc::internal::CallOpSendMessage,
|
||||
grpc::internal::CallOpClientSendClose>
|
||||
write_ops_;
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpRecvInitialMetadata,
|
||||
grpc::internal::CallOpGenericRecvMessage,
|
||||
grpc::internal::CallOpClientRecvStatus>
|
||||
finish_ops_;
|
||||
};
|
||||
|
||||
/// Async client-side interface for bi-directional streaming,
|
||||
/// where the client-to-server message stream has messages of type \a W,
|
||||
/// and the server-to-client message stream has messages of type \a R.
|
||||
template <class W, class R>
|
||||
class ClientAsyncReaderWriterInterface
|
||||
: public internal::ClientAsyncStreamingInterface,
|
||||
public internal::AsyncWriterInterface<W>,
|
||||
public internal::AsyncReaderInterface<R> {
|
||||
public:
|
||||
/// Signal the client is done with the writes (half-close the client stream).
|
||||
/// Thread-safe with respect to \a AsyncReaderInterface::Read
|
||||
///
|
||||
/// \param[in] tag The tag identifying the operation.
|
||||
virtual void WritesDone(void* tag) = 0;
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
template <class W, class R>
|
||||
class ClientAsyncReaderWriterFactory {
|
||||
public:
|
||||
/// Create a stream object.
|
||||
/// Start the RPC request if \a start is set.
|
||||
/// \a tag will be notified on \a cq when the call has been started (i.e.
|
||||
/// initial metadata sent). If \a start is not set, \a tag must be
|
||||
/// nullptr and the actual call must be initiated by StartCall
|
||||
/// Note that \a context will be used to fill in custom initial metadata
|
||||
/// used to send to the server when starting the call.
|
||||
static ClientAsyncReaderWriter<W, R>* Create(
|
||||
grpc::ChannelInterface* channel, grpc::CompletionQueue* cq,
|
||||
const grpc::internal::RpcMethod& method, grpc::ClientContext* context,
|
||||
bool start, void* tag) {
|
||||
grpc::internal::Call call = channel->CreateCall(method, context, cq);
|
||||
|
||||
return new (grpc_call_arena_alloc(call.call(),
|
||||
sizeof(ClientAsyncReaderWriter<W, R>)))
|
||||
ClientAsyncReaderWriter<W, R>(call, context, start, tag);
|
||||
}
|
||||
};
|
||||
} // namespace internal
|
||||
|
||||
/// Async client-side interface for bi-directional streaming,
|
||||
/// where the outgoing message stream going to the server
|
||||
/// has messages of type \a W, and the incoming message stream coming
|
||||
/// from the server has messages of type \a R.
|
||||
template <class W, class R>
|
||||
class ClientAsyncReaderWriter final
|
||||
: public ClientAsyncReaderWriterInterface<W, R> {
|
||||
public:
|
||||
// always allocated against a call arena, no memory free required
|
||||
static void operator delete(void* /*ptr*/, std::size_t size) {
|
||||
GPR_ASSERT(size == sizeof(ClientAsyncReaderWriter));
|
||||
}
|
||||
|
||||
// This operator should never be called as the memory should be freed as part
|
||||
// of the arena destruction. It only exists to provide a matching operator
|
||||
// delete to the operator new so that some compilers will not complain (see
|
||||
// https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
|
||||
// there are no tests catching the compiler warning.
|
||||
static void operator delete(void*, void*) { GPR_ASSERT(false); }
|
||||
|
||||
void StartCall(void* tag) override {
|
||||
GPR_ASSERT(!started_);
|
||||
started_ = true;
|
||||
StartCallInternal(tag);
|
||||
}
|
||||
|
||||
/// See the \a ClientAsyncStreamingInterface.ReadInitialMetadata method
|
||||
/// for semantics of this method.
|
||||
///
|
||||
/// Side effect:
|
||||
/// - upon receiving initial metadata from the server, the \a ClientContext
|
||||
/// is updated with it, and then the receiving initial metadata can
|
||||
/// be accessed through this \a ClientContext.
|
||||
void ReadInitialMetadata(void* tag) override {
|
||||
GPR_ASSERT(started_);
|
||||
GPR_ASSERT(!context_->initial_metadata_received_);
|
||||
|
||||
meta_ops_.set_output_tag(tag);
|
||||
meta_ops_.RecvInitialMetadata(context_);
|
||||
call_.PerformOps(&meta_ops_);
|
||||
}
|
||||
|
||||
void Read(R* msg, void* tag) override {
|
||||
GPR_ASSERT(started_);
|
||||
read_ops_.set_output_tag(tag);
|
||||
if (!context_->initial_metadata_received_) {
|
||||
read_ops_.RecvInitialMetadata(context_);
|
||||
}
|
||||
read_ops_.RecvMessage(msg);
|
||||
call_.PerformOps(&read_ops_);
|
||||
}
|
||||
|
||||
void Write(const W& msg, void* tag) override {
|
||||
GPR_ASSERT(started_);
|
||||
write_ops_.set_output_tag(tag);
|
||||
// TODO(ctiller): don't assert
|
||||
GPR_ASSERT(write_ops_.SendMessage(msg).ok());
|
||||
call_.PerformOps(&write_ops_);
|
||||
}
|
||||
|
||||
void Write(const W& msg, grpc::WriteOptions options, void* tag) override {
|
||||
GPR_ASSERT(started_);
|
||||
write_ops_.set_output_tag(tag);
|
||||
if (options.is_last_message()) {
|
||||
options.set_buffer_hint();
|
||||
write_ops_.ClientSendClose();
|
||||
}
|
||||
// TODO(ctiller): don't assert
|
||||
GPR_ASSERT(write_ops_.SendMessage(msg, options).ok());
|
||||
call_.PerformOps(&write_ops_);
|
||||
}
|
||||
|
||||
void WritesDone(void* tag) override {
|
||||
GPR_ASSERT(started_);
|
||||
write_ops_.set_output_tag(tag);
|
||||
write_ops_.ClientSendClose();
|
||||
call_.PerformOps(&write_ops_);
|
||||
}
|
||||
|
||||
/// See the \a ClientAsyncStreamingInterface.Finish method for semantics.
|
||||
/// Side effect
|
||||
/// - the \a ClientContext associated with this call is updated with
|
||||
/// possible initial and trailing metadata sent from the server.
|
||||
void Finish(grpc::Status* status, void* tag) override {
|
||||
GPR_ASSERT(started_);
|
||||
finish_ops_.set_output_tag(tag);
|
||||
if (!context_->initial_metadata_received_) {
|
||||
finish_ops_.RecvInitialMetadata(context_);
|
||||
}
|
||||
finish_ops_.ClientRecvStatus(context_, status);
|
||||
call_.PerformOps(&finish_ops_);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class internal::ClientAsyncReaderWriterFactory<W, R>;
|
||||
ClientAsyncReaderWriter(grpc::internal::Call call,
|
||||
grpc::ClientContext* context, bool start, void* tag)
|
||||
: context_(context), call_(call), started_(start) {
|
||||
if (start) {
|
||||
StartCallInternal(tag);
|
||||
} else {
|
||||
GPR_ASSERT(tag == nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void StartCallInternal(void* tag) {
|
||||
write_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
|
||||
context_->initial_metadata_flags());
|
||||
// if corked bit is set in context, we just keep the initial metadata
|
||||
// buffered up to coalesce with later message send. No op is performed.
|
||||
if (!context_->initial_metadata_corked_) {
|
||||
write_ops_.set_output_tag(tag);
|
||||
call_.PerformOps(&write_ops_);
|
||||
}
|
||||
}
|
||||
|
||||
grpc::ClientContext* context_;
|
||||
grpc::internal::Call call_;
|
||||
bool started_;
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpRecvInitialMetadata>
|
||||
meta_ops_;
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpRecvInitialMetadata,
|
||||
grpc::internal::CallOpRecvMessage<R>>
|
||||
read_ops_;
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,
|
||||
grpc::internal::CallOpSendMessage,
|
||||
grpc::internal::CallOpClientSendClose>
|
||||
write_ops_;
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpRecvInitialMetadata,
|
||||
grpc::internal::CallOpClientRecvStatus>
|
||||
finish_ops_;
|
||||
};
|
||||
|
||||
template <class W, class R>
|
||||
class ServerAsyncReaderInterface
|
||||
: public grpc::internal::ServerAsyncStreamingInterface,
|
||||
public internal::AsyncReaderInterface<R> {
|
||||
public:
|
||||
/// Indicate that the stream is to be finished with a certain status code
|
||||
/// and also send out \a msg response to the client.
|
||||
/// Request notification for when the server has sent the response and the
|
||||
/// appropriate signals to the client to end the call.
|
||||
/// Should not be used concurrently with other operations.
|
||||
///
|
||||
/// It is appropriate to call this method when:
|
||||
/// * all messages from the client have been received (either known
|
||||
/// implicitly, or explicitly because a previous
|
||||
/// \a AsyncReaderInterface::Read operation with a non-ok result,
|
||||
/// e.g., cq->Next(&read_tag, &ok) filled in 'ok' with 'false').
|
||||
///
|
||||
/// This operation will end when the server has finished sending out initial
|
||||
/// metadata (if not sent already), response message, and status, or if
|
||||
/// some failure occurred when trying to do so.
|
||||
///
|
||||
/// gRPC doesn't take ownership or a reference to \a msg or \a status, so it
|
||||
/// is safe to deallocate once Finish returns.
|
||||
///
|
||||
/// \param[in] tag Tag identifying this request.
|
||||
/// \param[in] status To be sent to the client as the result of this call.
|
||||
/// \param[in] msg To be sent to the client as the response for this call.
|
||||
virtual void Finish(const W& msg, const grpc::Status& status, void* tag) = 0;
|
||||
|
||||
/// Indicate that the stream is to be finished with a certain
|
||||
/// non-OK status code.
|
||||
/// Request notification for when the server has sent the appropriate
|
||||
/// signals to the client to end the call.
|
||||
/// Should not be used concurrently with other operations.
|
||||
///
|
||||
/// This call is meant to end the call with some error, and can be called at
|
||||
/// any point that the server would like to "fail" the call (though note
|
||||
/// this shouldn't be called concurrently with any other "sending" call, like
|
||||
/// \a AsyncWriterInterface::Write).
|
||||
///
|
||||
/// This operation will end when the server has finished sending out initial
|
||||
/// metadata (if not sent already), and status, or if some failure occurred
|
||||
/// when trying to do so.
|
||||
///
|
||||
/// gRPC doesn't take ownership or a reference to \a status, so it is safe to
|
||||
/// to deallocate once FinishWithError returns.
|
||||
///
|
||||
/// \param[in] tag Tag identifying this request.
|
||||
/// \param[in] status To be sent to the client as the result of this call.
|
||||
/// - Note: \a status must have a non-OK code.
|
||||
virtual void FinishWithError(const grpc::Status& status, void* tag) = 0;
|
||||
};
|
||||
|
||||
/// Async server-side API for doing client-streaming RPCs,
|
||||
/// where the incoming message stream from the client has messages of type \a R,
|
||||
/// and the single response message sent from the server is type \a W.
|
||||
template <class W, class R>
|
||||
class ServerAsyncReader final : public ServerAsyncReaderInterface<W, R> {
|
||||
public:
|
||||
explicit ServerAsyncReader(grpc::ServerContext* ctx)
|
||||
: call_(nullptr, nullptr, nullptr), ctx_(ctx) {}
|
||||
|
||||
/// See \a ServerAsyncStreamingInterface::SendInitialMetadata for semantics.
|
||||
///
|
||||
/// Implicit input parameter:
|
||||
/// - The initial metadata that will be sent to the client from this op will
|
||||
/// be taken from the \a ServerContext associated with the call.
|
||||
void SendInitialMetadata(void* tag) override {
|
||||
GPR_ASSERT(!ctx_->sent_initial_metadata_);
|
||||
|
||||
meta_ops_.set_output_tag(tag);
|
||||
meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
|
||||
ctx_->initial_metadata_flags());
|
||||
if (ctx_->compression_level_set()) {
|
||||
meta_ops_.set_compression_level(ctx_->compression_level());
|
||||
}
|
||||
ctx_->sent_initial_metadata_ = true;
|
||||
call_.PerformOps(&meta_ops_);
|
||||
}
|
||||
|
||||
void Read(R* msg, void* tag) override {
|
||||
read_ops_.set_output_tag(tag);
|
||||
read_ops_.RecvMessage(msg);
|
||||
call_.PerformOps(&read_ops_);
|
||||
}
|
||||
|
||||
/// See the \a ServerAsyncReaderInterface.Read method for semantics
|
||||
///
|
||||
/// Side effect:
|
||||
/// - also sends initial metadata if not already sent.
|
||||
/// - uses the \a ServerContext associated with this call to send possible
|
||||
/// initial and trailing metadata.
|
||||
///
|
||||
/// Note: \a msg is not sent if \a status has a non-OK code.
|
||||
///
|
||||
/// gRPC doesn't take ownership or a reference to \a msg and \a status, so it
|
||||
/// is safe to deallocate once Finish returns.
|
||||
void Finish(const W& msg, const grpc::Status& status, void* tag) override {
|
||||
finish_ops_.set_output_tag(tag);
|
||||
if (!ctx_->sent_initial_metadata_) {
|
||||
finish_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
|
||||
ctx_->initial_metadata_flags());
|
||||
if (ctx_->compression_level_set()) {
|
||||
finish_ops_.set_compression_level(ctx_->compression_level());
|
||||
}
|
||||
ctx_->sent_initial_metadata_ = true;
|
||||
}
|
||||
// The response is dropped if the status is not OK.
|
||||
if (status.ok()) {
|
||||
finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_,
|
||||
finish_ops_.SendMessage(msg));
|
||||
} else {
|
||||
finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, status);
|
||||
}
|
||||
call_.PerformOps(&finish_ops_);
|
||||
}
|
||||
|
||||
/// See the \a ServerAsyncReaderInterface.Read method for semantics
|
||||
///
|
||||
/// Side effect:
|
||||
/// - also sends initial metadata if not already sent.
|
||||
/// - uses the \a ServerContext associated with this call to send possible
|
||||
/// initial and trailing metadata.
|
||||
///
|
||||
/// gRPC doesn't take ownership or a reference to \a status, so it is safe to
|
||||
/// to deallocate once FinishWithError returns.
|
||||
void FinishWithError(const grpc::Status& status, void* tag) override {
|
||||
GPR_ASSERT(!status.ok());
|
||||
finish_ops_.set_output_tag(tag);
|
||||
if (!ctx_->sent_initial_metadata_) {
|
||||
finish_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
|
||||
ctx_->initial_metadata_flags());
|
||||
if (ctx_->compression_level_set()) {
|
||||
finish_ops_.set_compression_level(ctx_->compression_level());
|
||||
}
|
||||
ctx_->sent_initial_metadata_ = true;
|
||||
}
|
||||
finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, status);
|
||||
call_.PerformOps(&finish_ops_);
|
||||
}
|
||||
|
||||
private:
|
||||
void BindCall(grpc::internal::Call* call) override { call_ = *call; }
|
||||
|
||||
grpc::internal::Call call_;
|
||||
grpc::ServerContext* ctx_;
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata>
|
||||
meta_ops_;
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpRecvMessage<R>> read_ops_;
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,
|
||||
grpc::internal::CallOpSendMessage,
|
||||
grpc::internal::CallOpServerSendStatus>
|
||||
finish_ops_;
|
||||
};
|
||||
|
||||
template <class W>
|
||||
class ServerAsyncWriterInterface
|
||||
: public grpc::internal::ServerAsyncStreamingInterface,
|
||||
public internal::AsyncWriterInterface<W> {
|
||||
public:
|
||||
/// Indicate that the stream is to be finished with a certain status code.
|
||||
/// Request notification for when the server has sent the appropriate
|
||||
/// signals to the client to end the call.
|
||||
/// Should not be used concurrently with other operations.
|
||||
///
|
||||
/// It is appropriate to call this method when either:
|
||||
/// * all messages from the client have been received (either known
|
||||
/// implicitly, or explicitly because a previous \a
|
||||
/// AsyncReaderInterface::Read operation with a non-ok
|
||||
/// result (e.g., cq->Next(&read_tag, &ok) filled in 'ok' with 'false'.
|
||||
/// * it is desired to end the call early with some non-OK status code.
|
||||
///
|
||||
/// This operation will end when the server has finished sending out initial
|
||||
/// metadata (if not sent already), response message, and status, or if
|
||||
/// some failure occurred when trying to do so.
|
||||
///
|
||||
/// gRPC doesn't take ownership or a reference to \a status, so it is safe to
|
||||
/// to deallocate once Finish returns.
|
||||
///
|
||||
/// \param[in] tag Tag identifying this request.
|
||||
/// \param[in] status To be sent to the client as the result of this call.
|
||||
virtual void Finish(const grpc::Status& status, void* tag) = 0;
|
||||
|
||||
/// Request the writing of \a msg and coalesce it with trailing metadata which
|
||||
/// contains \a status, using WriteOptions options with
|
||||
/// identifying tag \a tag.
|
||||
///
|
||||
/// WriteAndFinish is equivalent of performing WriteLast and Finish
|
||||
/// in a single step.
|
||||
///
|
||||
/// gRPC doesn't take ownership or a reference to \a msg and \a status, so it
|
||||
/// is safe to deallocate once WriteAndFinish returns.
|
||||
///
|
||||
/// \param[in] msg The message to be written.
|
||||
/// \param[in] options The WriteOptions to be used to write this message.
|
||||
/// \param[in] status The Status that server returns to client.
|
||||
/// \param[in] tag The tag identifying the operation.
|
||||
virtual void WriteAndFinish(const W& msg, grpc::WriteOptions options,
|
||||
const grpc::Status& status, void* tag) = 0;
|
||||
};
|
||||
|
||||
/// Async server-side API for doing server streaming RPCs,
|
||||
/// where the outgoing message stream from the server has messages of type \a W.
|
||||
template <class W>
|
||||
class ServerAsyncWriter final : public ServerAsyncWriterInterface<W> {
|
||||
public:
|
||||
explicit ServerAsyncWriter(grpc::ServerContext* ctx)
|
||||
: call_(nullptr, nullptr, nullptr), ctx_(ctx) {}
|
||||
|
||||
/// See \a ServerAsyncStreamingInterface::SendInitialMetadata for semantics.
|
||||
///
|
||||
/// Implicit input parameter:
|
||||
/// - The initial metadata that will be sent to the client from this op will
|
||||
/// be taken from the \a ServerContext associated with the call.
|
||||
///
|
||||
/// \param[in] tag Tag identifying this request.
|
||||
void SendInitialMetadata(void* tag) override {
|
||||
GPR_ASSERT(!ctx_->sent_initial_metadata_);
|
||||
|
||||
meta_ops_.set_output_tag(tag);
|
||||
meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
|
||||
ctx_->initial_metadata_flags());
|
||||
if (ctx_->compression_level_set()) {
|
||||
meta_ops_.set_compression_level(ctx_->compression_level());
|
||||
}
|
||||
ctx_->sent_initial_metadata_ = true;
|
||||
call_.PerformOps(&meta_ops_);
|
||||
}
|
||||
|
||||
void Write(const W& msg, void* tag) override {
|
||||
write_ops_.set_output_tag(tag);
|
||||
EnsureInitialMetadataSent(&write_ops_);
|
||||
// TODO(ctiller): don't assert
|
||||
GPR_ASSERT(write_ops_.SendMessage(msg).ok());
|
||||
call_.PerformOps(&write_ops_);
|
||||
}
|
||||
|
||||
void Write(const W& msg, grpc::WriteOptions options, void* tag) override {
|
||||
write_ops_.set_output_tag(tag);
|
||||
if (options.is_last_message()) {
|
||||
options.set_buffer_hint();
|
||||
}
|
||||
|
||||
EnsureInitialMetadataSent(&write_ops_);
|
||||
// TODO(ctiller): don't assert
|
||||
GPR_ASSERT(write_ops_.SendMessage(msg, options).ok());
|
||||
call_.PerformOps(&write_ops_);
|
||||
}
|
||||
|
||||
/// See the \a ServerAsyncWriterInterface.WriteAndFinish method for semantics.
|
||||
///
|
||||
/// Implicit input parameter:
|
||||
/// - the \a ServerContext associated with this call is used
|
||||
/// for sending trailing (and initial) metadata to the client.
|
||||
///
|
||||
/// Note: \a status must have an OK code.
|
||||
///
|
||||
/// gRPC doesn't take ownership or a reference to \a msg and \a status, so it
|
||||
/// is safe to deallocate once WriteAndFinish returns.
|
||||
void WriteAndFinish(const W& msg, grpc::WriteOptions options,
|
||||
const grpc::Status& status, void* tag) override {
|
||||
write_ops_.set_output_tag(tag);
|
||||
EnsureInitialMetadataSent(&write_ops_);
|
||||
options.set_buffer_hint();
|
||||
GPR_ASSERT(write_ops_.SendMessage(msg, options).ok());
|
||||
write_ops_.ServerSendStatus(&ctx_->trailing_metadata_, status);
|
||||
call_.PerformOps(&write_ops_);
|
||||
}
|
||||
|
||||
/// See the \a ServerAsyncWriterInterface.Finish method for semantics.
|
||||
///
|
||||
/// Implicit input parameter:
|
||||
/// - the \a ServerContext associated with this call is used for sending
|
||||
/// trailing (and initial if not already sent) metadata to the client.
|
||||
///
|
||||
/// Note: there are no restrictions are the code of
|
||||
/// \a status,it may be non-OK
|
||||
///
|
||||
/// gRPC doesn't take ownership or a reference to \a status, so it is safe to
|
||||
/// to deallocate once Finish returns.
|
||||
void Finish(const grpc::Status& status, void* tag) override {
|
||||
finish_ops_.set_output_tag(tag);
|
||||
EnsureInitialMetadataSent(&finish_ops_);
|
||||
finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, status);
|
||||
call_.PerformOps(&finish_ops_);
|
||||
}
|
||||
|
||||
private:
|
||||
void BindCall(grpc::internal::Call* call) override { call_ = *call; }
|
||||
|
||||
template <class T>
|
||||
void EnsureInitialMetadataSent(T* ops) {
|
||||
if (!ctx_->sent_initial_metadata_) {
|
||||
ops->SendInitialMetadata(&ctx_->initial_metadata_,
|
||||
ctx_->initial_metadata_flags());
|
||||
if (ctx_->compression_level_set()) {
|
||||
ops->set_compression_level(ctx_->compression_level());
|
||||
}
|
||||
ctx_->sent_initial_metadata_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
grpc::internal::Call call_;
|
||||
grpc::ServerContext* ctx_;
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata>
|
||||
meta_ops_;
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,
|
||||
grpc::internal::CallOpSendMessage,
|
||||
grpc::internal::CallOpServerSendStatus>
|
||||
write_ops_;
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,
|
||||
grpc::internal::CallOpServerSendStatus>
|
||||
finish_ops_;
|
||||
};
|
||||
|
||||
/// Server-side interface for asynchronous bi-directional streaming.
|
||||
template <class W, class R>
|
||||
class ServerAsyncReaderWriterInterface
|
||||
: public grpc::internal::ServerAsyncStreamingInterface,
|
||||
public internal::AsyncWriterInterface<W>,
|
||||
public internal::AsyncReaderInterface<R> {
|
||||
public:
|
||||
/// Indicate that the stream is to be finished with a certain status code.
|
||||
/// Request notification for when the server has sent the appropriate
|
||||
/// signals to the client to end the call.
|
||||
/// Should not be used concurrently with other operations.
|
||||
///
|
||||
/// It is appropriate to call this method when either:
|
||||
/// * all messages from the client have been received (either known
|
||||
/// implicitly, or explicitly because a previous \a
|
||||
/// AsyncReaderInterface::Read operation
|
||||
/// with a non-ok result (e.g., cq->Next(&read_tag, &ok) filled in 'ok'
|
||||
/// with 'false'.
|
||||
/// * it is desired to end the call early with some non-OK status code.
|
||||
///
|
||||
/// This operation will end when the server has finished sending out initial
|
||||
/// metadata (if not sent already), response message, and status, or if some
|
||||
/// failure occurred when trying to do so.
|
||||
///
|
||||
/// gRPC doesn't take ownership or a reference to \a status, so it is safe to
|
||||
/// to deallocate once Finish returns.
|
||||
///
|
||||
/// \param[in] tag Tag identifying this request.
|
||||
/// \param[in] status To be sent to the client as the result of this call.
|
||||
virtual void Finish(const grpc::Status& status, void* tag) = 0;
|
||||
|
||||
/// Request the writing of \a msg and coalesce it with trailing metadata which
|
||||
/// contains \a status, using WriteOptions options with
|
||||
/// identifying tag \a tag.
|
||||
///
|
||||
/// WriteAndFinish is equivalent of performing WriteLast and Finish in a
|
||||
/// single step.
|
||||
///
|
||||
/// gRPC doesn't take ownership or a reference to \a msg and \a status, so it
|
||||
/// is safe to deallocate once WriteAndFinish returns.
|
||||
///
|
||||
/// \param[in] msg The message to be written.
|
||||
/// \param[in] options The WriteOptions to be used to write this message.
|
||||
/// \param[in] status The Status that server returns to client.
|
||||
/// \param[in] tag The tag identifying the operation.
|
||||
virtual void WriteAndFinish(const W& msg, grpc::WriteOptions options,
|
||||
const grpc::Status& status, void* tag) = 0;
|
||||
};
|
||||
|
||||
/// Async server-side API for doing bidirectional streaming RPCs,
|
||||
/// where the incoming message stream coming from the client has messages of
|
||||
/// type \a R, and the outgoing message stream coming from the server has
|
||||
/// messages of type \a W.
|
||||
template <class W, class R>
|
||||
class ServerAsyncReaderWriter final
|
||||
: public ServerAsyncReaderWriterInterface<W, R> {
|
||||
public:
|
||||
explicit ServerAsyncReaderWriter(grpc::ServerContext* ctx)
|
||||
: call_(nullptr, nullptr, nullptr), ctx_(ctx) {}
|
||||
|
||||
/// See \a ServerAsyncStreamingInterface::SendInitialMetadata for semantics.
|
||||
///
|
||||
/// Implicit input parameter:
|
||||
/// - The initial metadata that will be sent to the client from this op will
|
||||
/// be taken from the \a ServerContext associated with the call.
|
||||
///
|
||||
/// \param[in] tag Tag identifying this request.
|
||||
void SendInitialMetadata(void* tag) override {
|
||||
GPR_ASSERT(!ctx_->sent_initial_metadata_);
|
||||
|
||||
meta_ops_.set_output_tag(tag);
|
||||
meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
|
||||
ctx_->initial_metadata_flags());
|
||||
if (ctx_->compression_level_set()) {
|
||||
meta_ops_.set_compression_level(ctx_->compression_level());
|
||||
}
|
||||
ctx_->sent_initial_metadata_ = true;
|
||||
call_.PerformOps(&meta_ops_);
|
||||
}
|
||||
|
||||
void Read(R* msg, void* tag) override {
|
||||
read_ops_.set_output_tag(tag);
|
||||
read_ops_.RecvMessage(msg);
|
||||
call_.PerformOps(&read_ops_);
|
||||
}
|
||||
|
||||
void Write(const W& msg, void* tag) override {
|
||||
write_ops_.set_output_tag(tag);
|
||||
EnsureInitialMetadataSent(&write_ops_);
|
||||
// TODO(ctiller): don't assert
|
||||
GPR_ASSERT(write_ops_.SendMessage(msg).ok());
|
||||
call_.PerformOps(&write_ops_);
|
||||
}
|
||||
|
||||
void Write(const W& msg, grpc::WriteOptions options, void* tag) override {
|
||||
write_ops_.set_output_tag(tag);
|
||||
if (options.is_last_message()) {
|
||||
options.set_buffer_hint();
|
||||
}
|
||||
EnsureInitialMetadataSent(&write_ops_);
|
||||
GPR_ASSERT(write_ops_.SendMessage(msg, options).ok());
|
||||
call_.PerformOps(&write_ops_);
|
||||
}
|
||||
|
||||
/// See the \a ServerAsyncReaderWriterInterface.WriteAndFinish
|
||||
/// method for semantics.
|
||||
///
|
||||
/// Implicit input parameter:
|
||||
/// - the \a ServerContext associated with this call is used
|
||||
/// for sending trailing (and initial) metadata to the client.
|
||||
///
|
||||
/// Note: \a status must have an OK code.
|
||||
//
|
||||
/// gRPC doesn't take ownership or a reference to \a msg and \a status, so it
|
||||
/// is safe to deallocate once WriteAndFinish returns.
|
||||
void WriteAndFinish(const W& msg, grpc::WriteOptions options,
|
||||
const grpc::Status& status, void* tag) override {
|
||||
write_ops_.set_output_tag(tag);
|
||||
EnsureInitialMetadataSent(&write_ops_);
|
||||
options.set_buffer_hint();
|
||||
GPR_ASSERT(write_ops_.SendMessage(msg, options).ok());
|
||||
write_ops_.ServerSendStatus(&ctx_->trailing_metadata_, status);
|
||||
call_.PerformOps(&write_ops_);
|
||||
}
|
||||
|
||||
/// See the \a ServerAsyncReaderWriterInterface.Finish method for semantics.
|
||||
///
|
||||
/// Implicit input parameter:
|
||||
/// - the \a ServerContext associated with this call is used for sending
|
||||
/// trailing (and initial if not already sent) metadata to the client.
|
||||
///
|
||||
/// Note: there are no restrictions are the code of \a status,
|
||||
/// it may be non-OK
|
||||
//
|
||||
/// gRPC doesn't take ownership or a reference to \a status, so it is safe to
|
||||
/// to deallocate once Finish returns.
|
||||
void Finish(const grpc::Status& status, void* tag) override {
|
||||
finish_ops_.set_output_tag(tag);
|
||||
EnsureInitialMetadataSent(&finish_ops_);
|
||||
|
||||
finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, status);
|
||||
call_.PerformOps(&finish_ops_);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class grpc::Server;
|
||||
|
||||
void BindCall(grpc::internal::Call* call) override { call_ = *call; }
|
||||
|
||||
template <class T>
|
||||
void EnsureInitialMetadataSent(T* ops) {
|
||||
if (!ctx_->sent_initial_metadata_) {
|
||||
ops->SendInitialMetadata(&ctx_->initial_metadata_,
|
||||
ctx_->initial_metadata_flags());
|
||||
if (ctx_->compression_level_set()) {
|
||||
ops->set_compression_level(ctx_->compression_level());
|
||||
}
|
||||
ctx_->sent_initial_metadata_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
grpc::internal::Call call_;
|
||||
grpc::ServerContext* ctx_;
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata>
|
||||
meta_ops_;
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpRecvMessage<R>> read_ops_;
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,
|
||||
grpc::internal::CallOpSendMessage,
|
||||
grpc::internal::CallOpServerSendStatus>
|
||||
write_ops_;
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,
|
||||
grpc::internal::CallOpServerSendStatus>
|
||||
finish_ops_;
|
||||
};
|
||||
|
||||
} // namespace grpc
|
||||
|
||||
#endif // GRPCPP_SUPPORT_ASYNC_STREAM_H
|
||||
418
Pods/gRPC-C++/include/grpcpp/support/async_unary_call.h
generated
Normal file
418
Pods/gRPC-C++/include/grpcpp/support/async_unary_call.h
generated
Normal file
@@ -0,0 +1,418 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2015 gRPC 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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef GRPCPP_SUPPORT_ASYNC_UNARY_CALL_H
|
||||
#define GRPCPP_SUPPORT_ASYNC_UNARY_CALL_H
|
||||
|
||||
#include <grpc/grpc.h>
|
||||
#include <grpc/support/log.h>
|
||||
#include <grpcpp/client_context.h>
|
||||
#include <grpcpp/impl/call.h>
|
||||
#include <grpcpp/impl/call_op_set.h>
|
||||
#include <grpcpp/impl/call_op_set_interface.h>
|
||||
#include <grpcpp/impl/channel_interface.h>
|
||||
#include <grpcpp/impl/service_type.h>
|
||||
#include <grpcpp/server_context.h>
|
||||
#include <grpcpp/support/status.h>
|
||||
|
||||
namespace grpc {
|
||||
|
||||
// Forward declaration for use in Helper class
|
||||
template <class R>
|
||||
class ClientAsyncResponseReader;
|
||||
|
||||
/// An interface relevant for async client side unary RPCs (which send
|
||||
/// one request message to a server and receive one response message).
|
||||
template <class R>
|
||||
class ClientAsyncResponseReaderInterface {
|
||||
public:
|
||||
virtual ~ClientAsyncResponseReaderInterface() {}
|
||||
|
||||
/// Start the call that was set up by the constructor, but only if the
|
||||
/// constructor was invoked through the "Prepare" API which doesn't actually
|
||||
/// start the call
|
||||
virtual void StartCall() = 0;
|
||||
|
||||
/// Request notification of the reading of initial metadata. Completion
|
||||
/// will be notified by \a tag on the associated completion queue.
|
||||
/// This call is optional, but if it is used, it cannot be used concurrently
|
||||
/// with or after the \a Finish method.
|
||||
///
|
||||
/// \param[in] tag Tag identifying this request.
|
||||
virtual void ReadInitialMetadata(void* tag) = 0;
|
||||
|
||||
/// Request to receive the server's response \a msg and final \a status for
|
||||
/// the call, and to notify \a tag on this call's completion queue when
|
||||
/// finished.
|
||||
///
|
||||
/// This function will return when either:
|
||||
/// - when the server's response message and status have been received.
|
||||
/// - when the server has returned a non-OK status (no message expected in
|
||||
/// this case).
|
||||
/// - when the call failed for some reason and the library generated a
|
||||
/// non-OK status.
|
||||
///
|
||||
/// \param[in] tag Tag identifying this request.
|
||||
/// \param[out] status To be updated with the operation status.
|
||||
/// \param[out] msg To be filled in with the server's response message.
|
||||
virtual void Finish(R* msg, grpc::Status* status, void* tag) = 0;
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
|
||||
class ClientAsyncResponseReaderHelper {
|
||||
public:
|
||||
/// Start a call and write the request out if \a start is set.
|
||||
/// \a tag will be notified on \a cq when the call has been started (i.e.
|
||||
/// initial metadata sent) and \a request has been written out.
|
||||
/// If \a start is not set, the actual call must be initiated by StartCall
|
||||
/// Note that \a context will be used to fill in custom initial metadata
|
||||
/// used to send to the server when starting the call.
|
||||
///
|
||||
/// Optionally pass in a base class for request and response types so that the
|
||||
/// internal functions and structs can be templated based on that, allowing
|
||||
/// reuse across RPCs (e.g., MessageLite for protobuf). Since constructors
|
||||
/// can't have an explicit template parameter, the last argument is an
|
||||
/// extraneous parameter just to provide the needed type information.
|
||||
template <class R, class W, class BaseR = R, class BaseW = W>
|
||||
static ClientAsyncResponseReader<R>* Create(
|
||||
grpc::ChannelInterface* channel, grpc::CompletionQueue* cq,
|
||||
const grpc::internal::RpcMethod& method, grpc::ClientContext* context,
|
||||
const W& request) /* __attribute__((noinline)) */ {
|
||||
grpc::internal::Call call = channel->CreateCall(method, context, cq);
|
||||
ClientAsyncResponseReader<R>* result = new (grpc_call_arena_alloc(
|
||||
call.call(), sizeof(ClientAsyncResponseReader<R>)))
|
||||
ClientAsyncResponseReader<R>(call, context);
|
||||
SetupRequest<BaseR, BaseW>(
|
||||
call.call(), &result->single_buf_, &result->read_initial_metadata_,
|
||||
&result->finish_, static_cast<const BaseW&>(request));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Various helper functions to reduce templating use
|
||||
|
||||
template <class R, class W>
|
||||
static void SetupRequest(
|
||||
grpc_call* call,
|
||||
grpc::internal::CallOpSendInitialMetadata** single_buf_ptr,
|
||||
std::function<void(ClientContext*, internal::Call*,
|
||||
internal::CallOpSendInitialMetadata*, void*)>*
|
||||
read_initial_metadata,
|
||||
std::function<
|
||||
void(ClientContext*, internal::Call*, bool initial_metadata_read,
|
||||
internal::CallOpSendInitialMetadata*,
|
||||
internal::CallOpSetInterface**, void*, Status*, void*)>* finish,
|
||||
const W& request) {
|
||||
using SingleBufType =
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,
|
||||
grpc::internal::CallOpSendMessage,
|
||||
grpc::internal::CallOpClientSendClose,
|
||||
grpc::internal::CallOpRecvInitialMetadata,
|
||||
grpc::internal::CallOpRecvMessage<R>,
|
||||
grpc::internal::CallOpClientRecvStatus>;
|
||||
SingleBufType* single_buf =
|
||||
new (grpc_call_arena_alloc(call, sizeof(SingleBufType))) SingleBufType;
|
||||
*single_buf_ptr = single_buf;
|
||||
// TODO(ctiller): don't assert
|
||||
GPR_ASSERT(single_buf->SendMessage(request).ok());
|
||||
single_buf->ClientSendClose();
|
||||
|
||||
// The purpose of the following functions is to type-erase the actual
|
||||
// templated type of the CallOpSet being used by hiding that type inside the
|
||||
// function definition rather than specifying it as an argument of the
|
||||
// function or a member of the class. The type-erased CallOpSet will get
|
||||
// static_cast'ed back to the real type so that it can be used properly.
|
||||
*read_initial_metadata =
|
||||
[](ClientContext* context, internal::Call* call,
|
||||
internal::CallOpSendInitialMetadata* single_buf_view, void* tag) {
|
||||
auto* single_buf = static_cast<SingleBufType*>(single_buf_view);
|
||||
single_buf->set_output_tag(tag);
|
||||
single_buf->RecvInitialMetadata(context);
|
||||
call->PerformOps(single_buf);
|
||||
};
|
||||
|
||||
// Note that this function goes one step further than the previous one
|
||||
// because it type-erases the message being written down to a void*. This
|
||||
// will be static-cast'ed back to the class specified here by hiding that
|
||||
// class information inside the function definition. Note that this feature
|
||||
// expects the class being specified here for R to be a base-class of the
|
||||
// "real" R without any multiple-inheritance (as applies in protobuf wrt
|
||||
// MessageLite)
|
||||
*finish = [](ClientContext* context, internal::Call* call,
|
||||
bool initial_metadata_read,
|
||||
internal::CallOpSendInitialMetadata* single_buf_view,
|
||||
internal::CallOpSetInterface** finish_buf_ptr, void* msg,
|
||||
Status* status, void* tag) {
|
||||
if (initial_metadata_read) {
|
||||
using FinishBufType =
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpRecvMessage<R>,
|
||||
grpc::internal::CallOpClientRecvStatus>;
|
||||
FinishBufType* finish_buf =
|
||||
new (grpc_call_arena_alloc(call->call(), sizeof(FinishBufType)))
|
||||
FinishBufType;
|
||||
*finish_buf_ptr = finish_buf;
|
||||
finish_buf->set_output_tag(tag);
|
||||
finish_buf->RecvMessage(static_cast<R*>(msg));
|
||||
finish_buf->AllowNoMessage();
|
||||
finish_buf->ClientRecvStatus(context, status);
|
||||
call->PerformOps(finish_buf);
|
||||
} else {
|
||||
auto* single_buf = static_cast<SingleBufType*>(single_buf_view);
|
||||
single_buf->set_output_tag(tag);
|
||||
single_buf->RecvInitialMetadata(context);
|
||||
single_buf->RecvMessage(static_cast<R*>(msg));
|
||||
single_buf->AllowNoMessage();
|
||||
single_buf->ClientRecvStatus(context, status);
|
||||
call->PerformOps(single_buf);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static void StartCall(grpc::ClientContext* context,
|
||||
grpc::internal::CallOpSendInitialMetadata* single_buf) {
|
||||
single_buf->SendInitialMetadata(&context->send_initial_metadata_,
|
||||
context->initial_metadata_flags());
|
||||
}
|
||||
};
|
||||
|
||||
// TODO(vjpai): This templated factory is deprecated and will be replaced by
|
||||
//. the non-templated helper as soon as possible.
|
||||
template <class R>
|
||||
class ClientAsyncResponseReaderFactory {
|
||||
public:
|
||||
template <class W>
|
||||
static ClientAsyncResponseReader<R>* Create(
|
||||
grpc::ChannelInterface* channel, grpc::CompletionQueue* cq,
|
||||
const grpc::internal::RpcMethod& method, grpc::ClientContext* context,
|
||||
const W& request, bool start) {
|
||||
auto* result = ClientAsyncResponseReaderHelper::Create<R>(
|
||||
channel, cq, method, context, request);
|
||||
if (start) {
|
||||
result->StartCall();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/// Async API for client-side unary RPCs, where the message response
|
||||
/// received from the server is of type \a R.
|
||||
template <class R>
|
||||
class ClientAsyncResponseReader final
|
||||
: public ClientAsyncResponseReaderInterface<R> {
|
||||
public:
|
||||
// always allocated against a call arena, no memory free required
|
||||
static void operator delete(void* /*ptr*/, std::size_t size) {
|
||||
GPR_ASSERT(size == sizeof(ClientAsyncResponseReader));
|
||||
}
|
||||
|
||||
// This operator should never be called as the memory should be freed as part
|
||||
// of the arena destruction. It only exists to provide a matching operator
|
||||
// delete to the operator new so that some compilers will not complain (see
|
||||
// https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
|
||||
// there are no tests catching the compiler warning.
|
||||
static void operator delete(void*, void*) { GPR_ASSERT(false); }
|
||||
|
||||
void StartCall() override {
|
||||
GPR_DEBUG_ASSERT(!started_);
|
||||
started_ = true;
|
||||
internal::ClientAsyncResponseReaderHelper::StartCall(context_, single_buf_);
|
||||
}
|
||||
|
||||
/// See \a ClientAsyncResponseReaderInterface::ReadInitialMetadata for
|
||||
/// semantics.
|
||||
///
|
||||
/// Side effect:
|
||||
/// - the \a ClientContext associated with this call is updated with
|
||||
/// possible initial and trailing metadata sent from the server.
|
||||
void ReadInitialMetadata(void* tag) override {
|
||||
GPR_DEBUG_ASSERT(started_);
|
||||
GPR_DEBUG_ASSERT(!context_->initial_metadata_received_);
|
||||
read_initial_metadata_(context_, &call_, single_buf_, tag);
|
||||
initial_metadata_read_ = true;
|
||||
}
|
||||
|
||||
/// See \a ClientAsyncResponseReaderInterface::Finish for semantics.
|
||||
///
|
||||
/// Side effect:
|
||||
/// - the \a ClientContext associated with this call is updated with
|
||||
/// possible initial and trailing metadata sent from the server.
|
||||
void Finish(R* msg, grpc::Status* status, void* tag) override {
|
||||
GPR_DEBUG_ASSERT(started_);
|
||||
finish_(context_, &call_, initial_metadata_read_, single_buf_, &finish_buf_,
|
||||
static_cast<void*>(msg), status, tag);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class internal::ClientAsyncResponseReaderHelper;
|
||||
grpc::ClientContext* const context_;
|
||||
grpc::internal::Call call_;
|
||||
bool started_ = false;
|
||||
bool initial_metadata_read_ = false;
|
||||
|
||||
ClientAsyncResponseReader(grpc::internal::Call call,
|
||||
grpc::ClientContext* context)
|
||||
: context_(context), call_(call) {}
|
||||
|
||||
// disable operator new
|
||||
static void* operator new(std::size_t size);
|
||||
static void* operator new(std::size_t /*size*/, void* p) { return p; }
|
||||
|
||||
internal::CallOpSendInitialMetadata* single_buf_;
|
||||
internal::CallOpSetInterface* finish_buf_ = nullptr;
|
||||
std::function<void(ClientContext*, internal::Call*,
|
||||
internal::CallOpSendInitialMetadata*, void*)>
|
||||
read_initial_metadata_;
|
||||
std::function<void(ClientContext*, internal::Call*,
|
||||
bool initial_metadata_read,
|
||||
internal::CallOpSendInitialMetadata*,
|
||||
internal::CallOpSetInterface**, void*, Status*, void*)>
|
||||
finish_;
|
||||
};
|
||||
|
||||
/// Async server-side API for handling unary calls, where the single
|
||||
/// response message sent to the client is of type \a W.
|
||||
template <class W>
|
||||
class ServerAsyncResponseWriter final
|
||||
: public grpc::internal::ServerAsyncStreamingInterface {
|
||||
public:
|
||||
explicit ServerAsyncResponseWriter(grpc::ServerContext* ctx)
|
||||
: call_(nullptr, nullptr, nullptr), ctx_(ctx) {}
|
||||
|
||||
/// See \a ServerAsyncStreamingInterface::SendInitialMetadata for semantics.
|
||||
///
|
||||
/// Side effect:
|
||||
/// The initial metadata that will be sent to the client from this op will
|
||||
/// be taken from the \a ServerContext associated with the call.
|
||||
///
|
||||
/// \param[in] tag Tag identifying this request.
|
||||
void SendInitialMetadata(void* tag) override {
|
||||
GPR_ASSERT(!ctx_->sent_initial_metadata_);
|
||||
|
||||
meta_buf_.set_output_tag(tag);
|
||||
meta_buf_.SendInitialMetadata(&ctx_->initial_metadata_,
|
||||
ctx_->initial_metadata_flags());
|
||||
if (ctx_->compression_level_set()) {
|
||||
meta_buf_.set_compression_level(ctx_->compression_level());
|
||||
}
|
||||
ctx_->sent_initial_metadata_ = true;
|
||||
call_.PerformOps(&meta_buf_);
|
||||
}
|
||||
|
||||
/// Indicate that the stream is to be finished and request notification
|
||||
/// when the server has sent the appropriate signals to the client to
|
||||
/// end the call. Should not be used concurrently with other operations.
|
||||
///
|
||||
/// \param[in] tag Tag identifying this request.
|
||||
/// \param[in] status To be sent to the client as the result of the call.
|
||||
/// \param[in] msg Message to be sent to the client.
|
||||
///
|
||||
/// Side effect:
|
||||
/// - also sends initial metadata if not already sent (using the
|
||||
/// \a ServerContext associated with this call).
|
||||
///
|
||||
/// Note: if \a status has a non-OK code, then \a msg will not be sent,
|
||||
/// and the client will receive only the status with possible trailing
|
||||
/// metadata.
|
||||
///
|
||||
/// gRPC doesn't take ownership or a reference to msg and status, so it is
|
||||
/// safe to deallocate them once the Finish operation is complete (i.e. a
|
||||
/// result arrives in the completion queue).
|
||||
void Finish(const W& msg, const grpc::Status& status, void* tag) {
|
||||
finish_buf_.set_output_tag(tag);
|
||||
finish_buf_.set_core_cq_tag(&finish_buf_);
|
||||
if (!ctx_->sent_initial_metadata_) {
|
||||
finish_buf_.SendInitialMetadata(&ctx_->initial_metadata_,
|
||||
ctx_->initial_metadata_flags());
|
||||
if (ctx_->compression_level_set()) {
|
||||
finish_buf_.set_compression_level(ctx_->compression_level());
|
||||
}
|
||||
ctx_->sent_initial_metadata_ = true;
|
||||
}
|
||||
// The response is dropped if the status is not OK.
|
||||
if (status.ok()) {
|
||||
finish_buf_.ServerSendStatus(&ctx_->trailing_metadata_,
|
||||
finish_buf_.SendMessage(msg));
|
||||
} else {
|
||||
finish_buf_.ServerSendStatus(&ctx_->trailing_metadata_, status);
|
||||
}
|
||||
call_.PerformOps(&finish_buf_);
|
||||
}
|
||||
|
||||
/// Indicate that the stream is to be finished with a non-OK status,
|
||||
/// and request notification for when the server has finished sending the
|
||||
/// appropriate signals to the client to end the call.
|
||||
/// Should not be used concurrently with other operations.
|
||||
///
|
||||
/// \param[in] tag Tag identifying this request.
|
||||
/// \param[in] status To be sent to the client as the result of the call.
|
||||
/// - Note: \a status must have a non-OK code.
|
||||
///
|
||||
/// Side effect:
|
||||
/// - also sends initial metadata if not already sent (using the
|
||||
/// \a ServerContext associated with this call).
|
||||
///
|
||||
/// gRPC doesn't take ownership or a reference to status, so it is safe to
|
||||
/// deallocate them once the Finish operation is complete (i.e. a result
|
||||
/// arrives in the completion queue).
|
||||
void FinishWithError(const grpc::Status& status, void* tag) {
|
||||
GPR_ASSERT(!status.ok());
|
||||
finish_buf_.set_output_tag(tag);
|
||||
if (!ctx_->sent_initial_metadata_) {
|
||||
finish_buf_.SendInitialMetadata(&ctx_->initial_metadata_,
|
||||
ctx_->initial_metadata_flags());
|
||||
if (ctx_->compression_level_set()) {
|
||||
finish_buf_.set_compression_level(ctx_->compression_level());
|
||||
}
|
||||
ctx_->sent_initial_metadata_ = true;
|
||||
}
|
||||
finish_buf_.ServerSendStatus(&ctx_->trailing_metadata_, status);
|
||||
call_.PerformOps(&finish_buf_);
|
||||
}
|
||||
|
||||
private:
|
||||
void BindCall(grpc::internal::Call* call) override { call_ = *call; }
|
||||
|
||||
grpc::internal::Call call_;
|
||||
grpc::ServerContext* ctx_;
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata>
|
||||
meta_buf_;
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,
|
||||
grpc::internal::CallOpSendMessage,
|
||||
grpc::internal::CallOpServerSendStatus>
|
||||
finish_buf_;
|
||||
};
|
||||
|
||||
} // namespace grpc
|
||||
|
||||
namespace std {
|
||||
template <class R>
|
||||
class default_delete<grpc::ClientAsyncResponseReader<R>> {
|
||||
public:
|
||||
void operator()(void* /*p*/) {}
|
||||
};
|
||||
template <class R>
|
||||
class default_delete<grpc::ClientAsyncResponseReaderInterface<R>> {
|
||||
public:
|
||||
void operator()(void* /*p*/) {}
|
||||
};
|
||||
} // namespace std
|
||||
|
||||
#endif // GRPCPP_SUPPORT_ASYNC_UNARY_CALL_H
|
||||
234
Pods/gRPC-C++/include/grpcpp/support/byte_buffer.h
generated
Normal file
234
Pods/gRPC-C++/include/grpcpp/support/byte_buffer.h
generated
Normal file
@@ -0,0 +1,234 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2015 gRPC 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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef GRPCPP_SUPPORT_BYTE_BUFFER_H
|
||||
#define GRPCPP_SUPPORT_BYTE_BUFFER_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <grpc/byte_buffer.h>
|
||||
#include <grpc/grpc.h>
|
||||
#include <grpc/support/log.h>
|
||||
#include <grpcpp/impl/serialization_traits.h>
|
||||
#include <grpcpp/support/config.h>
|
||||
#include <grpcpp/support/slice.h>
|
||||
#include <grpcpp/support/status.h>
|
||||
|
||||
namespace grpc {
|
||||
|
||||
class ServerInterface;
|
||||
class ByteBuffer;
|
||||
class ServerInterface;
|
||||
|
||||
namespace internal {
|
||||
template <class RequestType, class ResponseType>
|
||||
class CallbackUnaryHandler;
|
||||
template <class RequestType, class ResponseType>
|
||||
class CallbackServerStreamingHandler;
|
||||
template <class RequestType>
|
||||
void* UnaryDeserializeHelper(grpc_byte_buffer*, grpc::Status*, RequestType*);
|
||||
template <class ServiceType, class RequestType, class ResponseType>
|
||||
class ServerStreamingHandler;
|
||||
template <grpc::StatusCode code>
|
||||
class ErrorMethodHandler;
|
||||
class CallOpSendMessage;
|
||||
template <class R>
|
||||
class CallOpRecvMessage;
|
||||
class CallOpGenericRecvMessage;
|
||||
class ExternalConnectionAcceptorImpl;
|
||||
template <class R>
|
||||
class DeserializeFuncType;
|
||||
class GrpcByteBufferPeer;
|
||||
|
||||
} // namespace internal
|
||||
/// A sequence of bytes.
|
||||
class ByteBuffer final {
|
||||
public:
|
||||
/// Constuct an empty buffer.
|
||||
ByteBuffer() : buffer_(nullptr) {}
|
||||
|
||||
/// Construct buffer from \a slices, of which there are \a nslices.
|
||||
ByteBuffer(const Slice* slices, size_t nslices) {
|
||||
// The following assertions check that the representation of a grpc::Slice
|
||||
// is identical to that of a grpc_slice: it has a grpc_slice field, and
|
||||
// nothing else.
|
||||
static_assert(std::is_same<decltype(slices[0].slice_), grpc_slice>::value,
|
||||
"Slice must have same representation as grpc_slice");
|
||||
static_assert(sizeof(Slice) == sizeof(grpc_slice),
|
||||
"Slice must have same representation as grpc_slice");
|
||||
// The following assertions check that the representation of a ByteBuffer is
|
||||
// identical to grpc_byte_buffer*: it has a grpc_byte_buffer* field,
|
||||
// and nothing else.
|
||||
static_assert(std::is_same<decltype(buffer_), grpc_byte_buffer*>::value,
|
||||
"ByteBuffer must have same representation as "
|
||||
"grpc_byte_buffer*");
|
||||
static_assert(sizeof(ByteBuffer) == sizeof(grpc_byte_buffer*),
|
||||
"ByteBuffer must have same representation as "
|
||||
"grpc_byte_buffer*");
|
||||
// The const_cast is legal if grpc_raw_byte_buffer_create() does no more
|
||||
// than its advertised side effect of increasing the reference count of the
|
||||
// slices it processes, and such an increase does not affect the semantics
|
||||
// seen by the caller of this constructor.
|
||||
buffer_ = grpc_raw_byte_buffer_create(
|
||||
reinterpret_cast<grpc_slice*>(const_cast<Slice*>(slices)), nslices);
|
||||
}
|
||||
|
||||
/// Construct a byte buffer by referencing elements of existing buffer
|
||||
/// \a buf. Wrapper of core function grpc_byte_buffer_copy . This is not
|
||||
/// a deep copy; it is just a referencing. As a result, its performance is
|
||||
/// size-independent.
|
||||
ByteBuffer(const ByteBuffer& buf) : buffer_(nullptr) { operator=(buf); }
|
||||
|
||||
~ByteBuffer() {
|
||||
if (buffer_) {
|
||||
grpc_byte_buffer_destroy(buffer_);
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper of core function grpc_byte_buffer_copy . This is not
|
||||
/// a deep copy; it is just a referencing. As a result, its performance is
|
||||
/// size-independent.
|
||||
ByteBuffer& operator=(const ByteBuffer& buf) {
|
||||
if (this != &buf) {
|
||||
Clear(); // first remove existing data
|
||||
}
|
||||
if (buf.buffer_) {
|
||||
// then copy
|
||||
buffer_ = grpc_byte_buffer_copy(buf.buffer_);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// If this ByteBuffer's representation is a single flat slice, returns a
|
||||
// slice referencing that array.
|
||||
Status TrySingleSlice(Slice* slice) const;
|
||||
|
||||
/// Dump (read) the buffer contents into \a slics.
|
||||
Status DumpToSingleSlice(Slice* slice) const;
|
||||
|
||||
/// Dump (read) the buffer contents into \a slices.
|
||||
Status Dump(std::vector<Slice>* slices) const;
|
||||
|
||||
/// Remove all data.
|
||||
void Clear() {
|
||||
if (buffer_) {
|
||||
grpc_byte_buffer_destroy(buffer_);
|
||||
buffer_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/// Make a duplicate copy of the internals of this byte
|
||||
/// buffer so that we have our own owned version of it.
|
||||
/// bbuf.Duplicate(); is equivalent to bbuf=bbuf; but is actually readable.
|
||||
/// This is not a deep copy; it is a referencing and its performance
|
||||
/// is size-independent.
|
||||
void Duplicate() { buffer_ = grpc_byte_buffer_copy(buffer_); }
|
||||
|
||||
/// Forget underlying byte buffer without destroying
|
||||
/// Use this only for un-owned byte buffers
|
||||
void Release() { buffer_ = nullptr; }
|
||||
|
||||
/// Buffer size in bytes.
|
||||
size_t Length() const {
|
||||
return buffer_ == nullptr ? 0 : grpc_byte_buffer_length(buffer_);
|
||||
}
|
||||
|
||||
/// Swap the state of *this and *other.
|
||||
void Swap(ByteBuffer* other) {
|
||||
grpc_byte_buffer* tmp = other->buffer_;
|
||||
other->buffer_ = buffer_;
|
||||
buffer_ = tmp;
|
||||
}
|
||||
|
||||
/// Is this ByteBuffer valid?
|
||||
bool Valid() const { return (buffer_ != nullptr); }
|
||||
|
||||
private:
|
||||
friend class SerializationTraits<ByteBuffer, void>;
|
||||
friend class ServerInterface;
|
||||
friend class internal::CallOpSendMessage;
|
||||
template <class R>
|
||||
friend class internal::CallOpRecvMessage;
|
||||
friend class internal::CallOpGenericRecvMessage;
|
||||
template <class RequestType>
|
||||
friend void* internal::UnaryDeserializeHelper(grpc_byte_buffer*,
|
||||
grpc::Status*, RequestType*);
|
||||
template <class ServiceType, class RequestType, class ResponseType>
|
||||
friend class internal::ServerStreamingHandler;
|
||||
template <class RequestType, class ResponseType>
|
||||
friend class internal::CallbackUnaryHandler;
|
||||
template <class RequestType, class ResponseType>
|
||||
friend class internal::CallbackServerStreamingHandler;
|
||||
template <StatusCode code>
|
||||
friend class internal::ErrorMethodHandler;
|
||||
template <class R>
|
||||
friend class internal::DeserializeFuncType;
|
||||
friend class ProtoBufferReader;
|
||||
friend class ProtoBufferWriter;
|
||||
friend class internal::GrpcByteBufferPeer;
|
||||
friend class internal::ExternalConnectionAcceptorImpl;
|
||||
|
||||
grpc_byte_buffer* buffer_;
|
||||
|
||||
// takes ownership
|
||||
void set_buffer(grpc_byte_buffer* buf) {
|
||||
if (buffer_) {
|
||||
Clear();
|
||||
}
|
||||
buffer_ = buf;
|
||||
}
|
||||
|
||||
grpc_byte_buffer* c_buffer() { return buffer_; }
|
||||
grpc_byte_buffer** c_buffer_ptr() { return &buffer_; }
|
||||
|
||||
class ByteBufferPointer {
|
||||
public:
|
||||
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||
ByteBufferPointer(const ByteBuffer* b)
|
||||
: bbuf_(const_cast<ByteBuffer*>(b)) {}
|
||||
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||
operator ByteBuffer*() { return bbuf_; }
|
||||
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||
operator grpc_byte_buffer*() { return bbuf_->buffer_; }
|
||||
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||
operator grpc_byte_buffer**() { return &bbuf_->buffer_; }
|
||||
|
||||
private:
|
||||
ByteBuffer* bbuf_;
|
||||
};
|
||||
ByteBufferPointer bbuf_ptr() const { return ByteBufferPointer(this); }
|
||||
};
|
||||
|
||||
template <>
|
||||
class SerializationTraits<ByteBuffer, void> {
|
||||
public:
|
||||
static Status Deserialize(ByteBuffer* byte_buffer, ByteBuffer* dest) {
|
||||
dest->set_buffer(byte_buffer->buffer_);
|
||||
return Status::OK;
|
||||
}
|
||||
static Status Serialize(const ByteBuffer& source, ByteBuffer* buffer,
|
||||
bool* own_buffer) {
|
||||
*buffer = source;
|
||||
*own_buffer = true;
|
||||
return grpc::Status::OK;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace grpc
|
||||
|
||||
#endif // GRPCPP_SUPPORT_BYTE_BUFFER_H
|
||||
221
Pods/gRPC-C++/include/grpcpp/support/callback_common.h
generated
Normal file
221
Pods/gRPC-C++/include/grpcpp/support/callback_common.h
generated
Normal file
@@ -0,0 +1,221 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2018 gRPC 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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef GRPCPP_SUPPORT_CALLBACK_COMMON_H
|
||||
#define GRPCPP_SUPPORT_CALLBACK_COMMON_H
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include <grpc/grpc.h>
|
||||
#include <grpc/impl/grpc_types.h>
|
||||
#include <grpc/support/log.h>
|
||||
#include <grpcpp/impl/call.h>
|
||||
#include <grpcpp/impl/codegen/channel_interface.h>
|
||||
#include <grpcpp/impl/completion_queue_tag.h>
|
||||
#include <grpcpp/support/config.h>
|
||||
#include <grpcpp/support/status.h>
|
||||
|
||||
namespace grpc {
|
||||
namespace internal {
|
||||
|
||||
/// An exception-safe way of invoking a user-specified callback function
|
||||
// TODO(vjpai): decide whether it is better for this to take a const lvalue
|
||||
// parameter or an rvalue parameter, or if it even matters
|
||||
template <class Func, class... Args>
|
||||
void CatchingCallback(Func&& func, Args&&... args) {
|
||||
#if GRPC_ALLOW_EXCEPTIONS
|
||||
try {
|
||||
func(std::forward<Args>(args)...);
|
||||
} catch (...) {
|
||||
// nothing to return or change here, just don't crash the library
|
||||
}
|
||||
#else // GRPC_ALLOW_EXCEPTIONS
|
||||
func(std::forward<Args>(args)...);
|
||||
#endif // GRPC_ALLOW_EXCEPTIONS
|
||||
}
|
||||
|
||||
template <class Reactor, class Func, class... Args>
|
||||
Reactor* CatchingReactorGetter(Func&& func, Args&&... args) {
|
||||
#if GRPC_ALLOW_EXCEPTIONS
|
||||
try {
|
||||
return func(std::forward<Args>(args)...);
|
||||
} catch (...) {
|
||||
// fail the RPC, don't crash the library
|
||||
return nullptr;
|
||||
}
|
||||
#else // GRPC_ALLOW_EXCEPTIONS
|
||||
return func(std::forward<Args>(args)...);
|
||||
#endif // GRPC_ALLOW_EXCEPTIONS
|
||||
}
|
||||
|
||||
// The contract on these tags is that they are single-shot. They must be
|
||||
// constructed and then fired at exactly one point. There is no expectation
|
||||
// that they can be reused without reconstruction.
|
||||
|
||||
class CallbackWithStatusTag : public grpc_completion_queue_functor {
|
||||
public:
|
||||
// always allocated against a call arena, no memory free required
|
||||
static void operator delete(void* /*ptr*/, std::size_t size) {
|
||||
GPR_ASSERT(size == sizeof(CallbackWithStatusTag));
|
||||
}
|
||||
|
||||
// This operator should never be called as the memory should be freed as part
|
||||
// of the arena destruction. It only exists to provide a matching operator
|
||||
// delete to the operator new so that some compilers will not complain (see
|
||||
// https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
|
||||
// there are no tests catching the compiler warning.
|
||||
static void operator delete(void*, void*) { GPR_ASSERT(false); }
|
||||
|
||||
CallbackWithStatusTag(grpc_call* call, std::function<void(Status)> f,
|
||||
CompletionQueueTag* ops)
|
||||
: call_(call), func_(std::move(f)), ops_(ops) {
|
||||
grpc_call_ref(call);
|
||||
functor_run = &CallbackWithStatusTag::StaticRun;
|
||||
// A client-side callback should never be run inline since they will always
|
||||
// have work to do from the user application. So, set the parent's
|
||||
// inlineable field to false
|
||||
inlineable = false;
|
||||
}
|
||||
~CallbackWithStatusTag() {}
|
||||
Status* status_ptr() { return &status_; }
|
||||
|
||||
// force_run can not be performed on a tag if operations using this tag
|
||||
// have been sent to PerformOpsOnCall. It is intended for error conditions
|
||||
// that are detected before the operations are internally processed.
|
||||
void force_run(Status s) {
|
||||
status_ = std::move(s);
|
||||
Run(true);
|
||||
}
|
||||
|
||||
private:
|
||||
grpc_call* call_;
|
||||
std::function<void(Status)> func_;
|
||||
CompletionQueueTag* ops_;
|
||||
Status status_;
|
||||
|
||||
static void StaticRun(grpc_completion_queue_functor* cb, int ok) {
|
||||
static_cast<CallbackWithStatusTag*>(cb)->Run(static_cast<bool>(ok));
|
||||
}
|
||||
void Run(bool ok) {
|
||||
void* ignored = ops_;
|
||||
|
||||
if (!ops_->FinalizeResult(&ignored, &ok)) {
|
||||
// The tag was swallowed
|
||||
return;
|
||||
}
|
||||
GPR_ASSERT(ignored == ops_);
|
||||
|
||||
// Last use of func_ or status_, so ok to move them out
|
||||
auto func = std::move(func_);
|
||||
auto status = std::move(status_);
|
||||
func_ = nullptr; // reset to clear this out for sure
|
||||
status_ = Status(); // reset to clear this out for sure
|
||||
CatchingCallback(std::move(func), std::move(status));
|
||||
grpc_call_unref(call_);
|
||||
}
|
||||
};
|
||||
|
||||
/// CallbackWithSuccessTag can be reused multiple times, and will be used in
|
||||
/// this fashion for streaming operations. As a result, it shouldn't clear
|
||||
/// anything up until its destructor
|
||||
class CallbackWithSuccessTag : public grpc_completion_queue_functor {
|
||||
public:
|
||||
// always allocated against a call arena, no memory free required
|
||||
static void operator delete(void* /*ptr*/, std::size_t size) {
|
||||
GPR_ASSERT(size == sizeof(CallbackWithSuccessTag));
|
||||
}
|
||||
|
||||
// This operator should never be called as the memory should be freed as part
|
||||
// of the arena destruction. It only exists to provide a matching operator
|
||||
// delete to the operator new so that some compilers will not complain (see
|
||||
// https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
|
||||
// there are no tests catching the compiler warning.
|
||||
static void operator delete(void*, void*) { GPR_ASSERT(false); }
|
||||
|
||||
CallbackWithSuccessTag() : call_(nullptr) {}
|
||||
|
||||
CallbackWithSuccessTag(const CallbackWithSuccessTag&) = delete;
|
||||
CallbackWithSuccessTag& operator=(const CallbackWithSuccessTag&) = delete;
|
||||
|
||||
~CallbackWithSuccessTag() { Clear(); }
|
||||
|
||||
// Set can only be called on a default-constructed or Clear'ed tag.
|
||||
// It should never be called on a tag that was constructed with arguments
|
||||
// or on a tag that has been Set before unless the tag has been cleared.
|
||||
// can_inline indicates that this particular callback can be executed inline
|
||||
// (without needing a thread hop) and is only used for library-provided server
|
||||
// callbacks.
|
||||
void Set(grpc_call* call, std::function<void(bool)> f,
|
||||
CompletionQueueTag* ops, bool can_inline) {
|
||||
GPR_ASSERT(call_ == nullptr);
|
||||
grpc_call_ref(call);
|
||||
call_ = call;
|
||||
func_ = std::move(f);
|
||||
ops_ = ops;
|
||||
functor_run = &CallbackWithSuccessTag::StaticRun;
|
||||
inlineable = can_inline;
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
if (call_ != nullptr) {
|
||||
grpc_call* call = call_;
|
||||
call_ = nullptr;
|
||||
func_ = nullptr;
|
||||
grpc_call_unref(call);
|
||||
}
|
||||
}
|
||||
|
||||
CompletionQueueTag* ops() { return ops_; }
|
||||
|
||||
// force_run can not be performed on a tag if operations using this tag
|
||||
// have been sent to PerformOpsOnCall. It is intended for error conditions
|
||||
// that are detected before the operations are internally processed.
|
||||
void force_run(bool ok) { Run(ok); }
|
||||
|
||||
/// check if this tag is currently set
|
||||
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||
operator bool() const { return call_ != nullptr; }
|
||||
|
||||
private:
|
||||
grpc_call* call_;
|
||||
std::function<void(bool)> func_;
|
||||
CompletionQueueTag* ops_;
|
||||
|
||||
static void StaticRun(grpc_completion_queue_functor* cb, int ok) {
|
||||
static_cast<CallbackWithSuccessTag*>(cb)->Run(static_cast<bool>(ok));
|
||||
}
|
||||
void Run(bool ok) {
|
||||
void* ignored = ops_;
|
||||
// Allow a "false" return value from FinalizeResult to silence the
|
||||
// callback, just as it silences a CQ tag in the async cases
|
||||
#ifndef NDEBUG
|
||||
auto* ops = ops_;
|
||||
#endif
|
||||
bool do_callback = ops_->FinalizeResult(&ignored, &ok);
|
||||
GPR_DEBUG_ASSERT(ignored == ops);
|
||||
|
||||
if (do_callback) {
|
||||
CatchingCallback(func_, ok);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace grpc
|
||||
|
||||
#endif // GRPCPP_SUPPORT_CALLBACK_COMMON_H
|
||||
146
Pods/gRPC-C++/include/grpcpp/support/channel_arguments.h
generated
Normal file
146
Pods/gRPC-C++/include/grpcpp/support/channel_arguments.h
generated
Normal file
@@ -0,0 +1,146 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2015 gRPC 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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef GRPCPP_SUPPORT_CHANNEL_ARGUMENTS_H
|
||||
#define GRPCPP_SUPPORT_CHANNEL_ARGUMENTS_H
|
||||
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
#include <grpc/compression.h>
|
||||
#include <grpc/grpc.h>
|
||||
#include <grpcpp/resource_quota.h>
|
||||
#include <grpcpp/support/config.h>
|
||||
|
||||
namespace grpc {
|
||||
class SecureChannelCredentials;
|
||||
namespace testing {
|
||||
class ChannelArgumentsTest;
|
||||
} // namespace testing
|
||||
|
||||
/// Options for channel creation. The user can use generic setters to pass
|
||||
/// key value pairs down to C channel creation code. For gRPC related options,
|
||||
/// concrete setters are provided.
|
||||
class ChannelArguments {
|
||||
public:
|
||||
ChannelArguments();
|
||||
~ChannelArguments();
|
||||
|
||||
ChannelArguments(const ChannelArguments& other);
|
||||
ChannelArguments& operator=(ChannelArguments other) {
|
||||
Swap(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Swap(ChannelArguments& other);
|
||||
|
||||
/// Dump arguments in this instance to \a channel_args. Does not take
|
||||
/// ownership of \a channel_args.
|
||||
///
|
||||
/// Note that the underlying arguments are shared. Changes made to either \a
|
||||
/// channel_args or this instance would be reflected on both.
|
||||
void SetChannelArgs(grpc_channel_args* channel_args) const;
|
||||
|
||||
// gRPC specific channel argument setters
|
||||
/// Set target name override for SSL host name checking. This option should
|
||||
/// be used with caution in production.
|
||||
void SetSslTargetNameOverride(const std::string& name);
|
||||
// TODO(yangg) add flow control options
|
||||
/// Set the compression algorithm for the channel.
|
||||
void SetCompressionAlgorithm(grpc_compression_algorithm algorithm);
|
||||
|
||||
/// Set the grpclb fallback timeout (in ms) for the channel. If this amount
|
||||
/// of time has passed but we have not gotten any non-empty \a serverlist from
|
||||
/// the balancer, we will fall back to use the backend address(es) returned by
|
||||
/// the resolver.
|
||||
void SetGrpclbFallbackTimeout(int fallback_timeout);
|
||||
|
||||
/// Set a mutator for the underlying socket.
|
||||
void SetSocketMutator(grpc_socket_mutator* mutator);
|
||||
|
||||
/// Set the string to prepend to the user agent.
|
||||
void SetUserAgentPrefix(const std::string& user_agent_prefix);
|
||||
|
||||
/// Set the buffer pool to be attached to the constructed channel.
|
||||
void SetResourceQuota(const grpc::ResourceQuota& resource_quota);
|
||||
|
||||
/// Set the max receive and send message sizes.
|
||||
void SetMaxReceiveMessageSize(int size);
|
||||
void SetMaxSendMessageSize(int size);
|
||||
|
||||
/// Set LB policy name.
|
||||
/// Note that if the name resolver returns only balancer addresses, the
|
||||
/// grpclb LB policy will be used, regardless of what is specified here.
|
||||
void SetLoadBalancingPolicyName(const std::string& lb_policy_name);
|
||||
|
||||
/// Set service config in JSON form.
|
||||
/// Primarily meant for use in unit tests.
|
||||
void SetServiceConfigJSON(const std::string& service_config_json);
|
||||
|
||||
// Generic channel argument setter. Only for advanced use cases.
|
||||
/// Set an integer argument \a value under \a key.
|
||||
void SetInt(const std::string& key, int value);
|
||||
|
||||
// Generic channel argument setter. Only for advanced use cases.
|
||||
/// Set a pointer argument \a value under \a key. Ownership is not
|
||||
/// transferred.
|
||||
void SetPointer(const std::string& key, void* value);
|
||||
|
||||
/// Set a pointer argument \a value under \a key, transferring ownership of
|
||||
/// \a value to the \a ChannelArguments object. The \a vtable::Delete function
|
||||
/// is responsible for \a value cleanup/destruction when called.
|
||||
void SetPointerWithVtable(const std::string& key, void* value,
|
||||
const grpc_arg_pointer_vtable* vtable);
|
||||
|
||||
/// Set a textual argument \a value under \a key.
|
||||
void SetString(const std::string& key, const std::string& value);
|
||||
|
||||
/// Return (by value) a C \a grpc_channel_args structure which points to
|
||||
/// arguments owned by this \a ChannelArguments instance
|
||||
grpc_channel_args c_channel_args() const {
|
||||
grpc_channel_args out;
|
||||
out.num_args = args_.size();
|
||||
out.args = args_.empty() ? nullptr : const_cast<grpc_arg*>(&args_[0]);
|
||||
return out;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class grpc::SecureChannelCredentials;
|
||||
friend class grpc::testing::ChannelArgumentsTest;
|
||||
|
||||
/// Default pointer argument operations.
|
||||
struct PointerVtableMembers {
|
||||
static void* Copy(void* in) { return in; }
|
||||
static void Destroy(void* /*in*/) {}
|
||||
static int Compare(void* a, void* b) {
|
||||
if (a < b) return -1;
|
||||
if (a > b) return 1;
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
// Returns empty string when it is not set.
|
||||
std::string GetSslTargetNameOverride() const;
|
||||
|
||||
std::vector<grpc_arg> args_;
|
||||
std::list<std::string> strings_;
|
||||
};
|
||||
|
||||
} // namespace grpc
|
||||
|
||||
#endif // GRPCPP_SUPPORT_CHANNEL_ARGUMENTS_H
|
||||
1225
Pods/gRPC-C++/include/grpcpp/support/client_callback.h
generated
Normal file
1225
Pods/gRPC-C++/include/grpcpp/support/client_callback.h
generated
Normal file
@@ -0,0 +1,1225 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2018 gRPC 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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef GRPCPP_SUPPORT_CLIENT_CALLBACK_H
|
||||
#define GRPCPP_SUPPORT_CLIENT_CALLBACK_H
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
|
||||
#include <grpc/grpc.h>
|
||||
#include <grpc/impl/call.h>
|
||||
#include <grpc/support/log.h>
|
||||
#include <grpcpp/impl/call.h>
|
||||
#include <grpcpp/impl/call_op_set.h>
|
||||
#include <grpcpp/impl/sync.h>
|
||||
#include <grpcpp/support/callback_common.h>
|
||||
#include <grpcpp/support/config.h>
|
||||
#include <grpcpp/support/status.h>
|
||||
|
||||
namespace grpc {
|
||||
class Channel;
|
||||
class ClientContext;
|
||||
|
||||
namespace internal {
|
||||
class RpcMethod;
|
||||
|
||||
/// Perform a callback-based unary call. May optionally specify the base
|
||||
/// class of the Request and Response so that the internal calls and structures
|
||||
/// below this may be based on those base classes and thus achieve code reuse
|
||||
/// across different RPCs (e.g., for protobuf, MessageLite would be a base
|
||||
/// class).
|
||||
/// TODO(vjpai): Combine as much as possible with the blocking unary call code
|
||||
template <class InputMessage, class OutputMessage,
|
||||
class BaseInputMessage = InputMessage,
|
||||
class BaseOutputMessage = OutputMessage>
|
||||
void CallbackUnaryCall(grpc::ChannelInterface* channel,
|
||||
const grpc::internal::RpcMethod& method,
|
||||
grpc::ClientContext* context,
|
||||
const InputMessage* request, OutputMessage* result,
|
||||
std::function<void(grpc::Status)> on_completion) {
|
||||
static_assert(std::is_base_of<BaseInputMessage, InputMessage>::value,
|
||||
"Invalid input message specification");
|
||||
static_assert(std::is_base_of<BaseOutputMessage, OutputMessage>::value,
|
||||
"Invalid output message specification");
|
||||
CallbackUnaryCallImpl<BaseInputMessage, BaseOutputMessage> x(
|
||||
channel, method, context, request, result, on_completion);
|
||||
}
|
||||
|
||||
template <class InputMessage, class OutputMessage>
|
||||
class CallbackUnaryCallImpl {
|
||||
public:
|
||||
CallbackUnaryCallImpl(grpc::ChannelInterface* channel,
|
||||
const grpc::internal::RpcMethod& method,
|
||||
grpc::ClientContext* context,
|
||||
const InputMessage* request, OutputMessage* result,
|
||||
std::function<void(grpc::Status)> on_completion) {
|
||||
grpc::CompletionQueue* cq = channel->CallbackCQ();
|
||||
GPR_ASSERT(cq != nullptr);
|
||||
grpc::internal::Call call(channel->CreateCall(method, context, cq));
|
||||
|
||||
using FullCallOpSet = grpc::internal::CallOpSet<
|
||||
grpc::internal::CallOpSendInitialMetadata,
|
||||
grpc::internal::CallOpSendMessage,
|
||||
grpc::internal::CallOpRecvInitialMetadata,
|
||||
grpc::internal::CallOpRecvMessage<OutputMessage>,
|
||||
grpc::internal::CallOpClientSendClose,
|
||||
grpc::internal::CallOpClientRecvStatus>;
|
||||
|
||||
struct OpSetAndTag {
|
||||
FullCallOpSet opset;
|
||||
grpc::internal::CallbackWithStatusTag tag;
|
||||
};
|
||||
const size_t alloc_sz = sizeof(OpSetAndTag);
|
||||
auto* const alloced =
|
||||
static_cast<OpSetAndTag*>(grpc_call_arena_alloc(call.call(), alloc_sz));
|
||||
auto* ops = new (&alloced->opset) FullCallOpSet;
|
||||
auto* tag = new (&alloced->tag)
|
||||
grpc::internal::CallbackWithStatusTag(call.call(), on_completion, ops);
|
||||
|
||||
// TODO(vjpai): Unify code with sync API as much as possible
|
||||
grpc::Status s = ops->SendMessagePtr(request);
|
||||
if (!s.ok()) {
|
||||
tag->force_run(s);
|
||||
return;
|
||||
}
|
||||
ops->SendInitialMetadata(&context->send_initial_metadata_,
|
||||
context->initial_metadata_flags());
|
||||
ops->RecvInitialMetadata(context);
|
||||
ops->RecvMessage(result);
|
||||
ops->AllowNoMessage();
|
||||
ops->ClientSendClose();
|
||||
ops->ClientRecvStatus(context, tag->status_ptr());
|
||||
ops->set_core_cq_tag(tag);
|
||||
call.PerformOps(ops);
|
||||
}
|
||||
};
|
||||
|
||||
// Base class for public API classes.
|
||||
class ClientReactor {
|
||||
public:
|
||||
virtual ~ClientReactor() = default;
|
||||
|
||||
/// Called by the library when all operations associated with this RPC have
|
||||
/// completed and all Holds have been removed. OnDone provides the RPC status
|
||||
/// outcome for both successful and failed RPCs. If it is never called on an
|
||||
/// RPC, it indicates an application-level problem (like failure to remove a
|
||||
/// hold).
|
||||
///
|
||||
/// \param[in] s The status outcome of this RPC
|
||||
virtual void OnDone(const grpc::Status& /*s*/) = 0;
|
||||
|
||||
/// InternalTrailersOnly is not part of the API and is not meant to be
|
||||
/// overridden. It is virtual to allow successful builds for certain bazel
|
||||
/// build users that only want to depend on gRPC codegen headers and not the
|
||||
/// full library (although this is not a generally-supported option). Although
|
||||
/// the virtual call is slower than a direct call, this function is
|
||||
/// heavyweight and the cost of the virtual call is not much in comparison.
|
||||
/// This function may be removed or devirtualized in the future.
|
||||
virtual bool InternalTrailersOnly(const grpc_call* call) const;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// Forward declarations
|
||||
template <class Request, class Response>
|
||||
class ClientBidiReactor;
|
||||
template <class Response>
|
||||
class ClientReadReactor;
|
||||
template <class Request>
|
||||
class ClientWriteReactor;
|
||||
class ClientUnaryReactor;
|
||||
|
||||
// NOTE: The streaming objects are not actually implemented in the public API.
|
||||
// These interfaces are provided for mocking only. Typical applications
|
||||
// will interact exclusively with the reactors that they define.
|
||||
template <class Request, class Response>
|
||||
class ClientCallbackReaderWriter {
|
||||
public:
|
||||
virtual ~ClientCallbackReaderWriter() {}
|
||||
virtual void StartCall() = 0;
|
||||
virtual void Write(const Request* req, grpc::WriteOptions options) = 0;
|
||||
virtual void WritesDone() = 0;
|
||||
virtual void Read(Response* resp) = 0;
|
||||
virtual void AddHold(int holds) = 0;
|
||||
virtual void RemoveHold() = 0;
|
||||
|
||||
protected:
|
||||
void BindReactor(ClientBidiReactor<Request, Response>* reactor) {
|
||||
reactor->BindStream(this);
|
||||
}
|
||||
};
|
||||
|
||||
template <class Response>
|
||||
class ClientCallbackReader {
|
||||
public:
|
||||
virtual ~ClientCallbackReader() {}
|
||||
virtual void StartCall() = 0;
|
||||
virtual void Read(Response* resp) = 0;
|
||||
virtual void AddHold(int holds) = 0;
|
||||
virtual void RemoveHold() = 0;
|
||||
|
||||
protected:
|
||||
void BindReactor(ClientReadReactor<Response>* reactor) {
|
||||
reactor->BindReader(this);
|
||||
}
|
||||
};
|
||||
|
||||
template <class Request>
|
||||
class ClientCallbackWriter {
|
||||
public:
|
||||
virtual ~ClientCallbackWriter() {}
|
||||
virtual void StartCall() = 0;
|
||||
void Write(const Request* req) { Write(req, grpc::WriteOptions()); }
|
||||
virtual void Write(const Request* req, grpc::WriteOptions options) = 0;
|
||||
void WriteLast(const Request* req, grpc::WriteOptions options) {
|
||||
Write(req, options.set_last_message());
|
||||
}
|
||||
virtual void WritesDone() = 0;
|
||||
|
||||
virtual void AddHold(int holds) = 0;
|
||||
virtual void RemoveHold() = 0;
|
||||
|
||||
protected:
|
||||
void BindReactor(ClientWriteReactor<Request>* reactor) {
|
||||
reactor->BindWriter(this);
|
||||
}
|
||||
};
|
||||
|
||||
class ClientCallbackUnary {
|
||||
public:
|
||||
virtual ~ClientCallbackUnary() {}
|
||||
virtual void StartCall() = 0;
|
||||
|
||||
protected:
|
||||
void BindReactor(ClientUnaryReactor* reactor);
|
||||
};
|
||||
|
||||
// The following classes are the reactor interfaces that are to be implemented
|
||||
// by the user. They are passed in to the library as an argument to a call on a
|
||||
// stub (either a codegen-ed call or a generic call). The streaming RPC is
|
||||
// activated by calling StartCall, possibly after initiating StartRead,
|
||||
// StartWrite, or AddHold operations on the streaming object. Note that none of
|
||||
// the classes are pure; all reactions have a default empty reaction so that the
|
||||
// user class only needs to override those reactions that it cares about.
|
||||
// The reactor must be passed to the stub invocation before any of the below
|
||||
// operations can be called and its reactions will be invoked by the library in
|
||||
// response to the completion of various operations. Reactions must not include
|
||||
// blocking operations (such as blocking I/O, starting synchronous RPCs, or
|
||||
// waiting on condition variables). Reactions may be invoked concurrently,
|
||||
// except that OnDone is called after all others (assuming proper API usage).
|
||||
// The reactor may not be deleted until OnDone is called.
|
||||
|
||||
/// \a ClientBidiReactor is the interface for a bidirectional streaming RPC.
|
||||
template <class Request, class Response>
|
||||
class ClientBidiReactor : public internal::ClientReactor {
|
||||
public:
|
||||
/// Activate the RPC and initiate any reads or writes that have been Start'ed
|
||||
/// before this call. All streaming RPCs issued by the client MUST have
|
||||
/// StartCall invoked on them (even if they are canceled) as this call is the
|
||||
/// activation of their lifecycle.
|
||||
void StartCall() { stream_->StartCall(); }
|
||||
|
||||
/// Initiate a read operation (or post it for later initiation if StartCall
|
||||
/// has not yet been invoked).
|
||||
///
|
||||
/// \param[out] resp Where to eventually store the read message. Valid when
|
||||
/// the library calls OnReadDone
|
||||
void StartRead(Response* resp) { stream_->Read(resp); }
|
||||
|
||||
/// Initiate a write operation (or post it for later initiation if StartCall
|
||||
/// has not yet been invoked).
|
||||
///
|
||||
/// \param[in] req The message to be written. The library does not take
|
||||
/// ownership but the caller must ensure that the message is
|
||||
/// not deleted or modified until OnWriteDone is called.
|
||||
void StartWrite(const Request* req) { StartWrite(req, grpc::WriteOptions()); }
|
||||
|
||||
/// Initiate/post a write operation with specified options.
|
||||
///
|
||||
/// \param[in] req The message to be written. The library does not take
|
||||
/// ownership but the caller must ensure that the message is
|
||||
/// not deleted or modified until OnWriteDone is called.
|
||||
/// \param[in] options The WriteOptions to use for writing this message
|
||||
void StartWrite(const Request* req, grpc::WriteOptions options) {
|
||||
stream_->Write(req, options);
|
||||
}
|
||||
|
||||
/// Initiate/post a write operation with specified options and an indication
|
||||
/// that this is the last write (like StartWrite and StartWritesDone, merged).
|
||||
/// Note that calling this means that no more calls to StartWrite,
|
||||
/// StartWriteLast, or StartWritesDone are allowed.
|
||||
///
|
||||
/// \param[in] req The message to be written. The library does not take
|
||||
/// ownership but the caller must ensure that the message is
|
||||
/// not deleted or modified until OnWriteDone is called.
|
||||
/// \param[in] options The WriteOptions to use for writing this message
|
||||
void StartWriteLast(const Request* req, grpc::WriteOptions options) {
|
||||
StartWrite(req, options.set_last_message());
|
||||
}
|
||||
|
||||
/// Indicate that the RPC will have no more write operations. This can only be
|
||||
/// issued once for a given RPC. This is not required or allowed if
|
||||
/// StartWriteLast is used since that already has the same implication.
|
||||
/// Note that calling this means that no more calls to StartWrite,
|
||||
/// StartWriteLast, or StartWritesDone are allowed.
|
||||
void StartWritesDone() { stream_->WritesDone(); }
|
||||
|
||||
/// Holds are needed if (and only if) this stream has operations that take
|
||||
/// place on it after StartCall but from outside one of the reactions
|
||||
/// (OnReadDone, etc). This is _not_ a common use of the streaming API.
|
||||
///
|
||||
/// Holds must be added before calling StartCall. If a stream still has a hold
|
||||
/// in place, its resources will not be destroyed even if the status has
|
||||
/// already come in from the wire and there are currently no active callbacks
|
||||
/// outstanding. Similarly, the stream will not call OnDone if there are still
|
||||
/// holds on it.
|
||||
///
|
||||
/// For example, if a StartRead or StartWrite operation is going to be
|
||||
/// initiated from elsewhere in the application, the application should call
|
||||
/// AddHold or AddMultipleHolds before StartCall. If there is going to be,
|
||||
/// for example, a read-flow and a write-flow taking place outside the
|
||||
/// reactions, then call AddMultipleHolds(2) before StartCall. When the
|
||||
/// application knows that it won't issue any more read operations (such as
|
||||
/// when a read comes back as not ok), it should issue a RemoveHold(). It
|
||||
/// should also call RemoveHold() again after it does StartWriteLast or
|
||||
/// StartWritesDone that indicates that there will be no more write ops.
|
||||
/// The number of RemoveHold calls must match the total number of AddHold
|
||||
/// calls plus the number of holds added by AddMultipleHolds.
|
||||
/// The argument to AddMultipleHolds must be positive.
|
||||
void AddHold() { AddMultipleHolds(1); }
|
||||
void AddMultipleHolds(int holds) {
|
||||
GPR_DEBUG_ASSERT(holds > 0);
|
||||
stream_->AddHold(holds);
|
||||
}
|
||||
void RemoveHold() { stream_->RemoveHold(); }
|
||||
|
||||
/// Notifies the application that all operations associated with this RPC
|
||||
/// have completed and all Holds have been removed. OnDone provides the RPC
|
||||
/// status outcome for both successful and failed RPCs and will be called in
|
||||
/// all cases. If it is not called, it indicates an application-level problem
|
||||
/// (like failure to remove a hold).
|
||||
///
|
||||
/// \param[in] s The status outcome of this RPC
|
||||
void OnDone(const grpc::Status& /*s*/) override {}
|
||||
|
||||
/// Notifies the application that a read of initial metadata from the
|
||||
/// server is done. If the application chooses not to implement this method,
|
||||
/// it can assume that the initial metadata has been read before the first
|
||||
/// call of OnReadDone or OnDone.
|
||||
///
|
||||
/// \param[in] ok Was the initial metadata read successfully? If false, no
|
||||
/// new read/write operation will succeed, and any further
|
||||
/// Start* operations should not be called.
|
||||
virtual void OnReadInitialMetadataDone(bool /*ok*/) {}
|
||||
|
||||
/// Notifies the application that a StartRead operation completed.
|
||||
///
|
||||
/// \param[in] ok Was it successful? If false, no new read/write operation
|
||||
/// will succeed, and any further Start* should not be called.
|
||||
virtual void OnReadDone(bool /*ok*/) {}
|
||||
|
||||
/// Notifies the application that a StartWrite or StartWriteLast operation
|
||||
/// completed.
|
||||
///
|
||||
/// \param[in] ok Was it successful? If false, no new read/write operation
|
||||
/// will succeed, and any further Start* should not be called.
|
||||
virtual void OnWriteDone(bool /*ok*/) {}
|
||||
|
||||
/// Notifies the application that a StartWritesDone operation completed. Note
|
||||
/// that this is only used on explicit StartWritesDone operations and not for
|
||||
/// those that are implicitly invoked as part of a StartWriteLast.
|
||||
///
|
||||
/// \param[in] ok Was it successful? If false, the application will later see
|
||||
/// the failure reflected as a bad status in OnDone and no
|
||||
/// further Start* should be called.
|
||||
virtual void OnWritesDoneDone(bool /*ok*/) {}
|
||||
|
||||
private:
|
||||
friend class ClientCallbackReaderWriter<Request, Response>;
|
||||
void BindStream(ClientCallbackReaderWriter<Request, Response>* stream) {
|
||||
stream_ = stream;
|
||||
}
|
||||
ClientCallbackReaderWriter<Request, Response>* stream_;
|
||||
};
|
||||
|
||||
/// \a ClientReadReactor is the interface for a server-streaming RPC.
|
||||
/// All public methods behave as in ClientBidiReactor.
|
||||
template <class Response>
|
||||
class ClientReadReactor : public internal::ClientReactor {
|
||||
public:
|
||||
void StartCall() { reader_->StartCall(); }
|
||||
void StartRead(Response* resp) { reader_->Read(resp); }
|
||||
|
||||
void AddHold() { AddMultipleHolds(1); }
|
||||
void AddMultipleHolds(int holds) {
|
||||
GPR_DEBUG_ASSERT(holds > 0);
|
||||
reader_->AddHold(holds);
|
||||
}
|
||||
void RemoveHold() { reader_->RemoveHold(); }
|
||||
|
||||
void OnDone(const grpc::Status& /*s*/) override {}
|
||||
virtual void OnReadInitialMetadataDone(bool /*ok*/) {}
|
||||
virtual void OnReadDone(bool /*ok*/) {}
|
||||
|
||||
private:
|
||||
friend class ClientCallbackReader<Response>;
|
||||
void BindReader(ClientCallbackReader<Response>* reader) { reader_ = reader; }
|
||||
ClientCallbackReader<Response>* reader_;
|
||||
};
|
||||
|
||||
/// \a ClientWriteReactor is the interface for a client-streaming RPC.
|
||||
/// All public methods behave as in ClientBidiReactor.
|
||||
template <class Request>
|
||||
class ClientWriteReactor : public internal::ClientReactor {
|
||||
public:
|
||||
void StartCall() { writer_->StartCall(); }
|
||||
void StartWrite(const Request* req) { StartWrite(req, grpc::WriteOptions()); }
|
||||
void StartWrite(const Request* req, grpc::WriteOptions options) {
|
||||
writer_->Write(req, options);
|
||||
}
|
||||
void StartWriteLast(const Request* req, grpc::WriteOptions options) {
|
||||
StartWrite(req, options.set_last_message());
|
||||
}
|
||||
void StartWritesDone() { writer_->WritesDone(); }
|
||||
|
||||
void AddHold() { AddMultipleHolds(1); }
|
||||
void AddMultipleHolds(int holds) {
|
||||
GPR_DEBUG_ASSERT(holds > 0);
|
||||
writer_->AddHold(holds);
|
||||
}
|
||||
void RemoveHold() { writer_->RemoveHold(); }
|
||||
|
||||
void OnDone(const grpc::Status& /*s*/) override {}
|
||||
virtual void OnReadInitialMetadataDone(bool /*ok*/) {}
|
||||
virtual void OnWriteDone(bool /*ok*/) {}
|
||||
virtual void OnWritesDoneDone(bool /*ok*/) {}
|
||||
|
||||
private:
|
||||
friend class ClientCallbackWriter<Request>;
|
||||
void BindWriter(ClientCallbackWriter<Request>* writer) { writer_ = writer; }
|
||||
|
||||
ClientCallbackWriter<Request>* writer_;
|
||||
};
|
||||
|
||||
/// \a ClientUnaryReactor is a reactor-style interface for a unary RPC.
|
||||
/// This is _not_ a common way of invoking a unary RPC. In practice, this
|
||||
/// option should be used only if the unary RPC wants to receive initial
|
||||
/// metadata without waiting for the response to complete. Most deployments of
|
||||
/// RPC systems do not use this option, but it is needed for generality.
|
||||
/// All public methods behave as in ClientBidiReactor.
|
||||
/// StartCall is included for consistency with the other reactor flavors: even
|
||||
/// though there are no StartRead or StartWrite operations to queue before the
|
||||
/// call (that is part of the unary call itself) and there is no reactor object
|
||||
/// being created as a result of this call, we keep a consistent 2-phase
|
||||
/// initiation API among all the reactor flavors.
|
||||
class ClientUnaryReactor : public internal::ClientReactor {
|
||||
public:
|
||||
void StartCall() { call_->StartCall(); }
|
||||
void OnDone(const grpc::Status& /*s*/) override {}
|
||||
virtual void OnReadInitialMetadataDone(bool /*ok*/) {}
|
||||
|
||||
private:
|
||||
friend class ClientCallbackUnary;
|
||||
void BindCall(ClientCallbackUnary* call) { call_ = call; }
|
||||
ClientCallbackUnary* call_;
|
||||
};
|
||||
|
||||
// Define function out-of-line from class to avoid forward declaration issue
|
||||
inline void ClientCallbackUnary::BindReactor(ClientUnaryReactor* reactor) {
|
||||
reactor->BindCall(this);
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
|
||||
// Forward declare factory classes for friendship
|
||||
template <class Request, class Response>
|
||||
class ClientCallbackReaderWriterFactory;
|
||||
template <class Response>
|
||||
class ClientCallbackReaderFactory;
|
||||
template <class Request>
|
||||
class ClientCallbackWriterFactory;
|
||||
|
||||
template <class Request, class Response>
|
||||
class ClientCallbackReaderWriterImpl
|
||||
: public ClientCallbackReaderWriter<Request, Response> {
|
||||
public:
|
||||
// always allocated against a call arena, no memory free required
|
||||
static void operator delete(void* /*ptr*/, std::size_t size) {
|
||||
GPR_ASSERT(size == sizeof(ClientCallbackReaderWriterImpl));
|
||||
}
|
||||
|
||||
// This operator should never be called as the memory should be freed as part
|
||||
// of the arena destruction. It only exists to provide a matching operator
|
||||
// delete to the operator new so that some compilers will not complain (see
|
||||
// https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
|
||||
// there are no tests catching the compiler warning.
|
||||
static void operator delete(void*, void*) { GPR_ASSERT(false); }
|
||||
|
||||
void StartCall() ABSL_LOCKS_EXCLUDED(start_mu_) override {
|
||||
// This call initiates two batches, plus any backlog, each with a callback
|
||||
// 1. Send initial metadata (unless corked) + recv initial metadata
|
||||
// 2. Any read backlog
|
||||
// 3. Any write backlog
|
||||
// 4. Recv trailing metadata (unless corked)
|
||||
if (!start_corked_) {
|
||||
start_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
|
||||
context_->initial_metadata_flags());
|
||||
}
|
||||
|
||||
call_.PerformOps(&start_ops_);
|
||||
|
||||
{
|
||||
grpc::internal::MutexLock lock(&start_mu_);
|
||||
|
||||
if (backlog_.read_ops) {
|
||||
call_.PerformOps(&read_ops_);
|
||||
}
|
||||
if (backlog_.write_ops) {
|
||||
call_.PerformOps(&write_ops_);
|
||||
}
|
||||
if (backlog_.writes_done_ops) {
|
||||
call_.PerformOps(&writes_done_ops_);
|
||||
}
|
||||
call_.PerformOps(&finish_ops_);
|
||||
// The last thing in this critical section is to set started_ so that it
|
||||
// can be used lock-free as well.
|
||||
started_.store(true, std::memory_order_release);
|
||||
}
|
||||
// MaybeFinish outside the lock to make sure that destruction of this object
|
||||
// doesn't take place while holding the lock (which would cause the lock to
|
||||
// be released after destruction)
|
||||
this->MaybeFinish(/*from_reaction=*/false);
|
||||
}
|
||||
|
||||
void Read(Response* msg) override {
|
||||
read_ops_.RecvMessage(msg);
|
||||
callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed);
|
||||
if (GPR_UNLIKELY(!started_.load(std::memory_order_acquire))) {
|
||||
grpc::internal::MutexLock lock(&start_mu_);
|
||||
if (GPR_LIKELY(!started_.load(std::memory_order_relaxed))) {
|
||||
backlog_.read_ops = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
call_.PerformOps(&read_ops_);
|
||||
}
|
||||
|
||||
void Write(const Request* msg, grpc::WriteOptions options)
|
||||
ABSL_LOCKS_EXCLUDED(start_mu_) override {
|
||||
if (options.is_last_message()) {
|
||||
options.set_buffer_hint();
|
||||
write_ops_.ClientSendClose();
|
||||
}
|
||||
// TODO(vjpai): don't assert
|
||||
GPR_ASSERT(write_ops_.SendMessagePtr(msg, options).ok());
|
||||
callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed);
|
||||
if (GPR_UNLIKELY(corked_write_needed_)) {
|
||||
write_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
|
||||
context_->initial_metadata_flags());
|
||||
corked_write_needed_ = false;
|
||||
}
|
||||
|
||||
if (GPR_UNLIKELY(!started_.load(std::memory_order_acquire))) {
|
||||
grpc::internal::MutexLock lock(&start_mu_);
|
||||
if (GPR_LIKELY(!started_.load(std::memory_order_relaxed))) {
|
||||
backlog_.write_ops = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
call_.PerformOps(&write_ops_);
|
||||
}
|
||||
void WritesDone() ABSL_LOCKS_EXCLUDED(start_mu_) override {
|
||||
writes_done_ops_.ClientSendClose();
|
||||
writes_done_tag_.Set(
|
||||
call_.call(),
|
||||
[this](bool ok) {
|
||||
reactor_->OnWritesDoneDone(ok);
|
||||
MaybeFinish(/*from_reaction=*/true);
|
||||
},
|
||||
&writes_done_ops_, /*can_inline=*/false);
|
||||
writes_done_ops_.set_core_cq_tag(&writes_done_tag_);
|
||||
callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed);
|
||||
if (GPR_UNLIKELY(corked_write_needed_)) {
|
||||
writes_done_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
|
||||
context_->initial_metadata_flags());
|
||||
corked_write_needed_ = false;
|
||||
}
|
||||
if (GPR_UNLIKELY(!started_.load(std::memory_order_acquire))) {
|
||||
grpc::internal::MutexLock lock(&start_mu_);
|
||||
if (GPR_LIKELY(!started_.load(std::memory_order_relaxed))) {
|
||||
backlog_.writes_done_ops = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
call_.PerformOps(&writes_done_ops_);
|
||||
}
|
||||
|
||||
void AddHold(int holds) override {
|
||||
callbacks_outstanding_.fetch_add(holds, std::memory_order_relaxed);
|
||||
}
|
||||
void RemoveHold() override { MaybeFinish(/*from_reaction=*/false); }
|
||||
|
||||
private:
|
||||
friend class ClientCallbackReaderWriterFactory<Request, Response>;
|
||||
|
||||
ClientCallbackReaderWriterImpl(grpc::internal::Call call,
|
||||
grpc::ClientContext* context,
|
||||
ClientBidiReactor<Request, Response>* reactor)
|
||||
: context_(context),
|
||||
call_(call),
|
||||
reactor_(reactor),
|
||||
start_corked_(context_->initial_metadata_corked_),
|
||||
corked_write_needed_(start_corked_) {
|
||||
this->BindReactor(reactor);
|
||||
|
||||
// Set up the unchanging parts of the start, read, and write tags and ops.
|
||||
start_tag_.Set(
|
||||
call_.call(),
|
||||
[this](bool ok) {
|
||||
reactor_->OnReadInitialMetadataDone(
|
||||
ok && !reactor_->InternalTrailersOnly(call_.call()));
|
||||
MaybeFinish(/*from_reaction=*/true);
|
||||
},
|
||||
&start_ops_, /*can_inline=*/false);
|
||||
start_ops_.RecvInitialMetadata(context_);
|
||||
start_ops_.set_core_cq_tag(&start_tag_);
|
||||
|
||||
write_tag_.Set(
|
||||
call_.call(),
|
||||
[this](bool ok) {
|
||||
reactor_->OnWriteDone(ok);
|
||||
MaybeFinish(/*from_reaction=*/true);
|
||||
},
|
||||
&write_ops_, /*can_inline=*/false);
|
||||
write_ops_.set_core_cq_tag(&write_tag_);
|
||||
|
||||
read_tag_.Set(
|
||||
call_.call(),
|
||||
[this](bool ok) {
|
||||
reactor_->OnReadDone(ok);
|
||||
MaybeFinish(/*from_reaction=*/true);
|
||||
},
|
||||
&read_ops_, /*can_inline=*/false);
|
||||
read_ops_.set_core_cq_tag(&read_tag_);
|
||||
|
||||
// Also set up the Finish tag and op set.
|
||||
finish_tag_.Set(
|
||||
call_.call(),
|
||||
[this](bool /*ok*/) { MaybeFinish(/*from_reaction=*/true); },
|
||||
&finish_ops_,
|
||||
/*can_inline=*/false);
|
||||
finish_ops_.ClientRecvStatus(context_, &finish_status_);
|
||||
finish_ops_.set_core_cq_tag(&finish_tag_);
|
||||
}
|
||||
|
||||
// MaybeFinish can be called from reactions or from user-initiated operations
|
||||
// like StartCall or RemoveHold. If this is the last operation or hold on this
|
||||
// object, it will invoke the OnDone reaction. If MaybeFinish was called from
|
||||
// a reaction, it can call OnDone directly. If not, it would need to schedule
|
||||
// OnDone onto an executor thread to avoid the possibility of deadlocking with
|
||||
// any locks in the user code that invoked it.
|
||||
void MaybeFinish(bool from_reaction) {
|
||||
if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub(
|
||||
1, std::memory_order_acq_rel) == 1)) {
|
||||
grpc::Status s = std::move(finish_status_);
|
||||
auto* reactor = reactor_;
|
||||
auto* call = call_.call();
|
||||
this->~ClientCallbackReaderWriterImpl();
|
||||
if (GPR_LIKELY(from_reaction)) {
|
||||
grpc_call_unref(call);
|
||||
reactor->OnDone(s);
|
||||
} else {
|
||||
grpc_call_run_in_event_engine(
|
||||
call, [reactor, s = std::move(s)]() { reactor->OnDone(s); });
|
||||
grpc_call_unref(call);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grpc::ClientContext* const context_;
|
||||
grpc::internal::Call call_;
|
||||
ClientBidiReactor<Request, Response>* const reactor_;
|
||||
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,
|
||||
grpc::internal::CallOpRecvInitialMetadata>
|
||||
start_ops_;
|
||||
grpc::internal::CallbackWithSuccessTag start_tag_;
|
||||
const bool start_corked_;
|
||||
bool corked_write_needed_; // no lock needed since only accessed in
|
||||
// Write/WritesDone which cannot be concurrent
|
||||
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpClientRecvStatus> finish_ops_;
|
||||
grpc::internal::CallbackWithSuccessTag finish_tag_;
|
||||
grpc::Status finish_status_;
|
||||
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,
|
||||
grpc::internal::CallOpSendMessage,
|
||||
grpc::internal::CallOpClientSendClose>
|
||||
write_ops_;
|
||||
grpc::internal::CallbackWithSuccessTag write_tag_;
|
||||
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,
|
||||
grpc::internal::CallOpClientSendClose>
|
||||
writes_done_ops_;
|
||||
grpc::internal::CallbackWithSuccessTag writes_done_tag_;
|
||||
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpRecvMessage<Response>>
|
||||
read_ops_;
|
||||
grpc::internal::CallbackWithSuccessTag read_tag_;
|
||||
|
||||
struct StartCallBacklog {
|
||||
bool write_ops = false;
|
||||
bool writes_done_ops = false;
|
||||
bool read_ops = false;
|
||||
};
|
||||
StartCallBacklog backlog_ ABSL_GUARDED_BY(start_mu_);
|
||||
|
||||
// Minimum of 3 callbacks to pre-register for start ops, StartCall, and finish
|
||||
std::atomic<intptr_t> callbacks_outstanding_{3};
|
||||
std::atomic_bool started_{false};
|
||||
grpc::internal::Mutex start_mu_;
|
||||
};
|
||||
|
||||
template <class Request, class Response>
|
||||
class ClientCallbackReaderWriterFactory {
|
||||
public:
|
||||
static void Create(grpc::ChannelInterface* channel,
|
||||
const grpc::internal::RpcMethod& method,
|
||||
grpc::ClientContext* context,
|
||||
ClientBidiReactor<Request, Response>* reactor) {
|
||||
grpc::internal::Call call =
|
||||
channel->CreateCall(method, context, channel->CallbackCQ());
|
||||
|
||||
grpc_call_ref(call.call());
|
||||
new (grpc_call_arena_alloc(
|
||||
call.call(), sizeof(ClientCallbackReaderWriterImpl<Request, Response>)))
|
||||
ClientCallbackReaderWriterImpl<Request, Response>(call, context,
|
||||
reactor);
|
||||
}
|
||||
};
|
||||
|
||||
template <class Response>
|
||||
class ClientCallbackReaderImpl : public ClientCallbackReader<Response> {
|
||||
public:
|
||||
// always allocated against a call arena, no memory free required
|
||||
static void operator delete(void* /*ptr*/, std::size_t size) {
|
||||
GPR_ASSERT(size == sizeof(ClientCallbackReaderImpl));
|
||||
}
|
||||
|
||||
// This operator should never be called as the memory should be freed as part
|
||||
// of the arena destruction. It only exists to provide a matching operator
|
||||
// delete to the operator new so that some compilers will not complain (see
|
||||
// https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
|
||||
// there are no tests catching the compiler warning.
|
||||
static void operator delete(void*, void*) { GPR_ASSERT(false); }
|
||||
|
||||
void StartCall() override {
|
||||
// This call initiates two batches, plus any backlog, each with a callback
|
||||
// 1. Send initial metadata (unless corked) + recv initial metadata
|
||||
// 2. Any backlog
|
||||
// 3. Recv trailing metadata
|
||||
|
||||
start_tag_.Set(
|
||||
call_.call(),
|
||||
[this](bool ok) {
|
||||
reactor_->OnReadInitialMetadataDone(
|
||||
ok && !reactor_->InternalTrailersOnly(call_.call()));
|
||||
MaybeFinish(/*from_reaction=*/true);
|
||||
},
|
||||
&start_ops_, /*can_inline=*/false);
|
||||
start_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
|
||||
context_->initial_metadata_flags());
|
||||
start_ops_.RecvInitialMetadata(context_);
|
||||
start_ops_.set_core_cq_tag(&start_tag_);
|
||||
call_.PerformOps(&start_ops_);
|
||||
|
||||
// Also set up the read tag so it doesn't have to be set up each time
|
||||
read_tag_.Set(
|
||||
call_.call(),
|
||||
[this](bool ok) {
|
||||
reactor_->OnReadDone(ok);
|
||||
MaybeFinish(/*from_reaction=*/true);
|
||||
},
|
||||
&read_ops_, /*can_inline=*/false);
|
||||
read_ops_.set_core_cq_tag(&read_tag_);
|
||||
|
||||
{
|
||||
grpc::internal::MutexLock lock(&start_mu_);
|
||||
if (backlog_.read_ops) {
|
||||
call_.PerformOps(&read_ops_);
|
||||
}
|
||||
started_.store(true, std::memory_order_release);
|
||||
}
|
||||
|
||||
finish_tag_.Set(
|
||||
call_.call(),
|
||||
[this](bool /*ok*/) { MaybeFinish(/*from_reaction=*/true); },
|
||||
&finish_ops_, /*can_inline=*/false);
|
||||
finish_ops_.ClientRecvStatus(context_, &finish_status_);
|
||||
finish_ops_.set_core_cq_tag(&finish_tag_);
|
||||
call_.PerformOps(&finish_ops_);
|
||||
}
|
||||
|
||||
void Read(Response* msg) override {
|
||||
read_ops_.RecvMessage(msg);
|
||||
callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed);
|
||||
if (GPR_UNLIKELY(!started_.load(std::memory_order_acquire))) {
|
||||
grpc::internal::MutexLock lock(&start_mu_);
|
||||
if (GPR_LIKELY(!started_.load(std::memory_order_relaxed))) {
|
||||
backlog_.read_ops = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
call_.PerformOps(&read_ops_);
|
||||
}
|
||||
|
||||
void AddHold(int holds) override {
|
||||
callbacks_outstanding_.fetch_add(holds, std::memory_order_relaxed);
|
||||
}
|
||||
void RemoveHold() override { MaybeFinish(/*from_reaction=*/false); }
|
||||
|
||||
private:
|
||||
friend class ClientCallbackReaderFactory<Response>;
|
||||
|
||||
template <class Request>
|
||||
ClientCallbackReaderImpl(grpc::internal::Call call,
|
||||
grpc::ClientContext* context, Request* request,
|
||||
ClientReadReactor<Response>* reactor)
|
||||
: context_(context), call_(call), reactor_(reactor) {
|
||||
this->BindReactor(reactor);
|
||||
// TODO(vjpai): don't assert
|
||||
GPR_ASSERT(start_ops_.SendMessagePtr(request).ok());
|
||||
start_ops_.ClientSendClose();
|
||||
}
|
||||
|
||||
// MaybeFinish behaves as in ClientCallbackReaderWriterImpl.
|
||||
void MaybeFinish(bool from_reaction) {
|
||||
if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub(
|
||||
1, std::memory_order_acq_rel) == 1)) {
|
||||
grpc::Status s = std::move(finish_status_);
|
||||
auto* reactor = reactor_;
|
||||
auto* call = call_.call();
|
||||
this->~ClientCallbackReaderImpl();
|
||||
if (GPR_LIKELY(from_reaction)) {
|
||||
grpc_call_unref(call);
|
||||
reactor->OnDone(s);
|
||||
} else {
|
||||
grpc_call_run_in_event_engine(
|
||||
call, [reactor, s = std::move(s)]() { reactor->OnDone(s); });
|
||||
grpc_call_unref(call);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grpc::ClientContext* const context_;
|
||||
grpc::internal::Call call_;
|
||||
ClientReadReactor<Response>* const reactor_;
|
||||
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,
|
||||
grpc::internal::CallOpSendMessage,
|
||||
grpc::internal::CallOpClientSendClose,
|
||||
grpc::internal::CallOpRecvInitialMetadata>
|
||||
start_ops_;
|
||||
grpc::internal::CallbackWithSuccessTag start_tag_;
|
||||
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpClientRecvStatus> finish_ops_;
|
||||
grpc::internal::CallbackWithSuccessTag finish_tag_;
|
||||
grpc::Status finish_status_;
|
||||
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpRecvMessage<Response>>
|
||||
read_ops_;
|
||||
grpc::internal::CallbackWithSuccessTag read_tag_;
|
||||
|
||||
struct StartCallBacklog {
|
||||
bool read_ops = false;
|
||||
};
|
||||
StartCallBacklog backlog_ ABSL_GUARDED_BY(start_mu_);
|
||||
|
||||
// Minimum of 2 callbacks to pre-register for start and finish
|
||||
std::atomic<intptr_t> callbacks_outstanding_{2};
|
||||
std::atomic_bool started_{false};
|
||||
grpc::internal::Mutex start_mu_;
|
||||
};
|
||||
|
||||
template <class Response>
|
||||
class ClientCallbackReaderFactory {
|
||||
public:
|
||||
template <class Request>
|
||||
static void Create(grpc::ChannelInterface* channel,
|
||||
const grpc::internal::RpcMethod& method,
|
||||
grpc::ClientContext* context, const Request* request,
|
||||
ClientReadReactor<Response>* reactor) {
|
||||
grpc::internal::Call call =
|
||||
channel->CreateCall(method, context, channel->CallbackCQ());
|
||||
|
||||
grpc_call_ref(call.call());
|
||||
new (grpc_call_arena_alloc(call.call(),
|
||||
sizeof(ClientCallbackReaderImpl<Response>)))
|
||||
ClientCallbackReaderImpl<Response>(call, context, request, reactor);
|
||||
}
|
||||
};
|
||||
|
||||
template <class Request>
|
||||
class ClientCallbackWriterImpl : public ClientCallbackWriter<Request> {
|
||||
public:
|
||||
// always allocated against a call arena, no memory free required
|
||||
static void operator delete(void* /*ptr*/, std::size_t size) {
|
||||
GPR_ASSERT(size == sizeof(ClientCallbackWriterImpl));
|
||||
}
|
||||
|
||||
// This operator should never be called as the memory should be freed as part
|
||||
// of the arena destruction. It only exists to provide a matching operator
|
||||
// delete to the operator new so that some compilers will not complain (see
|
||||
// https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
|
||||
// there are no tests catching the compiler warning.
|
||||
static void operator delete(void*, void*) { GPR_ASSERT(false); }
|
||||
|
||||
void StartCall() ABSL_LOCKS_EXCLUDED(start_mu_) override {
|
||||
// This call initiates two batches, plus any backlog, each with a callback
|
||||
// 1. Send initial metadata (unless corked) + recv initial metadata
|
||||
// 2. Any backlog
|
||||
// 3. Recv trailing metadata
|
||||
|
||||
if (!start_corked_) {
|
||||
start_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
|
||||
context_->initial_metadata_flags());
|
||||
}
|
||||
call_.PerformOps(&start_ops_);
|
||||
|
||||
{
|
||||
grpc::internal::MutexLock lock(&start_mu_);
|
||||
|
||||
if (backlog_.write_ops) {
|
||||
call_.PerformOps(&write_ops_);
|
||||
}
|
||||
if (backlog_.writes_done_ops) {
|
||||
call_.PerformOps(&writes_done_ops_);
|
||||
}
|
||||
call_.PerformOps(&finish_ops_);
|
||||
// The last thing in this critical section is to set started_ so that it
|
||||
// can be used lock-free as well.
|
||||
started_.store(true, std::memory_order_release);
|
||||
}
|
||||
// MaybeFinish outside the lock to make sure that destruction of this object
|
||||
// doesn't take place while holding the lock (which would cause the lock to
|
||||
// be released after destruction)
|
||||
this->MaybeFinish(/*from_reaction=*/false);
|
||||
}
|
||||
|
||||
void Write(const Request* msg, grpc::WriteOptions options)
|
||||
ABSL_LOCKS_EXCLUDED(start_mu_) override {
|
||||
if (GPR_UNLIKELY(options.is_last_message())) {
|
||||
options.set_buffer_hint();
|
||||
write_ops_.ClientSendClose();
|
||||
}
|
||||
// TODO(vjpai): don't assert
|
||||
GPR_ASSERT(write_ops_.SendMessagePtr(msg, options).ok());
|
||||
callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed);
|
||||
|
||||
if (GPR_UNLIKELY(corked_write_needed_)) {
|
||||
write_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
|
||||
context_->initial_metadata_flags());
|
||||
corked_write_needed_ = false;
|
||||
}
|
||||
|
||||
if (GPR_UNLIKELY(!started_.load(std::memory_order_acquire))) {
|
||||
grpc::internal::MutexLock lock(&start_mu_);
|
||||
if (GPR_LIKELY(!started_.load(std::memory_order_relaxed))) {
|
||||
backlog_.write_ops = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
call_.PerformOps(&write_ops_);
|
||||
}
|
||||
|
||||
void WritesDone() ABSL_LOCKS_EXCLUDED(start_mu_) override {
|
||||
writes_done_ops_.ClientSendClose();
|
||||
writes_done_tag_.Set(
|
||||
call_.call(),
|
||||
[this](bool ok) {
|
||||
reactor_->OnWritesDoneDone(ok);
|
||||
MaybeFinish(/*from_reaction=*/true);
|
||||
},
|
||||
&writes_done_ops_, /*can_inline=*/false);
|
||||
writes_done_ops_.set_core_cq_tag(&writes_done_tag_);
|
||||
callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed);
|
||||
|
||||
if (GPR_UNLIKELY(corked_write_needed_)) {
|
||||
writes_done_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
|
||||
context_->initial_metadata_flags());
|
||||
corked_write_needed_ = false;
|
||||
}
|
||||
|
||||
if (GPR_UNLIKELY(!started_.load(std::memory_order_acquire))) {
|
||||
grpc::internal::MutexLock lock(&start_mu_);
|
||||
if (GPR_LIKELY(!started_.load(std::memory_order_relaxed))) {
|
||||
backlog_.writes_done_ops = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
call_.PerformOps(&writes_done_ops_);
|
||||
}
|
||||
|
||||
void AddHold(int holds) override {
|
||||
callbacks_outstanding_.fetch_add(holds, std::memory_order_relaxed);
|
||||
}
|
||||
void RemoveHold() override { MaybeFinish(/*from_reaction=*/false); }
|
||||
|
||||
private:
|
||||
friend class ClientCallbackWriterFactory<Request>;
|
||||
|
||||
template <class Response>
|
||||
ClientCallbackWriterImpl(grpc::internal::Call call,
|
||||
grpc::ClientContext* context, Response* response,
|
||||
ClientWriteReactor<Request>* reactor)
|
||||
: context_(context),
|
||||
call_(call),
|
||||
reactor_(reactor),
|
||||
start_corked_(context_->initial_metadata_corked_),
|
||||
corked_write_needed_(start_corked_) {
|
||||
this->BindReactor(reactor);
|
||||
|
||||
// Set up the unchanging parts of the start and write tags and ops.
|
||||
start_tag_.Set(
|
||||
call_.call(),
|
||||
[this](bool ok) {
|
||||
reactor_->OnReadInitialMetadataDone(
|
||||
ok && !reactor_->InternalTrailersOnly(call_.call()));
|
||||
MaybeFinish(/*from_reaction=*/true);
|
||||
},
|
||||
&start_ops_, /*can_inline=*/false);
|
||||
start_ops_.RecvInitialMetadata(context_);
|
||||
start_ops_.set_core_cq_tag(&start_tag_);
|
||||
|
||||
write_tag_.Set(
|
||||
call_.call(),
|
||||
[this](bool ok) {
|
||||
reactor_->OnWriteDone(ok);
|
||||
MaybeFinish(/*from_reaction=*/true);
|
||||
},
|
||||
&write_ops_, /*can_inline=*/false);
|
||||
write_ops_.set_core_cq_tag(&write_tag_);
|
||||
|
||||
// Also set up the Finish tag and op set.
|
||||
finish_ops_.RecvMessage(response);
|
||||
finish_ops_.AllowNoMessage();
|
||||
finish_tag_.Set(
|
||||
call_.call(),
|
||||
[this](bool /*ok*/) { MaybeFinish(/*from_reaction=*/true); },
|
||||
&finish_ops_,
|
||||
/*can_inline=*/false);
|
||||
finish_ops_.ClientRecvStatus(context_, &finish_status_);
|
||||
finish_ops_.set_core_cq_tag(&finish_tag_);
|
||||
}
|
||||
|
||||
// MaybeFinish behaves as in ClientCallbackReaderWriterImpl.
|
||||
void MaybeFinish(bool from_reaction) {
|
||||
if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub(
|
||||
1, std::memory_order_acq_rel) == 1)) {
|
||||
grpc::Status s = std::move(finish_status_);
|
||||
auto* reactor = reactor_;
|
||||
auto* call = call_.call();
|
||||
this->~ClientCallbackWriterImpl();
|
||||
if (GPR_LIKELY(from_reaction)) {
|
||||
grpc_call_unref(call);
|
||||
reactor->OnDone(s);
|
||||
} else {
|
||||
grpc_call_run_in_event_engine(
|
||||
call, [reactor, s = std::move(s)]() { reactor->OnDone(s); });
|
||||
grpc_call_unref(call);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grpc::ClientContext* const context_;
|
||||
grpc::internal::Call call_;
|
||||
ClientWriteReactor<Request>* const reactor_;
|
||||
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,
|
||||
grpc::internal::CallOpRecvInitialMetadata>
|
||||
start_ops_;
|
||||
grpc::internal::CallbackWithSuccessTag start_tag_;
|
||||
const bool start_corked_;
|
||||
bool corked_write_needed_; // no lock needed since only accessed in
|
||||
// Write/WritesDone which cannot be concurrent
|
||||
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpGenericRecvMessage,
|
||||
grpc::internal::CallOpClientRecvStatus>
|
||||
finish_ops_;
|
||||
grpc::internal::CallbackWithSuccessTag finish_tag_;
|
||||
grpc::Status finish_status_;
|
||||
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,
|
||||
grpc::internal::CallOpSendMessage,
|
||||
grpc::internal::CallOpClientSendClose>
|
||||
write_ops_;
|
||||
grpc::internal::CallbackWithSuccessTag write_tag_;
|
||||
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,
|
||||
grpc::internal::CallOpClientSendClose>
|
||||
writes_done_ops_;
|
||||
grpc::internal::CallbackWithSuccessTag writes_done_tag_;
|
||||
|
||||
struct StartCallBacklog {
|
||||
bool write_ops = false;
|
||||
bool writes_done_ops = false;
|
||||
};
|
||||
StartCallBacklog backlog_ ABSL_GUARDED_BY(start_mu_);
|
||||
|
||||
// Minimum of 3 callbacks to pre-register for start ops, StartCall, and finish
|
||||
std::atomic<intptr_t> callbacks_outstanding_{3};
|
||||
std::atomic_bool started_{false};
|
||||
grpc::internal::Mutex start_mu_;
|
||||
};
|
||||
|
||||
template <class Request>
|
||||
class ClientCallbackWriterFactory {
|
||||
public:
|
||||
template <class Response>
|
||||
static void Create(grpc::ChannelInterface* channel,
|
||||
const grpc::internal::RpcMethod& method,
|
||||
grpc::ClientContext* context, Response* response,
|
||||
ClientWriteReactor<Request>* reactor) {
|
||||
grpc::internal::Call call =
|
||||
channel->CreateCall(method, context, channel->CallbackCQ());
|
||||
|
||||
grpc_call_ref(call.call());
|
||||
new (grpc_call_arena_alloc(call.call(),
|
||||
sizeof(ClientCallbackWriterImpl<Request>)))
|
||||
ClientCallbackWriterImpl<Request>(call, context, response, reactor);
|
||||
}
|
||||
};
|
||||
|
||||
class ClientCallbackUnaryImpl final : public ClientCallbackUnary {
|
||||
public:
|
||||
// always allocated against a call arena, no memory free required
|
||||
static void operator delete(void* /*ptr*/, std::size_t size) {
|
||||
GPR_ASSERT(size == sizeof(ClientCallbackUnaryImpl));
|
||||
}
|
||||
|
||||
// This operator should never be called as the memory should be freed as part
|
||||
// of the arena destruction. It only exists to provide a matching operator
|
||||
// delete to the operator new so that some compilers will not complain (see
|
||||
// https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
|
||||
// there are no tests catching the compiler warning.
|
||||
static void operator delete(void*, void*) { GPR_ASSERT(false); }
|
||||
|
||||
void StartCall() override {
|
||||
// This call initiates two batches, each with a callback
|
||||
// 1. Send initial metadata + write + writes done + recv initial metadata
|
||||
// 2. Read message, recv trailing metadata
|
||||
|
||||
start_tag_.Set(
|
||||
call_.call(),
|
||||
[this](bool ok) {
|
||||
reactor_->OnReadInitialMetadataDone(
|
||||
ok && !reactor_->InternalTrailersOnly(call_.call()));
|
||||
MaybeFinish();
|
||||
},
|
||||
&start_ops_, /*can_inline=*/false);
|
||||
start_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
|
||||
context_->initial_metadata_flags());
|
||||
start_ops_.RecvInitialMetadata(context_);
|
||||
start_ops_.set_core_cq_tag(&start_tag_);
|
||||
call_.PerformOps(&start_ops_);
|
||||
|
||||
finish_tag_.Set(
|
||||
call_.call(), [this](bool /*ok*/) { MaybeFinish(); }, &finish_ops_,
|
||||
/*can_inline=*/false);
|
||||
finish_ops_.ClientRecvStatus(context_, &finish_status_);
|
||||
finish_ops_.set_core_cq_tag(&finish_tag_);
|
||||
call_.PerformOps(&finish_ops_);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class ClientCallbackUnaryFactory;
|
||||
|
||||
template <class Request, class Response>
|
||||
ClientCallbackUnaryImpl(grpc::internal::Call call,
|
||||
grpc::ClientContext* context, Request* request,
|
||||
Response* response, ClientUnaryReactor* reactor)
|
||||
: context_(context), call_(call), reactor_(reactor) {
|
||||
this->BindReactor(reactor);
|
||||
// TODO(vjpai): don't assert
|
||||
GPR_ASSERT(start_ops_.SendMessagePtr(request).ok());
|
||||
start_ops_.ClientSendClose();
|
||||
finish_ops_.RecvMessage(response);
|
||||
finish_ops_.AllowNoMessage();
|
||||
}
|
||||
|
||||
// In the unary case, MaybeFinish is only ever invoked from a
|
||||
// library-initiated reaction, so it will just directly call OnDone if this is
|
||||
// the last reaction for this RPC.
|
||||
void MaybeFinish() {
|
||||
if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub(
|
||||
1, std::memory_order_acq_rel) == 1)) {
|
||||
grpc::Status s = std::move(finish_status_);
|
||||
auto* reactor = reactor_;
|
||||
auto* call = call_.call();
|
||||
this->~ClientCallbackUnaryImpl();
|
||||
grpc_call_unref(call);
|
||||
reactor->OnDone(s);
|
||||
}
|
||||
}
|
||||
|
||||
grpc::ClientContext* const context_;
|
||||
grpc::internal::Call call_;
|
||||
ClientUnaryReactor* const reactor_;
|
||||
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,
|
||||
grpc::internal::CallOpSendMessage,
|
||||
grpc::internal::CallOpClientSendClose,
|
||||
grpc::internal::CallOpRecvInitialMetadata>
|
||||
start_ops_;
|
||||
grpc::internal::CallbackWithSuccessTag start_tag_;
|
||||
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpGenericRecvMessage,
|
||||
grpc::internal::CallOpClientRecvStatus>
|
||||
finish_ops_;
|
||||
grpc::internal::CallbackWithSuccessTag finish_tag_;
|
||||
grpc::Status finish_status_;
|
||||
|
||||
// This call will have 2 callbacks: start and finish
|
||||
std::atomic<intptr_t> callbacks_outstanding_{2};
|
||||
};
|
||||
|
||||
class ClientCallbackUnaryFactory {
|
||||
public:
|
||||
template <class Request, class Response, class BaseRequest = Request,
|
||||
class BaseResponse = Response>
|
||||
static void Create(grpc::ChannelInterface* channel,
|
||||
const grpc::internal::RpcMethod& method,
|
||||
grpc::ClientContext* context, const Request* request,
|
||||
Response* response, ClientUnaryReactor* reactor) {
|
||||
grpc::internal::Call call =
|
||||
channel->CreateCall(method, context, channel->CallbackCQ());
|
||||
|
||||
grpc_call_ref(call.call());
|
||||
|
||||
new (grpc_call_arena_alloc(call.call(), sizeof(ClientCallbackUnaryImpl)))
|
||||
ClientCallbackUnaryImpl(call, context,
|
||||
static_cast<const BaseRequest*>(request),
|
||||
static_cast<BaseResponse*>(response), reactor);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace grpc
|
||||
|
||||
#endif // GRPCPP_SUPPORT_CLIENT_CALLBACK_H
|
||||
213
Pods/gRPC-C++/include/grpcpp/support/client_interceptor.h
generated
Normal file
213
Pods/gRPC-C++/include/grpcpp/support/client_interceptor.h
generated
Normal file
@@ -0,0 +1,213 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2015 gRPC 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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef GRPCPP_SUPPORT_CLIENT_INTERCEPTOR_H
|
||||
#define GRPCPP_SUPPORT_CLIENT_INTERCEPTOR_H
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include <grpc/support/log.h>
|
||||
#include <grpcpp/impl/rpc_method.h>
|
||||
#include <grpcpp/support/interceptor.h>
|
||||
#include <grpcpp/support/string_ref.h>
|
||||
|
||||
namespace grpc {
|
||||
|
||||
class Channel;
|
||||
class ClientContext;
|
||||
|
||||
namespace internal {
|
||||
class InterceptorBatchMethodsImpl;
|
||||
}
|
||||
|
||||
namespace experimental {
|
||||
class ClientRpcInfo;
|
||||
|
||||
// A factory interface for creation of client interceptors. A vector of
|
||||
// factories can be provided at channel creation which will be used to create a
|
||||
// new vector of client interceptors per RPC. Client interceptor authors should
|
||||
// create a subclass of ClientInterceptorFactorInterface which creates objects
|
||||
// of their interceptors.
|
||||
class ClientInterceptorFactoryInterface {
|
||||
public:
|
||||
virtual ~ClientInterceptorFactoryInterface() {}
|
||||
// Returns a pointer to an Interceptor object on successful creation, nullptr
|
||||
// otherwise. If nullptr is returned, this server interceptor factory is
|
||||
// ignored for the purposes of that RPC.
|
||||
virtual Interceptor* CreateClientInterceptor(ClientRpcInfo* info) = 0;
|
||||
};
|
||||
} // namespace experimental
|
||||
|
||||
namespace internal {
|
||||
extern experimental::ClientInterceptorFactoryInterface*
|
||||
g_global_client_interceptor_factory;
|
||||
|
||||
extern experimental::ClientInterceptorFactoryInterface*
|
||||
g_global_client_stats_interceptor_factory;
|
||||
} // namespace internal
|
||||
|
||||
/// ClientRpcInfo represents the state of a particular RPC as it
|
||||
/// appears to an interceptor. It is created and owned by the library and
|
||||
/// passed to the CreateClientInterceptor method of the application's
|
||||
/// ClientInterceptorFactoryInterface implementation
|
||||
namespace experimental {
|
||||
class ClientRpcInfo {
|
||||
public:
|
||||
// TODO(yashykt): Stop default-constructing ClientRpcInfo and remove UNKNOWN
|
||||
// from the list of possible Types.
|
||||
/// Type categorizes RPCs by unary or streaming type
|
||||
enum class Type {
|
||||
UNARY,
|
||||
CLIENT_STREAMING,
|
||||
SERVER_STREAMING,
|
||||
BIDI_STREAMING,
|
||||
UNKNOWN // UNKNOWN is not API and will be removed later
|
||||
};
|
||||
|
||||
~ClientRpcInfo() {}
|
||||
|
||||
// Delete copy constructor but allow default move constructor
|
||||
ClientRpcInfo(const ClientRpcInfo&) = delete;
|
||||
ClientRpcInfo(ClientRpcInfo&&) = default;
|
||||
|
||||
// Getter methods
|
||||
|
||||
/// Return the fully-specified method name
|
||||
const char* method() const { return method_; }
|
||||
|
||||
/// Return an identifying suffix for the client stub, or nullptr if one wasn't
|
||||
/// specified.
|
||||
const char* suffix_for_stats() const { return suffix_for_stats_; }
|
||||
|
||||
/// Return a pointer to the channel on which the RPC is being sent
|
||||
ChannelInterface* channel() { return channel_; }
|
||||
|
||||
/// Return a pointer to the underlying ClientContext structure associated
|
||||
/// with the RPC to support features that apply to it
|
||||
grpc::ClientContext* client_context() { return ctx_; }
|
||||
|
||||
/// Return the type of the RPC (unary or a streaming flavor)
|
||||
Type type() const { return type_; }
|
||||
|
||||
private:
|
||||
static_assert(Type::UNARY ==
|
||||
static_cast<Type>(internal::RpcMethod::NORMAL_RPC),
|
||||
"violated expectation about Type enum");
|
||||
static_assert(Type::CLIENT_STREAMING ==
|
||||
static_cast<Type>(internal::RpcMethod::CLIENT_STREAMING),
|
||||
"violated expectation about Type enum");
|
||||
static_assert(Type::SERVER_STREAMING ==
|
||||
static_cast<Type>(internal::RpcMethod::SERVER_STREAMING),
|
||||
"violated expectation about Type enum");
|
||||
static_assert(Type::BIDI_STREAMING ==
|
||||
static_cast<Type>(internal::RpcMethod::BIDI_STREAMING),
|
||||
"violated expectation about Type enum");
|
||||
|
||||
// Default constructor should only be used by ClientContext
|
||||
ClientRpcInfo() = default;
|
||||
|
||||
// Constructor will only be called from ClientContext
|
||||
ClientRpcInfo(grpc::ClientContext* ctx, internal::RpcMethod::RpcType type,
|
||||
const char* method, const char* suffix_for_stats,
|
||||
grpc::ChannelInterface* channel)
|
||||
: ctx_(ctx),
|
||||
type_(static_cast<Type>(type)),
|
||||
method_(method),
|
||||
suffix_for_stats_(suffix_for_stats),
|
||||
channel_(channel) {}
|
||||
|
||||
// Move assignment should only be used by ClientContext
|
||||
// TODO(yashykt): Delete move assignment
|
||||
ClientRpcInfo& operator=(ClientRpcInfo&&) = default;
|
||||
|
||||
// Runs interceptor at pos \a pos.
|
||||
void RunInterceptor(
|
||||
experimental::InterceptorBatchMethods* interceptor_methods, size_t pos) {
|
||||
GPR_ASSERT(pos < interceptors_.size());
|
||||
interceptors_[pos]->Intercept(interceptor_methods);
|
||||
}
|
||||
|
||||
void RegisterInterceptors(
|
||||
const std::vector<std::unique_ptr<
|
||||
experimental::ClientInterceptorFactoryInterface>>& creators,
|
||||
size_t interceptor_pos) {
|
||||
// TODO(yashykt): This calculation seems broken for the case where an
|
||||
// interceptor factor returns nullptr.
|
||||
size_t num_interceptors =
|
||||
creators.size() +
|
||||
(internal::g_global_client_stats_interceptor_factory != nullptr) +
|
||||
(internal::g_global_client_interceptor_factory != nullptr);
|
||||
if (interceptor_pos > num_interceptors) {
|
||||
// No interceptors to register
|
||||
return;
|
||||
}
|
||||
if (internal::g_global_client_stats_interceptor_factory != nullptr) {
|
||||
interceptors_.push_back(std::unique_ptr<experimental::Interceptor>(
|
||||
internal::g_global_client_stats_interceptor_factory
|
||||
->CreateClientInterceptor(this)));
|
||||
--interceptor_pos;
|
||||
}
|
||||
// NOTE: The following is not a range-based for loop because it will only
|
||||
// iterate over a portion of the creators vector.
|
||||
for (auto it = creators.begin() + interceptor_pos; it != creators.end();
|
||||
++it) {
|
||||
auto* interceptor = (*it)->CreateClientInterceptor(this);
|
||||
if (interceptor != nullptr) {
|
||||
interceptors_.push_back(
|
||||
std::unique_ptr<experimental::Interceptor>(interceptor));
|
||||
}
|
||||
}
|
||||
if (internal::g_global_client_interceptor_factory != nullptr) {
|
||||
interceptors_.push_back(std::unique_ptr<experimental::Interceptor>(
|
||||
internal::g_global_client_interceptor_factory
|
||||
->CreateClientInterceptor(this)));
|
||||
}
|
||||
}
|
||||
|
||||
grpc::ClientContext* ctx_ = nullptr;
|
||||
// TODO(yashykt): make type_ const once move-assignment is deleted
|
||||
Type type_{Type::UNKNOWN};
|
||||
const char* method_ = nullptr;
|
||||
const char* suffix_for_stats_ = nullptr;
|
||||
grpc::ChannelInterface* channel_ = nullptr;
|
||||
std::vector<std::unique_ptr<experimental::Interceptor>> interceptors_;
|
||||
bool hijacked_ = false;
|
||||
size_t hijacked_interceptor_ = 0;
|
||||
|
||||
friend class internal::InterceptorBatchMethodsImpl;
|
||||
friend class grpc::ClientContext;
|
||||
};
|
||||
|
||||
// PLEASE DO NOT USE THIS. ALWAYS PREFER PER CHANNEL INTERCEPTORS OVER A GLOBAL
|
||||
// INTERCEPTOR. IF USAGE IS ABSOLUTELY NECESSARY, PLEASE READ THE SAFETY NOTES.
|
||||
// Registers a global client interceptor factory object, which is used for all
|
||||
// RPCs made in this process. The application is responsible for maintaining the
|
||||
// life of the object while gRPC operations are in progress. The global
|
||||
// interceptor factory should only be registered once at the start of the
|
||||
// process before any gRPC operations have begun.
|
||||
void RegisterGlobalClientInterceptorFactory(
|
||||
ClientInterceptorFactoryInterface* factory);
|
||||
|
||||
// For testing purposes only
|
||||
void TestOnlyResetGlobalClientInterceptorFactory();
|
||||
|
||||
} // namespace experimental
|
||||
} // namespace grpc
|
||||
|
||||
#endif // GRPCPP_SUPPORT_CLIENT_INTERCEPTOR_H
|
||||
44
Pods/gRPC-C++/include/grpcpp/support/config.h
generated
Normal file
44
Pods/gRPC-C++/include/grpcpp/support/config.h
generated
Normal file
@@ -0,0 +1,44 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2015 gRPC 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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef GRPCPP_SUPPORT_CONFIG_H
|
||||
#define GRPCPP_SUPPORT_CONFIG_H
|
||||
|
||||
#include <string>
|
||||
|
||||
/// The following macros are deprecated and appear only for users
|
||||
/// with PB files generated using gRPC 1.0.x plugins. They should
|
||||
/// not be used in new code
|
||||
#define GRPC_OVERRIDE override // deprecated
|
||||
#define GRPC_FINAL final // deprecated
|
||||
|
||||
#ifdef GRPC_CUSTOM_STRING
|
||||
#warning GRPC_CUSTOM_STRING is no longer supported. Please use std::string.
|
||||
#endif
|
||||
|
||||
namespace grpc {
|
||||
|
||||
// Using grpc::string and grpc::to_string is discouraged in favor of
|
||||
// std::string and std::to_string. This is only for legacy code using
|
||||
// them explictly.
|
||||
using std::string; // deprecated // NOLINT(misc-unused-using-decls)
|
||||
using std::to_string; // deprecated // NOLINT(misc-unused-using-decls)
|
||||
|
||||
} // namespace grpc
|
||||
|
||||
#endif // GRPCPP_SUPPORT_CONFIG_H
|
||||
230
Pods/gRPC-C++/include/grpcpp/support/interceptor.h
generated
Normal file
230
Pods/gRPC-C++/include/grpcpp/support/interceptor.h
generated
Normal file
@@ -0,0 +1,230 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2015 gRPC 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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef GRPCPP_SUPPORT_INTERCEPTOR_H
|
||||
#define GRPCPP_SUPPORT_INTERCEPTOR_H
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <grpc/impl/grpc_types.h>
|
||||
#include <grpcpp/impl/metadata_map.h>
|
||||
#include <grpcpp/support/byte_buffer.h>
|
||||
#include <grpcpp/support/config.h>
|
||||
#include <grpcpp/support/string_ref.h>
|
||||
|
||||
namespace grpc {
|
||||
|
||||
class ChannelInterface;
|
||||
class Status;
|
||||
|
||||
namespace experimental {
|
||||
|
||||
/// An enumeration of different possible points at which the \a Intercept
|
||||
/// method of the \a Interceptor interface may be called. Any given call
|
||||
/// to \a Intercept will include one or more of these hook points, and
|
||||
/// each hook point makes certain types of information available to the
|
||||
/// interceptor.
|
||||
/// In these enumeration names, PRE_SEND means that an interception has taken
|
||||
/// place between the time the application provided a certain type of data
|
||||
/// (e.g., initial metadata, status) and the time that that data goes to the
|
||||
/// other side. POST_SEND means that the data has been committed for going to
|
||||
/// the other side (even if it has not yet been received at the other side).
|
||||
/// PRE_RECV means an interception between the time that a certain
|
||||
/// operation has been requested and it is available. POST_RECV means that a
|
||||
/// result is available but has not yet been passed back to the application.
|
||||
/// A batch of interception points will only contain either PRE or POST hooks
|
||||
/// but not both types. For example, a batch with PRE_SEND hook points will not
|
||||
/// contain POST_RECV or POST_SEND ops. Likewise, a batch with POST_* ops can
|
||||
/// not contain PRE_* ops.
|
||||
enum class InterceptionHookPoints {
|
||||
/// The first three in this list are for clients and servers
|
||||
PRE_SEND_INITIAL_METADATA,
|
||||
PRE_SEND_MESSAGE,
|
||||
POST_SEND_MESSAGE,
|
||||
PRE_SEND_STATUS, // server only
|
||||
PRE_SEND_CLOSE, // client only: WritesDone for stream; after write in unary
|
||||
/// The following three are for hijacked clients only. A batch with PRE_RECV_*
|
||||
/// hook points will never contain hook points of other types.
|
||||
PRE_RECV_INITIAL_METADATA,
|
||||
PRE_RECV_MESSAGE,
|
||||
PRE_RECV_STATUS,
|
||||
/// The following two are for all clients and servers
|
||||
POST_RECV_INITIAL_METADATA,
|
||||
POST_RECV_MESSAGE,
|
||||
POST_RECV_STATUS, // client only
|
||||
POST_RECV_CLOSE, // server only
|
||||
/// This is a special hook point available to both clients and servers when
|
||||
/// TryCancel() is performed.
|
||||
/// - No other hook points will be present along with this.
|
||||
/// - It is illegal for an interceptor to block/delay this operation.
|
||||
/// - ALL interceptors see this hook point irrespective of whether the
|
||||
/// RPC was hijacked or not.
|
||||
PRE_SEND_CANCEL,
|
||||
NUM_INTERCEPTION_HOOKS
|
||||
};
|
||||
|
||||
/// Class that is passed as an argument to the \a Intercept method
|
||||
/// of the application's \a Interceptor interface implementation. It has five
|
||||
/// purposes:
|
||||
/// 1. Indicate which hook points are present at a specific interception
|
||||
/// 2. Allow an interceptor to inform the library that an RPC should
|
||||
/// continue to the next stage of its processing (which may be another
|
||||
/// interceptor or the main path of the library)
|
||||
/// 3. Allow an interceptor to hijack the processing of the RPC (only for
|
||||
/// client-side RPCs with PRE_SEND_INITIAL_METADATA) so that it does not
|
||||
/// proceed with normal processing beyond that stage
|
||||
/// 4. Access the relevant fields of an RPC at each interception point
|
||||
/// 5. Set some fields of an RPC at each interception point, when possible
|
||||
class InterceptorBatchMethods {
|
||||
public:
|
||||
virtual ~InterceptorBatchMethods() {}
|
||||
/// Determine whether the current batch has an interception hook point
|
||||
/// of type \a type
|
||||
virtual bool QueryInterceptionHookPoint(InterceptionHookPoints type) = 0;
|
||||
/// Signal that the interceptor is done intercepting the current batch of the
|
||||
/// RPC. Every interceptor must either call Proceed or Hijack on each
|
||||
/// interception. In most cases, only Proceed will be used. Explicit use of
|
||||
/// Proceed is what enables interceptors to delay the processing of RPCs
|
||||
/// while they perform other work.
|
||||
/// Proceed is a no-op if the batch contains PRE_SEND_CANCEL. Simply returning
|
||||
/// from the Intercept method does the job of continuing the RPC in this case.
|
||||
/// This is because PRE_SEND_CANCEL is always in a separate batch and is not
|
||||
/// allowed to be delayed.
|
||||
virtual void Proceed() = 0;
|
||||
/// Indicate that the interceptor has hijacked the RPC (only valid if the
|
||||
/// batch contains send_initial_metadata on the client side). Later
|
||||
/// interceptors in the interceptor list will not be called. Later batches
|
||||
/// on the same RPC will go through interception, but only up to the point
|
||||
/// of the hijacking interceptor.
|
||||
virtual void Hijack() = 0;
|
||||
|
||||
/// Send Message Methods
|
||||
/// GetSerializedSendMessage and GetSendMessage/ModifySendMessage are the
|
||||
/// available methods to view and modify the request payload. An interceptor
|
||||
/// can access the payload in either serialized form or non-serialized form
|
||||
/// but not both at the same time.
|
||||
/// gRPC performs serialization in a lazy manner, which means
|
||||
/// that a call to GetSerializedSendMessage will result in a serialization
|
||||
/// operation if the payload stored is not in the serialized form already; the
|
||||
/// non-serialized form will be lost and GetSendMessage will no longer return
|
||||
/// a valid pointer, and this will remain true for later interceptors too.
|
||||
/// This can change however if ModifySendMessage is used to replace the
|
||||
/// current payload. Note that ModifySendMessage requires a new payload
|
||||
/// message in the non-serialized form. This will overwrite the existing
|
||||
/// payload irrespective of whether it had been serialized earlier. Also note
|
||||
/// that gRPC Async API requires early serialization of the payload which
|
||||
/// means that the payload would be available in the serialized form only
|
||||
/// unless an interceptor replaces the payload with ModifySendMessage.
|
||||
|
||||
/// Returns a modifable ByteBuffer holding the serialized form of the message
|
||||
/// that is going to be sent. Valid for PRE_SEND_MESSAGE interceptions.
|
||||
/// A return value of nullptr indicates that this ByteBuffer is not valid.
|
||||
virtual ByteBuffer* GetSerializedSendMessage() = 0;
|
||||
|
||||
/// Returns a non-modifiable pointer to the non-serialized form of the message
|
||||
/// to be sent. Valid for PRE_SEND_MESSAGE interceptions. A return value of
|
||||
/// nullptr indicates that this field is not valid.
|
||||
virtual const void* GetSendMessage() = 0;
|
||||
|
||||
/// Overwrites the message to be sent with \a message. \a message should be in
|
||||
/// the non-serialized form expected by the method. Valid for PRE_SEND_MESSAGE
|
||||
/// interceptions. Note that the interceptor is responsible for maintaining
|
||||
/// the life of the message till it is serialized or it receives the
|
||||
/// POST_SEND_MESSAGE interception point, whichever happens earlier. The
|
||||
/// modifying interceptor may itself force early serialization by calling
|
||||
/// GetSerializedSendMessage.
|
||||
virtual void ModifySendMessage(const void* message) = 0;
|
||||
|
||||
/// Checks whether the SEND MESSAGE op succeeded. Valid for POST_SEND_MESSAGE
|
||||
/// interceptions.
|
||||
virtual bool GetSendMessageStatus() = 0;
|
||||
|
||||
/// Returns a modifiable multimap of the initial metadata to be sent. Valid
|
||||
/// for PRE_SEND_INITIAL_METADATA interceptions. A value of nullptr indicates
|
||||
/// that this field is not valid.
|
||||
virtual std::multimap<std::string, std::string>* GetSendInitialMetadata() = 0;
|
||||
|
||||
/// Returns the status to be sent. Valid for PRE_SEND_STATUS interceptions.
|
||||
virtual Status GetSendStatus() = 0;
|
||||
|
||||
/// Overwrites the status with \a status. Valid for PRE_SEND_STATUS
|
||||
/// interceptions.
|
||||
virtual void ModifySendStatus(const Status& status) = 0;
|
||||
|
||||
/// Returns a modifiable multimap of the trailing metadata to be sent. Valid
|
||||
/// for PRE_SEND_STATUS interceptions. A value of nullptr indicates
|
||||
/// that this field is not valid.
|
||||
virtual std::multimap<std::string, std::string>*
|
||||
GetSendTrailingMetadata() = 0;
|
||||
|
||||
/// Returns a pointer to the modifiable received message. Note that the
|
||||
/// message is already deserialized but the type is not set; the interceptor
|
||||
/// should static_cast to the appropriate type before using it. This is valid
|
||||
/// for PRE_RECV_MESSAGE and POST_RECV_MESSAGE interceptions; nullptr for not
|
||||
/// valid
|
||||
virtual void* GetRecvMessage() = 0;
|
||||
|
||||
/// Returns a modifiable multimap of the received initial metadata.
|
||||
/// Valid for PRE_RECV_INITIAL_METADATA and POST_RECV_INITIAL_METADATA
|
||||
/// interceptions; nullptr if not valid
|
||||
virtual std::multimap<grpc::string_ref, grpc::string_ref>*
|
||||
GetRecvInitialMetadata() = 0;
|
||||
|
||||
/// Returns a modifiable view of the received status on PRE_RECV_STATUS and
|
||||
/// POST_RECV_STATUS interceptions; nullptr if not valid.
|
||||
virtual Status* GetRecvStatus() = 0;
|
||||
|
||||
/// Returns a modifiable multimap of the received trailing metadata on
|
||||
/// PRE_RECV_STATUS and POST_RECV_STATUS interceptions; nullptr if not valid
|
||||
virtual std::multimap<grpc::string_ref, grpc::string_ref>*
|
||||
GetRecvTrailingMetadata() = 0;
|
||||
|
||||
/// Gets an intercepted channel. When a call is started on this interceptor,
|
||||
/// only interceptors after the current interceptor are created from the
|
||||
/// factory objects registered with the channel. This allows calls to be
|
||||
/// started from interceptors without infinite regress through the interceptor
|
||||
/// list.
|
||||
virtual std::unique_ptr<ChannelInterface> GetInterceptedChannel() = 0;
|
||||
|
||||
/// On a hijacked RPC, an interceptor can decide to fail a PRE_RECV_MESSAGE
|
||||
/// op. This would be a signal to the reader that there will be no more
|
||||
/// messages, or the stream has failed or been cancelled.
|
||||
virtual void FailHijackedRecvMessage() = 0;
|
||||
|
||||
/// On a hijacked RPC/ to-be hijacked RPC, this can be called to fail a SEND
|
||||
/// MESSAGE op
|
||||
virtual void FailHijackedSendMessage() = 0;
|
||||
};
|
||||
|
||||
/// Interface for an interceptor. Interceptor authors must create a class
|
||||
/// that derives from this parent class.
|
||||
class Interceptor {
|
||||
public:
|
||||
virtual ~Interceptor() {}
|
||||
|
||||
/// The one public method of an Interceptor interface. Override this to
|
||||
/// trigger the desired actions at the hook points described above.
|
||||
virtual void Intercept(InterceptorBatchMethods* methods) = 0;
|
||||
};
|
||||
|
||||
} // namespace experimental
|
||||
} // namespace grpc
|
||||
|
||||
#endif // GRPCPP_SUPPORT_INTERCEPTOR_H
|
||||
71
Pods/gRPC-C++/include/grpcpp/support/message_allocator.h
generated
Normal file
71
Pods/gRPC-C++/include/grpcpp/support/message_allocator.h
generated
Normal file
@@ -0,0 +1,71 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2019 gRPC 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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef GRPCPP_SUPPORT_MESSAGE_ALLOCATOR_H
|
||||
#define GRPCPP_SUPPORT_MESSAGE_ALLOCATOR_H
|
||||
|
||||
namespace grpc {
|
||||
|
||||
// NOTE: This is an API for advanced users who need custom allocators.
|
||||
// Per rpc struct for the allocator. This is the interface to return to user.
|
||||
class RpcAllocatorState {
|
||||
public:
|
||||
virtual ~RpcAllocatorState() = default;
|
||||
// Optionally deallocate request early to reduce the size of working set.
|
||||
// A custom MessageAllocator needs to be registered to make use of this.
|
||||
// This is not abstract because implementing it is optional.
|
||||
virtual void FreeRequest() {}
|
||||
};
|
||||
|
||||
// This is the interface returned by the allocator.
|
||||
// grpc library will call the methods to get request/response pointers and to
|
||||
// release the object when it is done.
|
||||
template <typename RequestT, typename ResponseT>
|
||||
class MessageHolder : public RpcAllocatorState {
|
||||
public:
|
||||
// Release this object. For example, if the custom allocator's
|
||||
// AllocateMessasge creates an instance of a subclass with new, the Release()
|
||||
// should do a "delete this;".
|
||||
virtual void Release() = 0;
|
||||
RequestT* request() { return request_; }
|
||||
ResponseT* response() { return response_; }
|
||||
|
||||
protected:
|
||||
void set_request(RequestT* request) { request_ = request; }
|
||||
void set_response(ResponseT* response) { response_ = response; }
|
||||
|
||||
private:
|
||||
// NOTE: subclasses should set these pointers.
|
||||
RequestT* request_;
|
||||
ResponseT* response_;
|
||||
};
|
||||
|
||||
// A custom allocator can be set via the generated code to a callback unary
|
||||
// method, such as SetMessageAllocatorFor_Echo(custom_allocator). The allocator
|
||||
// needs to be alive for the lifetime of the server.
|
||||
// Implementations need to be thread-safe.
|
||||
template <typename RequestT, typename ResponseT>
|
||||
class MessageAllocator {
|
||||
public:
|
||||
virtual ~MessageAllocator() = default;
|
||||
virtual MessageHolder<RequestT, ResponseT>* AllocateMessages() = 0;
|
||||
};
|
||||
|
||||
} // namespace grpc
|
||||
|
||||
#endif // GRPCPP_SUPPORT_MESSAGE_ALLOCATOR_H
|
||||
405
Pods/gRPC-C++/include/grpcpp/support/method_handler.h
generated
Normal file
405
Pods/gRPC-C++/include/grpcpp/support/method_handler.h
generated
Normal file
@@ -0,0 +1,405 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2015 gRPC 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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef GRPCPP_SUPPORT_METHOD_HANDLER_H
|
||||
#define GRPCPP_SUPPORT_METHOD_HANDLER_H
|
||||
|
||||
#include <grpc/byte_buffer.h>
|
||||
#include <grpc/support/log.h>
|
||||
#include <grpcpp/impl/rpc_service_method.h>
|
||||
#include <grpcpp/support/byte_buffer.h>
|
||||
#include <grpcpp/support/sync_stream.h>
|
||||
|
||||
namespace grpc {
|
||||
|
||||
namespace internal {
|
||||
|
||||
// Invoke the method handler, fill in the status, and
|
||||
// return whether or not we finished safely (without an exception).
|
||||
// Note that exception handling is 0-cost in most compiler/library
|
||||
// implementations (except when an exception is actually thrown),
|
||||
// so this process doesn't require additional overhead in the common case.
|
||||
// Additionally, we don't need to return if we caught an exception or not;
|
||||
// the handling is the same in either case.
|
||||
template <class Callable>
|
||||
::grpc::Status CatchingFunctionHandler(Callable&& handler) {
|
||||
#if GRPC_ALLOW_EXCEPTIONS
|
||||
try {
|
||||
return handler();
|
||||
} catch (...) {
|
||||
return grpc::Status(grpc::StatusCode::UNKNOWN,
|
||||
"Unexpected error in RPC handling");
|
||||
}
|
||||
#else // GRPC_ALLOW_EXCEPTIONS
|
||||
return handler();
|
||||
#endif // GRPC_ALLOW_EXCEPTIONS
|
||||
}
|
||||
|
||||
/// A helper function with reduced templating to do the common work needed to
|
||||
/// actually send the server response. Uses non-const parameter for Status since
|
||||
/// this should only ever be called from the end of the RunHandler method.
|
||||
|
||||
template <class ResponseType>
|
||||
void UnaryRunHandlerHelper(const MethodHandler::HandlerParameter& param,
|
||||
ResponseType* rsp, grpc::Status& status) {
|
||||
GPR_ASSERT(!param.server_context->sent_initial_metadata_);
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,
|
||||
grpc::internal::CallOpSendMessage,
|
||||
grpc::internal::CallOpServerSendStatus>
|
||||
ops;
|
||||
ops.SendInitialMetadata(¶m.server_context->initial_metadata_,
|
||||
param.server_context->initial_metadata_flags());
|
||||
if (param.server_context->compression_level_set()) {
|
||||
ops.set_compression_level(param.server_context->compression_level());
|
||||
}
|
||||
if (status.ok()) {
|
||||
status = ops.SendMessagePtr(rsp);
|
||||
}
|
||||
ops.ServerSendStatus(¶m.server_context->trailing_metadata_, status);
|
||||
param.call->PerformOps(&ops);
|
||||
param.call->cq()->Pluck(&ops);
|
||||
}
|
||||
|
||||
/// A helper function with reduced templating to do deserializing.
|
||||
|
||||
template <class RequestType>
|
||||
void* UnaryDeserializeHelper(grpc_byte_buffer* req, grpc::Status* status,
|
||||
RequestType* request) {
|
||||
grpc::ByteBuffer buf;
|
||||
buf.set_buffer(req);
|
||||
*status = grpc::SerializationTraits<RequestType>::Deserialize(
|
||||
&buf, static_cast<RequestType*>(request));
|
||||
buf.Release();
|
||||
if (status->ok()) {
|
||||
return request;
|
||||
}
|
||||
request->~RequestType();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// A wrapper class of an application provided rpc method handler.
|
||||
template <class ServiceType, class RequestType, class ResponseType,
|
||||
class BaseRequestType = RequestType,
|
||||
class BaseResponseType = ResponseType>
|
||||
class RpcMethodHandler : public grpc::internal::MethodHandler {
|
||||
public:
|
||||
RpcMethodHandler(
|
||||
std::function<grpc::Status(ServiceType*, grpc::ServerContext*,
|
||||
const RequestType*, ResponseType*)>
|
||||
func,
|
||||
ServiceType* service)
|
||||
: func_(func), service_(service) {}
|
||||
|
||||
void RunHandler(const HandlerParameter& param) final {
|
||||
ResponseType rsp;
|
||||
grpc::Status status = param.status;
|
||||
if (status.ok()) {
|
||||
status = CatchingFunctionHandler([this, ¶m, &rsp] {
|
||||
return func_(service_,
|
||||
static_cast<grpc::ServerContext*>(param.server_context),
|
||||
static_cast<RequestType*>(param.request), &rsp);
|
||||
});
|
||||
static_cast<RequestType*>(param.request)->~RequestType();
|
||||
}
|
||||
UnaryRunHandlerHelper(param, static_cast<BaseResponseType*>(&rsp), status);
|
||||
}
|
||||
|
||||
void* Deserialize(grpc_call* call, grpc_byte_buffer* req,
|
||||
grpc::Status* status, void** /*handler_data*/) final {
|
||||
auto* request =
|
||||
new (grpc_call_arena_alloc(call, sizeof(RequestType))) RequestType;
|
||||
return UnaryDeserializeHelper(req, status,
|
||||
static_cast<BaseRequestType*>(request));
|
||||
}
|
||||
|
||||
private:
|
||||
/// Application provided rpc handler function.
|
||||
std::function<grpc::Status(ServiceType*, grpc::ServerContext*,
|
||||
const RequestType*, ResponseType*)>
|
||||
func_;
|
||||
// The class the above handler function lives in.
|
||||
ServiceType* service_;
|
||||
};
|
||||
|
||||
/// A wrapper class of an application provided client streaming handler.
|
||||
template <class ServiceType, class RequestType, class ResponseType>
|
||||
class ClientStreamingHandler : public grpc::internal::MethodHandler {
|
||||
public:
|
||||
ClientStreamingHandler(
|
||||
std::function<grpc::Status(ServiceType*, grpc::ServerContext*,
|
||||
ServerReader<RequestType>*, ResponseType*)>
|
||||
func,
|
||||
ServiceType* service)
|
||||
: func_(func), service_(service) {}
|
||||
|
||||
void RunHandler(const HandlerParameter& param) final {
|
||||
ServerReader<RequestType> reader(
|
||||
param.call, static_cast<grpc::ServerContext*>(param.server_context));
|
||||
ResponseType rsp;
|
||||
grpc::Status status =
|
||||
CatchingFunctionHandler([this, ¶m, &reader, &rsp] {
|
||||
return func_(service_,
|
||||
static_cast<grpc::ServerContext*>(param.server_context),
|
||||
&reader, &rsp);
|
||||
});
|
||||
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,
|
||||
grpc::internal::CallOpSendMessage,
|
||||
grpc::internal::CallOpServerSendStatus>
|
||||
ops;
|
||||
if (!param.server_context->sent_initial_metadata_) {
|
||||
ops.SendInitialMetadata(¶m.server_context->initial_metadata_,
|
||||
param.server_context->initial_metadata_flags());
|
||||
if (param.server_context->compression_level_set()) {
|
||||
ops.set_compression_level(param.server_context->compression_level());
|
||||
}
|
||||
}
|
||||
if (status.ok()) {
|
||||
status = ops.SendMessagePtr(&rsp);
|
||||
}
|
||||
ops.ServerSendStatus(¶m.server_context->trailing_metadata_, status);
|
||||
param.call->PerformOps(&ops);
|
||||
param.call->cq()->Pluck(&ops);
|
||||
}
|
||||
|
||||
private:
|
||||
std::function<grpc::Status(ServiceType*, grpc::ServerContext*,
|
||||
ServerReader<RequestType>*, ResponseType*)>
|
||||
func_;
|
||||
ServiceType* service_;
|
||||
};
|
||||
|
||||
/// A wrapper class of an application provided server streaming handler.
|
||||
template <class ServiceType, class RequestType, class ResponseType>
|
||||
class ServerStreamingHandler : public grpc::internal::MethodHandler {
|
||||
public:
|
||||
ServerStreamingHandler(std::function<grpc::Status(
|
||||
ServiceType*, grpc::ServerContext*,
|
||||
const RequestType*, ServerWriter<ResponseType>*)>
|
||||
func,
|
||||
ServiceType* service)
|
||||
: func_(func), service_(service) {}
|
||||
|
||||
void RunHandler(const HandlerParameter& param) final {
|
||||
grpc::Status status = param.status;
|
||||
if (status.ok()) {
|
||||
ServerWriter<ResponseType> writer(
|
||||
param.call, static_cast<grpc::ServerContext*>(param.server_context));
|
||||
status = CatchingFunctionHandler([this, ¶m, &writer] {
|
||||
return func_(service_,
|
||||
static_cast<grpc::ServerContext*>(param.server_context),
|
||||
static_cast<RequestType*>(param.request), &writer);
|
||||
});
|
||||
static_cast<RequestType*>(param.request)->~RequestType();
|
||||
}
|
||||
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,
|
||||
grpc::internal::CallOpServerSendStatus>
|
||||
ops;
|
||||
if (!param.server_context->sent_initial_metadata_) {
|
||||
ops.SendInitialMetadata(¶m.server_context->initial_metadata_,
|
||||
param.server_context->initial_metadata_flags());
|
||||
if (param.server_context->compression_level_set()) {
|
||||
ops.set_compression_level(param.server_context->compression_level());
|
||||
}
|
||||
}
|
||||
ops.ServerSendStatus(¶m.server_context->trailing_metadata_, status);
|
||||
param.call->PerformOps(&ops);
|
||||
if (param.server_context->has_pending_ops_) {
|
||||
param.call->cq()->Pluck(¶m.server_context->pending_ops_);
|
||||
}
|
||||
param.call->cq()->Pluck(&ops);
|
||||
}
|
||||
|
||||
void* Deserialize(grpc_call* call, grpc_byte_buffer* req,
|
||||
grpc::Status* status, void** /*handler_data*/) final {
|
||||
grpc::ByteBuffer buf;
|
||||
buf.set_buffer(req);
|
||||
auto* request =
|
||||
new (grpc_call_arena_alloc(call, sizeof(RequestType))) RequestType();
|
||||
*status =
|
||||
grpc::SerializationTraits<RequestType>::Deserialize(&buf, request);
|
||||
buf.Release();
|
||||
if (status->ok()) {
|
||||
return request;
|
||||
}
|
||||
request->~RequestType();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
std::function<grpc::Status(ServiceType*, grpc::ServerContext*,
|
||||
const RequestType*, ServerWriter<ResponseType>*)>
|
||||
func_;
|
||||
ServiceType* service_;
|
||||
};
|
||||
|
||||
/// A wrapper class of an application provided bidi-streaming handler.
|
||||
/// This also applies to server-streamed implementation of a unary method
|
||||
/// with the additional requirement that such methods must have done a
|
||||
/// write for status to be ok
|
||||
/// Since this is used by more than 1 class, the service is not passed in.
|
||||
/// Instead, it is expected to be an implicitly-captured argument of func
|
||||
/// (through bind or something along those lines)
|
||||
template <class Streamer, bool WriteNeeded>
|
||||
class TemplatedBidiStreamingHandler : public grpc::internal::MethodHandler {
|
||||
public:
|
||||
explicit TemplatedBidiStreamingHandler(
|
||||
std::function<grpc::Status(grpc::ServerContext*, Streamer*)> func)
|
||||
: func_(func), write_needed_(WriteNeeded) {}
|
||||
|
||||
void RunHandler(const HandlerParameter& param) final {
|
||||
Streamer stream(param.call,
|
||||
static_cast<grpc::ServerContext*>(param.server_context));
|
||||
grpc::Status status = CatchingFunctionHandler([this, ¶m, &stream] {
|
||||
return func_(static_cast<grpc::ServerContext*>(param.server_context),
|
||||
&stream);
|
||||
});
|
||||
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,
|
||||
grpc::internal::CallOpServerSendStatus>
|
||||
ops;
|
||||
if (!param.server_context->sent_initial_metadata_) {
|
||||
ops.SendInitialMetadata(¶m.server_context->initial_metadata_,
|
||||
param.server_context->initial_metadata_flags());
|
||||
if (param.server_context->compression_level_set()) {
|
||||
ops.set_compression_level(param.server_context->compression_level());
|
||||
}
|
||||
if (write_needed_ && status.ok()) {
|
||||
// If we needed a write but never did one, we need to mark the
|
||||
// status as a fail
|
||||
status = grpc::Status(grpc::StatusCode::INTERNAL,
|
||||
"Service did not provide response message");
|
||||
}
|
||||
}
|
||||
ops.ServerSendStatus(¶m.server_context->trailing_metadata_, status);
|
||||
param.call->PerformOps(&ops);
|
||||
if (param.server_context->has_pending_ops_) {
|
||||
param.call->cq()->Pluck(¶m.server_context->pending_ops_);
|
||||
}
|
||||
param.call->cq()->Pluck(&ops);
|
||||
}
|
||||
|
||||
private:
|
||||
std::function<grpc::Status(grpc::ServerContext*, Streamer*)> func_;
|
||||
const bool write_needed_;
|
||||
};
|
||||
|
||||
template <class ServiceType, class RequestType, class ResponseType>
|
||||
class BidiStreamingHandler
|
||||
: public TemplatedBidiStreamingHandler<
|
||||
ServerReaderWriter<ResponseType, RequestType>, false> {
|
||||
public:
|
||||
BidiStreamingHandler(std::function<grpc::Status(
|
||||
ServiceType*, grpc::ServerContext*,
|
||||
ServerReaderWriter<ResponseType, RequestType>*)>
|
||||
func,
|
||||
ServiceType* service)
|
||||
// TODO(vjpai): When gRPC supports C++14, move-capture func in the below
|
||||
: TemplatedBidiStreamingHandler<
|
||||
ServerReaderWriter<ResponseType, RequestType>, false>(
|
||||
[func, service](
|
||||
grpc::ServerContext* ctx,
|
||||
ServerReaderWriter<ResponseType, RequestType>* streamer) {
|
||||
return func(service, ctx, streamer);
|
||||
}) {}
|
||||
};
|
||||
|
||||
template <class RequestType, class ResponseType>
|
||||
class StreamedUnaryHandler
|
||||
: public TemplatedBidiStreamingHandler<
|
||||
ServerUnaryStreamer<RequestType, ResponseType>, true> {
|
||||
public:
|
||||
explicit StreamedUnaryHandler(
|
||||
std::function<
|
||||
grpc::Status(grpc::ServerContext*,
|
||||
ServerUnaryStreamer<RequestType, ResponseType>*)>
|
||||
func)
|
||||
: TemplatedBidiStreamingHandler<
|
||||
ServerUnaryStreamer<RequestType, ResponseType>, true>(
|
||||
std::move(func)) {}
|
||||
};
|
||||
|
||||
template <class RequestType, class ResponseType>
|
||||
class SplitServerStreamingHandler
|
||||
: public TemplatedBidiStreamingHandler<
|
||||
ServerSplitStreamer<RequestType, ResponseType>, false> {
|
||||
public:
|
||||
explicit SplitServerStreamingHandler(
|
||||
std::function<
|
||||
grpc::Status(grpc::ServerContext*,
|
||||
ServerSplitStreamer<RequestType, ResponseType>*)>
|
||||
func)
|
||||
: TemplatedBidiStreamingHandler<
|
||||
ServerSplitStreamer<RequestType, ResponseType>, false>(
|
||||
std::move(func)) {}
|
||||
};
|
||||
|
||||
/// General method handler class for errors that prevent real method use
|
||||
/// e.g., handle unknown method by returning UNIMPLEMENTED error.
|
||||
template <grpc::StatusCode code>
|
||||
class ErrorMethodHandler : public grpc::internal::MethodHandler {
|
||||
public:
|
||||
explicit ErrorMethodHandler(const std::string& message) : message_(message) {}
|
||||
|
||||
template <class T>
|
||||
static void FillOps(grpc::ServerContextBase* context,
|
||||
const std::string& message, T* ops) {
|
||||
grpc::Status status(code, message);
|
||||
if (!context->sent_initial_metadata_) {
|
||||
ops->SendInitialMetadata(&context->initial_metadata_,
|
||||
context->initial_metadata_flags());
|
||||
if (context->compression_level_set()) {
|
||||
ops->set_compression_level(context->compression_level());
|
||||
}
|
||||
context->sent_initial_metadata_ = true;
|
||||
}
|
||||
ops->ServerSendStatus(&context->trailing_metadata_, status);
|
||||
}
|
||||
|
||||
void RunHandler(const HandlerParameter& param) final {
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,
|
||||
grpc::internal::CallOpServerSendStatus>
|
||||
ops;
|
||||
FillOps(param.server_context, message_, &ops);
|
||||
param.call->PerformOps(&ops);
|
||||
param.call->cq()->Pluck(&ops);
|
||||
}
|
||||
|
||||
void* Deserialize(grpc_call* /*call*/, grpc_byte_buffer* req,
|
||||
grpc::Status* /*status*/, void** /*handler_data*/) final {
|
||||
// We have to destroy any request payload
|
||||
if (req != nullptr) {
|
||||
grpc_byte_buffer_destroy(req);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
const std::string message_;
|
||||
};
|
||||
|
||||
typedef ErrorMethodHandler<grpc::StatusCode::UNIMPLEMENTED>
|
||||
UnknownMethodHandler;
|
||||
typedef ErrorMethodHandler<grpc::StatusCode::RESOURCE_EXHAUSTED>
|
||||
ResourceExhaustedHandler;
|
||||
|
||||
} // namespace internal
|
||||
} // namespace grpc
|
||||
|
||||
#endif // GRPCPP_SUPPORT_METHOD_HANDLER_H
|
||||
223
Pods/gRPC-C++/include/grpcpp/support/proto_buffer_reader.h
generated
Normal file
223
Pods/gRPC-C++/include/grpcpp/support/proto_buffer_reader.h
generated
Normal file
@@ -0,0 +1,223 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2018 gRPC 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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef GRPCPP_SUPPORT_PROTO_BUFFER_READER_H
|
||||
#define GRPCPP_SUPPORT_PROTO_BUFFER_READER_H
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "absl/strings/cord.h"
|
||||
|
||||
#include <grpc/byte_buffer.h>
|
||||
#include <grpc/byte_buffer_reader.h>
|
||||
#include <grpc/impl/grpc_types.h>
|
||||
#include <grpc/slice.h>
|
||||
#include <grpc/support/log.h>
|
||||
#include <grpcpp/impl/codegen/config_protobuf.h>
|
||||
#include <grpcpp/impl/serialization_traits.h>
|
||||
#include <grpcpp/support/byte_buffer.h>
|
||||
#include <grpcpp/support/status.h>
|
||||
|
||||
/// This header provides an object that reads bytes directly from a
|
||||
/// grpc::ByteBuffer, via the ZeroCopyInputStream interface
|
||||
|
||||
namespace grpc {
|
||||
|
||||
/// This is a specialization of the protobuf class ZeroCopyInputStream
|
||||
/// The principle is to get one chunk of data at a time from the proto layer,
|
||||
/// with options to backup (re-see some bytes) or skip (forward past some bytes)
|
||||
///
|
||||
/// Read more about ZeroCopyInputStream interface here:
|
||||
/// https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.io.zero_copy_stream#ZeroCopyInputStream
|
||||
class ProtoBufferReader : public grpc::protobuf::io::ZeroCopyInputStream {
|
||||
public:
|
||||
/// Constructs buffer reader from \a buffer. Will set \a status() to non ok
|
||||
/// if \a buffer is invalid (the internal buffer has not been initialized).
|
||||
explicit ProtoBufferReader(ByteBuffer* buffer)
|
||||
: byte_count_(0), backup_count_(0), status_() {
|
||||
/// Implemented through a grpc_byte_buffer_reader which iterates
|
||||
/// over the slices that make up a byte buffer
|
||||
if (!buffer->Valid() ||
|
||||
!grpc_byte_buffer_reader_init(&reader_, buffer->c_buffer())) {
|
||||
status_ = Status(StatusCode::INTERNAL,
|
||||
"Couldn't initialize byte buffer reader");
|
||||
}
|
||||
}
|
||||
|
||||
~ProtoBufferReader() override {
|
||||
if (status_.ok()) {
|
||||
grpc_byte_buffer_reader_destroy(&reader_);
|
||||
}
|
||||
}
|
||||
|
||||
/// Give the proto library a chunk of data from the stream. The caller
|
||||
/// may safely read from data[0, size - 1].
|
||||
bool Next(const void** data, int* size) override {
|
||||
if (!status_.ok()) {
|
||||
return false;
|
||||
}
|
||||
/// If we have backed up previously, we need to return the backed-up slice
|
||||
if (backup_count_ > 0) {
|
||||
*data = GRPC_SLICE_START_PTR(*slice_) + GRPC_SLICE_LENGTH(*slice_) -
|
||||
backup_count_;
|
||||
GPR_ASSERT(backup_count_ <= INT_MAX);
|
||||
*size = static_cast<int>(backup_count_);
|
||||
backup_count_ = 0;
|
||||
return true;
|
||||
}
|
||||
/// Otherwise get the next slice from the byte buffer reader
|
||||
if (!grpc_byte_buffer_reader_peek(&reader_, &slice_)) {
|
||||
return false;
|
||||
}
|
||||
*data = GRPC_SLICE_START_PTR(*slice_);
|
||||
// On win x64, int is only 32bit
|
||||
GPR_ASSERT(GRPC_SLICE_LENGTH(*slice_) <= INT_MAX);
|
||||
byte_count_ += * size = static_cast<int>(GRPC_SLICE_LENGTH(*slice_));
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Returns the status of the buffer reader.
|
||||
Status status() const { return status_; }
|
||||
|
||||
/// The proto library calls this to indicate that we should back up \a count
|
||||
/// bytes that have already been returned by the last call of Next.
|
||||
/// So do the backup and have that ready for a later Next.
|
||||
void BackUp(int count) override {
|
||||
GPR_ASSERT(count <= static_cast<int>(GRPC_SLICE_LENGTH(*slice_)));
|
||||
backup_count_ = count;
|
||||
}
|
||||
|
||||
/// The proto library calls this to skip over \a count bytes. Implement this
|
||||
/// using Next and BackUp combined.
|
||||
bool Skip(int count) override {
|
||||
const void* data;
|
||||
int size;
|
||||
while (Next(&data, &size)) {
|
||||
if (size >= count) {
|
||||
BackUp(size - count);
|
||||
return true;
|
||||
}
|
||||
// size < count;
|
||||
count -= size;
|
||||
}
|
||||
// error or we have too large count;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Returns the total number of bytes read since this object was created.
|
||||
int64_t ByteCount() const override { return byte_count_ - backup_count_; }
|
||||
|
||||
#ifdef GRPC_PROTOBUF_CORD_SUPPORT_ENABLED
|
||||
/// Read the next `count` bytes and append it to the given Cord.
|
||||
// (override is conditionally omitted here to support old Protobuf which
|
||||
// doesn't have ReadCord method)
|
||||
// NOLINTBEGIN(modernize-use-override,
|
||||
// clang-diagnostic-inconsistent-missing-override)
|
||||
virtual bool ReadCord(absl::Cord* cord, int count)
|
||||
#if GOOGLE_PROTOBUF_VERSION >= 4022000
|
||||
override
|
||||
#endif
|
||||
// NOLINTEND(modernize-use-override,
|
||||
// clang-diagnostic-inconsistent-missing-override)
|
||||
{
|
||||
if (!status().ok()) {
|
||||
return false;
|
||||
}
|
||||
// check for backed up data
|
||||
if (backup_count() > 0) {
|
||||
if (backup_count() <= count) {
|
||||
cord->Append(MakeCordFromSlice(grpc_slice_split_tail(
|
||||
slice(), GRPC_SLICE_LENGTH(*slice()) - backup_count())));
|
||||
} else {
|
||||
cord->Append(MakeCordFromSlice(grpc_slice_sub(
|
||||
*slice(), GRPC_SLICE_LENGTH(*slice()) - backup_count(),
|
||||
GRPC_SLICE_LENGTH(*slice()) - backup_count() + count)));
|
||||
}
|
||||
int64_t take = (std::min)(backup_count(), static_cast<int64_t>(count));
|
||||
set_backup_count(backup_count() - take);
|
||||
// This cast is safe as the size of a serialized protobuf message
|
||||
// should be smaller than 2GiB.
|
||||
// (https://protobuf.dev/programming-guides/encoding/#size-limit)
|
||||
count -= static_cast<int>(take);
|
||||
if (count == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
while (count > 0) {
|
||||
if (!grpc_byte_buffer_reader_peek(reader(), mutable_slice_ptr())) {
|
||||
return false;
|
||||
}
|
||||
uint64_t slice_length = GRPC_SLICE_LENGTH(*slice());
|
||||
set_byte_count(ByteCount() + slice_length);
|
||||
if (slice_length <= static_cast<uint64_t>(count)) {
|
||||
cord->Append(MakeCordFromSlice(grpc_slice_ref(*slice())));
|
||||
// This cast is safe as above.
|
||||
count -= static_cast<int>(slice_length);
|
||||
} else {
|
||||
cord->Append(MakeCordFromSlice(grpc_slice_split_head(slice(), count)));
|
||||
set_backup_count(slice_length - count);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
GPR_ASSERT(count == 0);
|
||||
return true;
|
||||
}
|
||||
#endif // GRPC_PROTOBUF_CORD_SUPPORT_ENABLED
|
||||
|
||||
// These protected members are needed to support internal optimizations.
|
||||
// they expose internal bits of grpc core that are NOT stable. If you have
|
||||
// a use case needs to use one of these functions, please send an email to
|
||||
// https://groups.google.com/forum/#!forum/grpc-io.
|
||||
protected:
|
||||
void set_byte_count(int64_t byte_count) { byte_count_ = byte_count; }
|
||||
int64_t backup_count() { return backup_count_; }
|
||||
void set_backup_count(int64_t backup_count) { backup_count_ = backup_count; }
|
||||
grpc_byte_buffer_reader* reader() { return &reader_; }
|
||||
grpc_slice* slice() { return slice_; }
|
||||
grpc_slice** mutable_slice_ptr() { return &slice_; }
|
||||
|
||||
private:
|
||||
#ifdef GRPC_PROTOBUF_CORD_SUPPORT_ENABLED
|
||||
// This function takes ownership of slice and return a newly created Cord off
|
||||
// of it.
|
||||
static absl::Cord MakeCordFromSlice(grpc_slice slice) {
|
||||
// slice_for_cord is created to keep inlined data of the given slice
|
||||
grpc_slice* slice_for_cord = new grpc_slice;
|
||||
*slice_for_cord = slice;
|
||||
return absl::MakeCordFromExternal(
|
||||
absl::string_view(
|
||||
reinterpret_cast<char*>(GRPC_SLICE_START_PTR(*slice_for_cord)),
|
||||
GRPC_SLICE_LENGTH(*slice_for_cord)),
|
||||
[slice_for_cord](absl::string_view /* view */) {
|
||||
grpc_slice_unref(*slice_for_cord);
|
||||
delete slice_for_cord;
|
||||
});
|
||||
}
|
||||
#endif // GRPC_PROTOBUF_CORD_SUPPORT_ENABLED
|
||||
|
||||
int64_t byte_count_; ///< total bytes read since object creation
|
||||
int64_t backup_count_; ///< how far backed up in the stream we are
|
||||
grpc_byte_buffer_reader reader_; ///< internal object to read \a grpc_slice
|
||||
///< from the \a grpc_byte_buffer
|
||||
grpc_slice* slice_; ///< current slice passed back to the caller
|
||||
Status status_; ///< status of the entire object
|
||||
};
|
||||
|
||||
} // namespace grpc
|
||||
|
||||
#endif // GRPCPP_SUPPORT_PROTO_BUFFER_READER_H
|
||||
220
Pods/gRPC-C++/include/grpcpp/support/proto_buffer_writer.h
generated
Normal file
220
Pods/gRPC-C++/include/grpcpp/support/proto_buffer_writer.h
generated
Normal file
@@ -0,0 +1,220 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2018 gRPC 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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef GRPCPP_SUPPORT_PROTO_BUFFER_WRITER_H
|
||||
#define GRPCPP_SUPPORT_PROTO_BUFFER_WRITER_H
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "absl/strings/cord.h"
|
||||
|
||||
#include <grpc/byte_buffer.h>
|
||||
#include <grpc/impl/grpc_types.h>
|
||||
#include <grpc/slice.h>
|
||||
#include <grpc/slice_buffer.h>
|
||||
#include <grpc/support/log.h>
|
||||
#include <grpcpp/impl/codegen/config_protobuf.h>
|
||||
#include <grpcpp/impl/serialization_traits.h>
|
||||
#include <grpcpp/support/byte_buffer.h>
|
||||
#include <grpcpp/support/status.h>
|
||||
|
||||
/// This header provides an object that writes bytes directly into a
|
||||
/// grpc::ByteBuffer, via the ZeroCopyOutputStream interface
|
||||
|
||||
namespace grpc {
|
||||
|
||||
// Forward declaration for testing use only
|
||||
namespace internal {
|
||||
class ProtoBufferWriterPeer;
|
||||
} // namespace internal
|
||||
|
||||
const int kProtoBufferWriterMaxBufferLength = 1024 * 1024;
|
||||
|
||||
/// This is a specialization of the protobuf class ZeroCopyOutputStream.
|
||||
/// The principle is to give the proto layer one buffer of bytes at a time
|
||||
/// that it can use to serialize the next portion of the message, with the
|
||||
/// option to "backup" if more buffer is given than required at the last buffer.
|
||||
///
|
||||
/// Read more about ZeroCopyOutputStream interface here:
|
||||
/// https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.io.zero_copy_stream#ZeroCopyOutputStream
|
||||
class ProtoBufferWriter : public grpc::protobuf::io::ZeroCopyOutputStream {
|
||||
public:
|
||||
/// Constructor for this derived class
|
||||
///
|
||||
/// \param[out] byte_buffer A pointer to the grpc::ByteBuffer created
|
||||
/// \param block_size How big are the chunks to allocate at a time
|
||||
/// \param total_size How many total bytes are required for this proto
|
||||
ProtoBufferWriter(ByteBuffer* byte_buffer, int block_size, int total_size)
|
||||
: block_size_(block_size),
|
||||
total_size_(total_size),
|
||||
byte_count_(0),
|
||||
have_backup_(false) {
|
||||
GPR_ASSERT(!byte_buffer->Valid());
|
||||
/// Create an empty raw byte buffer and look at its underlying slice buffer
|
||||
grpc_byte_buffer* bp = grpc_raw_byte_buffer_create(nullptr, 0);
|
||||
byte_buffer->set_buffer(bp);
|
||||
slice_buffer_ = &bp->data.raw.slice_buffer;
|
||||
}
|
||||
|
||||
~ProtoBufferWriter() override {
|
||||
if (have_backup_) {
|
||||
grpc_slice_unref(backup_slice_);
|
||||
}
|
||||
}
|
||||
|
||||
/// Give the proto library the next buffer of bytes and its size. It is
|
||||
/// safe for the caller to write from data[0, size - 1].
|
||||
bool Next(void** data, int* size) override {
|
||||
// Protobuf should not ask for more memory than total_size_.
|
||||
GPR_ASSERT(byte_count_ < total_size_);
|
||||
// 1. Use the remaining backup slice if we have one
|
||||
// 2. Otherwise allocate a slice, up to the remaining length needed
|
||||
// or our maximum allocation size
|
||||
// 3. Provide the slice start and size available
|
||||
// 4. Add the slice being returned to the slice buffer
|
||||
size_t remain = static_cast<size_t>(total_size_ - byte_count_);
|
||||
if (have_backup_) {
|
||||
/// If we have a backup slice, we should use it first
|
||||
slice_ = backup_slice_;
|
||||
have_backup_ = false;
|
||||
if (GRPC_SLICE_LENGTH(slice_) > remain) {
|
||||
GRPC_SLICE_SET_LENGTH(slice_, remain);
|
||||
}
|
||||
} else {
|
||||
// When less than a whole block is needed, only allocate that much.
|
||||
// But make sure the allocated slice is not inlined.
|
||||
size_t allocate_length =
|
||||
remain > static_cast<size_t>(block_size_) ? block_size_ : remain;
|
||||
slice_ = grpc_slice_malloc(allocate_length > GRPC_SLICE_INLINED_SIZE
|
||||
? allocate_length
|
||||
: GRPC_SLICE_INLINED_SIZE + 1);
|
||||
}
|
||||
*data = GRPC_SLICE_START_PTR(slice_);
|
||||
// On win x64, int is only 32bit
|
||||
GPR_ASSERT(GRPC_SLICE_LENGTH(slice_) <= INT_MAX);
|
||||
byte_count_ += * size = static_cast<int>(GRPC_SLICE_LENGTH(slice_));
|
||||
// Using grpc_slice_buffer_add could modify slice_ and merge it with the
|
||||
// previous slice. Therefore, use grpc_slice_buffer_add_indexed method to
|
||||
// ensure the slice gets added at a separate index. It can then be kept
|
||||
// around and popped later in the BackUp function.
|
||||
grpc_slice_buffer_add_indexed(slice_buffer_, slice_);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Backup by \a count bytes because Next returned more bytes than needed
|
||||
/// (only used in the last buffer). \a count must be less than or equal too
|
||||
/// the last buffer returned from next.
|
||||
void BackUp(int count) override {
|
||||
// count == 0 is invoked by ZeroCopyOutputStream users indicating that any
|
||||
// potential buffer obtained through a previous call to Next() is final.
|
||||
// ZeroCopyOutputStream implementations such as streaming output can use
|
||||
// these calls to flush any temporary buffer and flush the output. The logic
|
||||
// below is not robust against count == 0 invocations, so directly return.
|
||||
if (count == 0) return;
|
||||
|
||||
/// 1. Remove the partially-used last slice from the slice buffer
|
||||
/// 2. Split it into the needed (if any) and unneeded part
|
||||
/// 3. Add the needed part back to the slice buffer
|
||||
/// 4. Mark that we still have the remaining part (for later use/unref)
|
||||
GPR_ASSERT(count <= static_cast<int>(GRPC_SLICE_LENGTH(slice_)));
|
||||
grpc_slice_buffer_pop(slice_buffer_);
|
||||
if (static_cast<size_t>(count) == GRPC_SLICE_LENGTH(slice_)) {
|
||||
backup_slice_ = slice_;
|
||||
} else {
|
||||
backup_slice_ =
|
||||
grpc_slice_split_tail(&slice_, GRPC_SLICE_LENGTH(slice_) - count);
|
||||
grpc_slice_buffer_add(slice_buffer_, slice_);
|
||||
}
|
||||
// It's dangerous to keep an inlined grpc_slice as the backup slice, since
|
||||
// on a following Next() call, a reference will be returned to this slice
|
||||
// via GRPC_SLICE_START_PTR, which will not be an address held by
|
||||
// slice_buffer_.
|
||||
have_backup_ = backup_slice_.refcount != nullptr;
|
||||
byte_count_ -= count;
|
||||
}
|
||||
|
||||
/// Returns the total number of bytes written since this object was created.
|
||||
int64_t ByteCount() const override { return byte_count_; }
|
||||
|
||||
#ifdef GRPC_PROTOBUF_CORD_SUPPORT_ENABLED
|
||||
/// Writes cord to the backing byte_buffer, sharing the memory between the
|
||||
/// blocks of the cord, and the slices of the byte_buffer.
|
||||
// (override is conditionally omitted here to support old Protobuf which
|
||||
// doesn't have ReadCord method)
|
||||
// NOLINTBEGIN(modernize-use-override,
|
||||
// clang-diagnostic-inconsistent-missing-override)
|
||||
virtual bool WriteCord(const absl::Cord& cord)
|
||||
#if GOOGLE_PROTOBUF_VERSION >= 4022000
|
||||
override
|
||||
#endif
|
||||
// NOLINTEND(modernize-use-override,
|
||||
// clang-diagnostic-inconsistent-missing-override)
|
||||
{
|
||||
grpc_slice_buffer* buffer = slice_buffer();
|
||||
size_t cur = 0;
|
||||
for (absl::string_view chunk : cord.Chunks()) {
|
||||
// TODO(veblush): Revisit this 512 threadhold which could be smaller.
|
||||
if (chunk.size() < 512) {
|
||||
// If chunk is small enough, just copy it.
|
||||
grpc_slice slice =
|
||||
grpc_slice_from_copied_buffer(chunk.data(), chunk.size());
|
||||
grpc_slice_buffer_add(buffer, slice);
|
||||
} else {
|
||||
// If chunk is large, just use the pointer instead of copying.
|
||||
// To make sure it's alive while being used, a subcord for chunk is
|
||||
// created and attached to a grpc_slice instance.
|
||||
absl::Cord* subcord = new absl::Cord(cord.Subcord(cur, chunk.size()));
|
||||
grpc_slice slice = grpc_slice_new_with_user_data(
|
||||
const_cast<uint8_t*>(
|
||||
reinterpret_cast<const uint8_t*>(chunk.data())),
|
||||
chunk.size(), [](void* p) { delete static_cast<absl::Cord*>(p); },
|
||||
subcord);
|
||||
grpc_slice_buffer_add(buffer, slice);
|
||||
}
|
||||
cur += chunk.size();
|
||||
}
|
||||
set_byte_count(ByteCount() + cur);
|
||||
return true;
|
||||
}
|
||||
#endif // GRPC_PROTOBUF_CORD_SUPPORT_ENABLED
|
||||
|
||||
// These protected members are needed to support internal optimizations.
|
||||
// they expose internal bits of grpc core that are NOT stable. If you have
|
||||
// a use case needs to use one of these functions, please send an email to
|
||||
// https://groups.google.com/forum/#!forum/grpc-io.
|
||||
protected:
|
||||
grpc_slice_buffer* slice_buffer() { return slice_buffer_; }
|
||||
void set_byte_count(int64_t byte_count) { byte_count_ = byte_count; }
|
||||
|
||||
private:
|
||||
// friend for testing purposes only
|
||||
friend class internal::ProtoBufferWriterPeer;
|
||||
const int block_size_; ///< size to alloc for each new \a grpc_slice needed
|
||||
const int total_size_; ///< byte size of proto being serialized
|
||||
int64_t byte_count_; ///< bytes written since this object was created
|
||||
grpc_slice_buffer*
|
||||
slice_buffer_; ///< internal buffer of slices holding the serialized data
|
||||
bool have_backup_; ///< if we are holding a backup slice or not
|
||||
grpc_slice backup_slice_; ///< holds space we can still write to, if the
|
||||
///< caller has called BackUp
|
||||
grpc_slice slice_; ///< current slice passed back to the caller
|
||||
};
|
||||
|
||||
} // namespace grpc
|
||||
|
||||
#endif // GRPCPP_SUPPORT_PROTO_BUFFER_WRITER_H
|
||||
797
Pods/gRPC-C++/include/grpcpp/support/server_callback.h
generated
Normal file
797
Pods/gRPC-C++/include/grpcpp/support/server_callback.h
generated
Normal file
@@ -0,0 +1,797 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2018 gRPC 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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef GRPCPP_SUPPORT_SERVER_CALLBACK_H
|
||||
#define GRPCPP_SUPPORT_SERVER_CALLBACK_H
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
#include <grpcpp/impl/call.h>
|
||||
#include <grpcpp/impl/call_op_set.h>
|
||||
#include <grpcpp/impl/sync.h>
|
||||
#include <grpcpp/support/callback_common.h>
|
||||
#include <grpcpp/support/config.h>
|
||||
#include <grpcpp/support/message_allocator.h>
|
||||
#include <grpcpp/support/status.h>
|
||||
|
||||
namespace grpc {
|
||||
|
||||
// Declare base class of all reactors as internal
|
||||
namespace internal {
|
||||
|
||||
// Forward declarations
|
||||
template <class Request, class Response>
|
||||
class CallbackUnaryHandler;
|
||||
template <class Request, class Response>
|
||||
class CallbackClientStreamingHandler;
|
||||
template <class Request, class Response>
|
||||
class CallbackServerStreamingHandler;
|
||||
template <class Request, class Response>
|
||||
class CallbackBidiHandler;
|
||||
|
||||
class ServerReactor {
|
||||
public:
|
||||
virtual ~ServerReactor() = default;
|
||||
virtual void OnDone() = 0;
|
||||
virtual void OnCancel() = 0;
|
||||
|
||||
// The following is not API. It is for internal use only and specifies whether
|
||||
// all reactions of this Reactor can be run without an extra executor
|
||||
// scheduling. This should only be used for internally-defined reactors with
|
||||
// trivial reactions.
|
||||
virtual bool InternalInlineable() { return false; }
|
||||
|
||||
private:
|
||||
template <class Request, class Response>
|
||||
friend class CallbackUnaryHandler;
|
||||
template <class Request, class Response>
|
||||
friend class CallbackClientStreamingHandler;
|
||||
template <class Request, class Response>
|
||||
friend class CallbackServerStreamingHandler;
|
||||
template <class Request, class Response>
|
||||
friend class CallbackBidiHandler;
|
||||
};
|
||||
|
||||
/// The base class of ServerCallbackUnary etc.
|
||||
class ServerCallbackCall {
|
||||
public:
|
||||
virtual ~ServerCallbackCall() {}
|
||||
|
||||
// This object is responsible for tracking when it is safe to call OnDone and
|
||||
// OnCancel. OnDone should not be called until the method handler is complete,
|
||||
// Finish has been called, the ServerContext CompletionOp (which tracks
|
||||
// cancellation or successful completion) has completed, and all outstanding
|
||||
// Read/Write actions have seen their reactions. OnCancel should not be called
|
||||
// until after the method handler is done and the RPC has completed with a
|
||||
// cancellation. This is tracked by counting how many of these conditions have
|
||||
// been met and calling OnCancel when none remain unmet.
|
||||
|
||||
// Public versions of MaybeDone: one where we don't know the reactor in
|
||||
// advance (used for the ServerContext CompletionOp), and one for where we
|
||||
// know the inlineability of the OnDone reaction. You should set the inline
|
||||
// flag to true if either the Reactor is InternalInlineable() or if this
|
||||
// callback is already being forced to run dispatched to an executor
|
||||
// (typically because it contains additional work than just the MaybeDone).
|
||||
|
||||
void MaybeDone() {
|
||||
if (GPR_UNLIKELY(Unref() == 1)) {
|
||||
ScheduleOnDone(reactor()->InternalInlineable());
|
||||
}
|
||||
}
|
||||
|
||||
void MaybeDone(bool inline_ondone) {
|
||||
if (GPR_UNLIKELY(Unref() == 1)) {
|
||||
ScheduleOnDone(inline_ondone);
|
||||
}
|
||||
}
|
||||
|
||||
// Fast version called with known reactor passed in, used from derived
|
||||
// classes, typically in non-cancel case
|
||||
void MaybeCallOnCancel(ServerReactor* reactor) {
|
||||
if (GPR_UNLIKELY(UnblockCancellation())) {
|
||||
CallOnCancel(reactor);
|
||||
}
|
||||
}
|
||||
|
||||
// Slower version called from object that doesn't know the reactor a priori
|
||||
// (such as the ServerContext CompletionOp which is formed before the
|
||||
// reactor). This is used in cancel cases only, so it's ok to be slower and
|
||||
// invoke a virtual function.
|
||||
void MaybeCallOnCancel() {
|
||||
if (GPR_UNLIKELY(UnblockCancellation())) {
|
||||
CallOnCancel(reactor());
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
/// Increases the reference count
|
||||
void Ref() { callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); }
|
||||
|
||||
private:
|
||||
virtual ServerReactor* reactor() = 0;
|
||||
|
||||
// CallOnDone performs the work required at completion of the RPC: invoking
|
||||
// the OnDone function and doing all necessary cleanup. This function is only
|
||||
// ever invoked on a fully-Unref'fed ServerCallbackCall.
|
||||
virtual void CallOnDone() = 0;
|
||||
|
||||
// If the OnDone reaction is inlineable, execute it inline. Otherwise send it
|
||||
// to an executor.
|
||||
void ScheduleOnDone(bool inline_ondone);
|
||||
|
||||
// If the OnCancel reaction is inlineable, execute it inline. Otherwise send
|
||||
// it to an executor.
|
||||
void CallOnCancel(ServerReactor* reactor);
|
||||
|
||||
// Implement the cancellation constraint counter. Return true if OnCancel
|
||||
// should be called, false otherwise.
|
||||
bool UnblockCancellation() {
|
||||
return on_cancel_conditions_remaining_.fetch_sub(
|
||||
1, std::memory_order_acq_rel) == 1;
|
||||
}
|
||||
|
||||
/// Decreases the reference count and returns the previous value
|
||||
int Unref() {
|
||||
return callbacks_outstanding_.fetch_sub(1, std::memory_order_acq_rel);
|
||||
}
|
||||
|
||||
std::atomic_int on_cancel_conditions_remaining_{2};
|
||||
std::atomic_int callbacks_outstanding_{
|
||||
3}; // reserve for start, Finish, and CompletionOp
|
||||
};
|
||||
|
||||
template <class Request, class Response>
|
||||
class DefaultMessageHolder : public MessageHolder<Request, Response> {
|
||||
public:
|
||||
DefaultMessageHolder() {
|
||||
this->set_request(&request_obj_);
|
||||
this->set_response(&response_obj_);
|
||||
}
|
||||
void Release() override {
|
||||
// the object is allocated in the call arena.
|
||||
this->~DefaultMessageHolder<Request, Response>();
|
||||
}
|
||||
|
||||
private:
|
||||
Request request_obj_;
|
||||
Response response_obj_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// Forward declarations
|
||||
class ServerUnaryReactor;
|
||||
template <class Request>
|
||||
class ServerReadReactor;
|
||||
template <class Response>
|
||||
class ServerWriteReactor;
|
||||
template <class Request, class Response>
|
||||
class ServerBidiReactor;
|
||||
|
||||
// NOTE: The actual call/stream object classes are provided as API only to
|
||||
// support mocking. There are no implementations of these class interfaces in
|
||||
// the API.
|
||||
class ServerCallbackUnary : public internal::ServerCallbackCall {
|
||||
public:
|
||||
~ServerCallbackUnary() override {}
|
||||
virtual void Finish(grpc::Status s) = 0;
|
||||
virtual void SendInitialMetadata() = 0;
|
||||
|
||||
protected:
|
||||
// Use a template rather than explicitly specifying ServerUnaryReactor to
|
||||
// delay binding and avoid a circular forward declaration issue
|
||||
template <class Reactor>
|
||||
void BindReactor(Reactor* reactor) {
|
||||
reactor->InternalBindCall(this);
|
||||
}
|
||||
};
|
||||
|
||||
template <class Request>
|
||||
class ServerCallbackReader : public internal::ServerCallbackCall {
|
||||
public:
|
||||
~ServerCallbackReader() override {}
|
||||
virtual void Finish(grpc::Status s) = 0;
|
||||
virtual void SendInitialMetadata() = 0;
|
||||
virtual void Read(Request* msg) = 0;
|
||||
|
||||
protected:
|
||||
void BindReactor(ServerReadReactor<Request>* reactor) {
|
||||
reactor->InternalBindReader(this);
|
||||
}
|
||||
};
|
||||
|
||||
template <class Response>
|
||||
class ServerCallbackWriter : public internal::ServerCallbackCall {
|
||||
public:
|
||||
~ServerCallbackWriter() override {}
|
||||
|
||||
virtual void Finish(grpc::Status s) = 0;
|
||||
virtual void SendInitialMetadata() = 0;
|
||||
virtual void Write(const Response* msg, grpc::WriteOptions options) = 0;
|
||||
virtual void WriteAndFinish(const Response* msg, grpc::WriteOptions options,
|
||||
grpc::Status s) = 0;
|
||||
|
||||
protected:
|
||||
void BindReactor(ServerWriteReactor<Response>* reactor) {
|
||||
reactor->InternalBindWriter(this);
|
||||
}
|
||||
};
|
||||
|
||||
template <class Request, class Response>
|
||||
class ServerCallbackReaderWriter : public internal::ServerCallbackCall {
|
||||
public:
|
||||
~ServerCallbackReaderWriter() override {}
|
||||
|
||||
virtual void Finish(grpc::Status s) = 0;
|
||||
virtual void SendInitialMetadata() = 0;
|
||||
virtual void Read(Request* msg) = 0;
|
||||
virtual void Write(const Response* msg, grpc::WriteOptions options) = 0;
|
||||
virtual void WriteAndFinish(const Response* msg, grpc::WriteOptions options,
|
||||
grpc::Status s) = 0;
|
||||
|
||||
protected:
|
||||
void BindReactor(ServerBidiReactor<Request, Response>* reactor) {
|
||||
reactor->InternalBindStream(this);
|
||||
}
|
||||
};
|
||||
|
||||
// The following classes are the reactor interfaces that are to be implemented
|
||||
// by the user, returned as the output parameter of the method handler for a
|
||||
// callback method. Note that none of the classes are pure; all reactions have a
|
||||
// default empty reaction so that the user class only needs to override those
|
||||
// reactions that it cares about. The reaction methods will be invoked by the
|
||||
// library in response to the completion of various operations. Reactions must
|
||||
// not include blocking operations (such as blocking I/O, starting synchronous
|
||||
// RPCs, or waiting on condition variables). Reactions may be invoked
|
||||
// concurrently, except that OnDone is called after all others (assuming proper
|
||||
// API usage). The reactor may not be deleted until OnDone is called.
|
||||
|
||||
/// \a ServerBidiReactor is the interface for a bidirectional streaming RPC.
|
||||
template <class Request, class Response>
|
||||
class ServerBidiReactor : public internal::ServerReactor {
|
||||
public:
|
||||
// NOTE: Initializing stream_ as a constructor initializer rather than a
|
||||
// default initializer because gcc-4.x requires a copy constructor for
|
||||
// default initializing a templated member, which isn't ok for atomic.
|
||||
// TODO(vjpai): Switch to default constructor and default initializer when
|
||||
// gcc-4.x is no longer supported
|
||||
ServerBidiReactor() : stream_(nullptr) {}
|
||||
~ServerBidiReactor() override = default;
|
||||
|
||||
/// Send any initial metadata stored in the RPC context. If not invoked,
|
||||
/// any initial metadata will be passed along with the first Write or the
|
||||
/// Finish (if there are no writes).
|
||||
void StartSendInitialMetadata() ABSL_LOCKS_EXCLUDED(stream_mu_) {
|
||||
ServerCallbackReaderWriter<Request, Response>* stream =
|
||||
stream_.load(std::memory_order_acquire);
|
||||
if (stream == nullptr) {
|
||||
grpc::internal::MutexLock l(&stream_mu_);
|
||||
stream = stream_.load(std::memory_order_relaxed);
|
||||
if (stream == nullptr) {
|
||||
backlog_.send_initial_metadata_wanted = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
stream->SendInitialMetadata();
|
||||
}
|
||||
|
||||
/// Initiate a read operation.
|
||||
///
|
||||
/// \param[out] req Where to eventually store the read message. Valid when
|
||||
/// the library calls OnReadDone
|
||||
void StartRead(Request* req) ABSL_LOCKS_EXCLUDED(stream_mu_) {
|
||||
ServerCallbackReaderWriter<Request, Response>* stream =
|
||||
stream_.load(std::memory_order_acquire);
|
||||
if (stream == nullptr) {
|
||||
grpc::internal::MutexLock l(&stream_mu_);
|
||||
stream = stream_.load(std::memory_order_relaxed);
|
||||
if (stream == nullptr) {
|
||||
backlog_.read_wanted = req;
|
||||
return;
|
||||
}
|
||||
}
|
||||
stream->Read(req);
|
||||
}
|
||||
|
||||
/// Initiate a write operation.
|
||||
///
|
||||
/// \param[in] resp The message to be written. The library does not take
|
||||
/// ownership but the caller must ensure that the message is
|
||||
/// not deleted or modified until OnWriteDone is called.
|
||||
void StartWrite(const Response* resp) {
|
||||
StartWrite(resp, grpc::WriteOptions());
|
||||
}
|
||||
|
||||
/// Initiate a write operation with specified options.
|
||||
///
|
||||
/// \param[in] resp The message to be written. The library does not take
|
||||
/// ownership but the caller must ensure that the message is
|
||||
/// not deleted or modified until OnWriteDone is called.
|
||||
/// \param[in] options The WriteOptions to use for writing this message
|
||||
void StartWrite(const Response* resp, grpc::WriteOptions options)
|
||||
ABSL_LOCKS_EXCLUDED(stream_mu_) {
|
||||
ServerCallbackReaderWriter<Request, Response>* stream =
|
||||
stream_.load(std::memory_order_acquire);
|
||||
if (stream == nullptr) {
|
||||
grpc::internal::MutexLock l(&stream_mu_);
|
||||
stream = stream_.load(std::memory_order_relaxed);
|
||||
if (stream == nullptr) {
|
||||
backlog_.write_wanted = resp;
|
||||
backlog_.write_options_wanted = options;
|
||||
return;
|
||||
}
|
||||
}
|
||||
stream->Write(resp, options);
|
||||
}
|
||||
|
||||
/// Initiate a write operation with specified options and final RPC Status,
|
||||
/// which also causes any trailing metadata for this RPC to be sent out.
|
||||
/// StartWriteAndFinish is like merging StartWriteLast and Finish into a
|
||||
/// single step. A key difference, though, is that this operation doesn't have
|
||||
/// an OnWriteDone reaction - it is considered complete only when OnDone is
|
||||
/// available. An RPC can either have StartWriteAndFinish or Finish, but not
|
||||
/// both.
|
||||
///
|
||||
/// \param[in] resp The message to be written. The library does not take
|
||||
/// ownership but the caller must ensure that the message is
|
||||
/// not deleted or modified until OnDone is called.
|
||||
/// \param[in] options The WriteOptions to use for writing this message
|
||||
/// \param[in] s The status outcome of this RPC
|
||||
void StartWriteAndFinish(const Response* resp, grpc::WriteOptions options,
|
||||
grpc::Status s) ABSL_LOCKS_EXCLUDED(stream_mu_) {
|
||||
ServerCallbackReaderWriter<Request, Response>* stream =
|
||||
stream_.load(std::memory_order_acquire);
|
||||
if (stream == nullptr) {
|
||||
grpc::internal::MutexLock l(&stream_mu_);
|
||||
stream = stream_.load(std::memory_order_relaxed);
|
||||
if (stream == nullptr) {
|
||||
backlog_.write_and_finish_wanted = true;
|
||||
backlog_.write_wanted = resp;
|
||||
backlog_.write_options_wanted = options;
|
||||
backlog_.status_wanted = std::move(s);
|
||||
return;
|
||||
}
|
||||
}
|
||||
stream->WriteAndFinish(resp, options, std::move(s));
|
||||
}
|
||||
|
||||
/// Inform system of a planned write operation with specified options, but
|
||||
/// allow the library to schedule the actual write coalesced with the writing
|
||||
/// of trailing metadata (which takes place on a Finish call).
|
||||
///
|
||||
/// \param[in] resp The message to be written. The library does not take
|
||||
/// ownership but the caller must ensure that the message is
|
||||
/// not deleted or modified until OnWriteDone is called.
|
||||
/// \param[in] options The WriteOptions to use for writing this message
|
||||
void StartWriteLast(const Response* resp, grpc::WriteOptions options) {
|
||||
StartWrite(resp, options.set_last_message());
|
||||
}
|
||||
|
||||
/// Indicate that the stream is to be finished and the trailing metadata and
|
||||
/// RPC status are to be sent. Every RPC MUST be finished using either Finish
|
||||
/// or StartWriteAndFinish (but not both), even if the RPC is already
|
||||
/// cancelled.
|
||||
///
|
||||
/// \param[in] s The status outcome of this RPC
|
||||
void Finish(grpc::Status s) ABSL_LOCKS_EXCLUDED(stream_mu_) {
|
||||
ServerCallbackReaderWriter<Request, Response>* stream =
|
||||
stream_.load(std::memory_order_acquire);
|
||||
if (stream == nullptr) {
|
||||
grpc::internal::MutexLock l(&stream_mu_);
|
||||
stream = stream_.load(std::memory_order_relaxed);
|
||||
if (stream == nullptr) {
|
||||
backlog_.finish_wanted = true;
|
||||
backlog_.status_wanted = std::move(s);
|
||||
return;
|
||||
}
|
||||
}
|
||||
stream->Finish(std::move(s));
|
||||
}
|
||||
|
||||
/// Notifies the application that an explicit StartSendInitialMetadata
|
||||
/// operation completed. Not used when the sending of initial metadata
|
||||
/// piggybacks onto the first write.
|
||||
///
|
||||
/// \param[in] ok Was it successful? If false, no further write-side operation
|
||||
/// will succeed.
|
||||
virtual void OnSendInitialMetadataDone(bool /*ok*/) {}
|
||||
|
||||
/// Notifies the application that a StartRead operation completed.
|
||||
///
|
||||
/// \param[in] ok Was it successful? If false, no further read-side operation
|
||||
/// will succeed.
|
||||
virtual void OnReadDone(bool /*ok*/) {}
|
||||
|
||||
/// Notifies the application that a StartWrite (or StartWriteLast) operation
|
||||
/// completed.
|
||||
///
|
||||
/// \param[in] ok Was it successful? If false, no further write-side operation
|
||||
/// will succeed.
|
||||
virtual void OnWriteDone(bool /*ok*/) {}
|
||||
|
||||
/// Notifies the application that all operations associated with this RPC
|
||||
/// have completed. This is an override (from the internal base class) but
|
||||
/// still abstract, so derived classes MUST override it to be instantiated.
|
||||
void OnDone() override = 0;
|
||||
|
||||
/// Notifies the application that this RPC has been cancelled. This is an
|
||||
/// override (from the internal base class) but not final, so derived classes
|
||||
/// should override it if they want to take action.
|
||||
void OnCancel() override {}
|
||||
|
||||
private:
|
||||
friend class ServerCallbackReaderWriter<Request, Response>;
|
||||
// May be overridden by internal implementation details. This is not a public
|
||||
// customization point.
|
||||
virtual void InternalBindStream(
|
||||
ServerCallbackReaderWriter<Request, Response>* stream) {
|
||||
grpc::internal::MutexLock l(&stream_mu_);
|
||||
|
||||
if (GPR_UNLIKELY(backlog_.send_initial_metadata_wanted)) {
|
||||
stream->SendInitialMetadata();
|
||||
}
|
||||
if (GPR_UNLIKELY(backlog_.read_wanted != nullptr)) {
|
||||
stream->Read(backlog_.read_wanted);
|
||||
}
|
||||
if (GPR_UNLIKELY(backlog_.write_and_finish_wanted)) {
|
||||
stream->WriteAndFinish(backlog_.write_wanted,
|
||||
std::move(backlog_.write_options_wanted),
|
||||
std::move(backlog_.status_wanted));
|
||||
} else {
|
||||
if (GPR_UNLIKELY(backlog_.write_wanted != nullptr)) {
|
||||
stream->Write(backlog_.write_wanted,
|
||||
std::move(backlog_.write_options_wanted));
|
||||
}
|
||||
if (GPR_UNLIKELY(backlog_.finish_wanted)) {
|
||||
stream->Finish(std::move(backlog_.status_wanted));
|
||||
}
|
||||
}
|
||||
// Set stream_ last so that other functions can use it lock-free
|
||||
stream_.store(stream, std::memory_order_release);
|
||||
}
|
||||
|
||||
grpc::internal::Mutex stream_mu_;
|
||||
// TODO(vjpai): Make stream_or_backlog_ into a std::variant or absl::variant
|
||||
// once C++17 or ABSL is supported since stream and backlog are
|
||||
// mutually exclusive in this class. Do likewise with the
|
||||
// remaining reactor classes and their backlogs as well.
|
||||
std::atomic<ServerCallbackReaderWriter<Request, Response>*> stream_{nullptr};
|
||||
struct PreBindBacklog {
|
||||
bool send_initial_metadata_wanted = false;
|
||||
bool write_and_finish_wanted = false;
|
||||
bool finish_wanted = false;
|
||||
Request* read_wanted = nullptr;
|
||||
const Response* write_wanted = nullptr;
|
||||
grpc::WriteOptions write_options_wanted;
|
||||
grpc::Status status_wanted;
|
||||
};
|
||||
PreBindBacklog backlog_ ABSL_GUARDED_BY(stream_mu_);
|
||||
};
|
||||
|
||||
/// \a ServerReadReactor is the interface for a client-streaming RPC.
|
||||
template <class Request>
|
||||
class ServerReadReactor : public internal::ServerReactor {
|
||||
public:
|
||||
ServerReadReactor() : reader_(nullptr) {}
|
||||
~ServerReadReactor() override = default;
|
||||
|
||||
/// The following operation initiations are exactly like ServerBidiReactor.
|
||||
void StartSendInitialMetadata() ABSL_LOCKS_EXCLUDED(reader_mu_) {
|
||||
ServerCallbackReader<Request>* reader =
|
||||
reader_.load(std::memory_order_acquire);
|
||||
if (reader == nullptr) {
|
||||
grpc::internal::MutexLock l(&reader_mu_);
|
||||
reader = reader_.load(std::memory_order_relaxed);
|
||||
if (reader == nullptr) {
|
||||
backlog_.send_initial_metadata_wanted = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
reader->SendInitialMetadata();
|
||||
}
|
||||
void StartRead(Request* req) ABSL_LOCKS_EXCLUDED(reader_mu_) {
|
||||
ServerCallbackReader<Request>* reader =
|
||||
reader_.load(std::memory_order_acquire);
|
||||
if (reader == nullptr) {
|
||||
grpc::internal::MutexLock l(&reader_mu_);
|
||||
reader = reader_.load(std::memory_order_relaxed);
|
||||
if (reader == nullptr) {
|
||||
backlog_.read_wanted = req;
|
||||
return;
|
||||
}
|
||||
}
|
||||
reader->Read(req);
|
||||
}
|
||||
void Finish(grpc::Status s) ABSL_LOCKS_EXCLUDED(reader_mu_) {
|
||||
ServerCallbackReader<Request>* reader =
|
||||
reader_.load(std::memory_order_acquire);
|
||||
if (reader == nullptr) {
|
||||
grpc::internal::MutexLock l(&reader_mu_);
|
||||
reader = reader_.load(std::memory_order_relaxed);
|
||||
if (reader == nullptr) {
|
||||
backlog_.finish_wanted = true;
|
||||
backlog_.status_wanted = std::move(s);
|
||||
return;
|
||||
}
|
||||
}
|
||||
reader->Finish(std::move(s));
|
||||
}
|
||||
|
||||
/// The following notifications are exactly like ServerBidiReactor.
|
||||
virtual void OnSendInitialMetadataDone(bool /*ok*/) {}
|
||||
virtual void OnReadDone(bool /*ok*/) {}
|
||||
void OnDone() override = 0;
|
||||
void OnCancel() override {}
|
||||
|
||||
private:
|
||||
friend class ServerCallbackReader<Request>;
|
||||
|
||||
// May be overridden by internal implementation details. This is not a public
|
||||
// customization point.
|
||||
virtual void InternalBindReader(ServerCallbackReader<Request>* reader)
|
||||
ABSL_LOCKS_EXCLUDED(reader_mu_) {
|
||||
grpc::internal::MutexLock l(&reader_mu_);
|
||||
|
||||
if (GPR_UNLIKELY(backlog_.send_initial_metadata_wanted)) {
|
||||
reader->SendInitialMetadata();
|
||||
}
|
||||
if (GPR_UNLIKELY(backlog_.read_wanted != nullptr)) {
|
||||
reader->Read(backlog_.read_wanted);
|
||||
}
|
||||
if (GPR_UNLIKELY(backlog_.finish_wanted)) {
|
||||
reader->Finish(std::move(backlog_.status_wanted));
|
||||
}
|
||||
// Set reader_ last so that other functions can use it lock-free
|
||||
reader_.store(reader, std::memory_order_release);
|
||||
}
|
||||
|
||||
grpc::internal::Mutex reader_mu_;
|
||||
std::atomic<ServerCallbackReader<Request>*> reader_{nullptr};
|
||||
struct PreBindBacklog {
|
||||
bool send_initial_metadata_wanted = false;
|
||||
bool finish_wanted = false;
|
||||
Request* read_wanted = nullptr;
|
||||
grpc::Status status_wanted;
|
||||
};
|
||||
PreBindBacklog backlog_ ABSL_GUARDED_BY(reader_mu_);
|
||||
};
|
||||
|
||||
/// \a ServerWriteReactor is the interface for a server-streaming RPC.
|
||||
template <class Response>
|
||||
class ServerWriteReactor : public internal::ServerReactor {
|
||||
public:
|
||||
ServerWriteReactor() : writer_(nullptr) {}
|
||||
~ServerWriteReactor() override = default;
|
||||
|
||||
/// The following operation initiations are exactly like ServerBidiReactor.
|
||||
void StartSendInitialMetadata() ABSL_LOCKS_EXCLUDED(writer_mu_) {
|
||||
ServerCallbackWriter<Response>* writer =
|
||||
writer_.load(std::memory_order_acquire);
|
||||
if (writer == nullptr) {
|
||||
grpc::internal::MutexLock l(&writer_mu_);
|
||||
writer = writer_.load(std::memory_order_relaxed);
|
||||
if (writer == nullptr) {
|
||||
backlog_.send_initial_metadata_wanted = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
writer->SendInitialMetadata();
|
||||
}
|
||||
void StartWrite(const Response* resp) {
|
||||
StartWrite(resp, grpc::WriteOptions());
|
||||
}
|
||||
void StartWrite(const Response* resp, grpc::WriteOptions options)
|
||||
ABSL_LOCKS_EXCLUDED(writer_mu_) {
|
||||
ServerCallbackWriter<Response>* writer =
|
||||
writer_.load(std::memory_order_acquire);
|
||||
if (writer == nullptr) {
|
||||
grpc::internal::MutexLock l(&writer_mu_);
|
||||
writer = writer_.load(std::memory_order_relaxed);
|
||||
if (writer == nullptr) {
|
||||
backlog_.write_wanted = resp;
|
||||
backlog_.write_options_wanted = options;
|
||||
return;
|
||||
}
|
||||
}
|
||||
writer->Write(resp, options);
|
||||
}
|
||||
void StartWriteAndFinish(const Response* resp, grpc::WriteOptions options,
|
||||
grpc::Status s) ABSL_LOCKS_EXCLUDED(writer_mu_) {
|
||||
ServerCallbackWriter<Response>* writer =
|
||||
writer_.load(std::memory_order_acquire);
|
||||
if (writer == nullptr) {
|
||||
grpc::internal::MutexLock l(&writer_mu_);
|
||||
writer = writer_.load(std::memory_order_relaxed);
|
||||
if (writer == nullptr) {
|
||||
backlog_.write_and_finish_wanted = true;
|
||||
backlog_.write_wanted = resp;
|
||||
backlog_.write_options_wanted = options;
|
||||
backlog_.status_wanted = std::move(s);
|
||||
return;
|
||||
}
|
||||
}
|
||||
writer->WriteAndFinish(resp, options, std::move(s));
|
||||
}
|
||||
void StartWriteLast(const Response* resp, grpc::WriteOptions options) {
|
||||
StartWrite(resp, options.set_last_message());
|
||||
}
|
||||
void Finish(grpc::Status s) ABSL_LOCKS_EXCLUDED(writer_mu_) {
|
||||
ServerCallbackWriter<Response>* writer =
|
||||
writer_.load(std::memory_order_acquire);
|
||||
if (writer == nullptr) {
|
||||
grpc::internal::MutexLock l(&writer_mu_);
|
||||
writer = writer_.load(std::memory_order_relaxed);
|
||||
if (writer == nullptr) {
|
||||
backlog_.finish_wanted = true;
|
||||
backlog_.status_wanted = std::move(s);
|
||||
return;
|
||||
}
|
||||
}
|
||||
writer->Finish(std::move(s));
|
||||
}
|
||||
|
||||
/// The following notifications are exactly like ServerBidiReactor.
|
||||
virtual void OnSendInitialMetadataDone(bool /*ok*/) {}
|
||||
virtual void OnWriteDone(bool /*ok*/) {}
|
||||
void OnDone() override = 0;
|
||||
void OnCancel() override {}
|
||||
|
||||
private:
|
||||
friend class ServerCallbackWriter<Response>;
|
||||
// May be overridden by internal implementation details. This is not a public
|
||||
// customization point.
|
||||
virtual void InternalBindWriter(ServerCallbackWriter<Response>* writer)
|
||||
ABSL_LOCKS_EXCLUDED(writer_mu_) {
|
||||
grpc::internal::MutexLock l(&writer_mu_);
|
||||
|
||||
if (GPR_UNLIKELY(backlog_.send_initial_metadata_wanted)) {
|
||||
writer->SendInitialMetadata();
|
||||
}
|
||||
if (GPR_UNLIKELY(backlog_.write_and_finish_wanted)) {
|
||||
writer->WriteAndFinish(backlog_.write_wanted,
|
||||
std::move(backlog_.write_options_wanted),
|
||||
std::move(backlog_.status_wanted));
|
||||
} else {
|
||||
if (GPR_UNLIKELY(backlog_.write_wanted != nullptr)) {
|
||||
writer->Write(backlog_.write_wanted,
|
||||
std::move(backlog_.write_options_wanted));
|
||||
}
|
||||
if (GPR_UNLIKELY(backlog_.finish_wanted)) {
|
||||
writer->Finish(std::move(backlog_.status_wanted));
|
||||
}
|
||||
}
|
||||
// Set writer_ last so that other functions can use it lock-free
|
||||
writer_.store(writer, std::memory_order_release);
|
||||
}
|
||||
|
||||
grpc::internal::Mutex writer_mu_;
|
||||
std::atomic<ServerCallbackWriter<Response>*> writer_{nullptr};
|
||||
struct PreBindBacklog {
|
||||
bool send_initial_metadata_wanted = false;
|
||||
bool write_and_finish_wanted = false;
|
||||
bool finish_wanted = false;
|
||||
const Response* write_wanted = nullptr;
|
||||
grpc::WriteOptions write_options_wanted;
|
||||
grpc::Status status_wanted;
|
||||
};
|
||||
PreBindBacklog backlog_ ABSL_GUARDED_BY(writer_mu_);
|
||||
};
|
||||
|
||||
class ServerUnaryReactor : public internal::ServerReactor {
|
||||
public:
|
||||
ServerUnaryReactor() : call_(nullptr) {}
|
||||
~ServerUnaryReactor() override = default;
|
||||
|
||||
/// StartSendInitialMetadata is exactly like ServerBidiReactor.
|
||||
void StartSendInitialMetadata() ABSL_LOCKS_EXCLUDED(call_mu_) {
|
||||
ServerCallbackUnary* call = call_.load(std::memory_order_acquire);
|
||||
if (call == nullptr) {
|
||||
grpc::internal::MutexLock l(&call_mu_);
|
||||
call = call_.load(std::memory_order_relaxed);
|
||||
if (call == nullptr) {
|
||||
backlog_.send_initial_metadata_wanted = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
call->SendInitialMetadata();
|
||||
}
|
||||
/// Finish is similar to ServerBidiReactor except for one detail.
|
||||
/// If the status is non-OK, any message will not be sent. Instead,
|
||||
/// the client will only receive the status and any trailing metadata.
|
||||
void Finish(grpc::Status s) ABSL_LOCKS_EXCLUDED(call_mu_) {
|
||||
ServerCallbackUnary* call = call_.load(std::memory_order_acquire);
|
||||
if (call == nullptr) {
|
||||
grpc::internal::MutexLock l(&call_mu_);
|
||||
call = call_.load(std::memory_order_relaxed);
|
||||
if (call == nullptr) {
|
||||
backlog_.finish_wanted = true;
|
||||
backlog_.status_wanted = std::move(s);
|
||||
return;
|
||||
}
|
||||
}
|
||||
call->Finish(std::move(s));
|
||||
}
|
||||
|
||||
/// The following notifications are exactly like ServerBidiReactor.
|
||||
virtual void OnSendInitialMetadataDone(bool /*ok*/) {}
|
||||
void OnDone() override = 0;
|
||||
void OnCancel() override {}
|
||||
|
||||
private:
|
||||
friend class ServerCallbackUnary;
|
||||
// May be overridden by internal implementation details. This is not a public
|
||||
// customization point.
|
||||
virtual void InternalBindCall(ServerCallbackUnary* call)
|
||||
ABSL_LOCKS_EXCLUDED(call_mu_) {
|
||||
grpc::internal::MutexLock l(&call_mu_);
|
||||
|
||||
if (GPR_UNLIKELY(backlog_.send_initial_metadata_wanted)) {
|
||||
call->SendInitialMetadata();
|
||||
}
|
||||
if (GPR_UNLIKELY(backlog_.finish_wanted)) {
|
||||
call->Finish(std::move(backlog_.status_wanted));
|
||||
}
|
||||
// Set call_ last so that other functions can use it lock-free
|
||||
call_.store(call, std::memory_order_release);
|
||||
}
|
||||
|
||||
grpc::internal::Mutex call_mu_;
|
||||
std::atomic<ServerCallbackUnary*> call_{nullptr};
|
||||
struct PreBindBacklog {
|
||||
bool send_initial_metadata_wanted = false;
|
||||
bool finish_wanted = false;
|
||||
grpc::Status status_wanted;
|
||||
};
|
||||
PreBindBacklog backlog_ ABSL_GUARDED_BY(call_mu_);
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
|
||||
template <class Base>
|
||||
class FinishOnlyReactor : public Base {
|
||||
public:
|
||||
explicit FinishOnlyReactor(grpc::Status s) { this->Finish(std::move(s)); }
|
||||
void OnDone() override { this->~FinishOnlyReactor(); }
|
||||
};
|
||||
|
||||
using UnimplementedUnaryReactor = FinishOnlyReactor<ServerUnaryReactor>;
|
||||
template <class Request>
|
||||
using UnimplementedReadReactor = FinishOnlyReactor<ServerReadReactor<Request>>;
|
||||
template <class Response>
|
||||
using UnimplementedWriteReactor =
|
||||
FinishOnlyReactor<ServerWriteReactor<Response>>;
|
||||
template <class Request, class Response>
|
||||
using UnimplementedBidiReactor =
|
||||
FinishOnlyReactor<ServerBidiReactor<Request, Response>>;
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// TODO(vjpai): Remove namespace experimental when last known users are migrated
|
||||
// off.
|
||||
namespace experimental {
|
||||
|
||||
template <class Request, class Response>
|
||||
using ServerBidiReactor = ::grpc::ServerBidiReactor<Request, Response>;
|
||||
|
||||
} // namespace experimental
|
||||
|
||||
} // namespace grpc
|
||||
|
||||
#endif // GRPCPP_SUPPORT_SERVER_CALLBACK_H
|
||||
140
Pods/gRPC-C++/include/grpcpp/support/server_interceptor.h
generated
Normal file
140
Pods/gRPC-C++/include/grpcpp/support/server_interceptor.h
generated
Normal file
@@ -0,0 +1,140 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2015 gRPC 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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef GRPCPP_SUPPORT_SERVER_INTERCEPTOR_H
|
||||
#define GRPCPP_SUPPORT_SERVER_INTERCEPTOR_H
|
||||
|
||||
#include <atomic>
|
||||
#include <vector>
|
||||
|
||||
#include <grpc/support/log.h>
|
||||
#include <grpcpp/impl/rpc_method.h>
|
||||
#include <grpcpp/support/interceptor.h>
|
||||
#include <grpcpp/support/string_ref.h>
|
||||
|
||||
namespace grpc {
|
||||
class ServerContextBase;
|
||||
namespace internal {
|
||||
class InterceptorBatchMethodsImpl;
|
||||
}
|
||||
|
||||
namespace experimental {
|
||||
class ServerRpcInfo;
|
||||
|
||||
// A factory interface for creation of server interceptors. A vector of
|
||||
// factories can be provided to ServerBuilder which will be used to create a new
|
||||
// vector of server interceptors per RPC. Server interceptor authors should
|
||||
// create a subclass of ServerInterceptorFactorInterface which creates objects
|
||||
// of their interceptors.
|
||||
class ServerInterceptorFactoryInterface {
|
||||
public:
|
||||
virtual ~ServerInterceptorFactoryInterface() {}
|
||||
// Returns a pointer to an Interceptor object on successful creation, nullptr
|
||||
// otherwise. If nullptr is returned, this server interceptor factory is
|
||||
// ignored for the purposes of that RPC.
|
||||
virtual Interceptor* CreateServerInterceptor(ServerRpcInfo* info) = 0;
|
||||
};
|
||||
|
||||
/// ServerRpcInfo represents the state of a particular RPC as it
|
||||
/// appears to an interceptor. It is created and owned by the library and
|
||||
/// passed to the CreateServerInterceptor method of the application's
|
||||
/// ServerInterceptorFactoryInterface implementation
|
||||
class ServerRpcInfo {
|
||||
public:
|
||||
/// Type categorizes RPCs by unary or streaming type
|
||||
enum class Type { UNARY, CLIENT_STREAMING, SERVER_STREAMING, BIDI_STREAMING };
|
||||
|
||||
~ServerRpcInfo() {}
|
||||
|
||||
// Delete all copy and move constructors and assignments
|
||||
ServerRpcInfo(const ServerRpcInfo&) = delete;
|
||||
ServerRpcInfo& operator=(const ServerRpcInfo&) = delete;
|
||||
ServerRpcInfo(ServerRpcInfo&&) = delete;
|
||||
ServerRpcInfo& operator=(ServerRpcInfo&&) = delete;
|
||||
|
||||
// Getter methods
|
||||
|
||||
/// Return the fully-specified method name
|
||||
const char* method() const { return method_; }
|
||||
|
||||
/// Return the type of the RPC (unary or a streaming flavor)
|
||||
Type type() const { return type_; }
|
||||
|
||||
/// Return a pointer to the underlying ServerContext structure associated
|
||||
/// with the RPC to support features that apply to it
|
||||
ServerContextBase* server_context() { return ctx_; }
|
||||
|
||||
private:
|
||||
static_assert(Type::UNARY ==
|
||||
static_cast<Type>(internal::RpcMethod::NORMAL_RPC),
|
||||
"violated expectation about Type enum");
|
||||
static_assert(Type::CLIENT_STREAMING ==
|
||||
static_cast<Type>(internal::RpcMethod::CLIENT_STREAMING),
|
||||
"violated expectation about Type enum");
|
||||
static_assert(Type::SERVER_STREAMING ==
|
||||
static_cast<Type>(internal::RpcMethod::SERVER_STREAMING),
|
||||
"violated expectation about Type enum");
|
||||
static_assert(Type::BIDI_STREAMING ==
|
||||
static_cast<Type>(internal::RpcMethod::BIDI_STREAMING),
|
||||
"violated expectation about Type enum");
|
||||
|
||||
ServerRpcInfo(ServerContextBase* ctx, const char* method,
|
||||
internal::RpcMethod::RpcType type)
|
||||
: ctx_(ctx), method_(method), type_(static_cast<Type>(type)) {}
|
||||
|
||||
// Runs interceptor at pos \a pos.
|
||||
void RunInterceptor(
|
||||
experimental::InterceptorBatchMethods* interceptor_methods, size_t pos) {
|
||||
GPR_ASSERT(pos < interceptors_.size());
|
||||
interceptors_[pos]->Intercept(interceptor_methods);
|
||||
}
|
||||
|
||||
void RegisterInterceptors(
|
||||
const std::vector<
|
||||
std::unique_ptr<experimental::ServerInterceptorFactoryInterface>>&
|
||||
creators) {
|
||||
for (const auto& creator : creators) {
|
||||
auto* interceptor = creator->CreateServerInterceptor(this);
|
||||
if (interceptor != nullptr) {
|
||||
interceptors_.push_back(
|
||||
std::unique_ptr<experimental::Interceptor>(interceptor));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Ref() { ref_.fetch_add(1, std::memory_order_relaxed); }
|
||||
void Unref() {
|
||||
if (GPR_UNLIKELY(ref_.fetch_sub(1, std::memory_order_acq_rel) == 1)) {
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
ServerContextBase* ctx_ = nullptr;
|
||||
const char* method_ = nullptr;
|
||||
const Type type_;
|
||||
std::atomic<intptr_t> ref_{1};
|
||||
std::vector<std::unique_ptr<experimental::Interceptor>> interceptors_;
|
||||
|
||||
friend class internal::InterceptorBatchMethodsImpl;
|
||||
friend class grpc::ServerContextBase;
|
||||
};
|
||||
|
||||
} // namespace experimental
|
||||
} // namespace grpc
|
||||
|
||||
#endif // GRPCPP_SUPPORT_SERVER_INTERCEPTOR_H
|
||||
142
Pods/gRPC-C++/include/grpcpp/support/slice.h
generated
Normal file
142
Pods/gRPC-C++/include/grpcpp/support/slice.h
generated
Normal file
@@ -0,0 +1,142 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2015 gRPC 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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef GRPCPP_SUPPORT_SLICE_H
|
||||
#define GRPCPP_SUPPORT_SLICE_H
|
||||
|
||||
#include <grpc/slice.h>
|
||||
#include <grpcpp/support/config.h>
|
||||
#include <grpcpp/support/string_ref.h>
|
||||
|
||||
namespace grpc {
|
||||
|
||||
/// A wrapper around \a grpc_slice.
|
||||
///
|
||||
/// A slice represents a contiguous reference counted array of bytes.
|
||||
/// It is cheap to take references to a slice, and it is cheap to create a
|
||||
/// slice pointing to a subset of another slice.
|
||||
class Slice final {
|
||||
public:
|
||||
/// Construct an empty slice.
|
||||
Slice() : slice_(grpc_empty_slice()) {}
|
||||
/// Destructor - drops one reference.
|
||||
~Slice() { grpc_slice_unref(slice_); }
|
||||
|
||||
enum AddRef { ADD_REF };
|
||||
/// Construct a slice from \a slice, adding a reference.
|
||||
Slice(grpc_slice slice, AddRef) : slice_(grpc_slice_ref(slice)) {}
|
||||
|
||||
enum StealRef { STEAL_REF };
|
||||
/// Construct a slice from \a slice, stealing a reference.
|
||||
Slice(grpc_slice slice, StealRef) : slice_(slice) {}
|
||||
|
||||
/// Allocate a slice of specified size
|
||||
explicit Slice(size_t len) : slice_(grpc_slice_malloc(len)) {}
|
||||
|
||||
/// Construct a slice from a copied buffer
|
||||
Slice(const void* buf, size_t len)
|
||||
: slice_(grpc_slice_from_copied_buffer(reinterpret_cast<const char*>(buf),
|
||||
len)) {}
|
||||
|
||||
/// Construct a slice from a copied string
|
||||
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||
Slice(const std::string& str)
|
||||
: slice_(grpc_slice_from_copied_buffer(str.c_str(), str.length())) {}
|
||||
|
||||
enum StaticSlice { STATIC_SLICE };
|
||||
|
||||
/// Construct a slice from a static buffer
|
||||
Slice(const void* buf, size_t len, StaticSlice)
|
||||
: slice_(grpc_slice_from_static_buffer(reinterpret_cast<const char*>(buf),
|
||||
len)) {}
|
||||
|
||||
/// Copy constructor, adds a reference.
|
||||
Slice(const Slice& other) : slice_(grpc_slice_ref(other.slice_)) {}
|
||||
|
||||
/// Move constructor, steals a reference.
|
||||
Slice(Slice&& other) noexcept : slice_(other.slice_) {
|
||||
other.slice_ = grpc_empty_slice();
|
||||
}
|
||||
|
||||
/// Assignment, reference count is unchanged.
|
||||
Slice& operator=(Slice other) {
|
||||
std::swap(slice_, other.slice_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Create a slice pointing at some data. Calls malloc to allocate a refcount
|
||||
/// for the object, and arranges that destroy will be called with the
|
||||
/// user data pointer passed in at destruction. Can be the same as buf or
|
||||
/// different (e.g., if data is part of a larger structure that must be
|
||||
/// destroyed when the data is no longer needed)
|
||||
Slice(void* buf, size_t len, void (*destroy)(void*), void* user_data)
|
||||
: slice_(grpc_slice_new_with_user_data(buf, len, destroy, user_data)) {}
|
||||
|
||||
/// Specialization of above for common case where buf == user_data
|
||||
Slice(void* buf, size_t len, void (*destroy)(void*))
|
||||
: Slice(buf, len, destroy, buf) {}
|
||||
|
||||
/// Similar to the above but has a destroy that also takes slice length
|
||||
Slice(void* buf, size_t len, void (*destroy)(void*, size_t))
|
||||
: slice_(grpc_slice_new_with_len(buf, len, destroy)) {}
|
||||
|
||||
/// Byte size.
|
||||
size_t size() const { return GRPC_SLICE_LENGTH(slice_); }
|
||||
|
||||
/// Raw pointer to the beginning (first element) of the slice.
|
||||
const uint8_t* begin() const { return GRPC_SLICE_START_PTR(slice_); }
|
||||
|
||||
/// Raw pointer to the end (one byte \em past the last element) of the slice.
|
||||
const uint8_t* end() const { return GRPC_SLICE_END_PTR(slice_); }
|
||||
|
||||
/// Returns a substring of the `slice` as another slice.
|
||||
Slice sub(size_t begin, size_t end) const {
|
||||
return Slice(grpc_slice_sub(slice_, begin, end), STEAL_REF);
|
||||
}
|
||||
|
||||
/// Raw C slice. Caller needs to call grpc_slice_unref when done.
|
||||
grpc_slice c_slice() const { return grpc_slice_ref(slice_); }
|
||||
|
||||
private:
|
||||
friend class ByteBuffer;
|
||||
|
||||
grpc_slice slice_;
|
||||
};
|
||||
|
||||
inline grpc::string_ref StringRefFromSlice(const grpc_slice* slice) {
|
||||
return grpc::string_ref(
|
||||
reinterpret_cast<const char*>(GRPC_SLICE_START_PTR(*slice)),
|
||||
GRPC_SLICE_LENGTH(*slice));
|
||||
}
|
||||
|
||||
inline std::string StringFromCopiedSlice(grpc_slice slice) {
|
||||
return std::string(reinterpret_cast<char*>(GRPC_SLICE_START_PTR(slice)),
|
||||
GRPC_SLICE_LENGTH(slice));
|
||||
}
|
||||
|
||||
inline grpc_slice SliceReferencingString(const std::string& str) {
|
||||
return grpc_slice_from_static_buffer(str.data(), str.length());
|
||||
}
|
||||
|
||||
inline grpc_slice SliceFromCopiedString(const std::string& str) {
|
||||
return grpc_slice_from_copied_buffer(str.data(), str.length());
|
||||
}
|
||||
|
||||
} // namespace grpc
|
||||
|
||||
#endif // GRPCPP_SUPPORT_SLICE_H
|
||||
24
Pods/gRPC-C++/include/grpcpp/support/status.h
generated
Normal file
24
Pods/gRPC-C++/include/grpcpp/support/status.h
generated
Normal file
@@ -0,0 +1,24 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2015 gRPC 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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef GRPCPP_SUPPORT_STATUS_H
|
||||
#define GRPCPP_SUPPORT_STATUS_H
|
||||
|
||||
#include <grpcpp/impl/status.h> // IWYU pragma: export
|
||||
|
||||
#endif // GRPCPP_SUPPORT_STATUS_H
|
||||
145
Pods/gRPC-C++/include/grpcpp/support/status_code_enum.h
generated
Normal file
145
Pods/gRPC-C++/include/grpcpp/support/status_code_enum.h
generated
Normal file
@@ -0,0 +1,145 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2015 gRPC 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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef GRPCPP_SUPPORT_STATUS_CODE_ENUM_H
|
||||
#define GRPCPP_SUPPORT_STATUS_CODE_ENUM_H
|
||||
|
||||
// IWYU pragma: private, include <grpcpp/support/status.h>
|
||||
|
||||
namespace grpc {
|
||||
|
||||
enum StatusCode {
|
||||
/// Not an error; returned on success.
|
||||
OK = 0,
|
||||
|
||||
/// The operation was cancelled (typically by the caller).
|
||||
CANCELLED = 1,
|
||||
|
||||
/// Unknown error. An example of where this error may be returned is if a
|
||||
/// Status value received from another address space belongs to an error-space
|
||||
/// that is not known in this address space. Also errors raised by APIs that
|
||||
/// do not return enough error information may be converted to this error.
|
||||
UNKNOWN = 2,
|
||||
|
||||
/// Client specified an invalid argument. Note that this differs from
|
||||
/// FAILED_PRECONDITION. INVALID_ARGUMENT indicates arguments that are
|
||||
/// problematic regardless of the state of the system (e.g., a malformed file
|
||||
/// name).
|
||||
INVALID_ARGUMENT = 3,
|
||||
|
||||
/// Deadline expired before operation could complete. For operations that
|
||||
/// change the state of the system, this error may be returned even if the
|
||||
/// operation has completed successfully. For example, a successful response
|
||||
/// from a server could have been delayed long enough for the deadline to
|
||||
/// expire.
|
||||
DEADLINE_EXCEEDED = 4,
|
||||
|
||||
/// Some requested entity (e.g., file or directory) was not found.
|
||||
NOT_FOUND = 5,
|
||||
|
||||
/// Some entity that we attempted to create (e.g., file or directory) already
|
||||
/// exists.
|
||||
ALREADY_EXISTS = 6,
|
||||
|
||||
/// The caller does not have permission to execute the specified operation.
|
||||
/// PERMISSION_DENIED must not be used for rejections caused by exhausting
|
||||
/// some resource (use RESOURCE_EXHAUSTED instead for those errors).
|
||||
/// PERMISSION_DENIED must not be used if the caller can not be identified
|
||||
/// (use UNAUTHENTICATED instead for those errors).
|
||||
PERMISSION_DENIED = 7,
|
||||
|
||||
/// The request does not have valid authentication credentials for the
|
||||
/// operation.
|
||||
UNAUTHENTICATED = 16,
|
||||
|
||||
/// Some resource has been exhausted, perhaps a per-user quota, or perhaps the
|
||||
/// entire file system is out of space.
|
||||
RESOURCE_EXHAUSTED = 8,
|
||||
|
||||
/// Operation was rejected because the system is not in a state required for
|
||||
/// the operation's execution. For example, directory to be deleted may be
|
||||
/// non-empty, an rmdir operation is applied to a non-directory, etc.
|
||||
///
|
||||
/// A litmus test that may help a service implementor in deciding
|
||||
/// between FAILED_PRECONDITION, ABORTED, and UNAVAILABLE:
|
||||
/// (a) Use UNAVAILABLE if the client can retry just the failing call.
|
||||
/// (b) Use ABORTED if the client should retry at a higher-level
|
||||
/// (e.g., restarting a read-modify-write sequence).
|
||||
/// (c) Use FAILED_PRECONDITION if the client should not retry until
|
||||
/// the system state has been explicitly fixed. E.g., if an "rmdir"
|
||||
/// fails because the directory is non-empty, FAILED_PRECONDITION
|
||||
/// should be returned since the client should not retry unless
|
||||
/// they have first fixed up the directory by deleting files from it.
|
||||
/// (d) Use FAILED_PRECONDITION if the client performs conditional
|
||||
/// REST Get/Update/Delete on a resource and the resource on the
|
||||
/// server does not match the condition. E.g., conflicting
|
||||
/// read-modify-write on the same resource.
|
||||
FAILED_PRECONDITION = 9,
|
||||
|
||||
/// The operation was aborted, typically due to a concurrency issue like
|
||||
/// sequencer check failures, transaction aborts, etc.
|
||||
///
|
||||
/// See litmus test above for deciding between FAILED_PRECONDITION, ABORTED,
|
||||
/// and UNAVAILABLE.
|
||||
ABORTED = 10,
|
||||
|
||||
/// Operation was attempted past the valid range. E.g., seeking or reading
|
||||
/// past end of file.
|
||||
///
|
||||
/// Unlike INVALID_ARGUMENT, this error indicates a problem that may be fixed
|
||||
/// if the system state changes. For example, a 32-bit file system will
|
||||
/// generate INVALID_ARGUMENT if asked to read at an offset that is not in the
|
||||
/// range [0,2^32-1], but it will generate OUT_OF_RANGE if asked to read from
|
||||
/// an offset past the current file size.
|
||||
///
|
||||
/// There is a fair bit of overlap between FAILED_PRECONDITION and
|
||||
/// OUT_OF_RANGE. We recommend using OUT_OF_RANGE (the more specific error)
|
||||
/// when it applies so that callers who are iterating through a space can
|
||||
/// easily look for an OUT_OF_RANGE error to detect when they are done.
|
||||
OUT_OF_RANGE = 11,
|
||||
|
||||
/// Operation is not implemented or not supported/enabled in this service.
|
||||
UNIMPLEMENTED = 12,
|
||||
|
||||
/// Internal errors. Means some invariants expected by underlying System has
|
||||
/// been broken. If you see one of these errors, Something is very broken.
|
||||
INTERNAL = 13,
|
||||
|
||||
/// The service is currently unavailable. This is a most likely a transient
|
||||
/// condition and may be corrected by retrying with a backoff. Note that it is
|
||||
/// not always safe to retry non-idempotent operations.
|
||||
///
|
||||
/// \warning Although data MIGHT not have been transmitted when this
|
||||
/// status occurs, there is NOT A GUARANTEE that the server has not seen
|
||||
/// anything. So in general it is unsafe to retry on this status code
|
||||
/// if the call is non-idempotent.
|
||||
///
|
||||
/// See litmus test above for deciding between FAILED_PRECONDITION, ABORTED,
|
||||
/// and UNAVAILABLE.
|
||||
UNAVAILABLE = 14,
|
||||
|
||||
/// Unrecoverable data loss or corruption.
|
||||
DATA_LOSS = 15,
|
||||
|
||||
/// Force users to include a default branch:
|
||||
DO_NOT_USE = -1
|
||||
};
|
||||
|
||||
} // namespace grpc
|
||||
|
||||
#endif // GRPCPP_SUPPORT_STATUS_CODE_ENUM_H
|
||||
149
Pods/gRPC-C++/include/grpcpp/support/string_ref.h
generated
Normal file
149
Pods/gRPC-C++/include/grpcpp/support/string_ref.h
generated
Normal file
@@ -0,0 +1,149 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2015 gRPC 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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef GRPCPP_SUPPORT_STRING_REF_H
|
||||
#define GRPCPP_SUPPORT_STRING_REF_H
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iosfwd>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
|
||||
#include <grpcpp/support/config.h>
|
||||
|
||||
namespace grpc {
|
||||
|
||||
/// This class is a non owning reference to a string.
|
||||
///
|
||||
/// It should be a strict subset of the upcoming std::string_ref.
|
||||
///
|
||||
/// \see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3442.html
|
||||
///
|
||||
/// The constexpr is dropped or replaced with const for legacy compiler
|
||||
/// compatibility.
|
||||
class string_ref {
|
||||
public:
|
||||
/// types
|
||||
typedef const char* const_iterator;
|
||||
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
|
||||
|
||||
/// constants
|
||||
const static size_t npos;
|
||||
|
||||
/// construct/copy.
|
||||
string_ref() : data_(nullptr), length_(0) {}
|
||||
string_ref(const string_ref& other)
|
||||
: data_(other.data_), length_(other.length_) {}
|
||||
// NOLINTNEXTLINE(bugprone-unhandled-self-assignment)
|
||||
string_ref& operator=(const string_ref& rhs) {
|
||||
data_ = rhs.data_;
|
||||
length_ = rhs.length_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||
string_ref(const char* s) : data_(s), length_(strlen(s)) {}
|
||||
string_ref(const char* s, size_t l) : data_(s), length_(l) {}
|
||||
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||
string_ref(const std::string& s) : data_(s.data()), length_(s.length()) {}
|
||||
|
||||
/// iterators
|
||||
const_iterator begin() const { return data_; }
|
||||
const_iterator end() const { return data_ + length_; }
|
||||
const_iterator cbegin() const { return data_; }
|
||||
const_iterator cend() const { return data_ + length_; }
|
||||
const_reverse_iterator rbegin() const {
|
||||
return const_reverse_iterator(end());
|
||||
}
|
||||
const_reverse_iterator rend() const {
|
||||
return const_reverse_iterator(begin());
|
||||
}
|
||||
const_reverse_iterator crbegin() const {
|
||||
return const_reverse_iterator(end());
|
||||
}
|
||||
const_reverse_iterator crend() const {
|
||||
return const_reverse_iterator(begin());
|
||||
}
|
||||
|
||||
/// capacity
|
||||
size_t size() const { return length_; }
|
||||
size_t length() const { return length_; }
|
||||
size_t max_size() const { return length_; }
|
||||
bool empty() const { return length_ == 0; }
|
||||
|
||||
/// element access
|
||||
const char* data() const { return data_; }
|
||||
|
||||
/// string operations
|
||||
int compare(string_ref x) const {
|
||||
size_t min_size = length_ < x.length_ ? length_ : x.length_;
|
||||
int r = memcmp(data_, x.data_, min_size);
|
||||
if (r < 0) return -1;
|
||||
if (r > 0) return 1;
|
||||
if (length_ < x.length_) return -1;
|
||||
if (length_ > x.length_) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool starts_with(string_ref x) const {
|
||||
return length_ >= x.length_ && (memcmp(data_, x.data_, x.length_) == 0);
|
||||
}
|
||||
|
||||
bool ends_with(string_ref x) const {
|
||||
return length_ >= x.length_ &&
|
||||
(memcmp(data_ + (length_ - x.length_), x.data_, x.length_) == 0);
|
||||
}
|
||||
|
||||
size_t find(string_ref s) const {
|
||||
auto it = std::search(cbegin(), cend(), s.cbegin(), s.cend());
|
||||
return it == cend() ? npos : std::distance(cbegin(), it);
|
||||
}
|
||||
|
||||
size_t find(char c) const {
|
||||
auto it = std::find(cbegin(), cend(), c);
|
||||
return it == cend() ? npos : std::distance(cbegin(), it);
|
||||
}
|
||||
|
||||
string_ref substr(size_t pos, size_t n = npos) const {
|
||||
if (pos > length_) pos = length_;
|
||||
if (n > (length_ - pos)) n = length_ - pos;
|
||||
return string_ref(data_ + pos, n);
|
||||
}
|
||||
|
||||
private:
|
||||
const char* data_;
|
||||
size_t length_;
|
||||
};
|
||||
|
||||
/// Comparison operators
|
||||
inline bool operator==(string_ref x, string_ref y) { return x.compare(y) == 0; }
|
||||
inline bool operator!=(string_ref x, string_ref y) { return x.compare(y) != 0; }
|
||||
inline bool operator<(string_ref x, string_ref y) { return x.compare(y) < 0; }
|
||||
inline bool operator<=(string_ref x, string_ref y) { return x.compare(y) <= 0; }
|
||||
inline bool operator>(string_ref x, string_ref y) { return x.compare(y) > 0; }
|
||||
inline bool operator>=(string_ref x, string_ref y) { return x.compare(y) >= 0; }
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& out, const string_ref& string) {
|
||||
return out << std::string(string.begin(), string.end());
|
||||
}
|
||||
|
||||
} // namespace grpc
|
||||
|
||||
#endif // GRPCPP_SUPPORT_STRING_REF_H
|
||||
42
Pods/gRPC-C++/include/grpcpp/support/stub_options.h
generated
Normal file
42
Pods/gRPC-C++/include/grpcpp/support/stub_options.h
generated
Normal file
@@ -0,0 +1,42 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2015 gRPC 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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef GRPCPP_SUPPORT_STUB_OPTIONS_H
|
||||
#define GRPCPP_SUPPORT_STUB_OPTIONS_H
|
||||
|
||||
namespace grpc {
|
||||
|
||||
/// Useful interface for generated stubs
|
||||
class StubOptions {
|
||||
public:
|
||||
StubOptions() = default;
|
||||
explicit StubOptions(const char* suffix_for_stats)
|
||||
: suffix_for_stats_(suffix_for_stats) {}
|
||||
|
||||
void set_suffix_for_stats(const char* suffix_for_stats) {
|
||||
suffix_for_stats_ = suffix_for_stats;
|
||||
}
|
||||
const char* suffix_for_stats() const { return suffix_for_stats_; }
|
||||
|
||||
private:
|
||||
const char* suffix_for_stats_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace grpc
|
||||
|
||||
#endif // GRPCPP_SUPPORT_STUB_OPTIONS_H
|
||||
949
Pods/gRPC-C++/include/grpcpp/support/sync_stream.h
generated
Normal file
949
Pods/gRPC-C++/include/grpcpp/support/sync_stream.h
generated
Normal file
@@ -0,0 +1,949 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2015 gRPC 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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef GRPCPP_SUPPORT_SYNC_STREAM_H
|
||||
#define GRPCPP_SUPPORT_SYNC_STREAM_H
|
||||
|
||||
#include <grpc/support/log.h>
|
||||
#include <grpcpp/client_context.h>
|
||||
#include <grpcpp/completion_queue.h>
|
||||
#include <grpcpp/impl/call.h>
|
||||
#include <grpcpp/impl/codegen/channel_interface.h>
|
||||
#include <grpcpp/impl/service_type.h>
|
||||
#include <grpcpp/server_context.h>
|
||||
#include <grpcpp/support/status.h>
|
||||
|
||||
namespace grpc {
|
||||
|
||||
namespace internal {
|
||||
/// Common interface for all synchronous client side streaming.
|
||||
class ClientStreamingInterface {
|
||||
public:
|
||||
virtual ~ClientStreamingInterface() {}
|
||||
|
||||
/// Block waiting until the stream finishes and a final status of the call is
|
||||
/// available.
|
||||
///
|
||||
/// It is appropriate to call this method exactly once when both:
|
||||
/// * the calling code (client-side) has no more message to send
|
||||
/// (this can be declared implicitly by calling this method, or
|
||||
/// explicitly through an earlier call to <i>WritesDone</i> method of the
|
||||
/// class in use, e.g. \a ClientWriterInterface::WritesDone or
|
||||
/// \a ClientReaderWriterInterface::WritesDone).
|
||||
/// * there are no more messages to be received from the server (which can
|
||||
/// be known implicitly, or explicitly from an earlier call to \a
|
||||
/// ReaderInterface::Read that returned "false").
|
||||
///
|
||||
/// This function will return either:
|
||||
/// - when all incoming messages have been read and the server has
|
||||
/// returned status.
|
||||
/// - when the server has returned a non-OK status.
|
||||
/// - OR when the call failed for some reason and the library generated a
|
||||
/// status.
|
||||
///
|
||||
/// Return values:
|
||||
/// - \a Status contains the status code, message and details for the call
|
||||
/// - the \a ClientContext associated with this call is updated with
|
||||
/// possible trailing metadata sent from the server.
|
||||
virtual grpc::Status Finish() = 0;
|
||||
};
|
||||
|
||||
/// Common interface for all synchronous server side streaming.
|
||||
class ServerStreamingInterface {
|
||||
public:
|
||||
virtual ~ServerStreamingInterface() {}
|
||||
|
||||
/// Block to send initial metadata to client.
|
||||
/// This call is optional, but if it is used, it cannot be used concurrently
|
||||
/// with or after the \a Finish method.
|
||||
///
|
||||
/// The initial metadata that will be sent to the client will be
|
||||
/// taken from the \a ServerContext associated with the call.
|
||||
virtual void SendInitialMetadata() = 0;
|
||||
};
|
||||
|
||||
/// An interface that yields a sequence of messages of type \a R.
|
||||
template <class R>
|
||||
class ReaderInterface {
|
||||
public:
|
||||
virtual ~ReaderInterface() {}
|
||||
|
||||
/// Get an upper bound on the next message size available for reading on this
|
||||
/// stream.
|
||||
virtual bool NextMessageSize(uint32_t* sz) = 0;
|
||||
|
||||
/// Block to read a message and parse to \a msg. Returns \a true on success.
|
||||
/// This is thread-safe with respect to \a Write or \WritesDone methods on
|
||||
/// the same stream. It should not be called concurrently with another \a
|
||||
/// Read on the same stream as the order of delivery will not be defined.
|
||||
///
|
||||
/// \param[out] msg The read message.
|
||||
///
|
||||
/// \return \a false when there will be no more incoming messages, either
|
||||
/// because the other side has called \a WritesDone() or the stream has failed
|
||||
/// (or been cancelled).
|
||||
virtual bool Read(R* msg) = 0;
|
||||
};
|
||||
|
||||
/// An interface that can be fed a sequence of messages of type \a W.
|
||||
template <class W>
|
||||
class WriterInterface {
|
||||
public:
|
||||
virtual ~WriterInterface() {}
|
||||
|
||||
/// Block to write \a msg to the stream with WriteOptions \a options.
|
||||
/// This is thread-safe with respect to \a ReaderInterface::Read
|
||||
///
|
||||
/// \param msg The message to be written to the stream.
|
||||
/// \param options The WriteOptions affecting the write operation.
|
||||
///
|
||||
/// \return \a true on success, \a false when the stream has been closed.
|
||||
virtual bool Write(const W& msg, grpc::WriteOptions options) = 0;
|
||||
|
||||
/// Block to write \a msg to the stream with default write options.
|
||||
/// This is thread-safe with respect to \a ReaderInterface::Read
|
||||
///
|
||||
/// \param msg The message to be written to the stream.
|
||||
///
|
||||
/// \return \a true on success, \a false when the stream has been closed.
|
||||
inline bool Write(const W& msg) { return Write(msg, grpc::WriteOptions()); }
|
||||
|
||||
/// Write \a msg and coalesce it with the writing of trailing metadata, using
|
||||
/// WriteOptions \a options.
|
||||
///
|
||||
/// For client, WriteLast is equivalent of performing Write and WritesDone in
|
||||
/// a single step. \a msg and trailing metadata are coalesced and sent on wire
|
||||
/// by calling this function. For server, WriteLast buffers the \a msg.
|
||||
/// The writing of \a msg is held until the service handler returns,
|
||||
/// where \a msg and trailing metadata are coalesced and sent on wire.
|
||||
/// Note that WriteLast can only buffer \a msg up to the flow control window
|
||||
/// size. If \a msg size is larger than the window size, it will be sent on
|
||||
/// wire without buffering.
|
||||
///
|
||||
/// \param[in] msg The message to be written to the stream.
|
||||
/// \param[in] options The WriteOptions to be used to write this message.
|
||||
void WriteLast(const W& msg, grpc::WriteOptions options) {
|
||||
Write(msg, options.set_last_message());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/// Client-side interface for streaming reads of message of type \a R.
|
||||
template <class 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
|
||||
/// the first read. Calling this method is optional, and if it is not called
|
||||
/// the metadata will be available in ClientContext after the first read.
|
||||
virtual void WaitForInitialMetadata() = 0;
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
template <class R>
|
||||
class ClientReaderFactory {
|
||||
public:
|
||||
template <class W>
|
||||
static ClientReader<R>* Create(grpc::ChannelInterface* channel,
|
||||
const grpc::internal::RpcMethod& method,
|
||||
grpc::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:
|
||||
/// See the \a ClientStreamingInterface.WaitForInitialMetadata method for
|
||||
/// semantics.
|
||||
///
|
||||
// Side effect:
|
||||
/// Once complete, the initial metadata read from
|
||||
/// the server will be accessible through the \a ClientContext used to
|
||||
/// construct this object.
|
||||
void WaitForInitialMetadata() override {
|
||||
GPR_ASSERT(!context_->initial_metadata_received_);
|
||||
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpRecvInitialMetadata> ops;
|
||||
ops.RecvInitialMetadata(context_);
|
||||
call_.PerformOps(&ops);
|
||||
cq_.Pluck(&ops); /// status ignored
|
||||
}
|
||||
|
||||
bool NextMessageSize(uint32_t* sz) override {
|
||||
int result = call_.max_receive_message_size();
|
||||
*sz = (result > 0) ? result : UINT32_MAX;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// See the \a ReaderInterface.Read method for semantics.
|
||||
/// Side effect:
|
||||
/// This also receives initial metadata from the server, if not
|
||||
/// 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 {
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpRecvInitialMetadata,
|
||||
grpc::internal::CallOpRecvMessage<R>>
|
||||
ops;
|
||||
if (!context_->initial_metadata_received_) {
|
||||
ops.RecvInitialMetadata(context_);
|
||||
}
|
||||
ops.RecvMessage(msg);
|
||||
call_.PerformOps(&ops);
|
||||
return cq_.Pluck(&ops) && ops.got_message;
|
||||
}
|
||||
|
||||
/// See the \a ClientStreamingInterface.Finish method for semantics.
|
||||
///
|
||||
/// Side effect:
|
||||
/// The \a ClientContext associated with this call is updated with
|
||||
/// possible metadata received from the server.
|
||||
grpc::Status Finish() override {
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpRecvInitialMetadata,
|
||||
grpc::internal::CallOpClientRecvStatus>
|
||||
ops;
|
||||
if (!context_->initial_metadata_received_) {
|
||||
ops.RecvInitialMetadata(context_);
|
||||
}
|
||||
grpc::Status status;
|
||||
ops.ClientRecvStatus(context_, &status);
|
||||
call_.PerformOps(&ops);
|
||||
GPR_ASSERT(cq_.Pluck(&ops));
|
||||
return status;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class internal::ClientReaderFactory<R>;
|
||||
grpc::ClientContext* context_;
|
||||
grpc::CompletionQueue cq_;
|
||||
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,
|
||||
grpc::ClientContext* context, const W& request)
|
||||
: context_(context),
|
||||
cq_(grpc_completion_queue_attributes{
|
||||
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, GRPC_CQ_DEFAULT_POLLING,
|
||||
nullptr}), // 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_ASSERT(ops.SendMessagePtr(&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 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).
|
||||
/// Blocks until currently-pending writes are completed.
|
||||
/// Thread safe with respect to \a ReaderInterface::Read operations only
|
||||
///
|
||||
/// \return Whether the writes were successful.
|
||||
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,
|
||||
grpc::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:
|
||||
/// See the \a ClientStreamingInterface.WaitForInitialMetadata method for
|
||||
/// semantics.
|
||||
///
|
||||
// Side effect:
|
||||
/// Once complete, the initial metadata read from the server will be
|
||||
/// accessible through the \a ClientContext used to construct this object.
|
||||
void WaitForInitialMetadata() {
|
||||
GPR_ASSERT(!context_->initial_metadata_received_);
|
||||
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpRecvInitialMetadata> ops;
|
||||
ops.RecvInitialMetadata(context_);
|
||||
call_.PerformOps(&ops);
|
||||
cq_.Pluck(&ops); // status ignored
|
||||
}
|
||||
|
||||
/// See the WriterInterface.Write(const W& msg, WriteOptions options) method
|
||||
/// for semantics.
|
||||
///
|
||||
/// Side effect:
|
||||
/// Also sends initial metadata if not already sent (using the
|
||||
/// \a ClientContext associated with this call).
|
||||
using internal::WriterInterface<W>::Write;
|
||||
bool Write(const W& msg, grpc::WriteOptions options) override {
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,
|
||||
grpc::internal::CallOpSendMessage,
|
||||
grpc::internal::CallOpClientSendClose>
|
||||
ops;
|
||||
|
||||
if (options.is_last_message()) {
|
||||
options.set_buffer_hint();
|
||||
ops.ClientSendClose();
|
||||
}
|
||||
if (context_->initial_metadata_corked_) {
|
||||
ops.SendInitialMetadata(&context_->send_initial_metadata_,
|
||||
context_->initial_metadata_flags());
|
||||
context_->set_initial_metadata_corked(false);
|
||||
}
|
||||
if (!ops.SendMessagePtr(&msg, options).ok()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
call_.PerformOps(&ops);
|
||||
return cq_.Pluck(&ops);
|
||||
}
|
||||
|
||||
bool WritesDone() override {
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpClientSendClose> ops;
|
||||
ops.ClientSendClose();
|
||||
call_.PerformOps(&ops);
|
||||
return cq_.Pluck(&ops);
|
||||
}
|
||||
|
||||
/// See the ClientStreamingInterface.Finish method for semantics.
|
||||
/// Side effects:
|
||||
/// - Also receives initial metadata if not already received.
|
||||
/// - Attempts to fill in the \a response parameter passed
|
||||
/// to the constructor of this instance with the response
|
||||
/// message from the server.
|
||||
grpc::Status Finish() override {
|
||||
grpc::Status status;
|
||||
if (!context_->initial_metadata_received_) {
|
||||
finish_ops_.RecvInitialMetadata(context_);
|
||||
}
|
||||
finish_ops_.ClientRecvStatus(context_, &status);
|
||||
call_.PerformOps(&finish_ops_);
|
||||
GPR_ASSERT(cq_.Pluck(&finish_ops_));
|
||||
return status;
|
||||
}
|
||||
|
||||
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(grpc::ChannelInterface* channel,
|
||||
const grpc::internal::RpcMethod& method,
|
||||
grpc::ClientContext* context, R* response)
|
||||
: context_(context),
|
||||
cq_(grpc_completion_queue_attributes{
|
||||
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, GRPC_CQ_DEFAULT_POLLING,
|
||||
nullptr}), // 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);
|
||||
}
|
||||
}
|
||||
|
||||
grpc::ClientContext* context_;
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpRecvInitialMetadata,
|
||||
grpc::internal::CallOpGenericRecvMessage,
|
||||
grpc::internal::CallOpClientRecvStatus>
|
||||
finish_ops_;
|
||||
grpc::CompletionQueue cq_;
|
||||
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 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
|
||||
/// the first read. Calling this method is optional, and if it is not called
|
||||
/// the metadata will be available in ClientContext after the first read.
|
||||
virtual void WaitForInitialMetadata() = 0;
|
||||
|
||||
/// Half close writing from the client. (signal that the stream of messages
|
||||
/// coming from the client is complete).
|
||||
/// Blocks until currently-pending writes are completed.
|
||||
/// Thread-safe with respect to \a ReaderInterface::Read
|
||||
///
|
||||
/// \return Whether the writes were successful.
|
||||
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,
|
||||
grpc::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
|
||||
/// messages of type \a R.
|
||||
template <class W, class R>
|
||||
class ClientReaderWriter final : public ClientReaderWriterInterface<W, R> {
|
||||
public:
|
||||
/// 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.
|
||||
///
|
||||
/// Once complete, the initial metadata read from the server will be
|
||||
/// accessible through the \a ClientContext used to construct this object.
|
||||
void WaitForInitialMetadata() override {
|
||||
GPR_ASSERT(!context_->initial_metadata_received_);
|
||||
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpRecvInitialMetadata> ops;
|
||||
ops.RecvInitialMetadata(context_);
|
||||
call_.PerformOps(&ops);
|
||||
cq_.Pluck(&ops); // status ignored
|
||||
}
|
||||
|
||||
bool NextMessageSize(uint32_t* sz) override {
|
||||
int result = call_.max_receive_message_size();
|
||||
*sz = (result > 0) ? result : UINT32_MAX;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// See the \a ReaderInterface.Read method for semantics.
|
||||
/// Side effect:
|
||||
/// Also receives initial metadata if not already received (updates the \a
|
||||
/// ClientContext associated with this call in that case).
|
||||
bool Read(R* msg) override {
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpRecvInitialMetadata,
|
||||
grpc::internal::CallOpRecvMessage<R>>
|
||||
ops;
|
||||
if (!context_->initial_metadata_received_) {
|
||||
ops.RecvInitialMetadata(context_);
|
||||
}
|
||||
ops.RecvMessage(msg);
|
||||
call_.PerformOps(&ops);
|
||||
return cq_.Pluck(&ops) && ops.got_message;
|
||||
}
|
||||
|
||||
/// See the \a WriterInterface.Write method for semantics.
|
||||
///
|
||||
/// Side effect:
|
||||
/// Also sends initial metadata if not already sent (using the
|
||||
/// \a ClientContext associated with this call to fill in values).
|
||||
using internal::WriterInterface<W>::Write;
|
||||
bool Write(const W& msg, grpc::WriteOptions options) override {
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,
|
||||
grpc::internal::CallOpSendMessage,
|
||||
grpc::internal::CallOpClientSendClose>
|
||||
ops;
|
||||
|
||||
if (options.is_last_message()) {
|
||||
options.set_buffer_hint();
|
||||
ops.ClientSendClose();
|
||||
}
|
||||
if (context_->initial_metadata_corked_) {
|
||||
ops.SendInitialMetadata(&context_->send_initial_metadata_,
|
||||
context_->initial_metadata_flags());
|
||||
context_->set_initial_metadata_corked(false);
|
||||
}
|
||||
if (!ops.SendMessagePtr(&msg, options).ok()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
call_.PerformOps(&ops);
|
||||
return cq_.Pluck(&ops);
|
||||
}
|
||||
|
||||
bool WritesDone() override {
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpClientSendClose> ops;
|
||||
ops.ClientSendClose();
|
||||
call_.PerformOps(&ops);
|
||||
return cq_.Pluck(&ops);
|
||||
}
|
||||
|
||||
/// See the ClientStreamingInterface.Finish method for semantics.
|
||||
///
|
||||
/// Side effect:
|
||||
/// - the \a ClientContext associated with this call is updated with
|
||||
/// possible trailing metadata sent from the server.
|
||||
grpc::Status Finish() override {
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpRecvInitialMetadata,
|
||||
grpc::internal::CallOpClientRecvStatus>
|
||||
ops;
|
||||
if (!context_->initial_metadata_received_) {
|
||||
ops.RecvInitialMetadata(context_);
|
||||
}
|
||||
grpc::Status status;
|
||||
ops.ClientRecvStatus(context_, &status);
|
||||
call_.PerformOps(&ops);
|
||||
GPR_ASSERT(cq_.Pluck(&ops));
|
||||
return status;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class internal::ClientReaderWriterFactory<W, R>;
|
||||
|
||||
grpc::ClientContext* context_;
|
||||
grpc::CompletionQueue cq_;
|
||||
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,
|
||||
grpc::ClientContext* context)
|
||||
: context_(context),
|
||||
cq_(grpc_completion_queue_attributes{
|
||||
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, GRPC_CQ_DEFAULT_POLLING,
|
||||
nullptr}), // 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 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
|
||||
/// type \a R.
|
||||
template <class R>
|
||||
class ServerReader final : public ServerReaderInterface<R> {
|
||||
public:
|
||||
/// 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_ASSERT(!ctx_->sent_initial_metadata_);
|
||||
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata> ops;
|
||||
ops.SendInitialMetadata(&ctx_->initial_metadata_,
|
||||
ctx_->initial_metadata_flags());
|
||||
if (ctx_->compression_level_set()) {
|
||||
ops.set_compression_level(ctx_->compression_level());
|
||||
}
|
||||
ctx_->sent_initial_metadata_ = true;
|
||||
call_->PerformOps(&ops);
|
||||
call_->cq()->Pluck(&ops);
|
||||
}
|
||||
|
||||
bool NextMessageSize(uint32_t* sz) override {
|
||||
int result = call_->max_receive_message_size();
|
||||
*sz = (result > 0) ? result : UINT32_MAX;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Read(R* msg) override {
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpRecvMessage<R>> ops;
|
||||
ops.RecvMessage(msg);
|
||||
call_->PerformOps(&ops);
|
||||
bool ok = call_->cq()->Pluck(&ops) && ops.got_message;
|
||||
if (!ok) {
|
||||
ctx_->MaybeMarkCancelledOnRead();
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
private:
|
||||
grpc::internal::Call* const call_;
|
||||
ServerContext* const ctx_;
|
||||
|
||||
template <class ServiceType, class RequestType, class ResponseType>
|
||||
friend class internal::ClientStreamingHandler;
|
||||
|
||||
ServerReader(grpc::internal::Call* call, grpc::ServerContext* ctx)
|
||||
: call_(call), ctx_(ctx) {}
|
||||
};
|
||||
|
||||
/// Server-side interface for streaming writes of message of type \a W.
|
||||
template <class 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
|
||||
/// server has messages of type \a W.
|
||||
template <class W>
|
||||
class ServerWriter final : public ServerWriterInterface<W> {
|
||||
public:
|
||||
/// 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_ASSERT(!ctx_->sent_initial_metadata_);
|
||||
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata> ops;
|
||||
ops.SendInitialMetadata(&ctx_->initial_metadata_,
|
||||
ctx_->initial_metadata_flags());
|
||||
if (ctx_->compression_level_set()) {
|
||||
ops.set_compression_level(ctx_->compression_level());
|
||||
}
|
||||
ctx_->sent_initial_metadata_ = true;
|
||||
call_->PerformOps(&ops);
|
||||
call_->cq()->Pluck(&ops);
|
||||
}
|
||||
|
||||
/// See the \a WriterInterface.Write method for semantics.
|
||||
///
|
||||
/// Side effect:
|
||||
/// Also sends initial metadata if not already sent (using the
|
||||
/// \a ClientContext associated with this call to fill in values).
|
||||
using internal::WriterInterface<W>::Write;
|
||||
bool Write(const W& msg, grpc::WriteOptions options) override {
|
||||
if (options.is_last_message()) {
|
||||
options.set_buffer_hint();
|
||||
}
|
||||
|
||||
if (!ctx_->pending_ops_.SendMessagePtr(&msg, options).ok()) {
|
||||
return false;
|
||||
}
|
||||
if (!ctx_->sent_initial_metadata_) {
|
||||
ctx_->pending_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
|
||||
ctx_->initial_metadata_flags());
|
||||
if (ctx_->compression_level_set()) {
|
||||
ctx_->pending_ops_.set_compression_level(ctx_->compression_level());
|
||||
}
|
||||
ctx_->sent_initial_metadata_ = true;
|
||||
}
|
||||
call_->PerformOps(&ctx_->pending_ops_);
|
||||
// if this is the last message we defer the pluck until AFTER we start
|
||||
// the trailing md op. This prevents hangs. See
|
||||
// https://github.com/grpc/grpc/issues/11546
|
||||
if (options.is_last_message()) {
|
||||
ctx_->has_pending_ops_ = true;
|
||||
return true;
|
||||
}
|
||||
ctx_->has_pending_ops_ = false;
|
||||
return call_->cq()->Pluck(&ctx_->pending_ops_);
|
||||
}
|
||||
|
||||
private:
|
||||
grpc::internal::Call* const call_;
|
||||
grpc::ServerContext* const ctx_;
|
||||
|
||||
template <class ServiceType, class RequestType, class ResponseType>
|
||||
friend class internal::ServerStreamingHandler;
|
||||
|
||||
ServerWriter(grpc::internal::Call* call, grpc::ServerContext* ctx)
|
||||
: call_(call), ctx_(ctx) {}
|
||||
};
|
||||
|
||||
/// Server-side interface for bi-directional streaming.
|
||||
template <class W, class R>
|
||||
class ServerReaderWriterInterface : public internal::ServerStreamingInterface,
|
||||
public internal::WriterInterface<W>,
|
||||
public internal::ReaderInterface<R> {};
|
||||
|
||||
/// Actual implementation of bi-directional streaming
|
||||
namespace internal {
|
||||
template <class W, class R>
|
||||
class ServerReaderWriterBody final {
|
||||
public:
|
||||
ServerReaderWriterBody(grpc::internal::Call* call, grpc::ServerContext* ctx)
|
||||
: call_(call), ctx_(ctx) {}
|
||||
|
||||
void SendInitialMetadata() {
|
||||
GPR_ASSERT(!ctx_->sent_initial_metadata_);
|
||||
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata> ops;
|
||||
ops.SendInitialMetadata(&ctx_->initial_metadata_,
|
||||
ctx_->initial_metadata_flags());
|
||||
if (ctx_->compression_level_set()) {
|
||||
ops.set_compression_level(ctx_->compression_level());
|
||||
}
|
||||
ctx_->sent_initial_metadata_ = true;
|
||||
call_->PerformOps(&ops);
|
||||
call_->cq()->Pluck(&ops);
|
||||
}
|
||||
|
||||
bool NextMessageSize(uint32_t* sz) {
|
||||
int result = call_->max_receive_message_size();
|
||||
*sz = (result > 0) ? result : UINT32_MAX;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Read(R* msg) {
|
||||
grpc::internal::CallOpSet<grpc::internal::CallOpRecvMessage<R>> ops;
|
||||
ops.RecvMessage(msg);
|
||||
call_->PerformOps(&ops);
|
||||
bool ok = call_->cq()->Pluck(&ops) && ops.got_message;
|
||||
if (!ok) {
|
||||
ctx_->MaybeMarkCancelledOnRead();
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool Write(const W& msg, grpc::WriteOptions options) {
|
||||
if (options.is_last_message()) {
|
||||
options.set_buffer_hint();
|
||||
}
|
||||
if (!ctx_->pending_ops_.SendMessagePtr(&msg, options).ok()) {
|
||||
return false;
|
||||
}
|
||||
if (!ctx_->sent_initial_metadata_) {
|
||||
ctx_->pending_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
|
||||
ctx_->initial_metadata_flags());
|
||||
if (ctx_->compression_level_set()) {
|
||||
ctx_->pending_ops_.set_compression_level(ctx_->compression_level());
|
||||
}
|
||||
ctx_->sent_initial_metadata_ = true;
|
||||
}
|
||||
call_->PerformOps(&ctx_->pending_ops_);
|
||||
// if this is the last message we defer the pluck until AFTER we start
|
||||
// the trailing md op. This prevents hangs. See
|
||||
// https://github.com/grpc/grpc/issues/11546
|
||||
if (options.is_last_message()) {
|
||||
ctx_->has_pending_ops_ = true;
|
||||
return true;
|
||||
}
|
||||
ctx_->has_pending_ops_ = false;
|
||||
return call_->cq()->Pluck(&ctx_->pending_ops_);
|
||||
}
|
||||
|
||||
private:
|
||||
grpc::internal::Call* const call_;
|
||||
grpc::ServerContext* const ctx_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/// Synchronous (blocking) server-side API for a bidirectional
|
||||
/// streaming call, where the incoming message stream coming from the client has
|
||||
/// messages of type \a R, and the outgoing message streaming coming from
|
||||
/// the server has messages of type \a W.
|
||||
template <class W, class R>
|
||||
class ServerReaderWriter final : public ServerReaderWriterInterface<W, R> {
|
||||
public:
|
||||
/// 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 { body_.SendInitialMetadata(); }
|
||||
|
||||
bool NextMessageSize(uint32_t* sz) override {
|
||||
return body_.NextMessageSize(sz);
|
||||
}
|
||||
|
||||
bool Read(R* msg) override { return body_.Read(msg); }
|
||||
|
||||
/// See the \a WriterInterface.Write(const W& msg, WriteOptions options)
|
||||
/// method for semantics.
|
||||
/// Side effect:
|
||||
/// Also sends initial metadata if not already sent (using the \a
|
||||
/// ServerContext associated with this call).
|
||||
using internal::WriterInterface<W>::Write;
|
||||
bool Write(const W& msg, grpc::WriteOptions options) override {
|
||||
return body_.Write(msg, options);
|
||||
}
|
||||
|
||||
private:
|
||||
internal::ServerReaderWriterBody<W, R> body_;
|
||||
|
||||
friend class internal::TemplatedBidiStreamingHandler<ServerReaderWriter<W, R>,
|
||||
false>;
|
||||
ServerReaderWriter(grpc::internal::Call* call, grpc::ServerContext* ctx)
|
||||
: body_(call, ctx) {}
|
||||
};
|
||||
|
||||
/// A class to represent a flow-controlled unary call. This is something
|
||||
/// of a hybrid between conventional unary and streaming. This is invoked
|
||||
/// through a unary call on the client side, but the server responds to it
|
||||
/// as though it were a single-ping-pong streaming call. The server can use
|
||||
/// the \a NextMessageSize method to determine an upper-bound on the size of
|
||||
/// the message. A key difference relative to streaming: ServerUnaryStreamer
|
||||
/// must have exactly 1 Read and exactly 1 Write, in that order, to function
|
||||
/// correctly. Otherwise, the RPC is in error.
|
||||
template <class RequestType, class ResponseType>
|
||||
class ServerUnaryStreamer final
|
||||
: public ServerReaderWriterInterface<ResponseType, RequestType> {
|
||||
public:
|
||||
/// Block to send initial metadata to client.
|
||||
/// Implicit input parameter:
|
||||
/// - the \a ServerContext associated with this call will be used for
|
||||
/// sending initial metadata.
|
||||
void SendInitialMetadata() override { body_.SendInitialMetadata(); }
|
||||
|
||||
/// Get an upper bound on the request message size from the client.
|
||||
bool NextMessageSize(uint32_t* sz) override {
|
||||
return body_.NextMessageSize(sz);
|
||||
}
|
||||
|
||||
/// Read a message of type \a R into \a msg. Completion will be notified by \a
|
||||
/// tag on the associated completion queue.
|
||||
/// This is thread-safe with respect to \a Write or \a WritesDone methods. It
|
||||
/// should not be called concurrently with other streaming APIs
|
||||
/// on the same stream. It is not meaningful to call it concurrently
|
||||
/// with another \a ReaderInterface::Read on the same stream since reads on
|
||||
/// the same stream are delivered in order.
|
||||
///
|
||||
/// \param[out] msg Where to eventually store the read message.
|
||||
/// \param[in] tag The tag identifying the operation.
|
||||
bool Read(RequestType* request) override {
|
||||
if (read_done_) {
|
||||
return false;
|
||||
}
|
||||
read_done_ = true;
|
||||
return body_.Read(request);
|
||||
}
|
||||
|
||||
/// Block to write \a msg to the stream with WriteOptions \a options.
|
||||
/// This is thread-safe with respect to \a ReaderInterface::Read
|
||||
///
|
||||
/// \param msg The message to be written to the stream.
|
||||
/// \param options The WriteOptions affecting the write operation.
|
||||
///
|
||||
/// \return \a true on success, \a false when the stream has been closed.
|
||||
using internal::WriterInterface<ResponseType>::Write;
|
||||
bool Write(const ResponseType& response,
|
||||
grpc::WriteOptions options) override {
|
||||
if (write_done_ || !read_done_) {
|
||||
return false;
|
||||
}
|
||||
write_done_ = true;
|
||||
return body_.Write(response, options);
|
||||
}
|
||||
|
||||
private:
|
||||
internal::ServerReaderWriterBody<ResponseType, RequestType> body_;
|
||||
bool read_done_;
|
||||
bool write_done_;
|
||||
|
||||
friend class internal::TemplatedBidiStreamingHandler<
|
||||
ServerUnaryStreamer<RequestType, ResponseType>, true>;
|
||||
ServerUnaryStreamer(grpc::internal::Call* call, grpc::ServerContext* ctx)
|
||||
: body_(call, ctx), read_done_(false), write_done_(false) {}
|
||||
};
|
||||
|
||||
/// A class to represent a flow-controlled server-side streaming call.
|
||||
/// This is something of a hybrid between server-side and bidi streaming.
|
||||
/// This is invoked through a server-side streaming call on the client side,
|
||||
/// but the server responds to it as though it were a bidi streaming call that
|
||||
/// must first have exactly 1 Read and then any number of Writes.
|
||||
template <class RequestType, class ResponseType>
|
||||
class ServerSplitStreamer final
|
||||
: public ServerReaderWriterInterface<ResponseType, RequestType> {
|
||||
public:
|
||||
/// Block to send initial metadata to client.
|
||||
/// Implicit input parameter:
|
||||
/// - the \a ServerContext associated with this call will be used for
|
||||
/// sending initial metadata.
|
||||
void SendInitialMetadata() override { body_.SendInitialMetadata(); }
|
||||
|
||||
/// Get an upper bound on the request message size from the client.
|
||||
bool NextMessageSize(uint32_t* sz) override {
|
||||
return body_.NextMessageSize(sz);
|
||||
}
|
||||
|
||||
/// Read a message of type \a R into \a msg. Completion will be notified by \a
|
||||
/// tag on the associated completion queue.
|
||||
/// This is thread-safe with respect to \a Write or \a WritesDone methods. It
|
||||
/// should not be called concurrently with other streaming APIs
|
||||
/// on the same stream. It is not meaningful to call it concurrently
|
||||
/// with another \a ReaderInterface::Read on the same stream since reads on
|
||||
/// the same stream are delivered in order.
|
||||
///
|
||||
/// \param[out] msg Where to eventually store the read message.
|
||||
/// \param[in] tag The tag identifying the operation.
|
||||
bool Read(RequestType* request) override {
|
||||
if (read_done_) {
|
||||
return false;
|
||||
}
|
||||
read_done_ = true;
|
||||
return body_.Read(request);
|
||||
}
|
||||
|
||||
/// Block to write \a msg to the stream with WriteOptions \a options.
|
||||
/// This is thread-safe with respect to \a ReaderInterface::Read
|
||||
///
|
||||
/// \param msg The message to be written to the stream.
|
||||
/// \param options The WriteOptions affecting the write operation.
|
||||
///
|
||||
/// \return \a true on success, \a false when the stream has been closed.
|
||||
using internal::WriterInterface<ResponseType>::Write;
|
||||
bool Write(const ResponseType& response,
|
||||
grpc::WriteOptions options) override {
|
||||
return read_done_ && body_.Write(response, options);
|
||||
}
|
||||
|
||||
private:
|
||||
internal::ServerReaderWriterBody<ResponseType, RequestType> body_;
|
||||
bool read_done_;
|
||||
|
||||
friend class internal::TemplatedBidiStreamingHandler<
|
||||
ServerSplitStreamer<RequestType, ResponseType>, false>;
|
||||
ServerSplitStreamer(grpc::internal::Call* call, grpc::ServerContext* ctx)
|
||||
: body_(call, ctx), read_done_(false) {}
|
||||
};
|
||||
|
||||
} // namespace grpc
|
||||
|
||||
#endif // GRPCPP_SUPPORT_SYNC_STREAM_H
|
||||
89
Pods/gRPC-C++/include/grpcpp/support/time.h
generated
Normal file
89
Pods/gRPC-C++/include/grpcpp/support/time.h
generated
Normal file
@@ -0,0 +1,89 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2015 gRPC 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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef GRPCPP_SUPPORT_TIME_H
|
||||
#define GRPCPP_SUPPORT_TIME_H
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include <grpc/impl/grpc_types.h>
|
||||
#include <grpcpp/support/config.h>
|
||||
|
||||
namespace grpc {
|
||||
|
||||
/// If you are trying to use CompletionQueue::AsyncNext with a time class that
|
||||
/// isn't either gpr_timespec or std::chrono::system_clock::time_point, you
|
||||
/// will most likely be looking at this comment as your compiler will have
|
||||
/// fired an error below. In order to fix this issue, you have two potential
|
||||
/// solutions:
|
||||
|
||||
/// 1. Use gpr_timespec or std::chrono::system_clock::time_point instead
|
||||
/// 2. Specialize the TimePoint class with whichever time class that you
|
||||
/// want to use here. See below for two examples of how to do this.
|
||||
///
|
||||
template <typename T>
|
||||
class TimePoint {
|
||||
public:
|
||||
// If you see the error with methods below, you may need either
|
||||
// i) using the existing types having a conversion class such as
|
||||
// gpr_timespec and std::chrono::system_clock::time_point or
|
||||
// ii) writing a new TimePoint<YourType> to address your case.
|
||||
TimePoint(const T& /*time*/) = delete;
|
||||
gpr_timespec raw_time() = delete;
|
||||
};
|
||||
|
||||
template <>
|
||||
class TimePoint<gpr_timespec> {
|
||||
public:
|
||||
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||
TimePoint(const gpr_timespec& time) : time_(time) {}
|
||||
gpr_timespec raw_time() { return time_; }
|
||||
|
||||
private:
|
||||
gpr_timespec time_;
|
||||
};
|
||||
|
||||
} // namespace grpc
|
||||
|
||||
namespace grpc {
|
||||
|
||||
// from and to should be absolute time.
|
||||
void Timepoint2Timespec(const std::chrono::system_clock::time_point& from,
|
||||
gpr_timespec* to);
|
||||
void TimepointHR2Timespec(
|
||||
const std::chrono::high_resolution_clock::time_point& from,
|
||||
gpr_timespec* to);
|
||||
|
||||
std::chrono::system_clock::time_point Timespec2Timepoint(gpr_timespec t);
|
||||
|
||||
template <>
|
||||
class TimePoint<std::chrono::system_clock::time_point> {
|
||||
public:
|
||||
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||
TimePoint(const std::chrono::system_clock::time_point& time) {
|
||||
Timepoint2Timespec(time, &time_);
|
||||
}
|
||||
gpr_timespec raw_time() const { return time_; }
|
||||
|
||||
private:
|
||||
gpr_timespec time_;
|
||||
};
|
||||
|
||||
} // namespace grpc
|
||||
|
||||
#endif // GRPCPP_SUPPORT_TIME_H
|
||||
36
Pods/gRPC-C++/include/grpcpp/support/validate_service_config.h
generated
Normal file
36
Pods/gRPC-C++/include/grpcpp/support/validate_service_config.h
generated
Normal file
@@ -0,0 +1,36 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2019 gRPC 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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef GRPCPP_SUPPORT_VALIDATE_SERVICE_CONFIG_H
|
||||
#define GRPCPP_SUPPORT_VALIDATE_SERVICE_CONFIG_H
|
||||
|
||||
#include <grpcpp/support/config.h>
|
||||
|
||||
namespace grpc {
|
||||
|
||||
namespace experimental {
|
||||
/// Validates \a service_config_json. If valid, returns an empty string.
|
||||
/// Otherwise, returns the validation error.
|
||||
/// TODO(yashykt): Promote it to out of experimental once it is proved useful
|
||||
/// and gRFC is accepted.
|
||||
std::string ValidateServiceConfigJSON(const std::string& service_config_json);
|
||||
} // namespace experimental
|
||||
|
||||
} // namespace grpc
|
||||
|
||||
#endif // GRPCPP_SUPPORT_VALIDATE_SERVICE_CONFIG_H
|
||||
Reference in New Issue
Block a user