| 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 | 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 | // 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(). |
| 113 | class 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 | |
| 321 | template <typename F, typename RequestType> |
| 322 | Session::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 | |
| 340 | template <typename F, typename RequestType, typename ResponseType> |
| 341 | Session::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 | |
| 356 | template <typename F, typename RequestType, typename ResponseType> |
| 357 | Session::IsRequestHandlerWithCallback<F, ResponseOrError<ResponseType>> |
| 358 | Session::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 | |
| 377 | template <typename F, typename T> |
| 378 | Session::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 | |
| 386 | template <typename F, typename T> |
| 387 | void 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 | |
| 399 | template <typename T, typename> |
| 400 | future<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 | |
| 418 | template <typename T, typename> |
| 419 | void Session::send(const T& event) { |
| 420 | const TypeInfo* typeinfo = TypeOf<T>::type(); |
| 421 | send(typeinfo, &event); |
| 422 | } |
| 423 | |
| 424 | void Session::connect(const std::shared_ptr<ReaderWriter>& rw) { |
| 425 | connect(rw, rw); |
| 426 | } |
| 427 | |
| 428 | void 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 | |
| 434 | void Session::bind(const std::shared_ptr<ReaderWriter>& rw) { |
| 435 | bind(rw, rw); |
| 436 | } |
| 437 | |
| 438 | } // namespace dap |
| 439 | |
| 440 | #endif // dap_session_h |
| 441 | |