Process a JSON-RPC request.
Request format: {"method": "name", "params": [...], "id": ...} Response format: {"result": ..., "id": ...} or {"error": {...}, "id": ...}
67 {
68
69 if (!request.contains("method")) {
70 FL_ERROR(
"RPC: Invalid Request - missing 'method' field");
72 }
73
74 auto methodOpt = request["method"].as_string();
75 if (!methodOpt.has_value()) {
76 FL_ERROR(
"RPC: Invalid Request - 'method' must be a string");
78 }
79 fl::string methodName = methodOpt.value();
80
81#if FL_PLATFORM_HAS_LARGE_MEMORY
82
83
84
85
86
87
88 if (methodName == "rpc.discover") {
92 if (request.contains("id")) {
94 }
96 }
97#endif
98
99
102 FL_WARN(
"RPC: Method not found: " << methodName.
c_str());
104 }
105
106
107 json params = request.contains(
"params") ? request[
"params"] :
json::parse(
"[]");
108 if (!params.is_array()) {
109 FL_ERROR(
"RPC: Invalid params - must be an array for method: " << methodName.
c_str());
111 }
112
113
114 const detail::RpcEntry& entry = it->second;
116
117
118 bool isResponseAware = entry.mIsResponseAware;
119
120
123 ack.set("jsonrpc", "2.0");
124 ack.set("id", request["id"]);
125
127 ackResult.set("acknowledged", true);
128 ack.set("result", ackResult);
129
131 FL_DBG(
"RPC: Sent ACK for async method: " << methodName.
c_str());
132 }
133
134 fl::tuple<TypeConversionResult, json> resultTuple;
135
136
137 if (isResponseAware) {
138
139 fl::json
requestId = request.contains(
"id") ? request[
"id"] : json(
nullptr);
141
142
143 entry.mResponseAwareFn(responseSend, params);
144
145
147 } else {
148
149 resultTuple = entry.mInvoker->invoke(params);
150 }
151
152 TypeConversionResult convResult =
fl::get<0>(resultTuple);
154
155
156 if (!convResult.ok()) {
157 FL_ERROR(
"RPC: Invalid params for method '" << methodName.
c_str() <<
"': " << convResult.errorMessage().c_str());
159 }
160
161
165
166
167 if (request.contains("id")) {
169 }
170
171
172 if (convResult.hasWarning()) {
174 for (fl::size i = 0; i < convResult.warnings().size(); ++i) {
175 warnings.push_back(json(convResult.warnings()[i]));
176 }
178 }
179
180
181 if (isAsync) {
183 }
184
186}
fl::unordered_map< fl::string, detail::RpcEntry > mRegistry
fl::function< void(const fl::json &)> mResponseSink
json schema() const
Returns flat schema document.
static TypeConversionResult success()
const char * c_str() const FL_NOEXCEPT
static json parse(const fl::string &txt) FL_NOEXCEPT
static json object() FL_NOEXCEPT
static json array() FL_NOEXCEPT
json makeJsonRpcError(int code, const fl::string &message, const json &id)
tuple< typename fl::decay< Ts >::type... > make_tuple(Ts &&... args) FL_NOEXCEPT
pair_element< I, T1, T2 >::type & get(pair< T1, T2 > &p) FL_NOEXCEPT