13#ifndef LLDB_HOST_JSONTRANSPORT_H
14#define LLDB_HOST_JSONTRANSPORT_H
21#include "llvm/ADT/FunctionExtras.h"
22#include "llvm/ADT/StringExtras.h"
23#include "llvm/ADT/StringRef.h"
24#include "llvm/Support/Error.h"
25#include "llvm/Support/ErrorHandling.h"
26#include "llvm/Support/FormatVariadic.h"
27#include "llvm/Support/JSON.h"
28#include "llvm/Support/raw_ostream.h"
34#include <system_error>
39#if __cplusplus >= 202002L
48 :
public llvm::ErrorInfo<TransportUnhandledContentsError> {
54 void log(llvm::raw_ostream &
OS)
const override;
76 void log(llvm::raw_ostream &
OS)
const override;
99 void log(llvm::raw_ostream &
OS)
const override;
116 void log(llvm::raw_ostream &
OS)
const override;
123#if __cplusplus >= 202002L
127concept ProtocolDescriptor =
requires {
142#if __cplusplus >= 202002L
143template <ProtocolDescriptor Proto>
145template <
typename Proto>
149 using Req =
typename Proto::Req;
150 using Resp =
typename Proto::Resp;
151 using Evt =
typename Proto::Evt;
167 llvm::StringRef reason) {
168 return llvm::Error::success();
201 template <
typename... Ts>
inline auto Logv(
const char *Fmt, Ts &&...Vals) {
202 Log(llvm::formatv(Fmt, std::forward<Ts>(Vals)...).str());
204 virtual void Log(llvm::StringRef message) = 0;
216 llvm::Error
Send(
const typename Proto::Evt &evt)
override {
220 llvm::Error
Send(
const typename Proto::Req &req)
override {
224 llvm::Error
Send(
const typename Proto::Resp &resp)
override {
241 llvm::Error
Write(
const llvm::json::Value &message) {
242 std::string output =
Encode(message);
243 size_t bytes_written = output.size();
244 llvm::Error err =
m_out->Write(output.data(), bytes_written).takeError();
246 this->
Logv(
"write failed [{0}]: <-- {1}",
247 llvm::toStringWithoutConsuming(err), message);
249 this->
Logv(
"<-- {0}", message);
253 virtual llvm::Expected<std::vector<std::string>>
Parse() = 0;
254 virtual std::string
Encode(
const llvm::json::Value &message) = 0;
261 size_t num_bytes =
sizeof(buf);
262 if (
Status status =
m_in->Read(buf, num_bytes); status.Fail()) {
263 handler.OnError(status.takeError());
268 m_buffer.append(llvm::StringRef(buf, num_bytes));
272 llvm::Expected<std::vector<std::string>> raw_messages =
Parse();
273 if (llvm::Error
error = raw_messages.takeError()) {
274 handler.OnError(std::move(
error));
278 for (
const std::string &raw_message : *raw_messages) {
279 llvm::Expected<Message> message =
280 llvm::json::parse<Message>(raw_message);
284 std::string reason = llvm::toString(message.takeError());
285 if (llvm::Error
error =
287 handler.OnError(std::move(
error));
289 llvm::make_error<InvalidMessage>(raw_message, std::move(reason)));
293 std::visit([&handler](
auto &&msg) { handler.Received(msg); }, *message);
298 if (num_bytes == 0) {
301 handler.OnError(llvm::make_error<TransportUnhandledContentsError>(
318#if __cplusplus >= 202002L
319template <ProtocolDescriptor Proto>
321template <
typename Proto>
330 std::string
Encode(
const llvm::json::Value &message)
override {
332 std::string raw_message = llvm::formatv(
"{0}", message).str();
333 llvm::raw_string_ostream
OS(output);
335 << std::to_string(raw_message.size()) <<
kEndOfHeader << raw_message;
341 llvm::Expected<std::vector<std::string>>
Parse()
override {
342 std::vector<std::string> messages;
343 llvm::StringRef buffer = this->
m_buffer;
346 size_t content_length = 0;
348 for (
const llvm::StringRef &header :
356 value = value.trim();
357 if (!llvm::to_integer(value, content_length, 10)) {
360 return llvm::createStringError(std::errc::invalid_argument,
361 "invalid content length: %s",
362 value.str().c_str());
367 if (content_length > rest.size())
370 llvm::StringRef body = rest.take_front(content_length);
371 buffer = rest.drop_front(content_length);
372 messages.emplace_back(body.str());
373 this->
Logv(
"--> {0}", body);
379 return std::move(messages);
389#if __cplusplus >= 202002L
390template <ProtocolDescriptor Proto>
392template <
typename Proto>
399 std::string
Encode(
const llvm::json::Value &message)
override {
403 llvm::Expected<std::vector<std::string>>
Parse()
override {
404 std::vector<std::string> messages;
405 llvm::StringRef buf = this->
m_buffer;
409 messages.emplace_back(raw_json.str());
410 this->
Logv(
"--> {0}", raw_json);
425 std::conditional_t<std::is_void_v<T>,
426 llvm::unique_function<void(llvm::Error)>,
427 llvm::unique_function<void(llvm::Expected<T>)>>;
430template <
typename R,
typename P>
struct request_t final {
437 using type = llvm::unique_function<void(
const P &)>;
440 using type = llvm::unique_function<void()>;
444template <
typename R,
typename P>
450#if __cplusplus >= 202002L
454concept BindingBuilder =
455 ProtocolDescriptor<T> &&
456 requires(T::Id
id, T::Req req, T::Resp resp, T::Evt evt,
457 llvm::StringRef method, std::optional<llvm::json::Value> params,
458 std::optional<llvm::json::Value> result, llvm::Error err) {
460 { T::InitialId() } -> std::same_as<typename T::Id>;
462 {
id++ } -> std::same_as<typename T::Id>;
467 { T::Make(
id, method, params) } -> std::same_as<typename T::Req>;
469 { T::Make(req, std::move(err)) } -> std::same_as<typename T::Resp>;
471 { T::Make(req, result) } -> std::same_as<typename T::Resp>;
473 { T::Make(method, params) } -> std::same_as<typename T::Evt>;
479 { T::KeyFor(resp) } -> std::same_as<typename T::Id>;
481 { T::KeyFor(req) } -> std::same_as<std::string>;
483 { T::KeyFor(evt) } -> std::same_as<std::string>;
489 { T::Extract(req) } -> std::same_as<std::optional<llvm::json::Value>>;
491 { T::Extract(resp) } -> std::same_as<llvm::Expected<llvm::json::Value>>;
493 { T::Extract(evt) } -> std::same_as<std::optional<llvm::json::Value>>;
524#if __cplusplus >= 202002L
525template <BindingBuilder Proto>
527template <
typename Proto>
530 using Req =
typename Proto::Req;
531 using Resp =
typename Proto::Resp;
532 using Evt =
typename Proto::Evt;
533 using Id =
typename Proto::Id;
544 template <
typename Fn,
typename...
Args>
548 template <
typename Fn,
typename...
Args>
555 template <
typename Result,
typename Params,
typename Fn,
typename...
Args>
556 void Bind(llvm::StringLiteral method, Fn &&fn,
Args &&...args);
563 template <
typename Result,
typename Params,
typename Fn,
typename...
Args>
570 template <
typename Params,
typename Fn,
typename...
Args>
571 void Bind(llvm::StringLiteral method, Fn &&fn,
Args &&...args);
576 template <
typename Result,
typename Params>
582 template <
typename Params>
586 std::scoped_lock<std::recursive_mutex> guard(
m_mutex);
589 OnError(llvm::createStringError(
590 llvm::formatv(
"no handler for event {0}",
toJSON(evt))));
599 std::scoped_lock<std::recursive_mutex> guard(
m_mutex);
602 reply(Proto::Make(req,
603 llvm::make_error<MethodNotFound>(Proto::KeyFor(req))));
607 it->second(req, std::move(reply));
611 std::scoped_lock<std::recursive_mutex> guard(
m_mutex);
613 Id id = Proto::KeyFor(resp);
616 OnError(llvm::createStringError(
617 llvm::formatv(
"no pending request for {0}",
toJSON(resp))));
626 std::scoped_lock<std::recursive_mutex> guard(
m_mutex);
637 Callback<void()> disconnect_handler;
639 std::scoped_lock<std::recursive_mutex> guard(
m_mutex);
642 if (disconnect_handler)
643 disconnect_handler();
650 std::scoped_lock<std::recursive_mutex> guard(
m_mutex);
653 for (
auto &entry : pending) {
654 Req req = Proto::Make(entry.first,
"", std::nullopt);
655 entry.second(Proto::Make(req, llvm::createStringError(reason)));
660 template <
typename T>
661 llvm::Expected<T>
static Parse(
const llvm::json::Value &raw,
662 llvm::StringRef method);
664 template <
typename T>
using Callback = llvm::unique_function<T>;
695 other.transport =
nullptr;
696 other.handler =
nullptr;
704 assert(
false &&
"must reply to all calls!");
705 (*this)(Proto::Make(
req, llvm::createStringError(
"failed to reply")));
712 assert(
false &&
"must reply to each call only once!");
722#if __cplusplus >= 202002L
723template <BindingBuilder Proto>
725template <
typename Proto>
727template <
typename Fn,
typename...
Args>
730 std::invoke(std::forward<Fn>(fn), std::forward<Args>(args)...);
734#if __cplusplus >= 202002L
735template <BindingBuilder Proto>
737template <
typename Proto>
739template <
typename Fn,
typename...
Args>
742 std::invoke(std::forward<Fn>(fn), std::forward<Args>(args)...,
747#if __cplusplus >= 202002L
748template <BindingBuilder Proto>
750template <
typename Proto>
752template <
typename Result,
typename Params,
typename Fn,
typename...
Args>
755 "request already bound");
756 if constexpr (std::is_void_v<Result> && std::is_void_v<Params>) {
758 [fn, args...](
const Req &req,
759 llvm::unique_function<void(
const Resp &)> reply)
mutable {
761 std::invoke(std::forward<Fn>(fn), std::forward<Args>(args)...);
762 reply(Proto::Make(req, std::move(result)));
764 }
else if constexpr (std::is_void_v<Params>) {
766 [fn, args...](
const Req &req,
767 llvm::unique_function<void(
const Resp &)> reply)
mutable {
768 llvm::Expected<Result> result =
769 std::invoke(std::forward<Fn>(fn), std::forward<Args>(args)...);
771 return reply(Proto::Make(req, result.takeError()));
772 reply(Proto::Make(req,
toJSON(*result)));
774 }
else if constexpr (std::is_void_v<Result>) {
777 args...](
const Req &req,
778 llvm::unique_function<void(
const Resp &)> reply)
mutable {
779 llvm::Expected<Params> params =
782 return reply(Proto::Make(req, params.takeError()));
784 llvm::Error result = std::invoke(
785 std::forward<Fn>(fn), std::forward<Args>(args)..., *params);
786 reply(Proto::Make(req, std::move(result)));
791 args...](
const Req &req,
792 llvm::unique_function<void(
const Resp &)> reply)
mutable {
793 llvm::Expected<Params> params =
796 return reply(Proto::Make(req, params.takeError()));
798 llvm::Expected<Result> result = std::invoke(
799 std::forward<Fn>(fn), std::forward<Args>(args)..., *params);
801 return reply(Proto::Make(req, result.takeError()));
803 reply(Proto::Make(req,
toJSON(*result)));
808#if __cplusplus >= 202002L
809template <BindingBuilder Proto>
811template <
typename Proto>
813template <
typename Params,
typename Fn,
typename...
Args>
816 "event already bound");
817 if constexpr (std::is_void_v<Params>) {
819 std::invoke(std::forward<Fn>(fn), std::forward<Args>(args)...);
823 args...](
const Evt &evt)
mutable {
824 llvm::Expected<Params> params =
827 return OnError(params.takeError());
828 std::invoke(std::forward<Fn>(fn), std::forward<Args>(args)..., *params);
833#if __cplusplus >= 202002L
834template <BindingBuilder Proto>
836template <
typename Proto>
838template <
typename Result,
typename Params>
841 if constexpr (std::is_void_v<Result> && std::is_void_v<Params>) {
843 std::scoped_lock<std::recursive_mutex> guard(
m_mutex);
845 Req req = Proto::Make(
id, method, std::nullopt);
847 llvm::Expected<llvm::json::Value> result = Proto::Extract(resp);
849 return fn(result.takeError());
850 fn(llvm::Error::success());
855 }
else if constexpr (std::is_void_v<Params>) {
857 std::scoped_lock<std::recursive_mutex> guard(
m_mutex);
859 Req req = Proto::Make(
id, method, std::nullopt);
861 method](
const Resp &resp)
mutable {
862 llvm::Expected<llvm::json::Value> result = Proto::Extract(resp);
864 return fn(result.takeError());
870 }
else if constexpr (std::is_void_v<Result>) {
871 return [
this, method](
const Params ¶ms,
Reply<Result> fn) {
872 std::scoped_lock<std::recursive_mutex> guard(
m_mutex);
874 Req req = Proto::Make(
id, method, llvm::json::Value(params));
876 llvm::Expected<llvm::json::Value> result = Proto::Extract(resp);
878 return fn(result.takeError());
879 fn(llvm::Error::success());
885 return [
this, method](
const Params ¶ms,
Reply<Result> fn) {
886 std::scoped_lock<std::recursive_mutex> guard(
m_mutex);
888 Req req = Proto::Make(
id, method, llvm::json::Value(params));
890 method](
const Resp &resp)
mutable {
891 llvm::Expected<llvm::json::Value> result = Proto::Extract(resp);
892 if (llvm::Error err = result.takeError())
893 return fn(std::move(err));
902#if __cplusplus >= 202002L
903template <BindingBuilder Proto>
905template <
typename Proto>
907template <
typename Params>
909 if constexpr (std::is_void_v<Params>) {
910 return [
this, method]() {
911 if (llvm::Error
error =
912 m_transport.Send(Proto::Make(method, std::nullopt)))
916 return [
this, method](
const Params ¶ms) {
917 if (llvm::Error
error =
924#if __cplusplus >= 202002L
925template <BindingBuilder Proto>
927template <
typename Proto>
931 llvm::StringRef method) {
933 llvm::json::Path::Root root;
937 llvm::raw_string_ostream
OS(context);
938 root.printErrorContext(raw,
OS);
939 return llvm::make_error<InvalidParams>(method.str(), context);
941 return std::move(result);
944#if __cplusplus >= 202002L
945template <BindingBuilder Proto>
947template <
typename Proto>
949template <
typename Result,
typename Params,
typename Fn,
typename...
Args>
953 "request already bound");
957 if constexpr (std::is_void_v<Params>) {
959 [fn, args...](
const Req &req,
962 [req, reply = std::move(reply)](
963 llvm::Expected<Result> result)
mutable {
965 return reply(Proto::Make(req, result.takeError()));
966 reply(Proto::Make(req,
toJSON(*result)));
968 std::invoke(fn, args..., std::move(typed_reply));
972 [method, fn, args...](
const Req &req,
975 [req, reply = std::move(reply)](
976 llvm::Expected<Result> result)
mutable {
978 return reply(Proto::Make(req, result.takeError()));
979 reply(Proto::Make(req,
toJSON(*result)));
981 llvm::Expected<Params> params =
984 return typed_reply(params.takeError());
985 std::invoke(fn, args..., *params, std::move(typed_reply));
static llvm::raw_ostream & error(Stream &strm)
A command line argument class.
std::unique_ptr< ReadHandle > ReadHandleUP
void operator()(const Resp &resp)
ReplyOnce & operator=(const ReplyOnce &)=delete
std::atomic< bool > replied
ReplyOnce(const Req req, Transport *transport, MessageHandler *handler)
ReplyOnce & operator=(ReplyOnce &&)=delete
ReplyOnce(ReplyOnce &&other)
ReplyOnce(const ReplyOnce &)=delete
void Received(const Resp &resp) override
Called when a response is received.
JSONTransport< Proto > Transport
typename Transport::MessageHandler MessageHandler
void OnDisconnect(Fn &&fn, Args &&...args)
Bind a handler on transport disconnect.
void Bind(llvm::StringLiteral method, Fn &&fn, Args &&...args)
Bind a handler for an incoming request.
void BindAsync(llvm::StringLiteral method, Fn &&fn, Args &&...args)
Bind an asynchronous handler for an incoming request.
void Bind(llvm::StringLiteral method, Fn &&fn, Args &&...args)
Bind a handler for an incoming event.
std::recursive_mutex m_mutex
llvm::StringMap< Callback< void(const Req &, Callback< void(const Resp &)>)> > m_request_handlers
void FailPendingRequests(llvm::StringRef reason)
Fails every in-flight outgoing request, invoking its reply with an error.
void OnClosed() override
Called on EOF or client disconnect.
Callback< void(llvm::Error)> m_error_handler
void OnError(Fn &&fn, Args &&...args)
Bind a handler on error when communicating with the transport.
void Received(const Evt &evt) override
Called when an event is received.
OutgoingRequest< Result, Params > Bind(llvm::StringLiteral method)
Bind a function object to be used for outgoing requests.
std::map< Id, Callback< void(const Resp &)> > m_pending_responses
Binder & operator=(const Binder &)=delete
Binder(Transport &transport)
void Received(const Req &req) override
Called when a request is received.
static llvm::Expected< T > Parse(const llvm::json::Value &raw, llvm::StringRef method)
OutgoingEvent< Params > Bind(llvm::StringLiteral method)
Bind a function object to be used for outgoing events.
Binder(const Binder &)=delete
void OnError(llvm::Error err) override
Called when an error occurs while reading from the transport.
typename Proto::Resp Resp
llvm::unique_function< T > Callback
llvm::StringMap< Callback< void(const Evt &)> > m_event_handlers
Callback< void()> m_disconnect_handler
A transport class for JSON with a HTTP header.
static constexpr llvm::StringLiteral kHeaderFieldSeparator
static constexpr llvm::StringLiteral kEndOfHeader
static constexpr llvm::StringLiteral kHeaderSeparator
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 kHeaderContentLength
void OnRead(MainLoopBase &loop, MessageHandler &handler)
IOTransport(MainLoop &loop, lldb::IOObjectSP in, lldb::IOObjectSP out)
static constexpr size_t kReadBufferSize
Public for testing purposes, otherwise this should be an implementation detail.
typename JSONTransport< Proto >::MessageHandler MessageHandler
llvm::Error Send(const typename Proto::Resp &resp) override
typename JSONTransport< Proto >::Message Message
llvm::Error Send(const typename Proto::Evt &evt) override
virtual std::string Encode(const llvm::json::Value &message)=0
virtual llvm::Expected< std::vector< std::string > > Parse()=0
MainLoop::ReadHandleUP m_read_handle
llvm::Error Write(const llvm::json::Value &message)
llvm::Error Send(const typename Proto::Req &req) override
llvm::SmallString< kReadBufferSize > m_buffer
llvm::Error RegisterMessageHandler(MessageHandler &handler) override
RegisterMessageHandler registers the Transport with the given MainLoop and handles any incoming messa...
void log(llvm::raw_ostream &OS) const override
InvalidMessage(std::string raw_message, std::string reason)
static constexpr int kErrorCode
std::string m_raw_message
std::error_code convertToErrorCode() const override
std::error_code convertToErrorCode() const override
std::string m_context
Additional context from the parsing failure, e.g.
InvalidParams(std::string method, std::string context)
static constexpr int kErrorCode
std::string m_method
The JSONRPC remote method call.
void log(llvm::raw_ostream &OS) const override
A transport class for JSON RPC.
llvm::Expected< std::vector< std::string > > Parse() override
static constexpr llvm::StringLiteral kMessageSeparator
std::string Encode(const llvm::json::Value &message) override
Implemented to handle incoming messages.
virtual void OnError(llvm::Error)=0
Called when an error occurs while reading from the transport.
virtual void OnClosed()=0
Called on EOF or client disconnect.
virtual ~MessageHandler()=default
virtual void Received(const Req &)=0
Called when a request is received.
virtual void Received(const Evt &)=0
Called when an event is received.
virtual void Received(const Resp &)=0
Called when a response is received.
A transport is responsible for maintaining the connection to a client application,...
virtual llvm::Error ReplyWithParseError(llvm::StringRef raw_message, llvm::StringRef reason)
Sends an error response for a message that failed to parse, described by reason.
virtual llvm::Error Send(const Resp &)=0
Sends a response to a specific request.
virtual ~JSONTransport()=default
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 RegisterMessageHandler(MessageHandler &handler)=0
RegisterMessageHandler registers the Transport with the given MainLoop and handles any incoming messa...
auto Logv(const char *Fmt, Ts &&...Vals)
virtual llvm::Error Send(const Req &)=0
Sends a request, a message that expects a response.
virtual void Log(llvm::StringRef message)=0
typename Proto::Resp Resp
static constexpr int kErrorCode
std::error_code convertToErrorCode() const override
MethodNotFound(std::string method)
void log(llvm::raw_ostream &OS) const override
const std::string & getUnhandledContents() const
void log(llvm::raw_ostream &OS) const override
TransportUnhandledContentsError(std::string unhandled_contents)
std::error_code convertToErrorCode() const override
std::string m_unhandled_contents
std::conditional_t< std::is_void_v< T >, llvm::unique_function< void(llvm::Error)>, llvm::unique_function< void(llvm::Expected< T >)> > Reply
A handler for the response to an outgoing request.
typename detail::event_t< P >::type OutgoingEvent
A function to send an outgoing event.
typename detail::request_t< R, P >::type OutgoingRequest
llvm::json::Value toJSON(const Diagnostics::Report &report)
Render a diagnostics report as JSON, for diagnostics dump's terminal output.
bool fromJSON(const llvm::json::Value &value, SymbolValue &data, llvm::json::Path path)
std::shared_ptr< lldb_private::IOObject > IOObjectSP
llvm::unique_function< void()> type
llvm::unique_function< void(const P &)> type
llvm::unique_function< void(Reply< R >)> type
llvm::unique_function< void(const P &, Reply< R >)> type