JSON-RPC 2.0
JSON-RPC 2.0 Modern C++ Library
Loading...
Searching...
No Matches
dispatcher.cpp
Go to the documentation of this file.
2
4
6
7namespace jsonrpc::endpoint {
8
11
13 asio::any_io_executor executor, std::shared_ptr<spdlog::logger> logger)
14 : executor_(std::move(executor)),
15 logger_(logger ? logger : spdlog::default_logger()) {
16}
17
19 const std::string& method, const MethodCallHandler& handler) {
20 method_handlers_[method] = handler;
21}
22
24 const std::string& method, const NotificationHandler& handler) {
25 notification_handlers_[method] = handler;
26}
27
28auto Dispatcher::DispatchRequest(std::string request)
29 -> asio::awaitable<std::optional<std::string>> {
30 auto root = nlohmann::json::parse(request, nullptr, false);
31 if (root.is_discarded()) {
32 co_return Response::CreateError(RpcErrorCode::kParseError).ToJson().dump();
33 }
34
35 // Single request
36 if (root.is_object()) {
37 auto request = Request::FromJson(root);
38 if (!request.has_value()) {
39 co_return Response::CreateError(request.error()).ToJson().dump();
40 }
41
42 auto response = co_await DispatchSingleRequest(request.value());
43 if (response.has_value()) {
44 co_return response.value().ToJson().dump();
45 }
46 co_return std::nullopt;
47 }
48
49 // Batch request
50 if (root.is_array()) {
51 if (root.empty()) {
52 co_return Response::CreateError(RpcErrorCode::kInvalidRequest)
53 .ToJson()
54 .dump();
55 }
56
57 std::vector<Request> requests;
58 std::vector<Response> responses;
59 for (const auto& element : root) {
60 auto request = Request::FromJson(element);
61 if (!request.has_value()) {
62 responses.push_back(Response::CreateError(request.error()));
63 continue;
64 }
65 requests.push_back(request.value());
66 }
67
68 auto dispatched = co_await DispatchBatchRequest(requests);
69 for (const auto& response : dispatched) {
70 responses.push_back(response);
71 }
72
73 co_return nlohmann::json(responses).dump();
74 }
75
76 co_return Response::CreateError(RpcErrorCode::kInvalidRequest)
77 .ToJson()
78 .dump();
79}
80
81auto Dispatcher::DispatchSingleRequest(Request request)
82 -> asio::awaitable<std::optional<Response>> {
83 auto method = request.GetMethod();
84
85 if (request.IsNotification()) {
86 auto it = notification_handlers_.find(method);
87 if (it != notification_handlers_.end()) {
88 Logger()->debug(
89 "Dispatcher found notification handler for method: {}", method);
90 co_spawn(
91 executor_,
92 [handler = it->second, params = request.GetParams()] {
93 return handler(params);
94 },
95 asio::detached);
96 co_return std::nullopt;
97 }
98 Logger()->debug(
99 "Dispatcher notification handler not found for method: {}", method);
100 co_return std::nullopt;
101 }
102
103 auto it = method_handlers_.find(method);
104 if (it != method_handlers_.end()) {
105 Logger()->debug("Dispatcher found method handler for method: {}", method);
106 auto result = co_await asio::co_spawn(
107 executor_,
108 [handler = it->second, params = request.GetParams()] {
109 return handler(params);
110 },
111 asio::use_awaitable);
112 co_return Response::CreateSuccess(result, request.GetId());
113 }
114 Logger()->debug("Dispatcher method handler not found for method: {}", method);
115 co_return Response::CreateError(
116 RpcErrorCode::kMethodNotFound, request.GetId());
117}
118
119auto Dispatcher::DispatchBatchRequest(std::vector<Request> requests)
120 -> asio::awaitable<std::vector<Response>> {
121 std::vector<asio::awaitable<std::optional<Response>>> pending;
122 pending.reserve(requests.size());
123
124 // Queue all requests in parallel
125 for (const auto& request : requests) {
126 // For valid requests, dispatch them normally
127 pending.push_back(DispatchSingleRequest(request));
128 }
129
130 // Wait for all requests to complete
131 std::vector<Response> responses;
132 for (auto& awaitable_response : pending) {
133 auto response = co_await std::move(awaitable_response);
134 if (response.has_value()) {
135 responses.push_back(response.value());
136 }
137 }
138
139 co_return responses;
140}
141
142} // namespace jsonrpc::endpoint
Dispatcher(asio::any_io_executor executor, std::shared_ptr< spdlog::logger > logger=nullptr)
std::function< asio::awaitable< nlohmann::json >( const std::optional< nlohmann::json > &)> MethodCallHandler
void RegisterNotification(const std::string &method, const NotificationHandler &handler)
std::function< asio::awaitable< void >( const std::optional< nlohmann::json > &)> NotificationHandler
auto DispatchRequest(std::string request) -> asio::awaitable< std::optional< std::string > >
void RegisterMethodCall(const std::string &method, const MethodCallHandler &handler)
static auto FromJson(const nlohmann::json &json_obj) -> std::expected< Request, error::RpcError >
Definition request.cpp:31
static auto CreateSuccess(const nlohmann::json &result, const std::optional< RequestId > &id) -> Response
Definition response.cpp:18
static auto CreateError(RpcErrorCode code, const std::optional< RequestId > &id=std::nullopt) -> Response
Definition response.cpp:28