13#ifndef LLDB_HOST_JSONTRANSPORT_H
14#define LLDB_HOST_JSONTRANSPORT_H
21#include "llvm/ADT/StringExtras.h"
22#include "llvm/ADT/StringRef.h"
23#include "llvm/Support/Error.h"
24#include "llvm/Support/ErrorHandling.h"
25#include "llvm/Support/FormatVariadic.h"
26#include "llvm/Support/JSON.h"
27#include "llvm/Support/raw_ostream.h"
29#include <system_error>
36 :
public llvm::ErrorInfo<TransportUnhandledContentsError> {
42 void log(llvm::raw_ostream &
OS)
const override;
59template <
typename Req,
typename Resp,
typename Evt>
class Transport {
61 using Message = std::variant<Req, Resp, Evt>;
66 virtual llvm::Error
Send(
const Evt &) = 0;
68 virtual llvm::Error
Send(
const Req &) = 0;
70 virtual llvm::Error
Send(
const Resp &) = 0;
100 virtual llvm::Expected<MainLoop::ReadHandleUP>
104 template <
typename... Ts>
inline auto Logv(
const char *Fmt, Ts &&...Vals) {
105 Log(llvm::formatv(Fmt, std::forward<Ts>(Vals)...).str());
107 virtual void Log(llvm::StringRef message) = 0;
111template <
typename Req,
typename Resp,
typename Evt>
120 llvm::Error
Send(
const Evt &evt)
override {
return Write(evt); }
121 llvm::Error
Send(
const Req &req)
override {
return Write(req); }
122 llvm::Error
Send(
const Resp &resp)
override {
return Write(resp); }
124 llvm::Expected<MainLoop::ReadHandleUP>
143 llvm::Error
Write(
const llvm::json::Value &message) {
144 this->
Logv(
"<-- {0}", message);
145 std::string output =
Encode(message);
146 size_t bytes_written = output.size();
147 return m_out->Write(output.data(), bytes_written).takeError();
151 virtual llvm::Expected<std::vector<std::string>>
Parse() = 0;
152 virtual std::string
Encode(
const llvm::json::Value &message) = 0;
159 size_t num_bytes =
sizeof(buf);
160 if (
Status status =
m_in->Read(buf, num_bytes); status.Fail()) {
161 handler.OnError(status.takeError());
166 m_buffer.append(llvm::StringRef(buf, num_bytes));
170 llvm::Expected<std::vector<std::string>> raw_messages =
Parse();
171 if (llvm::Error
error = raw_messages.takeError()) {
172 handler.OnError(std::move(
error));
176 for (
const std::string &raw_message : *raw_messages) {
177 llvm::Expected<typename Transport<Req, Resp, Evt>::Message> message =
178 llvm::json::parse<typename Transport<Req, Resp, Evt>::Message>(
181 handler.OnError(message.takeError());
185 std::visit([&handler](
auto &&msg) { handler.Received(msg); }, *message);
190 if (num_bytes == 0) {
193 handler.OnError(llvm::make_error<TransportUnhandledContentsError>(
204template <
typename Req,
typename Resp,
typename Evt>
212 std::string
Encode(
const llvm::json::Value &message)
override {
214 std::string raw_message = llvm::formatv(
"{0}", message).str();
215 llvm::raw_string_ostream
OS(output);
217 << std::to_string(raw_message.size()) <<
kEndOfHeader << raw_message;
223 llvm::Expected<std::vector<std::string>>
Parse()
override {
224 std::vector<std::string> messages;
225 llvm::StringRef buffer = this->
m_buffer;
228 size_t content_length = 0;
230 for (
const llvm::StringRef &header :
238 value = value.trim();
239 if (!llvm::to_integer(value, content_length, 10)) {
242 return llvm::createStringError(std::errc::invalid_argument,
243 "invalid content length: %s",
244 value.str().c_str());
249 if (content_length > rest.size())
252 llvm::StringRef body = rest.take_front(content_length);
253 buffer = rest.drop_front(content_length);
254 messages.emplace_back(body.str());
255 this->
Logv(
"--> {0}", body);
261 return std::move(messages);
271template <
typename Req,
typename Resp,
typename Evt>
277 std::string
Encode(
const llvm::json::Value &message)
override {
281 llvm::Expected<std::vector<std::string>>
Parse()
override {
282 std::vector<std::string> messages;
283 llvm::StringRef buf = this->
m_buffer;
287 messages.emplace_back(raw_json.str());
288 this->
Logv(
"--> {0}", raw_json);
static llvm::raw_ostream & error(Stream &strm)
A transport class for JSON with a HTTP header.
static constexpr llvm::StringLiteral kEndOfHeader
static constexpr llvm::StringLiteral kHeaderFieldSeparator
static constexpr llvm::StringLiteral kHeaderContentLength
std::string Encode(const llvm::json::Value &message) override
Encodes messages based on https://microsoft.github.io/debug-adapter-protocol/overview#base-protocol.
llvm::Expected< std::vector< std::string > > Parse() override
Parses messages based on https://microsoft.github.io/debug-adapter-protocol/overview#base-protocol.
static constexpr llvm::StringLiteral kHeaderSeparator
virtual std::string Encode(const llvm::json::Value &message)=0
llvm::Error Write(const llvm::json::Value &message)
llvm::Expected< MainLoop::ReadHandleUP > RegisterMessageHandler(MainLoop &loop, MessageHandler &handler) override
RegisterMessageHandler registers the Transport with the given MainLoop and handles any incoming messa...
virtual llvm::Expected< std::vector< std::string > > Parse()=0
llvm::Error Send(const Resp &resp) override
Sends a response to a specific request.
typename Transport< Req, Resp, Evt >::MessageHandler MessageHandler
void OnRead(MainLoopBase &loop, MessageHandler &handler)
llvm::SmallString< kReadBufferSize > m_buffer
llvm::Error Send(const Req &req) override
Sends a request, a message that expects a response.
llvm::Error Send(const Evt &evt) override
Sends an event, a message that does not require a response.
IOTransport(lldb::IOObjectSP in, lldb::IOObjectSP out)
static constexpr size_t kReadBufferSize
Public for testing purposes, otherwise this should be an implementation detail.
A transport class for JSON RPC.
std::string Encode(const llvm::json::Value &message) override
static constexpr llvm::StringLiteral kMessageSeparator
llvm::Expected< std::vector< std::string > > Parse() override
std::unique_ptr< ReadHandle > ReadHandleUP
ReadHandleUP RegisterReadObject(const lldb::IOObjectSP &object_sp, const Callback &callback, Status &error) override
bool Fail() const
Test for error condition.
void log(llvm::raw_ostream &OS) const override
TransportUnhandledContentsError(std::string unhandled_contents)
std::error_code convertToErrorCode() const override
std::string m_unhandled_contents
const std::string & getUnhandledContents() const
Implemented to handle incoming messages. (See Run() below).
virtual void Received(const Evt &)=0
Called when an event is received.
virtual void OnError(llvm::Error)=0
Called when an error occurs while reading from the transport.
virtual ~MessageHandler()=default
virtual void OnClosed()=0
Called on EOF or client disconnect.
virtual void Received(const Resp &)=0
Called when a response is received.
virtual void Received(const Req &)=0
Called when a request is received.
A transport is responsible for maintaining the connection to a client application,...
virtual llvm::Expected< MainLoop::ReadHandleUP > RegisterMessageHandler(MainLoop &loop, MessageHandler &handler)=0
RegisterMessageHandler registers the Transport with the given MainLoop and handles any incoming messa...
std::variant< Req, Resp, Evt > Message
virtual llvm::Error Send(const Evt &)=0
Sends an event, a message that does not require a response.
virtual llvm::Error Send(const Resp &)=0
Sends a response to a specific request.
virtual void Log(llvm::StringRef message)=0
std::shared_ptr< MessageHandler > MessageHandlerSP
auto Logv(const char *Fmt, Ts &&...Vals)
virtual llvm::Error Send(const Req &)=0
Sends a request, a message that expects a response.
virtual ~Transport()=default
A class that represents a running process on the host machine.
std::shared_ptr< lldb_private::IOObject > IOObjectSP