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 32 namespace grpc { 33 34 class CompletionQueue; 35 36 typedef ClientAsyncReaderWriter<ByteBuffer, ByteBuffer> 37 GenericClientAsyncReaderWriter; 38 typedef ClientAsyncResponseReader<ByteBuffer> GenericClientAsyncResponseReader; 39 40 /// Generic stubs provide a type-unaware interface to call gRPC methods 41 /// by name. In practice, the Request and Response types should be basic 42 /// types like grpc::ByteBuffer or proto::MessageLite (the base protobuf). 43 template <class RequestType, class ResponseType> 44 class TemplatedGenericStub final { 45 public: TemplatedGenericStub(std::shared_ptr<grpc::ChannelInterface> channel)46 explicit TemplatedGenericStub(std::shared_ptr<grpc::ChannelInterface> channel) 47 : channel_(channel) {} 48 49 /// Setup a call to a named method \a method using \a context, but don't 50 /// start it. Let it be started explicitly with StartCall and a tag. 51 /// The return value only indicates whether or not registration of the call 52 /// succeeded (i.e. the call won't proceed if the return value is nullptr). 53 std::unique_ptr<ClientAsyncReaderWriter<RequestType, ResponseType>> PrepareCall(ClientContext * context,const std::string & method,::grpc::CompletionQueue * cq)54 PrepareCall(ClientContext* context, const std::string& method, 55 ::grpc::CompletionQueue* cq) { 56 return CallInternal(channel_.get(), context, method, cq, false, nullptr); 57 } 58 59 /// Setup a unary call to a named method \a method using \a context, and don't 60 /// start it. Let it be started explicitly with StartCall. 61 /// The return value only indicates whether or not registration of the call 62 /// 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)63 std::unique_ptr<ClientAsyncResponseReader<ResponseType>> PrepareUnaryCall( 64 ClientContext* context, const std::string& method, 65 const RequestType& request, ::grpc::CompletionQueue* cq) { 66 return std::unique_ptr<ClientAsyncResponseReader<ResponseType>>( 67 internal::ClientAsyncResponseReaderHelper::Create<ResponseType>( 68 channel_.get(), cq, 69 grpc::internal::RpcMethod(method.c_str(), 70 grpc::internal::RpcMethod::NORMAL_RPC), 71 context, request)); 72 } 73 74 /// DEPRECATED for multi-threaded use 75 /// Begin a call to a named method \a method using \a context. 76 /// A tag \a tag will be delivered to \a cq when the call has been started 77 /// (i.e, initial metadata has been sent). 78 /// The return value only indicates whether or not registration of the call 79 /// 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)80 std::unique_ptr<ClientAsyncReaderWriter<RequestType, ResponseType>> Call( 81 ClientContext* context, const std::string& method, 82 ::grpc::CompletionQueue* cq, void* tag) { 83 return CallInternal(channel_.get(), context, method, cq, true, tag); 84 } 85 86 #ifdef GRPC_CALLBACK_API_NONEXPERIMENTAL 87 /// Setup and start a unary call to a named method \a method using 88 /// \a context and specifying the \a request and \a response buffers. UnaryCall(ClientContext * context,const std::string & method,const RequestType * request,ResponseType * response,std::function<void (grpc::Status)> on_completion)89 void UnaryCall(ClientContext* context, const std::string& method, 90 const RequestType* request, ResponseType* response, 91 std::function<void(grpc::Status)> on_completion) { 92 UnaryCallInternal(context, method, request, response, 93 std::move(on_completion)); 94 } 95 96 /// Setup a unary call to a named method \a method using 97 /// \a context and specifying the \a request and \a response buffers. 98 /// Like any other reactor-based RPC, it will not be activated until 99 /// StartCall is invoked on its reactor. PrepareUnaryCall(ClientContext * context,const std::string & method,const RequestType * request,ResponseType * response,ClientUnaryReactor * reactor)100 void PrepareUnaryCall(ClientContext* context, const std::string& method, 101 const RequestType* request, ResponseType* response, 102 ClientUnaryReactor* reactor) { 103 PrepareUnaryCallInternal(context, method, request, response, reactor); 104 } 105 106 /// Setup a call to a named method \a method using \a context and tied to 107 /// \a reactor . Like any other bidi streaming RPC, it will not be activated 108 /// until StartCall is invoked on its reactor. PrepareBidiStreamingCall(ClientContext * context,const std::string & method,ClientBidiReactor<RequestType,ResponseType> * reactor)109 void PrepareBidiStreamingCall( 110 ClientContext* context, const std::string& method, 111 ClientBidiReactor<RequestType, ResponseType>* reactor) { 112 PrepareBidiStreamingCallInternal(context, method, reactor); 113 } 114 #endif 115 116 /// NOTE: class experimental_type is not part of the public API of this class 117 /// TODO(vjpai): Move these contents to the public API of GenericStub when 118 /// they are no longer experimental 119 class experimental_type { 120 public: experimental_type(TemplatedGenericStub * stub)121 explicit experimental_type(TemplatedGenericStub* stub) : stub_(stub) {} 122 123 /// Setup and start a unary call to a named method \a method using 124 /// \a context and specifying the \a request and \a response buffers. UnaryCall(ClientContext * context,const std::string & method,const RequestType * request,ResponseType * response,std::function<void (grpc::Status)> on_completion)125 void UnaryCall(ClientContext* context, const std::string& method, 126 const RequestType* request, ResponseType* response, 127 std::function<void(grpc::Status)> on_completion) { 128 stub_->UnaryCallInternal(context, method, request, response, 129 std::move(on_completion)); 130 } 131 132 /// Setup a unary call to a named method \a method using 133 /// \a context and specifying the \a request and \a response buffers. 134 /// Like any other reactor-based RPC, it will not be activated until 135 /// StartCall is invoked on its reactor. PrepareUnaryCall(ClientContext * context,const std::string & method,const RequestType * request,ResponseType * response,ClientUnaryReactor * reactor)136 void PrepareUnaryCall(ClientContext* context, const std::string& method, 137 const RequestType* request, ResponseType* response, 138 ClientUnaryReactor* reactor) { 139 stub_->PrepareUnaryCallInternal(context, method, request, response, 140 reactor); 141 } 142 143 /// Setup a call to a named method \a method using \a context and tied to 144 /// \a reactor . Like any other bidi streaming RPC, it will not be activated 145 /// until StartCall is invoked on its reactor. PrepareBidiStreamingCall(ClientContext * context,const std::string & method,ClientBidiReactor<RequestType,ResponseType> * reactor)146 void PrepareBidiStreamingCall( 147 ClientContext* context, const std::string& method, 148 ClientBidiReactor<RequestType, ResponseType>* reactor) { 149 stub_->PrepareBidiStreamingCallInternal(context, method, reactor); 150 } 151 152 private: 153 TemplatedGenericStub* stub_; 154 }; 155 156 /// NOTE: The function experimental() is not stable public API. It is a view 157 /// to the experimental components of this class. It may be changed or removed 158 /// at any time. experimental()159 experimental_type experimental() { return experimental_type(this); } 160 161 private: 162 std::shared_ptr<grpc::ChannelInterface> channel_; 163 UnaryCallInternal(ClientContext * context,const std::string & method,const RequestType * request,ResponseType * response,std::function<void (grpc::Status)> on_completion)164 void UnaryCallInternal(ClientContext* context, const std::string& method, 165 const RequestType* request, ResponseType* response, 166 std::function<void(grpc::Status)> on_completion) { 167 internal::CallbackUnaryCall( 168 channel_.get(), 169 grpc::internal::RpcMethod(method.c_str(), 170 grpc::internal::RpcMethod::NORMAL_RPC), 171 context, request, response, std::move(on_completion)); 172 } 173 PrepareUnaryCallInternal(ClientContext * context,const std::string & method,const RequestType * request,ResponseType * response,ClientUnaryReactor * reactor)174 void PrepareUnaryCallInternal(ClientContext* context, 175 const std::string& method, 176 const RequestType* request, 177 ResponseType* response, 178 ClientUnaryReactor* reactor) { 179 internal::ClientCallbackUnaryFactory::Create<RequestType, ResponseType>( 180 channel_.get(), 181 grpc::internal::RpcMethod(method.c_str(), 182 grpc::internal::RpcMethod::NORMAL_RPC), 183 context, request, response, reactor); 184 } 185 PrepareBidiStreamingCallInternal(ClientContext * context,const std::string & method,ClientBidiReactor<RequestType,ResponseType> * reactor)186 void PrepareBidiStreamingCallInternal( 187 ClientContext* context, const std::string& method, 188 ClientBidiReactor<RequestType, ResponseType>* reactor) { 189 internal::ClientCallbackReaderWriterFactory<RequestType, ResponseType>:: 190 Create(channel_.get(), 191 grpc::internal::RpcMethod( 192 method.c_str(), grpc::internal::RpcMethod::BIDI_STREAMING), 193 context, reactor); 194 } 195 196 std::unique_ptr<ClientAsyncReaderWriter<RequestType, ResponseType>> CallInternal(grpc::ChannelInterface * channel,ClientContext * context,const std::string & method,::grpc::CompletionQueue * cq,bool start,void * tag)197 CallInternal(grpc::ChannelInterface* channel, ClientContext* context, 198 const std::string& method, ::grpc::CompletionQueue* cq, 199 bool start, void* tag) { 200 return std::unique_ptr<ClientAsyncReaderWriter<RequestType, ResponseType>>( 201 internal::ClientAsyncReaderWriterFactory<RequestType, ResponseType>:: 202 Create( 203 channel, cq, 204 grpc::internal::RpcMethod( 205 method.c_str(), grpc::internal::RpcMethod::BIDI_STREAMING), 206 context, start, tag)); 207 } 208 }; 209 210 typedef TemplatedGenericStub<grpc::ByteBuffer, grpc::ByteBuffer> GenericStub; 211 212 } // namespace grpc 213 214 #endif // GRPCPP_GENERIC_GENERIC_STUB_H 215