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
26namespace dap {
27
28// Forward declarations
29struct Request;
30struct Response;
31struct Event;
32
33////////////////////////////////////////////////////////////////////////////////
34// Error
35////////////////////////////////////////////////////////////////////////////////
36
37// Error represents an error message in response to a DAP request.
38struct 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 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.
55template <typename T>
56struct 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
74template <typename T>
75ResponseOrError<T>::ResponseOrError(const T& resp) : response(resp) {}
76template <typename T>
77ResponseOrError<T>::ResponseOrError(T&& resp) : response(std::move(resp)) {}
78template <typename T>
79ResponseOrError<T>::ResponseOrError(const Error& err) : error(err) {}
80template <typename T>
81ResponseOrError<T>::ResponseOrError(Error&& err) : error(std::move(err)) {}
82template <typename T>
83ResponseOrError<T>::ResponseOrError(const ResponseOrError& other)
84 : response(other.response), error(other.error) {}
85template <typename T>
86ResponseOrError<T>::ResponseOrError(ResponseOrError&& other)
87 : response(std::move(other.response)), error(std::move(other.error)) {}
88template <typename T>
89ResponseOrError<T>& ResponseOrError<T>::operator=(
90 const ResponseOrError& other) {
91 response = other.response;
92 error = other.error;
93 return *this;
94}
95template <typename T>
96ResponseOrError<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// Session implements a DAP client or server endpoint.
107// The general usage is as follows:
108// (1) Create a session with Session::create().
109// (2) Register request and event handlers with registerHandler().
110// (3) Optionally register a protocol error handler with onError().
111// (3) Bind the session to the remote endpoint with bind().
112// (4) Send requests or events with send().
113class Session {
114 template <typename F, int N>
115 using ParamType = traits::ParameterType<F, N>;
116
117 template <typename T>
118 using IsRequest = traits::EnableIfIsType<dap::Request, T>;
119
120 template <typename T>
121 using IsEvent = traits::EnableIfIsType<dap::Event, T>;
122
123 template <typename F>
124 using IsRequestHandlerWithoutCallback = traits::EnableIf<
125 traits::CompatibleWith<F, std::function<void(dap::Request)>>::value>;
126
127 template <typename F, typename CallbackType>
128 using IsRequestHandlerWithCallback = traits::EnableIf<traits::CompatibleWith<
129 F,
130 std::function<void(dap::Request, std::function<void(CallbackType)>)>>::
131 value>;
132
133 public:
134 virtual ~Session();
135
136 // ErrorHandler is the type of callback function used for reporting protocol
137 // errors.
138 using ErrorHandler = std::function<void(const char*)>;
139
140 // create() constructs and returns a new Session.
141 static std::unique_ptr<Session> create();
142
143 // onError() registers a error handler that will be called whenever a protocol
144 // error is encountered.
145 // Only one error handler can be bound at any given time, and later calls
146 // will replace the existing error handler.
147 virtual void onError(const ErrorHandler&) = 0;
148
149 // registerHandler() registers a request handler for a specific request type.
150 // The function F must have one of the following signatures:
151 // ResponseOrError<ResponseType>(const RequestType&)
152 // ResponseType(const RequestType&)
153 // Error(const RequestType&)
154 template <typename F, typename RequestType = ParamType<F, 0>>
155 inline IsRequestHandlerWithoutCallback<F> registerHandler(F&& handler);
156
157 // registerHandler() registers a request handler for a specific request type.
158 // The handler has a response callback function for the second argument of the
159 // handler function. This callback may be called after the handler has
160 // returned.
161 // The function F must have the following signature:
162 // void(const RequestType& request,
163 // std::function<void(ResponseType)> response)
164 template <typename F,
165 typename RequestType = ParamType<F, 0>,
166 typename ResponseType = typename RequestType::Response>
167 inline IsRequestHandlerWithCallback<F, ResponseType> registerHandler(
168 F&& handler);
169
170 // registerHandler() registers a request handler for a specific request type.
171 // The handler has a response callback function for the second argument of the
172 // handler function. This callback may be called after the handler has
173 // returned.
174 // The function F must have the following signature:
175 // void(const RequestType& request,
176 // std::function<void(ResponseOrError<ResponseType>)> response)
177 template <typename F,
178 typename RequestType = ParamType<F, 0>,
179 typename ResponseType = typename RequestType::Response>
180 inline IsRequestHandlerWithCallback<F, ResponseOrError<ResponseType>>
181 registerHandler(F&& handler);
182
183 // registerHandler() registers a event handler for a specific event type.
184 // The function F must have the following signature:
185 // void(const EventType&)
186 template <typename F, typename EventType = ParamType<F, 0>>
187 inline IsEvent<EventType> registerHandler(F&& handler);
188
189 // registerSentHandler() registers the function F to be called when a response
190 // of the specific type has been sent.
191 // The function F must have the following signature:
192 // void(const ResponseOrError<ResponseType>&)
193 template <typename F,
194 typename ResponseType = typename ParamType<F, 0>::Request>
195 inline void registerSentHandler(F&& handler);
196
197 // send() sends the request to the connected endpoint and returns a
198 // future that is assigned the request response or error.
199 template <typename T, typename = IsRequest<T>>
200 future<ResponseOrError<typename T::Response>> send(const T& request);
201
202 // send() sends the event to the connected endpoint.
203 template <typename T, typename = IsEvent<T>>
204 void send(const T& event);
205
206 // bind() connects this Session to an endpoint using connect(), and then
207 // starts processing incoming messages with startProcessingMessages().
208 inline void bind(const std::shared_ptr<Reader>&,
209 const std::shared_ptr<Writer>&);
210 inline void bind(const std::shared_ptr<ReaderWriter>&);
211
212 //////////////////////////////////////////////////////////////////////////////
213 // Note:
214 // Methods and members below this point are for advanced usage, and are more
215 // likely to change signature than the methods above.
216 // The methods above this point should be sufficient for most use cases.
217 //////////////////////////////////////////////////////////////////////////////
218
219 // connect() connects this Session to an endpoint.
220 // connect() can only be called once. Repeated calls will raise an error, but
221 // otherwise will do nothing.
222 // Note: This method is used for explicit control over message handling.
223 // Most users will use bind() instead of calling this method directly.
224 virtual void connect(const std::shared_ptr<Reader>&,
225 const std::shared_ptr<Writer>&) = 0;
226 inline void connect(const std::shared_ptr<ReaderWriter>&);
227
228 // startProcessingMessages() starts a new thread to receive and dispatch
229 // incoming messages.
230 // Note: This method is used for explicit control over message handling.
231 // Most users will use bind() instead of calling this method directly.
232 virtual void startProcessingMessages() = 0;
233
234 // getPayload() blocks until the next incoming message is received, returning
235 // the payload or an empty function if the connection was lost. The returned
236 // payload is function that can be called on any thread to dispatch the
237 // message to the Session handler.
238 // Note: This method is used for explicit control over message handling.
239 // Most users will use bind() instead of calling this method directly.
240 virtual std::function<void()> getPayload() = 0;
241
242 // The callback function type called when a request handler is invoked, and
243 // the request returns a successful result.
244 // 'responseTypeInfo' is the type information of the response data structure.
245 // 'responseData' is a pointer to response payload data.
246 using RequestHandlerSuccessCallback =
247 std::function<void(const TypeInfo* responseTypeInfo,
248 const void* responseData)>;
249
250 // The callback function type used to notify when a DAP request fails.
251 // 'responseTypeInfo' is the type information of the response data structure.
252 // 'message' is the error message
253 using RequestHandlerErrorCallback =
254 std::function<void(const TypeInfo* responseTypeInfo,
255 const Error& message)>;
256
257 // The callback function type used to invoke a request handler.
258 // 'request' is a pointer to the request data structure
259 // 'onSuccess' is the function to call if the request completed succesfully.
260 // 'onError' is the function to call if the request failed.
261 // For each call of the request handler, 'onSuccess' or 'onError' must be
262 // called exactly once.
263 using GenericRequestHandler =
264 std::function<void(const void* request,
265 const RequestHandlerSuccessCallback& onSuccess,
266 const RequestHandlerErrorCallback& onError)>;
267
268 // The callback function type used to handle a response to a request.
269 // 'response' is a pointer to the response data structure. May be nullptr.
270 // 'error' is a pointer to the reponse error message. May be nullptr.
271 // One of 'data' or 'error' will be nullptr.
272 using GenericResponseHandler =
273 std::function<void(const void* response, const Error* error)>;
274
275 // The callback function type used to handle an event.
276 // 'event' is a pointer to the event data structure.
277 using GenericEventHandler = std::function<void(const void* event)>;
278
279 // The callback function type used to notify when a response has been sent
280 // from this session endpoint.
281 // 'response' is a pointer to the response data structure.
282 // 'error' is a pointer to the reponse error message. May be nullptr.
283 using GenericResponseSentHandler =
284 std::function<void(const void* response, const Error* error)>;
285
286 // registerHandler() registers 'handler' as the request handler callback for
287 // requests of the type 'typeinfo'.
288 virtual void registerHandler(const TypeInfo* typeinfo,
289 const GenericRequestHandler& handler) = 0;
290
291 // registerHandler() registers 'handler' as the event handler callback for
292 // events of the type 'typeinfo'.
293 virtual void registerHandler(const TypeInfo* typeinfo,
294 const GenericEventHandler& handler) = 0;
295
296 // registerHandler() registers 'handler' as the response-sent handler function
297 // which is called whenever a response of the type 'typeinfo' is sent from
298 // this session endpoint.
299 virtual void registerHandler(const TypeInfo* typeinfo,
300 const GenericResponseSentHandler& handler) = 0;
301
302 // send() sends a request to the remote endpoint.
303 // 'requestTypeInfo' is the type info of the request data structure.
304 // 'requestTypeInfo' is the type info of the response data structure.
305 // 'request' is a pointer to the request data structure.
306 // 'responseHandler' is the handler function for the response.
307 virtual bool send(const dap::TypeInfo* requestTypeInfo,
308 const dap::TypeInfo* responseTypeInfo,
309 const void* request,
310 const GenericResponseHandler& responseHandler) = 0;
311
312 // send() sends an event to the remote endpoint.
313 // 'eventTypeInfo' is the type info for the event data structure.
314 // 'event' is a pointer to the event data structure.
315 virtual bool send(const TypeInfo* eventTypeInfo, const void* event) = 0;
316
317 // mozart:sometime we should send something by ourself.
318 virtual bool send(const std::string& s) = 0;
319};
320
321template <typename F, typename RequestType>
322Session::IsRequestHandlerWithoutCallback<F> Session::registerHandler(
323 F&& handler) {
324 using ResponseType = typename RequestType::Response;
325 const TypeInfo* typeinfo = TypeOf<RequestType>::type();
326 registerHandler(typeinfo,
327 [handler](const void* args,
328 const RequestHandlerSuccessCallback& onSuccess,
329 const RequestHandlerErrorCallback& onError) {
330 ResponseOrError<ResponseType> res =
331 handler(*reinterpret_cast<const RequestType*>(args));
332 if (res.error) {
333 onError(TypeOf<ResponseType>::type(), res.error);
334 } else {
335 onSuccess(TypeOf<ResponseType>::type(), &res.response);
336 }
337 });
338}
339
340template <typename F, typename RequestType, typename ResponseType>
341Session::IsRequestHandlerWithCallback<F, ResponseType> Session::registerHandler(
342 F&& handler) {
343 using CallbackType = ParamType<F, 1>;
344 registerHandler(
345 TypeOf<RequestType>::type(),
346 [handler](const void* args,
347 const RequestHandlerSuccessCallback& onSuccess,
348 const RequestHandlerErrorCallback&) {
349 CallbackType responseCallback = [onSuccess](const ResponseType& res) {
350 onSuccess(TypeOf<ResponseType>::type(), &res);
351 };
352 handler(*reinterpret_cast<const RequestType*>(args), responseCallback);
353 });
354}
355
356template <typename F, typename RequestType, typename ResponseType>
357Session::IsRequestHandlerWithCallback<F, ResponseOrError<ResponseType>>
358Session::registerHandler(F&& handler) {
359 using CallbackType = ParamType<F, 1>;
360 registerHandler(
361 TypeOf<RequestType>::type(),
362 [handler](const void* args,
363 const RequestHandlerSuccessCallback& onSuccess,
364 const RequestHandlerErrorCallback& onError) {
365 CallbackType responseCallback =
366 [onError, onSuccess](const ResponseOrError<ResponseType>& res) {
367 if (res.error) {
368 onError(TypeOf<ResponseType>::type(), res.error);
369 } else {
370 onSuccess(TypeOf<ResponseType>::type(), &res.response);
371 }
372 };
373 handler(*reinterpret_cast<const RequestType*>(args), responseCallback);
374 });
375}
376
377template <typename F, typename T>
378Session::IsEvent<T> Session::registerHandler(F&& handler) {
379 auto cb = [handler](const void* args) {
380 handler(*reinterpret_cast<const T*>(args));
381 };
382 const TypeInfo* typeinfo = TypeOf<T>::type();
383 registerHandler(typeinfo, cb);
384}
385
386template <typename F, typename T>
387void Session::registerSentHandler(F&& handler) {
388 auto cb = [handler](const void* response, const Error* error) {
389 if (error != nullptr) {
390 handler(ResponseOrError<T>(*error));
391 } else {
392 handler(ResponseOrError<T>(*reinterpret_cast<const T*>(response)));
393 }
394 };
395 const TypeInfo* typeinfo = TypeOf<T>::type();
396 registerHandler(typeinfo, cb);
397}
398
399template <typename T, typename>
400future<ResponseOrError<typename T::Response>> Session::send(const T& request) {
401 using Response = typename T::Response;
402 promise<ResponseOrError<Response>> promise;
403 auto sent = send(TypeOf<T>::type(), TypeOf<Response>::type(), &request,
404 [=](const void* result, const Error* error) {
405 if (error != nullptr) {
406 promise.set_value(ResponseOrError<Response>(*error));
407 } else {
408 promise.set_value(ResponseOrError<Response>(
409 *reinterpret_cast<const Response*>(result)));
410 }
411 });
412 if (!sent) {
413 promise.set_value(Error("Failed to send request"));
414 }
415 return promise.get_future();
416}
417
418template <typename T, typename>
419void Session::send(const T& event) {
420 const TypeInfo* typeinfo = TypeOf<T>::type();
421 send(typeinfo, &event);
422}
423
424void Session::connect(const std::shared_ptr<ReaderWriter>& rw) {
425 connect(rw, rw);
426}
427
428void Session::bind(const std::shared_ptr<dap::Reader>& r,
429 const std::shared_ptr<dap::Writer>& w) {
430 connect(r, w);
431 startProcessingMessages();
432}
433
434void Session::bind(const std::shared_ptr<ReaderWriter>& rw) {
435 bind(rw, rw);
436}
437
438} // namespace dap
439
440#endif // dap_session_h
441