/src/CMake/Utilities/cmcppdap/include/dap/session.h
Line | Count | Source |
1 | | // Copyright 2019 Google LLC |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // https://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | |
15 | | #ifndef dap_session_h |
16 | | #define dap_session_h |
17 | | |
18 | | #include "future.h" |
19 | | #include "io.h" |
20 | | #include "traits.h" |
21 | | #include "typeinfo.h" |
22 | | #include "typeof.h" |
23 | | |
24 | | #include <functional> |
25 | | |
26 | | namespace dap { |
27 | | |
28 | | // Forward declarations |
29 | | struct Request; |
30 | | struct Response; |
31 | | struct Event; |
32 | | |
33 | | //////////////////////////////////////////////////////////////////////////////// |
34 | | // Error |
35 | | //////////////////////////////////////////////////////////////////////////////// |
36 | | |
37 | | // Error represents an error message in response to a DAP request. |
38 | | struct Error { |
39 | | Error() = default; |
40 | | Error(const std::string& error); |
41 | | Error(const char* msg, ...); |
42 | | |
43 | | // operator bool() returns true if there is an error. |
44 | 0 | inline operator bool() const { return message.size() > 0; } |
45 | | |
46 | | std::string message; // empty represents success. |
47 | | }; |
48 | | |
49 | | //////////////////////////////////////////////////////////////////////////////// |
50 | | // ResponseOrError<T> |
51 | | //////////////////////////////////////////////////////////////////////////////// |
52 | | |
53 | | // ResponseOrError holds either the response to a DAP request or an error |
54 | | // message. |
55 | | template <typename T> |
56 | | struct ResponseOrError { |
57 | | using Request = T; |
58 | | |
59 | | inline ResponseOrError() = default; |
60 | | inline ResponseOrError(const T& response); |
61 | | inline ResponseOrError(T&& response); |
62 | | inline ResponseOrError(const Error& error); |
63 | | inline ResponseOrError(Error&& error); |
64 | | inline ResponseOrError(const ResponseOrError& other); |
65 | | inline ResponseOrError(ResponseOrError&& other); |
66 | | |
67 | | inline ResponseOrError& operator=(const ResponseOrError& other); |
68 | | inline ResponseOrError& operator=(ResponseOrError&& other); |
69 | | |
70 | | T response; |
71 | | Error error; // empty represents success. |
72 | | }; |
73 | | |
74 | | template <typename T> |
75 | | ResponseOrError<T>::ResponseOrError(const T& resp) : response(resp) {} |
76 | | template <typename T> |
77 | | ResponseOrError<T>::ResponseOrError(T&& resp) : response(std::move(resp)) {} |
78 | | template <typename T> |
79 | | ResponseOrError<T>::ResponseOrError(const Error& err) : error(err) {} |
80 | | template <typename T> |
81 | | ResponseOrError<T>::ResponseOrError(Error&& err) : error(std::move(err)) {} |
82 | | template <typename T> |
83 | | ResponseOrError<T>::ResponseOrError(const ResponseOrError& other) |
84 | | : response(other.response), error(other.error) {} |
85 | | template <typename T> |
86 | | ResponseOrError<T>::ResponseOrError(ResponseOrError&& other) |
87 | | : response(std::move(other.response)), error(std::move(other.error)) {} |
88 | | template <typename T> |
89 | | ResponseOrError<T>& ResponseOrError<T>::operator=( |
90 | | const ResponseOrError& other) { |
91 | | response = other.response; |
92 | | error = other.error; |
93 | | return *this; |
94 | | } |
95 | | template <typename T> |
96 | | ResponseOrError<T>& ResponseOrError<T>::operator=(ResponseOrError&& other) { |
97 | | response = std::move(other.response); |
98 | | error = std::move(other.error); |
99 | | return *this; |
100 | | } |
101 | | |
102 | | //////////////////////////////////////////////////////////////////////////////// |
103 | | // Session |
104 | | //////////////////////////////////////////////////////////////////////////////// |
105 | | |
106 | | // An enum flag that controls how the Session handles invalid data. |
107 | | enum OnInvalidData { |
108 | | // Ignore invalid data. |
109 | | kIgnore, |
110 | | // Close the underlying reader when invalid data is received. |
111 | | kClose, |
112 | | }; |
113 | | |
114 | | // Session implements a DAP client or server endpoint. |
115 | | // The general usage is as follows: |
116 | | // (1) Create a session with Session::create(). |
117 | | // (2) Register request and event handlers with registerHandler(). |
118 | | // (3) Optionally register a protocol error handler with onError(). |
119 | | // (3) Bind the session to the remote endpoint with bind(). |
120 | | // (4) Send requests or events with send(). |
121 | | class Session { |
122 | | template <typename F, int N> |
123 | | using ParamType = traits::ParameterType<F, N>; |
124 | | |
125 | | template <typename T> |
126 | | using IsRequest = traits::EnableIfIsType<dap::Request, T>; |
127 | | |
128 | | template <typename T> |
129 | | using IsEvent = traits::EnableIfIsType<dap::Event, T>; |
130 | | |
131 | | template <typename F> |
132 | | using IsRequestHandlerWithoutCallback = traits::EnableIf< |
133 | | traits::CompatibleWith<F, std::function<void(dap::Request)>>::value>; |
134 | | |
135 | | template <typename F, typename CallbackType> |
136 | | using IsRequestHandlerWithCallback = traits::EnableIf<traits::CompatibleWith< |
137 | | F, |
138 | | std::function<void(dap::Request, std::function<void(CallbackType)>)>>:: |
139 | | value>; |
140 | | |
141 | | public: |
142 | | virtual ~Session(); |
143 | | |
144 | | // ErrorHandler is the type of callback function used for reporting protocol |
145 | | // errors. |
146 | | using ErrorHandler = std::function<void(const char*)>; |
147 | | |
148 | | // ClosedHandler is the type of callback function used to signal that a |
149 | | // connected endpoint has closed. |
150 | | using ClosedHandler = std::function<void()>; |
151 | | |
152 | | // create() constructs and returns a new Session. |
153 | | static std::unique_ptr<Session> create(); |
154 | | |
155 | | // Sets how the Session handles invalid data. |
156 | | virtual void setOnInvalidData(OnInvalidData) = 0; |
157 | | |
158 | | // onError() registers a error handler that will be called whenever a protocol |
159 | | // error is encountered. |
160 | | // Only one error handler can be bound at any given time, and later calls |
161 | | // will replace the existing error handler. |
162 | | virtual void onError(const ErrorHandler&) = 0; |
163 | | |
164 | | // registerHandler() registers a request handler for a specific request type. |
165 | | // The function F must have one of the following signatures: |
166 | | // ResponseOrError<ResponseType>(const RequestType&) |
167 | | // ResponseType(const RequestType&) |
168 | | // Error(const RequestType&) |
169 | | template <typename F, typename RequestType = ParamType<F, 0>> |
170 | | inline IsRequestHandlerWithoutCallback<F> registerHandler(F&& handler); |
171 | | |
172 | | // registerHandler() registers a request handler for a specific request type. |
173 | | // The handler has a response callback function for the second argument of the |
174 | | // handler function. This callback may be called after the handler has |
175 | | // returned. |
176 | | // The function F must have the following signature: |
177 | | // void(const RequestType& request, |
178 | | // std::function<void(ResponseType)> response) |
179 | | template <typename F, |
180 | | typename RequestType = ParamType<F, 0>, |
181 | | typename ResponseType = typename RequestType::Response> |
182 | | inline IsRequestHandlerWithCallback<F, ResponseType> registerHandler( |
183 | | F&& handler); |
184 | | |
185 | | // registerHandler() registers a request handler for a specific request type. |
186 | | // The handler has a response callback function for the second argument of the |
187 | | // handler function. This callback may be called after the handler has |
188 | | // returned. |
189 | | // The function F must have the following signature: |
190 | | // void(const RequestType& request, |
191 | | // std::function<void(ResponseOrError<ResponseType>)> response) |
192 | | template <typename F, |
193 | | typename RequestType = ParamType<F, 0>, |
194 | | typename ResponseType = typename RequestType::Response> |
195 | | inline IsRequestHandlerWithCallback<F, ResponseOrError<ResponseType>> |
196 | | registerHandler(F&& handler); |
197 | | |
198 | | // registerHandler() registers a event handler for a specific event type. |
199 | | // The function F must have the following signature: |
200 | | // void(const EventType&) |
201 | | template <typename F, typename EventType = ParamType<F, 0>> |
202 | | inline IsEvent<EventType> registerHandler(F&& handler); |
203 | | |
204 | | // registerSentHandler() registers the function F to be called when a response |
205 | | // of the specific type has been sent. |
206 | | // The function F must have the following signature: |
207 | | // void(const ResponseOrError<ResponseType>&) |
208 | | template <typename F, |
209 | | typename ResponseType = typename ParamType<F, 0>::Request> |
210 | | inline void registerSentHandler(F&& handler); |
211 | | |
212 | | // send() sends the request to the connected endpoint and returns a |
213 | | // future that is assigned the request response or error. |
214 | | template <typename T, typename = IsRequest<T>> |
215 | | future<ResponseOrError<typename T::Response>> send(const T& request); |
216 | | |
217 | | // send() sends the event to the connected endpoint. |
218 | | template <typename T, typename = IsEvent<T>> |
219 | | void send(const T& event); |
220 | | |
221 | | // bind() connects this Session to an endpoint using connect(), and then |
222 | | // starts processing incoming messages with startProcessingMessages(). |
223 | | // onClose is the optional callback which will be called when the session |
224 | | // endpoint has been closed. |
225 | | inline void bind(const std::shared_ptr<Reader>& reader, |
226 | | const std::shared_ptr<Writer>& writer, |
227 | | const ClosedHandler& onClose); |
228 | | inline void bind(const std::shared_ptr<ReaderWriter>& readerWriter, |
229 | | const ClosedHandler& onClose); |
230 | | |
231 | | ////////////////////////////////////////////////////////////////////////////// |
232 | | // Note: |
233 | | // Methods and members below this point are for advanced usage, and are more |
234 | | // likely to change signature than the methods above. |
235 | | // The methods above this point should be sufficient for most use cases. |
236 | | ////////////////////////////////////////////////////////////////////////////// |
237 | | |
238 | | // connect() connects this Session to an endpoint. |
239 | | // connect() can only be called once. Repeated calls will raise an error, but |
240 | | // otherwise will do nothing. |
241 | | // Note: This method is used for explicit control over message handling. |
242 | | // Most users will use bind() instead of calling this method directly. |
243 | | virtual void connect(const std::shared_ptr<Reader>&, |
244 | | const std::shared_ptr<Writer>&) = 0; |
245 | | inline void connect(const std::shared_ptr<ReaderWriter>&); |
246 | | |
247 | | // startProcessingMessages() starts a new thread to receive and dispatch |
248 | | // incoming messages. |
249 | | // onClose is the optional callback which will be called when the session |
250 | | // endpoint has been closed. |
251 | | // Note: This method is used for explicit control over message handling. |
252 | | // Most users will use bind() instead of calling this method directly. |
253 | | virtual void startProcessingMessages(const ClosedHandler& onClose = {}) = 0; |
254 | | |
255 | | // getPayload() blocks until the next incoming message is received, returning |
256 | | // the payload or an empty function if the connection was lost. The returned |
257 | | // payload is function that can be called on any thread to dispatch the |
258 | | // message to the Session handler. |
259 | | // Note: This method is used for explicit control over message handling. |
260 | | // Most users will use bind() instead of calling this method directly. |
261 | | virtual std::function<void()> getPayload() = 0; |
262 | | |
263 | | // The callback function type called when a request handler is invoked, and |
264 | | // the request returns a successful result. |
265 | | // 'responseTypeInfo' is the type information of the response data structure. |
266 | | // 'responseData' is a pointer to response payload data. |
267 | | using RequestHandlerSuccessCallback = |
268 | | std::function<void(const TypeInfo* responseTypeInfo, |
269 | | const void* responseData)>; |
270 | | |
271 | | // The callback function type used to notify when a DAP request fails. |
272 | | // 'responseTypeInfo' is the type information of the response data structure. |
273 | | // 'message' is the error message |
274 | | using RequestHandlerErrorCallback = |
275 | | std::function<void(const TypeInfo* responseTypeInfo, |
276 | | const Error& message)>; |
277 | | |
278 | | // The callback function type used to invoke a request handler. |
279 | | // 'request' is a pointer to the request data structure |
280 | | // 'onSuccess' is the function to call if the request completed succesfully. |
281 | | // 'onError' is the function to call if the request failed. |
282 | | // For each call of the request handler, 'onSuccess' or 'onError' must be |
283 | | // called exactly once. |
284 | | using GenericRequestHandler = |
285 | | std::function<void(const void* request, |
286 | | const RequestHandlerSuccessCallback& onSuccess, |
287 | | const RequestHandlerErrorCallback& onError)>; |
288 | | |
289 | | // The callback function type used to handle a response to a request. |
290 | | // 'response' is a pointer to the response data structure. May be nullptr. |
291 | | // 'error' is a pointer to the reponse error message. May be nullptr. |
292 | | // One of 'data' or 'error' will be nullptr. |
293 | | using GenericResponseHandler = |
294 | | std::function<void(const void* response, const Error* error)>; |
295 | | |
296 | | // The callback function type used to handle an event. |
297 | | // 'event' is a pointer to the event data structure. |
298 | | using GenericEventHandler = std::function<void(const void* event)>; |
299 | | |
300 | | // The callback function type used to notify when a response has been sent |
301 | | // from this session endpoint. |
302 | | // 'response' is a pointer to the response data structure. |
303 | | // 'error' is a pointer to the reponse error message. May be nullptr. |
304 | | using GenericResponseSentHandler = |
305 | | std::function<void(const void* response, const Error* error)>; |
306 | | |
307 | | // registerHandler() registers 'handler' as the request handler callback for |
308 | | // requests of the type 'typeinfo'. |
309 | | virtual void registerHandler(const TypeInfo* typeinfo, |
310 | | const GenericRequestHandler& handler) = 0; |
311 | | |
312 | | // registerHandler() registers 'handler' as the event handler callback for |
313 | | // events of the type 'typeinfo'. |
314 | | virtual void registerHandler(const TypeInfo* typeinfo, |
315 | | const GenericEventHandler& handler) = 0; |
316 | | |
317 | | // registerHandler() registers 'handler' as the response-sent handler function |
318 | | // which is called whenever a response of the type 'typeinfo' is sent from |
319 | | // this session endpoint. |
320 | | virtual void registerHandler(const TypeInfo* typeinfo, |
321 | | const GenericResponseSentHandler& handler) = 0; |
322 | | |
323 | | // send() sends a request to the remote endpoint. |
324 | | // 'requestTypeInfo' is the type info of the request data structure. |
325 | | // 'requestTypeInfo' is the type info of the response data structure. |
326 | | // 'request' is a pointer to the request data structure. |
327 | | // 'responseHandler' is the handler function for the response. |
328 | | virtual bool send(const dap::TypeInfo* requestTypeInfo, |
329 | | const dap::TypeInfo* responseTypeInfo, |
330 | | const void* request, |
331 | | const GenericResponseHandler& responseHandler) = 0; |
332 | | |
333 | | // send() sends an event to the remote endpoint. |
334 | | // 'eventTypeInfo' is the type info for the event data structure. |
335 | | // 'event' is a pointer to the event data structure. |
336 | | virtual bool send(const TypeInfo* eventTypeInfo, const void* event) = 0; |
337 | | }; |
338 | | |
339 | | template <typename F, typename RequestType> |
340 | | Session::IsRequestHandlerWithoutCallback<F> Session::registerHandler( |
341 | | F&& handler) { |
342 | | using ResponseType = typename RequestType::Response; |
343 | | const TypeInfo* typeinfo = TypeOf<RequestType>::type(); |
344 | | registerHandler(typeinfo, |
345 | | [handler](const void* args, |
346 | | const RequestHandlerSuccessCallback& onSuccess, |
347 | | const RequestHandlerErrorCallback& onError) { |
348 | | ResponseOrError<ResponseType> res = |
349 | | handler(*reinterpret_cast<const RequestType*>(args)); |
350 | | if (res.error) { |
351 | | onError(TypeOf<ResponseType>::type(), res.error); |
352 | | } else { |
353 | | onSuccess(TypeOf<ResponseType>::type(), &res.response); |
354 | | } |
355 | | }); |
356 | | } |
357 | | |
358 | | template <typename F, typename RequestType, typename ResponseType> |
359 | | Session::IsRequestHandlerWithCallback<F, ResponseType> Session::registerHandler( |
360 | | F&& handler) { |
361 | | using CallbackType = ParamType<F, 1>; |
362 | | registerHandler( |
363 | | TypeOf<RequestType>::type(), |
364 | | [handler](const void* args, |
365 | | const RequestHandlerSuccessCallback& onSuccess, |
366 | | const RequestHandlerErrorCallback&) { |
367 | | CallbackType responseCallback = [onSuccess](const ResponseType& res) { |
368 | | onSuccess(TypeOf<ResponseType>::type(), &res); |
369 | | }; |
370 | | handler(*reinterpret_cast<const RequestType*>(args), responseCallback); |
371 | | }); |
372 | | } |
373 | | |
374 | | template <typename F, typename RequestType, typename ResponseType> |
375 | | Session::IsRequestHandlerWithCallback<F, ResponseOrError<ResponseType>> |
376 | | Session::registerHandler(F&& handler) { |
377 | | using CallbackType = ParamType<F, 1>; |
378 | | registerHandler( |
379 | | TypeOf<RequestType>::type(), |
380 | | [handler](const void* args, |
381 | | const RequestHandlerSuccessCallback& onSuccess, |
382 | | const RequestHandlerErrorCallback& onError) { |
383 | | CallbackType responseCallback = |
384 | | [onError, onSuccess](const ResponseOrError<ResponseType>& res) { |
385 | | if (res.error) { |
386 | | onError(TypeOf<ResponseType>::type(), res.error); |
387 | | } else { |
388 | | onSuccess(TypeOf<ResponseType>::type(), &res.response); |
389 | | } |
390 | | }; |
391 | | handler(*reinterpret_cast<const RequestType*>(args), responseCallback); |
392 | | }); |
393 | | } |
394 | | |
395 | | template <typename F, typename T> |
396 | | Session::IsEvent<T> Session::registerHandler(F&& handler) { |
397 | | auto cb = [handler](const void* args) { |
398 | | handler(*reinterpret_cast<const T*>(args)); |
399 | | }; |
400 | | const TypeInfo* typeinfo = TypeOf<T>::type(); |
401 | | registerHandler(typeinfo, cb); |
402 | | } |
403 | | |
404 | | template <typename F, typename T> |
405 | | void Session::registerSentHandler(F&& handler) { |
406 | | auto cb = [handler](const void* response, const Error* error) { |
407 | | if (error != nullptr) { |
408 | | handler(ResponseOrError<T>(*error)); |
409 | | } else { |
410 | | handler(ResponseOrError<T>(*reinterpret_cast<const T*>(response))); |
411 | | } |
412 | | }; |
413 | | const TypeInfo* typeinfo = TypeOf<T>::type(); |
414 | | registerHandler(typeinfo, cb); |
415 | | } |
416 | | |
417 | | template <typename T, typename> |
418 | | future<ResponseOrError<typename T::Response>> Session::send(const T& request) { |
419 | | using Response = typename T::Response; |
420 | | promise<ResponseOrError<Response>> promise; |
421 | | auto sent = send(TypeOf<T>::type(), TypeOf<Response>::type(), &request, |
422 | | [=](const void* result, const Error* error) { |
423 | | if (error != nullptr) { |
424 | | promise.set_value(ResponseOrError<Response>(*error)); |
425 | | } else { |
426 | | promise.set_value(ResponseOrError<Response>( |
427 | | *reinterpret_cast<const Response*>(result))); |
428 | | } |
429 | | }); |
430 | | if (!sent) { |
431 | | promise.set_value(Error("Failed to send request")); |
432 | | } |
433 | | return promise.get_future(); |
434 | | } |
435 | | |
436 | | template <typename T, typename> |
437 | | void Session::send(const T& event) { |
438 | | const TypeInfo* typeinfo = TypeOf<T>::type(); |
439 | | send(typeinfo, &event); |
440 | | } |
441 | | |
442 | 0 | void Session::connect(const std::shared_ptr<ReaderWriter>& rw) { |
443 | 0 | connect(rw, rw); |
444 | 0 | } |
445 | | |
446 | | void Session::bind(const std::shared_ptr<dap::Reader>& r, |
447 | | const std::shared_ptr<dap::Writer>& w, |
448 | 0 | const ClosedHandler& onClose = {}) { |
449 | 0 | connect(r, w); |
450 | 0 | startProcessingMessages(onClose); |
451 | 0 | } |
452 | | |
453 | | void Session::bind(const std::shared_ptr<ReaderWriter>& rw, |
454 | 0 | const ClosedHandler& onClose = {}) { |
455 | 0 | bind(rw, rw, onClose); |
456 | 0 | } |
457 | | |
458 | | } // namespace dap |
459 | | |
460 | | #endif // dap_session_h |