================ @@ -54,112 +50,227 @@ class TransportUnhandledContentsError std::string m_unhandled_contents; }; -class TransportInvalidError : public llvm::ErrorInfo<TransportInvalidError> { +/// A transport is responsible for maintaining the connection to a client +/// application, and reading/writing structured messages to it. +/// +/// Transports have limited thread safety requirements: +/// - Messages will not be sent concurrently. +/// - Messages MAY be sent while Run() is reading, or its callback is active. +template <typename Req, typename Resp, typename Evt> class Transport { public: - static char ID; - - TransportInvalidError() = default; + using Message = std::variant<Req, Resp, Evt>; + + virtual ~Transport() = default; + + // Called by transport to send outgoing messages. + virtual void Event(const Evt &) = 0; + virtual void Request(const Req &) = 0; + virtual void Response(const Resp &) = 0; + + /// Implemented to handle incoming messages. (See Run() below). + class MessageHandler { + public: + virtual ~MessageHandler() = default; + virtual void OnEvent(const Evt &) = 0; + virtual void OnRequest(const Req &) = 0; + virtual void OnResponse(const Resp &) = 0; + }; + + /// Called by server or client to receive messages from the connection. + /// The transport should in turn invoke the handler to process messages. + /// The MainLoop is used to handle reading from the incoming connection and + /// will run until the loop is terminated. + virtual llvm::Error Run(MainLoop &, MessageHandler &) = 0; - void log(llvm::raw_ostream &OS) const override; - std::error_code convertToErrorCode() const override; +protected: + template <typename... Ts> inline auto Logv(const char *Fmt, Ts &&...Vals) { + Log(llvm::formatv(Fmt, std::forward<Ts>(Vals)...).str()); + } + virtual void Log(llvm::StringRef message) = 0; }; -/// A transport class that uses JSON for communication. -class JSONTransport { +/// A JSONTransport will encode and decode messages using JSON. +template <typename Req, typename Resp, typename Evt> +class JSONTransport : public Transport<Req, Resp, Evt> { public: - using ReadHandleUP = MainLoopBase::ReadHandleUP; - template <typename T> - using Callback = std::function<void(MainLoopBase &, const llvm::Expected<T>)>; - - JSONTransport(lldb::IOObjectSP input, lldb::IOObjectSP output); - virtual ~JSONTransport() = default; - - /// Transport is not copyable. - /// @{ - JSONTransport(const JSONTransport &rhs) = delete; - void operator=(const JSONTransport &rhs) = delete; - /// @} - - /// Writes a message to the output stream. - template <typename T> llvm::Error Write(const T &t) { - const std::string message = llvm::formatv("{0}", toJSON(t)).str(); - return WriteImpl(message); + using Transport<Req, Resp, Evt>::Transport; + + JSONTransport(lldb::IOObjectSP in, lldb::IOObjectSP out) + : m_in(in), m_out(out) {} + + void Event(const Evt &evt) override { Write(evt); } + void Request(const Req &req) override { Write(req); } + void Response(const Resp &resp) override { Write(resp); } + + /// Run registers the transport with the given MainLoop and handles any + /// incoming messages using the given MessageHandler. + llvm::Error + Run(MainLoop &loop, + typename Transport<Req, Resp, Evt>::MessageHandler &handler) override { + llvm::Error error = llvm::Error::success(); + Status status; + auto read_handle = loop.RegisterReadObject( + m_in, + std::bind(&JSONTransport::OnRead, this, &error, std::placeholders::_1, + std::ref(handler)), + status); + if (status.Fail()) { + // This error is only set if the read object handler is invoked, mark it + // as consumed if registration of the handler failed. + llvm::consumeError(std::move(error)); + return status.takeError(); + } + + status = loop.Run(); ---------------- ashgti wrote:
Updated to have a register function instead of a `Run` function. https://github.com/llvm/llvm-project/pull/153121 _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits