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