1 /*
2 *
3 * Copyright 2018 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_IMPL_CODEGEN_CLIENT_CALLBACK_H
20 #define GRPCPP_IMPL_CODEGEN_CLIENT_CALLBACK_H
21
22 #include <functional>
23
24 #include <grpcpp/impl/codegen/call.h>
25 #include <grpcpp/impl/codegen/callback_common.h>
26 #include <grpcpp/impl/codegen/channel_interface.h>
27 #include <grpcpp/impl/codegen/config.h>
28 #include <grpcpp/impl/codegen/core_codegen_interface.h>
29 #include <grpcpp/impl/codegen/status.h>
30
31 namespace grpc {
32
33 class Channel;
34 class ClientContext;
35 class CompletionQueue;
36
37 namespace internal {
38 class RpcMethod;
39
40 /// Perform a callback-based unary call
41 /// TODO(vjpai): Combine as much as possible with the blocking unary call code
42 template <class InputMessage, class OutputMessage>
CallbackUnaryCall(ChannelInterface * channel,const RpcMethod & method,ClientContext * context,const InputMessage * request,OutputMessage * result,std::function<void (Status)> on_completion)43 void CallbackUnaryCall(ChannelInterface* channel, const RpcMethod& method,
44 ClientContext* context, const InputMessage* request,
45 OutputMessage* result,
46 std::function<void(Status)> on_completion) {
47 CallbackUnaryCallImpl<InputMessage, OutputMessage> x(
48 channel, method, context, request, result, on_completion);
49 }
50
51 template <class InputMessage, class OutputMessage>
52 class CallbackUnaryCallImpl {
53 public:
CallbackUnaryCallImpl(ChannelInterface * channel,const RpcMethod & method,ClientContext * context,const InputMessage * request,OutputMessage * result,std::function<void (Status)> on_completion)54 CallbackUnaryCallImpl(ChannelInterface* channel, const RpcMethod& method,
55 ClientContext* context, const InputMessage* request,
56 OutputMessage* result,
57 std::function<void(Status)> on_completion) {
58 CompletionQueue* cq = channel->CallbackCQ();
59 GPR_CODEGEN_ASSERT(cq != nullptr);
60 Call call(channel->CreateCall(method, context, cq));
61
62 using FullCallOpSet =
63 CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
64 CallOpRecvInitialMetadata, CallOpRecvMessage<OutputMessage>,
65 CallOpClientSendClose, CallOpClientRecvStatus>;
66
67 auto* ops = new (g_core_codegen_interface->grpc_call_arena_alloc(
68 call.call(), sizeof(FullCallOpSet))) FullCallOpSet;
69
70 auto* tag = new (g_core_codegen_interface->grpc_call_arena_alloc(
71 call.call(), sizeof(CallbackWithStatusTag)))
72 CallbackWithStatusTag(call.call(), on_completion, ops);
73
74 // TODO(vjpai): Unify code with sync API as much as possible
75 Status s = ops->SendMessage(*request);
76 if (!s.ok()) {
77 tag->force_run(s);
78 return;
79 }
80 ops->SendInitialMetadata(context->send_initial_metadata_,
81 context->initial_metadata_flags());
82 ops->RecvInitialMetadata(context);
83 ops->RecvMessage(result);
84 ops->AllowNoMessage();
85 ops->ClientSendClose();
86 ops->ClientRecvStatus(context, tag->status_ptr());
87 ops->set_cq_tag(tag);
88 call.PerformOps(ops);
89 }
90 };
91
92 } // namespace internal
93 } // namespace grpc
94
95 #endif // GRPCPP_IMPL_CODEGEN_CLIENT_CALLBACK_H
96