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>
105 template <
typename... Ts>
inline auto Logv(
const char *Fmt, Ts &&...Vals) {
106 Log(llvm::formatv(Fmt, std::forward<Ts>(Vals)...).str());
108 virtual void Log(llvm::StringRef message) = 0;
112template <
typename Req,
typename Resp,
typename Evt>
121 llvm::Error
Send(
const Evt &evt)
override {
return Write(evt); }
122 llvm::Error
Send(
const Req &req)
override {
return Write(req); }
123 llvm::Error
Send(
const Resp &resp)
override {
return Write(resp); }
125 llvm::Expected<MainLoop::ReadHandleUP>
144 llvm::Error
Write(
const llvm::json::Value &message) {
145 this->
Logv(
"<-- {0}", message);
146 std::string output =
Encode(message);
147 size_t bytes_written = output.size();
148 return m_out->Write(output.data(), bytes_written).takeError();
152 virtual llvm::Expected<std::vector<std::string>>
Parse() = 0;
153 virtual std::string
Encode(
const llvm::json::Value &message) = 0;
160 size_t num_bytes =
sizeof(buf);
161 if (
Status status =
m_in->Read(buf, num_bytes); status.Fail()) {
162 handler.OnError(status.takeError());
167 m_buffer.append(llvm::StringRef(buf, num_bytes));
171 llvm::Expected<std::vector<std::string>> raw_messages =
Parse();
172 if (llvm::Error
error = raw_messages.takeError()) {
173 handler.OnError(std::move(
error));
177 for (
const std::string &raw_message : *raw_messages) {
178 llvm::Expected<typename Transport<Req, Resp, Evt>::Message> message =
179 llvm::json::parse<typename Transport<Req, Resp, Evt>::Message>(
182 handler.OnError(message.takeError());
186 std::visit([&handler](
auto &&msg) { handler.Received(msg); }, *message);
191 if (num_bytes == 0) {
194 handler.OnError(llvm::make_error<TransportUnhandledContentsError>(
205template <
typename Req,
typename Resp,
typename Evt>
213 std::string
Encode(
const llvm::json::Value &message)
override {
215 std::string raw_message = llvm::formatv(
"{0}", message).str();
216 llvm::raw_string_ostream
OS(output);
218 << std::to_string(raw_message.size()) <<
kEndOfHeader << raw_message;
224 llvm::Expected<std::vector<std::string>>
Parse()
override {
225 std::vector<std::string> messages;
226 llvm::StringRef buffer = this->
m_buffer;
229 size_t content_length = 0;
231 for (
const llvm::StringRef &header :
239 value = value.trim();
240 if (!llvm::to_integer(value, content_length, 10)) {
243 return llvm::createStringError(std::errc::invalid_argument,
244 "invalid content length: %s",
245 value.str().c_str());
250 if (content_length > rest.size())
253 llvm::StringRef body = rest.take_front(content_length);
254 buffer = rest.drop_front(content_length);
255 messages.emplace_back(body.str());
256 this->
Logv(
"--> {0}", body);
262 return std::move(messages);
272template <
typename Req,
typename Resp,
typename Evt>
278 std::string
Encode(
const llvm::json::Value &message)
override {
282 llvm::Expected<std::vector<std::string>>
Parse()
override {
283 std::vector<std::string> messages;
284 llvm::StringRef buf = this->
m_buffer;
288 messages.emplace_back(raw_json.str());
289 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
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
llvm::Error Send(const Evt &evt) override
Sends an event, a message that does not require a response.
virtual llvm::Expected< std::vector< std::string > > Parse()=0
llvm::SmallString< kReadBufferSize > m_buffer
llvm::Error Send(const Req &req) override
Sends a request, a message that expects a response.
void OnRead(MainLoopBase &loop, MessageHandler &handler)
static constexpr size_t kReadBufferSize
Public for testing purposes, otherwise this should be an implementation detail.
virtual std::string Encode(const llvm::json::Value &message)=0
typename Transport< Req, Resp, Evt >::MessageHandler MessageHandler
llvm::Error Write(const llvm::json::Value &message)
llvm::Error Send(const Resp &resp) override
Sends a response to a specific request.
llvm::Expected< MainLoop::ReadHandleUP > RegisterMessageHandler(MainLoop &loop, MessageHandler &handler) override
RegisterMessageHandler registers the Transport with the given MainLoop and handles any incoming messa...
JSONTransport(lldb::IOObjectSP in, lldb::IOObjectSP out)
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