Path: blob/master/Utilities/cmcppdap/include/dap/session.h
3158 views
// Copyright 2019 Google LLC1//2// Licensed under the Apache License, Version 2.0 (the "License");3// you may not use this file except in compliance with the License.4// You may obtain a copy of the License at5//6// https://www.apache.org/licenses/LICENSE-2.07//8// Unless required by applicable law or agreed to in writing, software9// distributed under the License is distributed on an "AS IS" BASIS,10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.11// See the License for the specific language governing permissions and12// limitations under the License.1314#ifndef dap_session_h15#define dap_session_h1617#include "future.h"18#include "io.h"19#include "traits.h"20#include "typeinfo.h"21#include "typeof.h"2223#include <functional>2425namespace dap {2627// Forward declarations28struct Request;29struct Response;30struct Event;3132////////////////////////////////////////////////////////////////////////////////33// Error34////////////////////////////////////////////////////////////////////////////////3536// Error represents an error message in response to a DAP request.37struct Error {38Error() = default;39Error(const std::string& error);40Error(const char* msg, ...);4142// operator bool() returns true if there is an error.43inline operator bool() const { return message.size() > 0; }4445std::string message; // empty represents success.46};4748////////////////////////////////////////////////////////////////////////////////49// ResponseOrError<T>50////////////////////////////////////////////////////////////////////////////////5152// ResponseOrError holds either the response to a DAP request or an error53// message.54template <typename T>55struct ResponseOrError {56using Request = T;5758inline ResponseOrError() = default;59inline ResponseOrError(const T& response);60inline ResponseOrError(T&& response);61inline ResponseOrError(const Error& error);62inline ResponseOrError(Error&& error);63inline ResponseOrError(const ResponseOrError& other);64inline ResponseOrError(ResponseOrError&& other);6566inline ResponseOrError& operator=(const ResponseOrError& other);67inline ResponseOrError& operator=(ResponseOrError&& other);6869T response;70Error error; // empty represents success.71};7273template <typename T>74ResponseOrError<T>::ResponseOrError(const T& resp) : response(resp) {}75template <typename T>76ResponseOrError<T>::ResponseOrError(T&& resp) : response(std::move(resp)) {}77template <typename T>78ResponseOrError<T>::ResponseOrError(const Error& err) : error(err) {}79template <typename T>80ResponseOrError<T>::ResponseOrError(Error&& err) : error(std::move(err)) {}81template <typename T>82ResponseOrError<T>::ResponseOrError(const ResponseOrError& other)83: response(other.response), error(other.error) {}84template <typename T>85ResponseOrError<T>::ResponseOrError(ResponseOrError&& other)86: response(std::move(other.response)), error(std::move(other.error)) {}87template <typename T>88ResponseOrError<T>& ResponseOrError<T>::operator=(89const ResponseOrError& other) {90response = other.response;91error = other.error;92return *this;93}94template <typename T>95ResponseOrError<T>& ResponseOrError<T>::operator=(ResponseOrError&& other) {96response = std::move(other.response);97error = std::move(other.error);98return *this;99}100101////////////////////////////////////////////////////////////////////////////////102// Session103////////////////////////////////////////////////////////////////////////////////104105// An enum flag that controls how the Session handles invalid data.106enum OnInvalidData {107// Ignore invalid data.108kIgnore,109// Close the underlying reader when invalid data is received.110kClose,111};112113// Session implements a DAP client or server endpoint.114// The general usage is as follows:115// (1) Create a session with Session::create().116// (2) Register request and event handlers with registerHandler().117// (3) Optionally register a protocol error handler with onError().118// (3) Bind the session to the remote endpoint with bind().119// (4) Send requests or events with send().120class Session {121template <typename F, int N>122using ParamType = traits::ParameterType<F, N>;123124template <typename T>125using IsRequest = traits::EnableIfIsType<dap::Request, T>;126127template <typename T>128using IsEvent = traits::EnableIfIsType<dap::Event, T>;129130template <typename F>131using IsRequestHandlerWithoutCallback = traits::EnableIf<132traits::CompatibleWith<F, std::function<void(dap::Request)>>::value>;133134template <typename F, typename CallbackType>135using IsRequestHandlerWithCallback = traits::EnableIf<traits::CompatibleWith<136F,137std::function<void(dap::Request, std::function<void(CallbackType)>)>>::138value>;139140public:141virtual ~Session();142143// ErrorHandler is the type of callback function used for reporting protocol144// errors.145using ErrorHandler = std::function<void(const char*)>;146147// ClosedHandler is the type of callback function used to signal that a148// connected endpoint has closed.149using ClosedHandler = std::function<void()>;150151// create() constructs and returns a new Session.152static std::unique_ptr<Session> create();153154// Sets how the Session handles invalid data.155virtual void setOnInvalidData(OnInvalidData) = 0;156157// onError() registers a error handler that will be called whenever a protocol158// error is encountered.159// Only one error handler can be bound at any given time, and later calls160// will replace the existing error handler.161virtual void onError(const ErrorHandler&) = 0;162163// registerHandler() registers a request handler for a specific request type.164// The function F must have one of the following signatures:165// ResponseOrError<ResponseType>(const RequestType&)166// ResponseType(const RequestType&)167// Error(const RequestType&)168template <typename F, typename RequestType = ParamType<F, 0>>169inline IsRequestHandlerWithoutCallback<F> registerHandler(F&& handler);170171// registerHandler() registers a request handler for a specific request type.172// The handler has a response callback function for the second argument of the173// handler function. This callback may be called after the handler has174// returned.175// The function F must have the following signature:176// void(const RequestType& request,177// std::function<void(ResponseType)> response)178template <typename F,179typename RequestType = ParamType<F, 0>,180typename ResponseType = typename RequestType::Response>181inline IsRequestHandlerWithCallback<F, ResponseType> registerHandler(182F&& handler);183184// registerHandler() registers a request handler for a specific request type.185// The handler has a response callback function for the second argument of the186// handler function. This callback may be called after the handler has187// returned.188// The function F must have the following signature:189// void(const RequestType& request,190// std::function<void(ResponseOrError<ResponseType>)> response)191template <typename F,192typename RequestType = ParamType<F, 0>,193typename ResponseType = typename RequestType::Response>194inline IsRequestHandlerWithCallback<F, ResponseOrError<ResponseType>>195registerHandler(F&& handler);196197// registerHandler() registers a event handler for a specific event type.198// The function F must have the following signature:199// void(const EventType&)200template <typename F, typename EventType = ParamType<F, 0>>201inline IsEvent<EventType> registerHandler(F&& handler);202203// registerSentHandler() registers the function F to be called when a response204// of the specific type has been sent.205// The function F must have the following signature:206// void(const ResponseOrError<ResponseType>&)207template <typename F,208typename ResponseType = typename ParamType<F, 0>::Request>209inline void registerSentHandler(F&& handler);210211// send() sends the request to the connected endpoint and returns a212// future that is assigned the request response or error.213template <typename T, typename = IsRequest<T>>214future<ResponseOrError<typename T::Response>> send(const T& request);215216// send() sends the event to the connected endpoint.217template <typename T, typename = IsEvent<T>>218void send(const T& event);219220// bind() connects this Session to an endpoint using connect(), and then221// starts processing incoming messages with startProcessingMessages().222// onClose is the optional callback which will be called when the session223// endpoint has been closed.224inline void bind(const std::shared_ptr<Reader>& reader,225const std::shared_ptr<Writer>& writer,226const ClosedHandler& onClose);227inline void bind(const std::shared_ptr<ReaderWriter>& readerWriter,228const ClosedHandler& onClose);229230//////////////////////////////////////////////////////////////////////////////231// Note:232// Methods and members below this point are for advanced usage, and are more233// likely to change signature than the methods above.234// The methods above this point should be sufficient for most use cases.235//////////////////////////////////////////////////////////////////////////////236237// connect() connects this Session to an endpoint.238// connect() can only be called once. Repeated calls will raise an error, but239// otherwise will do nothing.240// Note: This method is used for explicit control over message handling.241// Most users will use bind() instead of calling this method directly.242virtual void connect(const std::shared_ptr<Reader>&,243const std::shared_ptr<Writer>&) = 0;244inline void connect(const std::shared_ptr<ReaderWriter>&);245246// startProcessingMessages() starts a new thread to receive and dispatch247// incoming messages.248// onClose is the optional callback which will be called when the session249// endpoint has been closed.250// Note: This method is used for explicit control over message handling.251// Most users will use bind() instead of calling this method directly.252virtual void startProcessingMessages(const ClosedHandler& onClose = {}) = 0;253254// getPayload() blocks until the next incoming message is received, returning255// the payload or an empty function if the connection was lost. The returned256// payload is function that can be called on any thread to dispatch the257// message to the Session handler.258// Note: This method is used for explicit control over message handling.259// Most users will use bind() instead of calling this method directly.260virtual std::function<void()> getPayload() = 0;261262// The callback function type called when a request handler is invoked, and263// the request returns a successful result.264// 'responseTypeInfo' is the type information of the response data structure.265// 'responseData' is a pointer to response payload data.266using RequestHandlerSuccessCallback =267std::function<void(const TypeInfo* responseTypeInfo,268const void* responseData)>;269270// The callback function type used to notify when a DAP request fails.271// 'responseTypeInfo' is the type information of the response data structure.272// 'message' is the error message273using RequestHandlerErrorCallback =274std::function<void(const TypeInfo* responseTypeInfo,275const Error& message)>;276277// The callback function type used to invoke a request handler.278// 'request' is a pointer to the request data structure279// 'onSuccess' is the function to call if the request completed succesfully.280// 'onError' is the function to call if the request failed.281// For each call of the request handler, 'onSuccess' or 'onError' must be282// called exactly once.283using GenericRequestHandler =284std::function<void(const void* request,285const RequestHandlerSuccessCallback& onSuccess,286const RequestHandlerErrorCallback& onError)>;287288// The callback function type used to handle a response to a request.289// 'response' is a pointer to the response data structure. May be nullptr.290// 'error' is a pointer to the reponse error message. May be nullptr.291// One of 'data' or 'error' will be nullptr.292using GenericResponseHandler =293std::function<void(const void* response, const Error* error)>;294295// The callback function type used to handle an event.296// 'event' is a pointer to the event data structure.297using GenericEventHandler = std::function<void(const void* event)>;298299// The callback function type used to notify when a response has been sent300// from this session endpoint.301// 'response' is a pointer to the response data structure.302// 'error' is a pointer to the reponse error message. May be nullptr.303using GenericResponseSentHandler =304std::function<void(const void* response, const Error* error)>;305306// registerHandler() registers 'handler' as the request handler callback for307// requests of the type 'typeinfo'.308virtual void registerHandler(const TypeInfo* typeinfo,309const GenericRequestHandler& handler) = 0;310311// registerHandler() registers 'handler' as the event handler callback for312// events of the type 'typeinfo'.313virtual void registerHandler(const TypeInfo* typeinfo,314const GenericEventHandler& handler) = 0;315316// registerHandler() registers 'handler' as the response-sent handler function317// which is called whenever a response of the type 'typeinfo' is sent from318// this session endpoint.319virtual void registerHandler(const TypeInfo* typeinfo,320const GenericResponseSentHandler& handler) = 0;321322// send() sends a request to the remote endpoint.323// 'requestTypeInfo' is the type info of the request data structure.324// 'requestTypeInfo' is the type info of the response data structure.325// 'request' is a pointer to the request data structure.326// 'responseHandler' is the handler function for the response.327virtual bool send(const dap::TypeInfo* requestTypeInfo,328const dap::TypeInfo* responseTypeInfo,329const void* request,330const GenericResponseHandler& responseHandler) = 0;331332// send() sends an event to the remote endpoint.333// 'eventTypeInfo' is the type info for the event data structure.334// 'event' is a pointer to the event data structure.335virtual bool send(const TypeInfo* eventTypeInfo, const void* event) = 0;336};337338template <typename F, typename RequestType>339Session::IsRequestHandlerWithoutCallback<F> Session::registerHandler(340F&& handler) {341using ResponseType = typename RequestType::Response;342const TypeInfo* typeinfo = TypeOf<RequestType>::type();343registerHandler(typeinfo,344[handler](const void* args,345const RequestHandlerSuccessCallback& onSuccess,346const RequestHandlerErrorCallback& onError) {347ResponseOrError<ResponseType> res =348handler(*reinterpret_cast<const RequestType*>(args));349if (res.error) {350onError(TypeOf<ResponseType>::type(), res.error);351} else {352onSuccess(TypeOf<ResponseType>::type(), &res.response);353}354});355}356357template <typename F, typename RequestType, typename ResponseType>358Session::IsRequestHandlerWithCallback<F, ResponseType> Session::registerHandler(359F&& handler) {360using CallbackType = ParamType<F, 1>;361registerHandler(362TypeOf<RequestType>::type(),363[handler](const void* args,364const RequestHandlerSuccessCallback& onSuccess,365const RequestHandlerErrorCallback&) {366CallbackType responseCallback = [onSuccess](const ResponseType& res) {367onSuccess(TypeOf<ResponseType>::type(), &res);368};369handler(*reinterpret_cast<const RequestType*>(args), responseCallback);370});371}372373template <typename F, typename RequestType, typename ResponseType>374Session::IsRequestHandlerWithCallback<F, ResponseOrError<ResponseType>>375Session::registerHandler(F&& handler) {376using CallbackType = ParamType<F, 1>;377registerHandler(378TypeOf<RequestType>::type(),379[handler](const void* args,380const RequestHandlerSuccessCallback& onSuccess,381const RequestHandlerErrorCallback& onError) {382CallbackType responseCallback =383[onError, onSuccess](const ResponseOrError<ResponseType>& res) {384if (res.error) {385onError(TypeOf<ResponseType>::type(), res.error);386} else {387onSuccess(TypeOf<ResponseType>::type(), &res.response);388}389};390handler(*reinterpret_cast<const RequestType*>(args), responseCallback);391});392}393394template <typename F, typename T>395Session::IsEvent<T> Session::registerHandler(F&& handler) {396auto cb = [handler](const void* args) {397handler(*reinterpret_cast<const T*>(args));398};399const TypeInfo* typeinfo = TypeOf<T>::type();400registerHandler(typeinfo, cb);401}402403template <typename F, typename T>404void Session::registerSentHandler(F&& handler) {405auto cb = [handler](const void* response, const Error* error) {406if (error != nullptr) {407handler(ResponseOrError<T>(*error));408} else {409handler(ResponseOrError<T>(*reinterpret_cast<const T*>(response)));410}411};412const TypeInfo* typeinfo = TypeOf<T>::type();413registerHandler(typeinfo, cb);414}415416template <typename T, typename>417future<ResponseOrError<typename T::Response>> Session::send(const T& request) {418using Response = typename T::Response;419promise<ResponseOrError<Response>> promise;420auto sent = send(TypeOf<T>::type(), TypeOf<Response>::type(), &request,421[=](const void* result, const Error* error) {422if (error != nullptr) {423promise.set_value(ResponseOrError<Response>(*error));424} else {425promise.set_value(ResponseOrError<Response>(426*reinterpret_cast<const Response*>(result)));427}428});429if (!sent) {430promise.set_value(Error("Failed to send request"));431}432return promise.get_future();433}434435template <typename T, typename>436void Session::send(const T& event) {437const TypeInfo* typeinfo = TypeOf<T>::type();438send(typeinfo, &event);439}440441void Session::connect(const std::shared_ptr<ReaderWriter>& rw) {442connect(rw, rw);443}444445void Session::bind(const std::shared_ptr<dap::Reader>& r,446const std::shared_ptr<dap::Writer>& w,447const ClosedHandler& onClose = {}) {448connect(r, w);449startProcessingMessages(onClose);450}451452void Session::bind(const std::shared_ptr<ReaderWriter>& rw,453const ClosedHandler& onClose = {}) {454bind(rw, rw, onClose);455}456457} // namespace dap458459#endif // dap_session_h460461462