23 bool removed =
mRpc.unbind(name.c_str());
25 FL_DBG(
"Unregistered RPC function: " << name);
31 return mRpc.has(name.c_str());
40#if FL_PLATFORM_HAS_LARGE_MEMORY
43 auto it = mAsyncRequests.find(methodName);
44 if (it == mAsyncRequests.end()) {
45 FL_WARN(
"No pending async request for method: " << method);
50 mAsyncRequests.erase(it);
54 response.set(
"jsonrpc",
"2.0");
56 response.set(
"result",
result);
60 mResponseSink(response);
61 FL_DBG(
"Sent async response for " << method <<
" (id=" <<
requestId <<
")");
66 fl::string methodName(method);
67 auto it = mAsyncRequests.find(methodName);
68 if (it == mAsyncRequests.end()) {
69 FL_WARN(
"No pending async request for method: " << method);
82 resultObj.
set(
"update", update);
87 mResponseSink(response);
88 FL_DBG(
"Sent stream update for " << method <<
" (id=" <<
requestId <<
")");
93 fl::string methodName(method);
94 auto it = mAsyncRequests.find(methodName);
95 if (it == mAsyncRequests.end()) {
96 FL_WARN(
"No pending async request for method: " << method);
101 mAsyncRequests.erase(it);
110 resultObj.
set(
"stop",
true);
115 mResponseSink(response);
116 FL_DBG(
"Sent stream final for " << method <<
" (id=" <<
requestId <<
")");
123 FL_WARN_LIT(
"sendAsyncResponse: async dispatch not supported on Low-memory targets");
126 FL_WARN_LIT(
"sendStreamUpdate: async streams not supported on Low-memory targets");
129 FL_WARN_LIT(
"sendStreamFinal: async streams not supported on Low-memory targets");
137 params.
set(
"message", message);
146 notification.
set(
"jsonrpc",
"2.0");
147 notification.
set(
"method",
"__error");
148 notification.
set(
"params", data);
155#if FL_PLATFORM_HAS_LARGE_MEMORY
160 if (request.contains(
"timestamp") && request[
"timestamp"].is_int()) {
161 timestamp =
static_cast<u32
>(request[
"timestamp"].as_int().
value());
167#if FL_PLATFORM_HAS_LARGE_MEMORY
169 if (timestamp != 0) {
171 scheduleFunction(timestamp, receivedAt, request);
172 FL_DBG(
"RPC: Scheduled function - result will be pushed after execution");
176 if (request.contains(
"id")) {
177 response.set(
"id", request[
"id"]);
179 response.set(
"result",
fl::json(
nullptr));
180 response.set(
"scheduled",
true);
187#if FL_PLATFORM_HAS_LARGE_MEMORY
193 if (request.contains(
"id") && request.contains(
"method")) {
194 fl::string methodName = request[
"method"].as_string().value_or(
"");
195 int requestId = request[
"id"].as_int().value_or(0);
196 mAsyncRequests[methodName] = {
requestId, receivedAt};
204#if FL_PLATFORM_HAS_LARGE_MEMORY
208 bool ackAlready = (response.contains(
"ackOnly") && response[
"ackOnly"].as_bool().value_or(
false))
209 || (response.contains(
"__async") && response[
"__async"].as_bool().value_or(
false));
214 nullResponse.
set(
"noEnqueue",
true);
219 if (request.contains(
"method")) {
220 fl::string methodName = request[
"method"].as_string().value_or(
"");
221 mAsyncRequests.
erase(methodName);
225#if FL_PLATFORM_HAS_LARGE_MEMORY
229 if (response.contains(
"result") && request.contains(
"method")) {
230 fl::string funcName = request[
"method"].as_string().value_or(
"");
231 recordResult(funcName, response[
"result"], 0, receivedAt, receivedAt,
false);
240#if FL_PLATFORM_HAS_LARGE_MEMORY
241void Remote::scheduleFunction(u32 timestamp, u32 receivedAt,
const fl::json& jsonRpcRequest)
FL_NO_EXCEPT {
243 fl::json requestCopy = jsonRpcRequest;
247 mScheduler.schedule(timestamp, [
this, requestCopy, timestamp, receivedAt, funcName]() {
251 fl::json response = mRpc.handle(requestCopy);
254 if (response.contains(
"result") && requestCopy.
contains(
"method")) {
255 recordResult(funcName, response[
"result"], timestamp, receivedAt, executedAt,
true);
259 FL_DBG(
"Scheduled RPC: " << funcName <<
" at " << timestamp);
262void Remote::recordResult(
const fl::string& funcName,
const fl::json&
result, u32 scheduledAt, u32 receivedAt, u32 executedAt,
bool wasScheduled)
FL_NO_EXCEPT {
263 mResults.push_back({funcName,
result, scheduledAt, receivedAt, executedAt, wasScheduled});
270#if FL_PLATFORM_HAS_LARGE_MEMORY
275 return mScheduler.tick(currentTimeMs);
285#if FL_PLATFORM_HAS_LARGE_MEMORY
286 return mScheduler.pendingCount();
293#if FL_PLATFORM_HAS_LARGE_MEMORY
294 if ((flags & ClearFlags::Results) != ClearFlags::None) {
296 FL_DBG(
"Cleared RPC results");
298 if ((flags & ClearFlags::Scheduled) != ClearFlags::None) {
300 FL_DBG(
"Cleared scheduled RPC calls");
303 if ((flags & ClearFlags::Functions) != ClearFlags::None) {
305 FL_DBG(
"Cleared registered RPC functions");
318#if FL_PLATFORM_HAS_LARGE_MEMORY
337#if FL_PLATFORM_HAS_LARGE_MEMORY
339 if (mResponseStreamSink) {
340 mResponseStreamSink(
fl::move(writeJson));
350 size_t executed =
tick(currentTimeMs);
352#if FL_PLATFORM_HAS_LARGE_MEMORY
355 for (
const auto& r : mResults) {
357 response.set(
"result", r.result);
365 return processed + executed + sent;
382 for (fl::size i = 0; i < jsonMethods.
size(); i++) {
400 for (fl::size j = 0; j < params.
size(); j++) {
FastLED chrono implementation - duration types for time measurements.
Remote(RequestSource source, ResponseSink sink) FL_NO_EXCEPT
Construct with I/O callbacks.
void clear(ClearFlags flags) FL_NO_EXCEPT
Clear state (bitwise OR of ClearFlags)
fl::json processRpc(const fl::json &request) FL_NO_EXCEPT
Process JSON-RPC request (with optional "timestamp" field for scheduling) Returns JSON-RPC response: ...
fl::MethodInfo MethodInfo
size_t pendingCount() const FL_NO_EXCEPT
Get number of pending scheduled calls.
bool has(const fl::string &name) const FL_NO_EXCEPT
Check if method is registered.
fl::RemoteClearFlags ClearFlags
bool unbind(const fl::string &name) FL_NO_EXCEPT
Unregister method by name.
fl::vector< MethodInfo > methods() const FL_NO_EXCEPT
Get method information for all registered methods.
void sendAsyncResponse(const char *method, const fl::json &result) FL_NO_EXCEPT
Send async response for a previously-called async method The request ID is automatically retrieved fr...
void sendStreamUpdate(const char *method, const fl::json &update) FL_NO_EXCEPT
Send stream update for a streaming async method (ASYNC_STREAM mode) The request ID is automatically r...
void sendStreamFinal(const char *method, const fl::json &result) FL_NO_EXCEPT
Send final stream response for a streaming async method (ASYNC_STREAM mode) The request ID is automat...
void reportError(const fl::string &message) FL_NO_EXCEPT
Send an error notification to the remote peer.
size_t tick(u32 currentTimeMs) FL_NO_EXCEPT
Process scheduled calls (call regularly)
fl::vector< fl::json > mOutgoingQueue
fl::function< fl::optional< fl::json >()> RequestSource
void setRequestHandler(RequestHandler handler) FL_NO_EXCEPT
Set request handler.
size_t update() FL_NO_EXCEPT
Main update: pull + push.
Server() FL_NO_EXCEPT
Default constructor.
size_t pull() FL_NO_EXCEPT
Pull requests from source, process, queue responses.
void setResponseStreamSink(ResponseStreamSink sink) FL_NO_EXCEPT
Set streaming response sink callback.
size_t push() FL_NO_EXCEPT
Push queued responses to sink.
fl::function< void(const fl::json &)> ResponseSink
ResponseSink mResponseSink
const char * c_str() const FL_NO_EXCEPT
basic_string & erase(fl::size pos=0, fl::size count=npos) FL_NO_EXCEPT
size_t size() const FL_NO_EXCEPT
fl::optional< fl::string > as_string() const FL_NO_EXCEPT
void set(const fl::string &key, const json &value) FL_NO_EXCEPT
bool is_array() const FL_NO_EXCEPT
bool contains(size_t idx) const FL_NO_EXCEPT
static json object() FL_NO_EXCEPT
void clear() FL_NO_EXCEPT
FastLED's Elegant JSON Library: fl::json
#define FL_WARN_LIT(LITERAL)
Centralized logging categories for FastLED hardware interfaces and subsystems.
constexpr remove_reference< T >::type && move(T &&t) FL_NO_EXCEPT
u8 u8 fract8 blur_amount FL_NO_EXCEPT
constexpr int type_rank< T >::value
fl::u32 millis() FL_NO_EXCEPT
Universal millisecond timer - returns milliseconds since system startup.
fl::function< void(fl::JsonStreamWriter &)> JsonStreamCallback
expected< T, E > result
Alias for expected (Rust-style naming)
fl::function< void(fl::JsonStreamCallback)> ResponseStreamSink
Base definition for an LED controller.
fl::vector< ParamInfo > params
fl::vector< fl::string > tags