1 // 2 // 3 // Copyright 2015 gRPC authors. 4 // 5 // Licensed under the Apache License, Version 2.0 (the "License"); 6 // you may not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, software 12 // distributed under the License is distributed on an "AS IS" BASIS, 13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 // See the License for the specific language governing permissions and 15 // limitations under the License. 16 // 17 // 18 19 #ifndef GRPCPP_GENERIC_GENERIC_STUB_H 20 #define GRPCPP_GENERIC_GENERIC_STUB_H 21 22 #include <functional> 23 24 #include <grpcpp/client_context.h> 25 #include <grpcpp/impl/rpc_method.h> 26 #include <grpcpp/support/async_stream.h> 27 #include <grpcpp/support/async_unary_call.h> 28 #include <grpcpp/support/byte_buffer.h> 29 #include <grpcpp/support/client_callback.h> 30 #include <grpcpp/support/status.h> 31 #include <grpcpp/support/stub_options.h> 32 33 namespace grpc { 34 35 class CompletionQueue; 36 37 typedef ClientAsyncReaderWriter<ByteBuffer, ByteBuffer> 38 GenericClientAsyncReaderWriter; 39 typedef ClientAsyncResponseReader<ByteBuffer> GenericClientAsyncResponseReader; 40 41 /// Generic stubs provide a type-unaware interface to call gRPC methods 42 /// by name. In practice, the Request and Response types should be basic 43 /// types like grpc::ByteBuffer or proto::MessageLite (the base protobuf). 44 template <class RequestType, class ResponseType> 45 class TemplatedGenericStub final { 46 public: TemplatedGenericStub(std::shared_ptr<grpc::ChannelInterface> channel)47 explicit TemplatedGenericStub(std::shared_ptr<grpc::ChannelInterface> channel) 48 : channel_(channel) {} 49 50 /// Setup a call to a named method \a method using \a context, but don't 51 /// start it. Let it be started explicitly with StartCall and a tag. 52 /// The return value only indicates whether or not registration of the call 53 /// succeeded (i.e. the call won't proceed if the return value is nullptr). 54 std::unique_ptr<ClientAsyncReaderWriter<RequestType, ResponseType>> PrepareCall(ClientContext * context,const std::string & method,grpc::CompletionQueue * cq)55 PrepareCall(ClientContext* context, const std::string& method, 56 grpc::CompletionQueue* cq) { 57 return CallInternal(channel_.get(), context, method, /*options=*/{}, cq, 58 false, nullptr); 59 } 60 61 /// Setup a unary call to a named method \a method using \a context, and don't 62 /// start it. Let it be started explicitly with StartCall. 63 /// The return value only indicates whether or not registration of the call 64 /// succeeded (i.e. the call won't proceed if the return value is nullptr). PrepareUnaryCall(ClientContext * context,const std::string & method,const RequestType & request,grpc::CompletionQueue * cq)65 std::unique_ptr<ClientAsyncResponseReader<ResponseType>> PrepareUnaryCall( 66 ClientContext* context, const std::string& method, 67 const RequestType& request, grpc::CompletionQueue* cq) { 68 return std::unique_ptr<ClientAsyncResponseReader<ResponseType>>( 69 internal::ClientAsyncResponseReaderHelper::Create<ResponseType>( 70 channel_.get(), cq, 71 grpc::internal::RpcMethod(method.c_str(), 72 /*suffix_for_stats=*/nullptr, 73 grpc::internal::RpcMethod::NORMAL_RPC), 74 context, request)); 75 } 76 77 /// DEPRECATED for multi-threaded use 78 /// Begin a call to a named method \a method using \a context. 79 /// A tag \a tag will be delivered to \a cq when the call has been started 80 /// (i.e, initial metadata has been sent). 81 /// The return value only indicates whether or not registration of the call 82 /// succeeded (i.e. the call won't proceed if the return value is nullptr). Call(ClientContext * context,const std::string & method,grpc::CompletionQueue * cq,void * tag)83 std::unique_ptr<ClientAsyncReaderWriter<RequestType, ResponseType>> Call( 84 ClientContext* context, const std::string& method, 85 grpc::CompletionQueue* cq, void* tag) { 86 return CallInternal(channel_.get(), context, method, /*options=*/{}, cq, 87 true, tag); 88 } 89 90 /// Setup and start a unary call to a named method \a method using 91 /// \a context and specifying the \a request and \a response buffers. UnaryCall(ClientContext * context,const std::string & method,StubOptions options,const RequestType * request,ResponseType * response,std::function<void (grpc::Status)> on_completion)92 void UnaryCall(ClientContext* context, const std::string& method, 93 StubOptions options, const RequestType* request, 94 ResponseType* response, 95 std::function<void(grpc::Status)> on_completion) { 96 UnaryCallInternal(context, method, options, request, response, 97 std::move(on_completion)); 98 } 99 100 /// Setup a unary call to a named method \a method using 101 /// \a context and specifying the \a request and \a response buffers. 102 /// Like any other reactor-based RPC, it will not be activated until 103 /// StartCall is invoked on its reactor. PrepareUnaryCall(ClientContext * context,const std::string & method,StubOptions options,const RequestType * request,ResponseType * response,ClientUnaryReactor * reactor)104 void PrepareUnaryCall(ClientContext* context, const std::string& method, 105 StubOptions options, const RequestType* request, 106 ResponseType* response, ClientUnaryReactor* reactor) { 107 PrepareUnaryCallInternal(context, method, options, request, response, 108 reactor); 109 } 110 111 /// Setup a call to a named method \a method using \a context and tied to 112 /// \a reactor . Like any other bidi streaming RPC, it will not be activated 113 /// until StartCall is invoked on its reactor. PrepareBidiStreamingCall(ClientContext * context,const std::string & method,StubOptions options,ClientBidiReactor<RequestType,ResponseType> * reactor)114 void PrepareBidiStreamingCall( 115 ClientContext* context, const std::string& method, StubOptions options, 116 ClientBidiReactor<RequestType, ResponseType>* reactor) { 117 PrepareBidiStreamingCallInternal(context, method, options, reactor); 118 } 119 120 private: 121 std::shared_ptr<grpc::ChannelInterface> channel_; 122 UnaryCallInternal(ClientContext * context,const std::string & method,StubOptions options,const RequestType * request,ResponseType * response,std::function<void (grpc::Status)> on_completion)123 void UnaryCallInternal(ClientContext* context, const std::string& method, 124 StubOptions options, const RequestType* request, 125 ResponseType* response, 126 std::function<void(grpc::Status)> on_completion) { 127 internal::CallbackUnaryCall( 128 channel_.get(), 129 grpc::internal::RpcMethod(method.c_str(), options.suffix_for_stats(), 130 grpc::internal::RpcMethod::NORMAL_RPC), 131 context, request, response, std::move(on_completion)); 132 } 133 PrepareUnaryCallInternal(ClientContext * context,const std::string & method,StubOptions options,const RequestType * request,ResponseType * response,ClientUnaryReactor * reactor)134 void PrepareUnaryCallInternal(ClientContext* context, 135 const std::string& method, StubOptions options, 136 const RequestType* request, 137 ResponseType* response, 138 ClientUnaryReactor* reactor) { 139 internal::ClientCallbackUnaryFactory::Create<RequestType, ResponseType>( 140 channel_.get(), 141 grpc::internal::RpcMethod(method.c_str(), options.suffix_for_stats(), 142 grpc::internal::RpcMethod::NORMAL_RPC), 143 context, request, response, reactor); 144 } 145 PrepareBidiStreamingCallInternal(ClientContext * context,const std::string & method,StubOptions options,ClientBidiReactor<RequestType,ResponseType> * reactor)146 void PrepareBidiStreamingCallInternal( 147 ClientContext* context, const std::string& method, StubOptions options, 148 ClientBidiReactor<RequestType, ResponseType>* reactor) { 149 internal::ClientCallbackReaderWriterFactory<RequestType, ResponseType>:: 150 Create(channel_.get(), 151 grpc::internal::RpcMethod( 152 method.c_str(), options.suffix_for_stats(), 153 grpc::internal::RpcMethod::BIDI_STREAMING), 154 context, reactor); 155 } 156 157 std::unique_ptr<ClientAsyncReaderWriter<RequestType, ResponseType>> CallInternal(grpc::ChannelInterface * channel,ClientContext * context,const std::string & method,StubOptions options,grpc::CompletionQueue * cq,bool start,void * tag)158 CallInternal(grpc::ChannelInterface* channel, ClientContext* context, 159 const std::string& method, StubOptions options, 160 grpc::CompletionQueue* cq, bool start, void* tag) { 161 return std::unique_ptr<ClientAsyncReaderWriter<RequestType, ResponseType>>( 162 internal::ClientAsyncReaderWriterFactory<RequestType, ResponseType>:: 163 Create(channel, cq, 164 grpc::internal::RpcMethod( 165 method.c_str(), options.suffix_for_stats(), 166 grpc::internal::RpcMethod::BIDI_STREAMING), 167 context, start, tag)); 168 } 169 }; 170 171 typedef TemplatedGenericStub<grpc::ByteBuffer, grpc::ByteBuffer> GenericStub; 172 173 } // namespace grpc 174 175 #endif // GRPCPP_GENERIC_GENERIC_STUB_H 176