3#include <spdlog/spdlog.h>
8 : transport_(std::move(transport)) {
9 spdlog::info(
"Initializing JSON-RPC client");
13 spdlog::info(
"Starting JSON-RPC client");
14 is_running_.store(
true);
15 listener_ = std::thread(&Client::Listener,
this);
19 spdlog::info(
"Stopping JSON-RPC client");
20 is_running_.store(
false);
21 if (listener_.joinable()) {
27 return is_running_.load();
31 std::lock_guard<std::mutex> lock(requests_mutex_);
32 return !requests_map_.empty();
35void Client::Listener() {
36 spdlog::info(
"Starting JSON-RPC client listener thread");
38 if (expected_count_ > 0) {
39 std::string response = transport_->ReceiveMessage();
40 HandleResponse(response);
47 const std::string &method,
48 std::optional<nlohmann::json> params) -> nlohmann::json {
49 Request request(method, std::move(params),
false, [
this]() {
50 return GetNextRequestId();
52 return SendRequest(request);
56 const std::string &method,
57 std::optional<nlohmann::json> params) -> std::future<nlohmann::json> {
58 Request request(method, std::move(params),
false, [
this]() {
59 return GetNextRequestId();
61 return SendRequestAsync(request);
65 const std::string &method, std::optional<nlohmann::json> params) {
67 method, std::move(params),
true, [
this]() {
return GetNextRequestId(); });
68 transport_->SendMessage(request.Dump());
71auto Client::SendRequest(
const Request &request) -> nlohmann::json {
72 auto future_response = SendRequestAsync(request);
73 return future_response.get();
76auto Client::SendRequestAsync(
const Request &request)
77 -> std::future<nlohmann::json> {
79 request.RequiresResponse() &&
80 "SendRequestAsync called for a request "
81 "that does not require a response.");
83 std::promise<nlohmann::json> response_promise;
84 auto future_response = response_promise.get_future();
87 std::lock_guard<std::mutex> lock(requests_mutex_);
88 requests_map_[request.GetKey()] = std::move(response_promise);
92 transport_->SendMessage(request.Dump());
94 return future_response;
97auto Client::GetNextRequestId() ->
int {
98 return req_id_counter_++;
101void Client::HandleResponse(
const std::string &response) {
102 nlohmann::json json_response;
104 json_response = nlohmann::json::parse(response);
105 }
catch (
const std::exception &e) {
106 spdlog::error(
"Failed to parse JSON response: {}", e.what());
107 throw std::runtime_error(
108 "Failed to parse JSON response: " + std::string(e.what()));
111 if (ValidateResponse(json_response)) {
112 int request_id = json_response[
"id"].get<
int>();
114 std::lock_guard<std::mutex> lock(requests_mutex_);
115 auto req_iter = requests_map_.find(request_id);
116 if (req_iter != requests_map_.end()) {
117 req_iter->second.set_value(json_response);
118 requests_map_.erase(req_iter);
120 spdlog::error(
"Received response for unknown request ID: {}", request_id);
121 throw std::runtime_error(
122 "Received response for unknown request ID: " +
123 std::to_string(request_id));
126 spdlog::error(
"Invalid JSON-RPC response: {}", json_response.dump());
127 throw std::runtime_error(
128 "Invalid JSON-RPC response: " + json_response.dump());
132auto Client::ValidateResponse(
const nlohmann::json &response) ->
bool {
133 if (!response.contains(
"jsonrpc") || response[
"jsonrpc"] !=
"2.0") {
137 if (!response.contains(
"id")) {
141 bool has_result = response.contains(
"result");
142 bool has_error = response.contains(
"error");
144 if (has_result == has_error) {
149 const nlohmann::json &error = response[
"error"];
150 if (!error.contains(
"code") || !error[
"code"].is_number() ||
151 !error.contains(
"message") || !error[
"message"].is_string()) {
void SendNotification(const std::string &method, std::optional< nlohmann::json > params=std::nullopt)
Sends a JSON-RPC notification.
void Start()
Starts the JSON-RPC client listener thread.
Client(std::unique_ptr< transport::Transport > transport)
Constructs a JSON-RPC client with a specified transport layer.
auto IsRunning() const -> bool
Checks if the client listener is running.
auto SendMethodCall(const std::string &method, std::optional< nlohmann::json > params=std::nullopt) -> nlohmann::json
Sends a JSON-RPC method call and waits for the response.
auto SendMethodCallAsync(const std::string &method, std::optional< nlohmann::json > params=std::nullopt) -> std::future< nlohmann::json >
Sends a JSON-RPC method call asynchronously.
void Stop()
Stops the JSON-RPC client listener thread.
auto HasPendingRequests() const -> bool
Checks if there are any pending requests.
Represents a JSON-RPC request.