/
niceSOFT
/
cmake
Обзор
Документация
Войти
/
niceSOFT
/
cmake
Код
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
Utilities/cmcppdap/include/dap/session.h
460 строк
19 KB
Brad King
Merge branch 'upstream-cppdap' into update-cppdap
18 авг 2023, 16:00
18 авг 2023, 16:00
90df1e5
Код
Авторство
О чём код?
// Copyright 2019 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef dap_session_h #define dap_session_h #include "future.h" #include "io.h" #include "traits.h" #include "typeinfo.h" #include "typeof.h" #include <functional> namespace dap { // Forward declarations struct Request; struct Response; struct Event; //////////////////////////////////////////////////////////////////////////////// // Error //////////////////////////////////////////////////////////////////////////////// // Error represents an error message in response to a DAP request. struct Error { Error() = default; Error(const std::string& error); Error(const char* msg, ...); // operator bool() returns true if there is an error. inline operator bool() const { return message.size() > 0; } std::string message; // empty represents success. }; //////////////////////////////////////////////////////////////////////////////// // ResponseOrError<T> //////////////////////////////////////////////////////////////////////////////// // ResponseOrError holds either the response to a DAP request or an error // message. template <typename T> struct ResponseOrError { using Request = T; inline ResponseOrError() = default; inline ResponseOrError(const T& response); inline ResponseOrError(T&& response); inline ResponseOrError(const Error& error); inline ResponseOrError(Error&& error); inline ResponseOrError(const ResponseOrError& other); inline ResponseOrError(ResponseOrError&& other); inline ResponseOrError& operator=(const ResponseOrError& other); inline ResponseOrError& operator=(ResponseOrError&& other); T response; Error error; // empty represents success. }; template <typename T> ResponseOrError<T>::ResponseOrError(const T& resp) : response(resp) {} template <typename T> ResponseOrError<T>::ResponseOrError(T&& resp) : response(std::move(resp)) {} template <typename T> ResponseOrError<T>::ResponseOrError(const Error& err) : error(err) {} template <typename T> ResponseOrError<T>::ResponseOrError(Error&& err) : error(std::move(err)) {} template <typename T> ResponseOrError<T>::ResponseOrError(const ResponseOrError& other) : response(other.response), error(other.error) {} template <typename T> ResponseOrError<T>::ResponseOrError(ResponseOrError&& other) : response(std::move(other.response)), error(std::move(other.error)) {} template <typename T> ResponseOrError<T>& ResponseOrError<T>::operator=( const ResponseOrError& other) { response = other.response; error = other.error; return *this; } template <typename T> ResponseOrError<T>& ResponseOrError<T>::operator=(ResponseOrError&& other) { response = std::move(other.response); error = std::move(other.error); return *this; } //////////////////////////////////////////////////////////////////////////////// // Session //////////////////////////////////////////////////////////////////////////////// // An enum flag that controls how the Session handles invalid data. enum OnInvalidData { // Ignore invalid data. kIgnore, // Close the underlying reader when invalid data is received. kClose, }; // Session implements a DAP client or server endpoint. // The general usage is as follows: // (1) Create a session with Session::create(). // (2) Register request and event handlers with registerHandler(). // (3) Optionally register a protocol error handler with onError(). // (3) Bind the session to the remote endpoint with bind(). // (4) Send requests or events with send(). class Session { template <typename F, int N> using ParamType = traits::ParameterType<F, N>; template <typename T> using IsRequest = traits::EnableIfIsType<dap::Request, T>; template <typename T> using IsEvent = traits::EnableIfIsType<dap::Event, T>; template <typename F> using IsRequestHandlerWithoutCallback = traits::EnableIf< traits::CompatibleWith<F, std::function<void(dap::Request)>>::value>; template <typename F, typename CallbackType> using IsRequestHandlerWithCallback = traits::EnableIf<traits::CompatibleWith< F, std::function<void(dap::Request, std::function<void(CallbackType)>)>>:: value>; public: virtual ~Session(); // ErrorHandler is the type of callback function used for reporting protocol // errors. using ErrorHandler = std::function<void(const char*)>; // ClosedHandler is the type of callback function used to signal that a // connected endpoint has closed. using ClosedHandler = std::function<void()>; // create() constructs and returns a new Session. static std::unique_ptr<Session> create(); // Sets how the Session handles invalid data. virtual void setOnInvalidData(OnInvalidData) = 0; // onError() registers a error handler that will be called whenever a protocol // error is encountered. // Only one error handler can be bound at any given time, and later calls // will replace the existing error handler. virtual void onError(const ErrorHandler&) = 0; // registerHandler() registers a request handler for a specific request type. // The function F must have one of the following signatures: // ResponseOrError<ResponseType>(const RequestType&) // ResponseType(const RequestType&) // Error(const RequestType&) template <typename F, typename RequestType = ParamType<F, 0>> inline IsRequestHandlerWithoutCallback<F> registerHandler(F&& handler); // registerHandler() registers a request handler for a specific request type. // The handler has a response callback function for the second argument of the // handler function. This callback may be called after the handler has // returned. // The function F must have the following signature: // void(const RequestType& request, // std::function<void(ResponseType)> response) template <typename F, typename RequestType = ParamType<F, 0>, typename ResponseType = typename RequestType::Response> inline IsRequestHandlerWithCallback<F, ResponseType> registerHandler( F&& handler); // registerHandler() registers a request handler for a specific request type. // The handler has a response callback function for the second argument of the // handler function. This callback may be called after the handler has // returned. // The function F must have the following signature: // void(const RequestType& request, // std::function<void(ResponseOrError<ResponseType>)> response) template <typename F, typename RequestType = ParamType<F, 0>, typename ResponseType = typename RequestType::Response> inline IsRequestHandlerWithCallback<F, ResponseOrError<ResponseType>> registerHandler(F&& handler); // registerHandler() registers a event handler for a specific event type. // The function F must have the following signature: // void(const EventType&) template <typename F, typename EventType = ParamType<F, 0>> inline IsEvent<EventType> registerHandler(F&& handler); // registerSentHandler() registers the function F to be called when a response // of the specific type has been sent. // The function F must have the following signature: // void(const ResponseOrError<ResponseType>&) template <typename F, typename ResponseType = typename ParamType<F, 0>::Request> inline void registerSentHandler(F&& handler); // send() sends the request to the connected endpoint and returns a // future that is assigned the request response or error. template <typename T, typename = IsRequest<T>> future<ResponseOrError<typename T::Response>> send(const T& request); // send() sends the event to the connected endpoint. template <typename T, typename = IsEvent<T>> void send(const T& event); // bind() connects this Session to an endpoint using connect(), and then // starts processing incoming messages with startProcessingMessages(). // onClose is the optional callback which will be called when the session // endpoint has been closed. inline void bind(const std::shared_ptr<Reader>& reader, const std::shared_ptr<Writer>& writer, const ClosedHandler& onClose); inline void bind(const std::shared_ptr<ReaderWriter>& readerWriter, const ClosedHandler& onClose); ////////////////////////////////////////////////////////////////////////////// // Note: // Methods and members below this point are for advanced usage, and are more // likely to change signature than the methods above. // The methods above this point should be sufficient for most use cases. ////////////////////////////////////////////////////////////////////////////// // connect() connects this Session to an endpoint. // connect() can only be called once. Repeated calls will raise an error, but // otherwise will do nothing. // Note: This method is used for explicit control over message handling. // Most users will use bind() instead of calling this method directly. virtual void connect(const std::shared_ptr<Reader>&, const std::shared_ptr<Writer>&) = 0; inline void connect(const std::shared_ptr<ReaderWriter>&); // startProcessingMessages() starts a new thread to receive and dispatch // incoming messages. // onClose is the optional callback which will be called when the session // endpoint has been closed. // Note: This method is used for explicit control over message handling. // Most users will use bind() instead of calling this method directly. virtual void startProcessingMessages(const ClosedHandler& onClose = {}) = 0; // getPayload() blocks until the next incoming message is received, returning // the payload or an empty function if the connection was lost. The returned // payload is function that can be called on any thread to dispatch the // message to the Session handler. // Note: This method is used for explicit control over message handling. // Most users will use bind() instead of calling this method directly. virtual std::function<void()> getPayload() = 0; // The callback function type called when a request handler is invoked, and // the request returns a successful result. // 'responseTypeInfo' is the type information of the response data structure. // 'responseData' is a pointer to response payload data. using RequestHandlerSuccessCallback = std::function<void(const TypeInfo* responseTypeInfo, const void* responseData)>; // The callback function type used to notify when a DAP request fails. // 'responseTypeInfo' is the type information of the response data structure. // 'message' is the error message using RequestHandlerErrorCallback = std::function<void(const TypeInfo* responseTypeInfo, const Error& message)>; // The callback function type used to invoke a request handler. // 'request' is a pointer to the request data structure // 'onSuccess' is the function to call if the request completed succesfully. // 'onError' is the function to call if the request failed. // For each call of the request handler, 'onSuccess' or 'onError' must be // called exactly once. using GenericRequestHandler = std::function<void(const void* request, const RequestHandlerSuccessCallback& onSuccess, const RequestHandlerErrorCallback& onError)>; // The callback function type used to handle a response to a request. // 'response' is a pointer to the response data structure. May be nullptr. // 'error' is a pointer to the reponse error message. May be nullptr. // One of 'data' or 'error' will be nullptr. using GenericResponseHandler = std::function<void(const void* response, const Error* error)>; // The callback function type used to handle an event. // 'event' is a pointer to the event data structure. using GenericEventHandler = std::function<void(const void* event)>; // The callback function type used to notify when a response has been sent // from this session endpoint. // 'response' is a pointer to the response data structure. // 'error' is a pointer to the reponse error message. May be nullptr. using GenericResponseSentHandler = std::function<void(const void* response, const Error* error)>; // registerHandler() registers 'handler' as the request handler callback for // requests of the type 'typeinfo'. virtual void registerHandler(const TypeInfo* typeinfo, const GenericRequestHandler& handler) = 0; // registerHandler() registers 'handler' as the event handler callback for // events of the type 'typeinfo'. virtual void registerHandler(const TypeInfo* typeinfo, const GenericEventHandler& handler) = 0; // registerHandler() registers 'handler' as the response-sent handler function // which is called whenever a response of the type 'typeinfo' is sent from // this session endpoint. virtual void registerHandler(const TypeInfo* typeinfo, const GenericResponseSentHandler& handler) = 0; // send() sends a request to the remote endpoint. // 'requestTypeInfo' is the type info of the request data structure. // 'requestTypeInfo' is the type info of the response data structure. // 'request' is a pointer to the request data structure. // 'responseHandler' is the handler function for the response. virtual bool send(const dap::TypeInfo* requestTypeInfo, const dap::TypeInfo* responseTypeInfo, const void* request, const GenericResponseHandler& responseHandler) = 0; // send() sends an event to the remote endpoint. // 'eventTypeInfo' is the type info for the event data structure. // 'event' is a pointer to the event data structure. virtual bool send(const TypeInfo* eventTypeInfo, const void* event) = 0; }; template <typename F, typename RequestType> Session::IsRequestHandlerWithoutCallback<F> Session::registerHandler( F&& handler) { using ResponseType = typename RequestType::Response; const TypeInfo* typeinfo = TypeOf<RequestType>::type(); registerHandler(typeinfo, [handler](const void* args, const RequestHandlerSuccessCallback& onSuccess, const RequestHandlerErrorCallback& onError) { ResponseOrError<ResponseType> res = handler(*reinterpret_cast<const RequestType*>(args)); if (res.error) { onError(TypeOf<ResponseType>::type(), res.error); } else { onSuccess(TypeOf<ResponseType>::type(), &res.response); } }); } template <typename F, typename RequestType, typename ResponseType> Session::IsRequestHandlerWithCallback<F, ResponseType> Session::registerHandler( F&& handler) { using CallbackType = ParamType<F, 1>; registerHandler( TypeOf<RequestType>::type(), [handler](const void* args, const RequestHandlerSuccessCallback& onSuccess, const RequestHandlerErrorCallback&) { CallbackType responseCallback = [onSuccess](const ResponseType& res) { onSuccess(TypeOf<ResponseType>::type(), &res); }; handler(*reinterpret_cast<const RequestType*>(args), responseCallback); }); } template <typename F, typename RequestType, typename ResponseType> Session::IsRequestHandlerWithCallback<F, ResponseOrError<ResponseType>> Session::registerHandler(F&& handler) { using CallbackType = ParamType<F, 1>; registerHandler( TypeOf<RequestType>::type(), [handler](const void* args, const RequestHandlerSuccessCallback& onSuccess, const RequestHandlerErrorCallback& onError) { CallbackType responseCallback = [onError, onSuccess](const ResponseOrError<ResponseType>& res) { if (res.error) { onError(TypeOf<ResponseType>::type(), res.error); } else { onSuccess(TypeOf<ResponseType>::type(), &res.response); } }; handler(*reinterpret_cast<const RequestType*>(args), responseCallback); }); } template <typename F, typename T> Session::IsEvent<T> Session::registerHandler(F&& handler) { auto cb = [handler](const void* args) { handler(*reinterpret_cast<const T*>(args)); }; const TypeInfo* typeinfo = TypeOf<T>::type(); registerHandler(typeinfo, cb); } template <typename F, typename T> void Session::registerSentHandler(F&& handler) { auto cb = [handler](const void* response, const Error* error) { if (error != nullptr) { handler(ResponseOrError<T>(*error)); } else { handler(ResponseOrError<T>(*reinterpret_cast<const T*>(response))); } }; const TypeInfo* typeinfo = TypeOf<T>::type(); registerHandler(typeinfo, cb); } template <typename T, typename> future<ResponseOrError<typename T::Response>> Session::send(const T& request) { using Response = typename T::Response; promise<ResponseOrError<Response>> promise; auto sent = send(TypeOf<T>::type(), TypeOf<Response>::type(), &request, [=](const void* result, const Error* error) { if (error != nullptr) { promise.set_value(ResponseOrError<Response>(*error)); } else { promise.set_value(ResponseOrError<Response>( *reinterpret_cast<const Response*>(result))); } }); if (!sent) { promise.set_value(Error("Failed to send request")); } return promise.get_future(); } template <typename T, typename> void Session::send(const T& event) { const TypeInfo* typeinfo = TypeOf<T>::type(); send(typeinfo, &event); } void Session::connect(const std::shared_ptr<ReaderWriter>& rw) { connect(rw, rw); } void Session::bind(const std::shared_ptr<dap::Reader>& r, const std::shared_ptr<dap::Writer>& w, const ClosedHandler& onClose = {}) { connect(r, w); startProcessingMessages(onClose); } void Session::bind(const std::shared_ptr<ReaderWriter>& rw, const ClosedHandler& onClose = {}) { bind(rw, rw, onClose); } } // namespace dap #endif // dap_session_h