1 | /* |
2 | * |
3 | * Copyright 2016 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_RPC_SERVICE_METHOD_H |
20 | #define GRPCPP_IMPL_CODEGEN_RPC_SERVICE_METHOD_H |
21 | |
22 | #include <climits> |
23 | #include <functional> |
24 | #include <map> |
25 | #include <memory> |
26 | #include <vector> |
27 | |
28 | #include <grpc/impl/codegen/log.h> |
29 | #include <grpcpp/impl/codegen/byte_buffer.h> |
30 | #include <grpcpp/impl/codegen/config.h> |
31 | #include <grpcpp/impl/codegen/rpc_method.h> |
32 | #include <grpcpp/impl/codegen/status.h> |
33 | |
34 | namespace grpc_impl { |
35 | class ServerContextBase; |
36 | } // namespace grpc_impl |
37 | |
38 | namespace grpc { |
39 | namespace internal { |
40 | /// Base class for running an RPC handler. |
41 | class MethodHandler { |
42 | public: |
43 | virtual ~MethodHandler() {} |
44 | struct HandlerParameter { |
45 | /// Constructor for HandlerParameter |
46 | /// |
47 | /// \param c : the gRPC Call structure for this server call |
48 | /// \param context : the ServerContext structure for this server call |
49 | /// \param req : the request payload, if appropriate for this RPC |
50 | /// \param req_status : the request status after any interceptors have run |
51 | /// \param handler_data: internal data for the handler. |
52 | /// \param requester : used only by the callback API. It is a function |
53 | /// called by the RPC Controller to request another RPC (and also |
54 | /// to set up the state required to make that request possible) |
55 | HandlerParameter(Call* c, ::grpc_impl::ServerContextBase* context, |
56 | void* req, Status req_status, void* handler_data, |
57 | std::function<void()> requester) |
58 | : call(c), |
59 | server_context(context), |
60 | request(req), |
61 | status(req_status), |
62 | internal_data(handler_data), |
63 | call_requester(std::move(requester)) {} |
64 | ~HandlerParameter() {} |
65 | Call* const call; |
66 | ::grpc_impl::ServerContextBase* const server_context; |
67 | void* const request; |
68 | const Status status; |
69 | void* const internal_data; |
70 | const std::function<void()> call_requester; |
71 | }; |
72 | virtual void RunHandler(const HandlerParameter& param) = 0; |
73 | |
74 | /* Returns a pointer to the deserialized request. \a status reflects the |
75 | result of deserialization. This pointer and the status should be filled in |
76 | a HandlerParameter and passed to RunHandler. It is illegal to access the |
77 | pointer after calling RunHandler. Ownership of the deserialized request is |
78 | retained by the handler. Returns nullptr if deserialization failed. */ |
79 | virtual void* Deserialize(grpc_call* /*call*/, grpc_byte_buffer* req, |
80 | Status* /*status*/, void** /*handler_data*/) { |
81 | GPR_CODEGEN_ASSERT(req == nullptr); |
82 | return nullptr; |
83 | } |
84 | }; |
85 | |
86 | /// Server side rpc method class |
87 | class RpcServiceMethod : public RpcMethod { |
88 | public: |
89 | /// Takes ownership of the handler |
90 | RpcServiceMethod(const char* name, RpcMethod::RpcType type, |
91 | MethodHandler* handler) |
92 | : RpcMethod(name, type), |
93 | server_tag_(nullptr), |
94 | api_type_(ApiType::SYNC), |
95 | handler_(handler) {} |
96 | |
97 | enum class ApiType { |
98 | SYNC, |
99 | ASYNC, |
100 | RAW, |
101 | CALL_BACK, // not CALLBACK because that is reserved in Windows |
102 | RAW_CALL_BACK, |
103 | }; |
104 | |
105 | void set_server_tag(void* tag) { server_tag_ = tag; } |
106 | void* server_tag() const { return server_tag_; } |
107 | /// if MethodHandler is nullptr, then this is an async method |
108 | MethodHandler* handler() const { return handler_.get(); } |
109 | ApiType api_type() const { return api_type_; } |
110 | void SetHandler(MethodHandler* handler) { handler_.reset(p: handler); } |
111 | void SetServerApiType(RpcServiceMethod::ApiType type) { |
112 | if ((api_type_ == ApiType::SYNC) && |
113 | (type == ApiType::ASYNC || type == ApiType::RAW)) { |
114 | // this marks this method as async |
115 | handler_.reset(); |
116 | } else if (api_type_ != ApiType::SYNC) { |
117 | // this is not an error condition, as it allows users to declare a server |
118 | // like WithRawMethod_foo<AsyncService>. However since it |
119 | // overwrites behavior, it should be logged. |
120 | gpr_log( |
121 | GPR_INFO, |
122 | format: "You are marking method %s as '%s', even though it was " |
123 | "previously marked '%s'. This behavior will overwrite the original " |
124 | "behavior. If you expected this then ignore this message." , |
125 | name(), TypeToString(type: api_type_), TypeToString(type)); |
126 | } |
127 | api_type_ = type; |
128 | } |
129 | |
130 | private: |
131 | void* server_tag_; |
132 | ApiType api_type_; |
133 | std::unique_ptr<MethodHandler> handler_; |
134 | |
135 | const char* TypeToString(RpcServiceMethod::ApiType type) { |
136 | switch (type) { |
137 | case ApiType::SYNC: |
138 | return "sync" ; |
139 | case ApiType::ASYNC: |
140 | return "async" ; |
141 | case ApiType::RAW: |
142 | return "raw" ; |
143 | case ApiType::CALL_BACK: |
144 | return "callback" ; |
145 | case ApiType::RAW_CALL_BACK: |
146 | return "raw_callback" ; |
147 | default: |
148 | GPR_UNREACHABLE_CODE(return "unknown" ); |
149 | } |
150 | } |
151 | }; |
152 | } // namespace internal |
153 | |
154 | } // namespace grpc |
155 | |
156 | #endif // GRPCPP_IMPL_CODEGEN_RPC_SERVICE_METHOD_H |
157 | |