FastLED 3.10.8
Loading...
Searching...
No Matches
fetch.cpp.hpp
Go to the documentation of this file.
1#include "fl/net/http/fetch.h"
2#include "fl/stl/singleton.h"
4#include "fl/task/executor.h"
5#include "fl/stl/unique_ptr.h" // For make_unique
6#include "fl/task/task.h" // For fl::task::every_ms
7#include "fl/net/rpc_scheduler.h" // For fl::net::RpcScheduler
8#include "fl/net/http/fetch_request.h" // For fl::net::http::FetchRequest
9
10// IWYU pragma: begin_keep
11#ifdef FL_IS_WASM
12#include <emscripten.h>
13#include <emscripten/val.h>
14#endif
15// IWYU pragma: end_keep
16
17// Include WASM-specific implementation
18// IWYU pragma: begin_keep
19#include "platforms/wasm/js_fetch.h" // ok platform headers
20#include "fl/stl/compiler_control.h" // IWYU pragma: keep - FL_UNUSED
21// IWYU pragma: end_keep
22
23// Native networking includes
24#if defined(FASTLED_HAS_NETWORKING) && !defined(FL_IS_WASM)
25#include "fl/stl/cstdlib.h" // for atoi
26#include "fl/stl/int.h" // for u16
27
28#ifdef FL_IS_WIN
29 #include "platforms/win/socket_win.h" // ok platform headers // IWYU pragma: keep
30#else
31 #include "platforms/posix/socket_posix.h" // ok platform headers // IWYU pragma: keep
32 #include <fcntl.h> // ok platform headers (for O_NONBLOCK flag) // IWYU pragma: keep
33#include "fl/stl/noexcept.h"
34#endif
35#endif
36
37namespace fl {
38namespace net {
39namespace http {
40
41#ifdef FL_IS_WASM
42// ========== WASM Implementation using JavaScript fetch ==========
43
44
45
46// Promise storage moved to FetchManager singleton
47
48// Use existing WASM fetch infrastructure
49void fetch(const fl::string& url, const FetchCallback& callback) FL_NO_EXCEPT {
50 // Use the existing WASM fetch implementation - no conversion needed since both use fl::response
51 ::fl::wasm_fetch.get(url).response(callback);
52}
53
54// Internal helper to execute a fetch request and return a promise
55fl::task::Promise<Response> execute_fetch_request(const fl::string& url, const FetchOptions& request) FL_NO_EXCEPT {
56 // Create a promise for this request
58
59 // Register with fetch manager to ensure it's tracked
61
62 // Get the actual URL to use (use request URL if provided, otherwise use parameter URL)
63 fl::string fetch_url = request.url().empty() ? url : request.url();
64
65 // Convert our request to the existing WASM fetch system
66 auto wasm_request = ::fl::WasmFetchRequest(fetch_url);
67
68 // Use lambda that captures the promise directly (shared_ptr is safe to copy)
69 // Make the lambda mutable so we can call non-const methods on the captured promise
70 wasm_request.response([promise](const Response& resp) mutable {
71 // Complete the promise directly - no need for double storage
72 if (promise.valid()) {
73 promise.complete_with_value(resp);
74 }
75 });
76
77 return promise;
78}
79
80
81
82#elif defined(FASTLED_HAS_NETWORKING)
83// ========== Native Socket Implementation (POSIX/Windows) ==========
84
85#ifdef FL_IS_WIN
86 #define SOCKET_ERROR_WOULD_BLOCK WSAEWOULDBLOCK
87 #define SOCKET_ERROR_IN_PROGRESS WSAEINPROGRESS
88#else
89 #define SOCKET_ERROR_WOULD_BLOCK EWOULDBLOCK
90 #define SOCKET_ERROR_IN_PROGRESS EINPROGRESS
91#endif
92
93namespace {
94
95// Old blocking implementation removed - now using FetchRequest with fl::task
96
97/*
98// Helper: Perform synchronous HTTP request (DEPRECATED - now async with fl::task)
99response perform_http_request(const fl::string& url, const FetchOptions& request) FL_NO_EXCEPT {
100 ParsedURL parsed = parse_url(url);
101
102 if (!parsed.valid) {
103 response resp(400, "Bad Request");
104 resp.set_body("Invalid URL");
105 return resp;
106 }
107
108 if (parsed.protocol == "https") {
109 response resp(501, "Not Implemented");
110 resp.set_body("HTTPS not supported on this platform");
111 return resp;
112 }
113
114 // Create socket (initialization handled by socket wrapper)
115 int sock = socket(AF_INET, SOCK_STREAM, 0);
116 if (sock < 0) {
117 response resp(500, "Internal Server Error");
118 resp.set_body("Failed to create socket");
119 return resp;
120 }
121
122 // Resolve hostname
123 FL_WARN("[FETCH] Resolving hostname: " << parsed.host);
124 struct hostent* server = gethostbyname(parsed.host.c_str());
125 if (server == nullptr) {
126 close(sock);
127 response resp(500, "Internal Server Error");
128 resp.set_body("Failed to resolve hostname");
129 return resp;
130 }
131
132 // Set socket to non-blocking mode (allows async integration)
133#ifdef FL_IS_WIN
134 u_long mode = 1; // 1 = non-blocking
135 ioctlsocket(sock, FIONBIO, &mode);
136#else
137 int flags = fcntl(sock, F_GETFL, 0);
138 fcntl(sock, F_SETFL, flags | O_NONBLOCK);
139#endif
140
141 // Connect to server
142 struct sockaddr_in server_addr{};
143 server_addr.sin_family = AF_INET;
144 server_addr.sin_port = htons(static_cast<u16>(parsed.port));
145 memcpy(&server_addr.sin_addr.s_addr, server->h_addr, static_cast<size_t>(server->h_length));
146
147 // Non-blocking connect may return EINPROGRESS/EWOULDBLOCK immediately
148 int conn_result = connect(sock, (struct sockaddr*)&server_addr, sizeof(server_addr));
149 if (conn_result < 0) {
150#ifdef FL_IS_WIN
151 int err = WSAGetLastError();
152#else
153 int err = errno;
154#endif
155 if (err != SOCKET_ERROR_IN_PROGRESS && err != SOCKET_ERROR_WOULD_BLOCK) {
156 close(sock);
157 response resp(500, "Internal Server Error");
158 resp.set_body("Failed to connect to server");
159 return resp;
160 }
161 // Connection in progress, wait for it to complete
162 fd_set write_fds;
163 struct timeval timeout;
164 timeout.tv_sec = 5; // 5 second timeout
165 timeout.tv_usec = 0;
166
167 FD_ZERO(&write_fds);
168 FD_SET(sock, &write_fds);
169
170 // Wait for connection with async pumping
171 FL_WARN("[FETCH] Waiting for connection to " << parsed.host << ":" << parsed.port);
172 while (true) {
173 timeout.tv_sec = 0;
174 timeout.tv_usec = 10000; // 10ms
175 int sel_result = select(sock + 1, nullptr, &write_fds, nullptr, &timeout);
176 if (sel_result > 0) {
177 // Check if connection succeeded
178 int sock_err = 0;
179 socklen_t len = sizeof(sock_err);
180 getsockopt(sock, SOL_SOCKET, SO_ERROR, (char*)&sock_err, &len);
181 if (sock_err != 0) {
182 close(sock);
183 response resp(500, "Internal Server Error");
184 resp.set_body("Failed to connect to server");
185 return resp;
186 }
187 break; // Connection successful
188 } else if (sel_result < 0) {
189 close(sock);
190 response resp(500, "Internal Server Error");
191 resp.set_body("select() failed during connection");
192 return resp;
193 }
194 // Timeout or no data yet - pump async system to allow server to process
195 task::run(0);
196 }
197 }
198
199 // Build HTTP request
200 const auto& opts = request.options();
201 fl::string method = opts.method.empty() ? "GET" : opts.method;
202
203 fl::string http_request;
204 http_request += method + " " + parsed.path + " HTTP/1.0\r\n";
205 http_request += "Host: " + parsed.host + "\r\n";
206 http_request += "Connection: close\r\n";
207
208 // Add custom headers
209 for (const auto& header : opts.headers) {
210 http_request += header.first + ": " + header.second + "\r\n";
211 }
212
213 // Add body if present
214 if (!opts.body.empty()) {
215 http_request += "Content-Length: " + fl::to_string(opts.body.size()) + "\r\n";
216 http_request += "\r\n";
217 http_request += opts.body;
218 } else {
219 http_request += "\r\n";
220 }
221
222 // Send request
223 if (send(sock, http_request.c_str(), static_cast<int>(http_request.size()), 0) < 0) {
224 close(sock);
225 response resp(500, "Internal Server Error");
226 resp.set_body("Failed to send request");
227 return resp;
228 }
229
230 // Read response (non-blocking with async pumping)
231 FL_WARN("[FETCH] Waiting for HTTP response...");
232 fl::string response_data;
233 char buffer[4096];
234 int retries = 0;
235 const int max_retries = 5000; // 5000 * 10ms = 50 seconds timeout
236
237 while (retries < max_retries) {
238 int bytes = recv(sock, buffer, sizeof(buffer), 0);
239 if (bytes > 0) {
240 // Got data - append and reset retry counter
241 response_data.append(buffer, static_cast<size_t>(bytes));
242 retries = 0; // Reset on successful read
243 } else if (bytes == 0) {
244 // Connection closed by server
245 break;
246 } else {
247 // Error or would block
248#ifdef FL_IS_WIN
249 int err = WSAGetLastError();
250#else
251 int err = errno;
252#endif
253 if (err == SOCKET_ERROR_WOULD_BLOCK) {
254 // No data available yet - pump async system to allow server to process
255 task::run(0);
256 retries++;
257
258 // Small delay to avoid busy-waiting
259#ifdef FL_IS_WIN
260 Sleep(10); // 10ms
261#else
262 usleep(10000); // 10ms
263#endif
264 } else {
265 // Real error
266 close(sock);
267 response resp(500, "Internal Server Error");
268 resp.set_body("Failed to read response");
269 return resp;
270 }
271 }
272 }
273
274 close(sock);
275
276 if (retries >= max_retries) {
277 response resp(500, "Internal Server Error");
278 resp.set_body("Timeout reading response");
279 return resp;
280 }
281
282 // Parse HTTP response
283 size_t header_end = response_data.find("\r\n\r\n");
284 if (header_end == fl::string::npos) {
285 response resp(500, "Internal Server Error");
286 resp.set_body("Invalid HTTP response");
287 return resp;
288 }
289
290 fl::string header_section = response_data.substr(0, header_end);
291 fl::string body = response_data.substr(header_end + 4);
292
293 // Parse status line
294 size_t first_line_end = header_section.find("\r\n");
295 fl::string status_line = header_section.substr(0, first_line_end);
296
297 // Extract status code (format: "HTTP/1.1 200 OK")
298 size_t code_start = status_line.find(' ');
299 if (code_start == fl::string::npos) {
300 response resp(500, "Internal Server Error");
301 resp.set_body("Invalid status line");
302 return resp;
303 }
304
305 size_t code_end = status_line.find(' ', code_start + 1);
306 fl::string code_str = status_line.substr(code_start + 1, code_end - code_start - 1);
307 int status_code = atoi(code_str.c_str());
308
309 fl::string status_text = (code_end != fl::string::npos)
310 ? status_line.substr(code_end + 1)
311 : "";
312
313 // Create response object
314 response resp(status_code, status_text);
315 resp.set_body(body);
316
317 // Parse headers
318 size_t header_start = first_line_end + 2;
319 while (header_start < header_section.size()) {
320 size_t line_end = header_section.find("\r\n", header_start);
321 if (line_end == fl::string::npos) break;
322
323 fl::string header_line = header_section.substr(header_start, line_end - header_start);
324 size_t colon = header_line.find(':');
325 if (colon != fl::string::npos) {
326 fl::string name = header_line.substr(0, colon);
327 fl::string value = header_line.substr(colon + 1);
328 // Trim leading space from value
329 if (!value.empty() && value[0] == ' ') {
330 value = value.substr(1);
331 }
332 // Normalize header name to lowercase for case-insensitive lookup (RFC 2616)
333 for (size_t i = 0; i < name.size(); ++i) {
334 if (name[i] >= 'A' && name[i] <= 'Z') {
335 name[i] = name[i] + ('a' - 'A');
336 }
337 }
338 resp.set_header(name, value);
339 }
340
341 header_start = line_end + 2;
342 }
343
344 return resp;
345}
346*/
347
348} // anonymous namespace
349
350void fetch(const fl::string& url, const FetchCallback& callback) FL_NO_EXCEPT {
351 // Use async execute_fetch_request and attach callback to promise
353 .then([callback](const Response& resp) {
354 callback(resp);
355 })
356 .catch_([callback](const fl::task::Error& err) {
357 // On error, return 500 response
358 Response resp(500, "Internal Server Error");
359 resp.set_body(err.message);
360 callback(resp);
361 });
362}
363
364// Internal helper to execute a fetch request and return a promise
365fl::task::Promise<Response> execute_fetch_request(const fl::string& url, const FetchOptions& request) FL_NO_EXCEPT {
366 // Create promise for this request
368
369 // Register promise with FetchManager for tracking
371
372 // Create shared FetchRequest (managed by task lambda)
373 auto fetch_req = fl::make_shared<FetchRequest>(url, request, promise);
374
375 // Create self-canceling task (stored in shared_ptr for lambda capture)
376 auto task_ptr = fl::make_shared<fl::task::Handle>();
377
378 *task_ptr = fl::task::every_ms(1) // Update every 1ms
379 .then([fetch_req, task_ptr]() {
380 // Pump the fetch state machine
381 fetch_req->update();
382
383 // Self-cancel when done
384 if (fetch_req->is_done()) {
385 task_ptr->cancel();
386 }
387 })
388 .catch_([promise](const fl::task::Error& e) mutable {
389 // Task error - reject promise if not already completed
390 if (promise.valid() && !promise.is_completed()) {
391 promise.complete_with_error(e);
392 }
393 });
394
395 // Add to scheduler
397
398 return promise;
399}
400
401#else
402// ========== True Stub Implementation (no networking) ==========
403
404void fetch(const fl::string& url, const FetchCallback& callback) FL_NO_EXCEPT {
405 (void)url;
406 Response resp(501, "Not Implemented");
407 resp.set_text("HTTP fetch not supported on this platform");
408 callback(resp);
409}
410
412 FL_UNUSED(request);
413 FL_UNUSED(url); // only consumed by FL_WARN, a no-op on small platforms
414 FL_WARN("HTTP fetch is not supported on this platform. URL: " << url);
415 Response error_response(501, "Not Implemented");
416 error_response.set_body("HTTP fetch is not available on this platform.");
417 return fl::task::Promise<Response>::resolve(error_response);
418}
419
420#endif
421
422// ========== Engine Events Integration ==========
423
424
425
426// ========== Promise-Based API Implementation ==========
427
429public:
434 // Listener base class automatically removes itself
436 }
437
438 void onEndFrame() FL_NO_EXCEPT override {
439 // Update all async tasks (fetch, timers, etc.) at the end of each frame
440 fl::task::run(0);
441 }
442};
443
447
449 // Auto-register with async system and engine listener on first promise
450 if (mActivePromises.empty()) {
452
453 if (!mEngineListener) {
456 }
457 }
458
459 mActivePromises.push_back(promise);
460}
461
463 // Update all active promises first
464 for (auto& promise : mActivePromises) {
465 if (promise.valid()) {
466 promise.update();
467 }
468 }
469
470 // Then clean up completed/invalid promises in a separate pass
472
473 // Auto-unregister from async system when no more promises
474 if (mActivePromises.empty()) {
476
477 if (mEngineListener) {
479 mEngineListener.reset();
480 }
481 }
482}
483
485 return !mActivePromises.empty();
486}
487
489 return mActivePromises.size();
490}
491
493 return mActivePromises.size();
494}
495
497 // Rebuild vector without completed promises
499 for (const auto& promise : mActivePromises) {
500 if (promise.valid() && !promise.is_completed()) {
501 active_promises.push_back(promise);
502 }
503 }
504 mActivePromises = fl::move(active_promises);
505}
506
507// WASM promise management methods removed - no longer needed
508// Promises are now handled directly via shared_ptr capture in callbacks
509
510// ========== Public API Functions ==========
511
513 // Create a new request with GET method
514 FetchOptions get_request(url, RequestOptions("GET"));
515
516 // Apply any additional options from the provided request
517 const auto& opts = request.options();
518 get_request.timeout(opts.timeout_ms);
519 for (const auto& header : opts.headers) {
520 get_request.header(header.first, header.second);
521 }
522 if (!opts.body.empty()) {
523 get_request.body(opts.body);
524 }
525
526 return execute_fetch_request(url, get_request);
527}
528
530 // Create a new request with POST method
531 FetchOptions post_request(url, RequestOptions("POST"));
532
533 // Apply any additional options from the provided request
534 const auto& opts = request.options();
535 post_request.timeout(opts.timeout_ms);
536 for (const auto& header : opts.headers) {
537 post_request.header(header.first, header.second);
538 }
539 if (!opts.body.empty()) {
540 post_request.body(opts.body);
541 }
542
543 return execute_fetch_request(url, post_request);
544}
545
547 // Create a new request with PUT method
548 FetchOptions put_request(url, RequestOptions("PUT"));
549
550 // Apply any additional options from the provided request
551 const auto& opts = request.options();
552 put_request.timeout(opts.timeout_ms);
553 for (const auto& header : opts.headers) {
554 put_request.header(header.first, header.second);
555 }
556 if (!opts.body.empty()) {
557 put_request.body(opts.body);
558 }
559
560 return execute_fetch_request(url, put_request);
561}
562
564 // Create a new request with DELETE method
565 FetchOptions delete_request(url, RequestOptions("DELETE"));
566
567 // Apply any additional options from the provided request
568 const auto& opts = request.options();
569 delete_request.timeout(opts.timeout_ms);
570 for (const auto& header : opts.headers) {
571 delete_request.header(header.first, header.second);
572 }
573 if (!opts.body.empty()) {
574 delete_request.body(opts.body);
575 }
576
577 return execute_fetch_request(url, delete_request);
578}
579
581 // Create a new request with HEAD method
582 FetchOptions head_request(url, RequestOptions("HEAD"));
583
584 // Apply any additional options from the provided request
585 const auto& opts = request.options();
586 head_request.timeout(opts.timeout_ms);
587 for (const auto& header : opts.headers) {
588 head_request.header(header.first, header.second);
589 }
590 if (!opts.body.empty()) {
591 head_request.body(opts.body);
592 }
593
594 return execute_fetch_request(url, head_request);
595}
596
598 // Create a new request with OPTIONS method
599 FetchOptions options_request(url, RequestOptions("OPTIONS"));
600
601 // Apply any additional options from the provided request
602 const auto& opts = request.options();
603 options_request.timeout(opts.timeout_ms);
604 for (const auto& header : opts.headers) {
605 options_request.header(header.first, header.second);
606 }
607 if (!opts.body.empty()) {
608 options_request.body(opts.body);
609 }
610
611 return execute_fetch_request(url, options_request);
612}
613
615 // Create a new request with PATCH method
616 FetchOptions patch_request(url, RequestOptions("PATCH"));
617
618 // Apply any additional options from the provided request
619 const auto& opts = request.options();
620 patch_request.timeout(opts.timeout_ms);
621 for (const auto& header : opts.headers) {
622 patch_request.header(header.first, header.second);
623 }
624 if (!opts.body.empty()) {
625 patch_request.body(opts.body);
626 }
627
628 return execute_fetch_request(url, patch_request);
629}
630
632 // Create a FetchOptions with the provided options
633 FetchOptions request(url, options);
634
635 // Use the helper function to execute the request
636 return execute_fetch_request(url, request);
637}
638
640 // Legacy function - use fl::task::run() for new code
641 // This provides backwards compatibility for existing code
642 fl::task::run(0);
643}
644
648
649// ========== Response Class Method Implementations ==========
650
652 if (!mJsonParsed) {
653 if (is_json() || mBody.find("{") != fl::string::npos || mBody.find("[") != fl::string::npos) {
655 } else {
656 FL_WARN("Response is not JSON: " << mBody);
657 mCachedJson = fl::json(nullptr); // Not JSON content
658 }
659 mJsonParsed = true;
660 }
661
662 return mCachedJson.has_value() ? *mCachedJson : fl::json(nullptr);
663}
664
665} // namespace http
666} // namespace net
667} // namespace fl
static void removeListener(Listener *listener) FL_NO_EXCEPT
static void addListener(Listener *listener, int priority=0) FL_NO_EXCEPT
static T & instance() FL_NO_EXCEPT
Definition singleton.h:41
~FetchEngineListener() FL_NO_EXCEPT override
void onEndFrame() FL_NO_EXCEPT override
void cleanup_completed_promises() FL_NO_EXCEPT
size_t active_task_count() const FL_NO_EXCEPT override
Get number of active tasks (for debugging/monitoring)
fl::size active_requests() const FL_NO_EXCEPT
fl::unique_ptr< FetchEngineListener > mEngineListener
Definition fetch.h:265
void register_promise(const fl::task::Promise< Response > &promise) FL_NO_EXCEPT
fl::vector< fl::task::Promise< Response > > mActivePromises
Definition fetch.h:264
bool has_active_tasks() const FL_NO_EXCEPT override
Check if this runner has active tasks.
static FetchManager & instance() FL_NO_EXCEPT
void update() FL_NO_EXCEPT override
Update this runner (called during task pumping)
Internal fetch manager for promise tracking.
Definition fetch.h:248
FetchOptions & timeout(int timeout_ms) FL_NO_EXCEPT
Set timeout in milliseconds.
Definition fetch.h:227
FetchOptions & header(const fl::string &name, const fl::string &value) FL_NO_EXCEPT
Add header.
Definition fetch.h:208
FetchOptions & body(const fl::string &data) FL_NO_EXCEPT
Set request body.
Definition fetch.h:214
Fetch options builder (fluent interface)
Definition fetch.h:195
void set_body(const fl::string &body) FL_NO_EXCEPT
Definition fetch.h:136
fl::json parse_json_body() const FL_NO_EXCEPT
Parse JSON from response body with error handling.
Definition fetch.h:152
void set_text(const fl::string &body) FL_NO_EXCEPT
Definition fetch.h:135
bool is_json() const FL_NO_EXCEPT
Check if response appears to contain JSON content.
Definition fetch.h:122
fl::json json() const FL_NO_EXCEPT
Response body parsed as JSON (JavaScript-like API)
fl::optional< fl::json > mCachedJson
Definition fetch.h:148
HTTP response class (unified interface)
Definition fetch.h:78
static constexpr fl::size npos
Definition string.h:204
void register_runner(Runner *r) FL_NO_EXCEPT
Register a runner.
void unregister_runner(Runner *r) FL_NO_EXCEPT
Unregister a runner.
static Executor & instance() FL_NO_EXCEPT
Handle & then(function< void()> on_then) FL_NO_EXCEPT
Sets the callback invoked when the task runs successfully.
Definition task.cpp.hpp:276
static Promise< T > resolve(const T &value) FL_NO_EXCEPT
Create a resolved Promise with value.
Definition promise.h:67
static Promise< T > create() FL_NO_EXCEPT
Create a pending Promise.
Definition promise.h:61
Promise class that provides fluent .then() and .catch_() semantics This is a lightweight wrapper arou...
Definition promise.h:58
static Scheduler & instance() FL_NO_EXCEPT
int add_task(Handle t) FL_NO_EXCEPT
Definition url.h:15
void push_back(const T &value) FL_NO_EXCEPT
Definition vector.h:624
Task executor — runs registered task runners and manages the run loop.
Unified HTTP fetch API for FastLED (cross-platform)
#define FL_WARN(...)
Definition log.h:437
fl::enable_if<!fl::is_array< T >::value, unique_ptr< T > >::type make_unique(Args &&... args) FL_NO_EXCEPT
Definition unique_ptr.h:263
shared_ptr< T > make_shared(Args &&... args) FL_NO_EXCEPT
Definition shared_ptr.h:423
constexpr remove_reference< T >::type && move(T &&t) FL_NO_EXCEPT
Definition s16x16x4.h:30
void fetch_update() FL_NO_EXCEPT
Legacy manual update for fetch promises (use fl::task::run() for new code)
fl::task::Promise< Response > fetch_put(const fl::string &url, const FetchOptions &request) FL_NO_EXCEPT
HTTP PUT request.
fl::task::Promise< Response > fetch_patch(const fl::string &url, const FetchOptions &request) FL_NO_EXCEPT
HTTP PATCH request.
void fetch(const fl::string &url, const FetchCallback &callback) FL_NO_EXCEPT
Make an HTTP GET request (cross-platform, backward compatible)
fl::size fetch_active_requests() FL_NO_EXCEPT
Get number of active requests.
fl::function< void(const Response &)> FetchCallback
Callback type for simple fetch responses (backward compatible)
Definition fetch.h:181
fl::task::Promise< Response > fetch_head(const fl::string &url, const FetchOptions &request) FL_NO_EXCEPT
HTTP HEAD request.
fl::task::Promise< Response > execute_fetch_request(const fl::string &url, const FetchOptions &request) FL_NO_EXCEPT
Internal helper to execute a fetch request and return a promise.
fl::task::Promise< Response > fetch_http_options(const fl::string &url, const FetchOptions &request) FL_NO_EXCEPT
HTTP OPTIONS request.
fl::task::Promise< Response > fetch_post(const fl::string &url, const FetchOptions &request) FL_NO_EXCEPT
HTTP POST request.
fl::task::Promise< Response > fetch_request(const fl::string &url, const RequestOptions &options) FL_NO_EXCEPT
Generic request with options (like fetch(url, options))
fl::task::Promise< Response > fetch_get(const fl::string &url, const FetchOptions &request) FL_NO_EXCEPT
HTTP GET request.
fl::task::Promise< Response > fetch_delete(const fl::string &url, const FetchOptions &request) FL_NO_EXCEPT
HTTP DELETE request.
void run(fl::u32 microseconds, ExecFlags flags) FL_NO_EXCEPT
Run selected task subsystems.
Handle every_ms(int interval_ms) FL_NO_EXCEPT
Creates a task that runs at a fixed millisecond interval.
Definition task.cpp.hpp:320
u8 u8 fract8 blur_amount FL_NO_EXCEPT
Definition blur.h:186
Base definition for an LED controller.
#define FL_UNUSED(x)
Request options (matches JavaScript fetch RequestInit)
Definition fetch.h:184
fl::string message
Definition promise.h:40