FastLED 3.9.15
Loading...
Searching...
No Matches
fetch.cpp
Go to the documentation of this file.
1#include "fl/fetch.h"
2#include "fl/warn.h"
3#include "fl/str.h"
4#include "fl/mutex.h"
5#include "fl/singleton.h"
6#include "fl/engine_events.h"
7#include "fl/async.h"
8
9#ifdef __EMSCRIPTEN__
10#include <emscripten.h>
11#include <emscripten/val.h>
12#endif
13
14// Include WASM-specific implementation
15#include "platforms/wasm/js_fetch.h"
16
17namespace fl {
18
19#ifdef __EMSCRIPTEN__
20// ========== WASM Implementation using JavaScript fetch ==========
21
22
23
24// Promise storage moved to FetchManager singleton
25
26// Use existing WASM fetch infrastructure
27void fetch(const fl::string& url, const FetchCallback& callback) {
28 // Use the existing WASM fetch implementation - no conversion needed since both use fl::response
29 wasm_fetch.get(url).response(callback);
30}
31
32// Internal helper to execute a fetch request and return a promise
33fl::promise<response> execute_fetch_request(const fl::string& url, const fetch_options& request) {
34 // Create a promise for this request
36
37 // Register with fetch manager to ensure it's tracked
39
40 // Get the actual URL to use (use request URL if provided, otherwise use parameter URL)
41 fl::string fetch_url = request.url().empty() ? url : request.url();
42
43 // Convert our request to the existing WASM fetch system
44 auto wasm_request = WasmFetchRequest(fetch_url);
45
46 // Use lambda that captures the promise directly (shared_ptr is safe to copy)
47 // Make the lambda mutable so we can call non-const methods on the captured promise
48 wasm_request.response([promise](const response& resp) mutable {
49 // Complete the promise directly - no need for double storage
50 if (promise.valid()) {
52 }
53 });
54
55 return promise;
56}
57
58
59
60#else
61// ========== Embedded/Stub Implementation ==========
62
63void fetch(const fl::string& url, const FetchCallback& callback) {
64 (void)url; // Unused in stub implementation
65 // For embedded platforms, immediately call callback with a "not supported" response
66 response resp(501, "Not Implemented");
67 resp.set_text("HTTP fetch not supported on this platform");
68 callback(resp);
69}
70
71// Internal helper to execute a fetch request and return a promise
73 (void)request; // Unused in stub implementation
74 FL_WARN("HTTP fetch is not supported on non-WASM platforms. URL: " << url);
75
76 // Create error response
77 response error_response(501, "Not Implemented");
78 error_response.set_body("HTTP fetch is only available in WASM/browser builds. This platform does not support network requests.");
79
80 // Create resolved promise with error response
81 auto promise = fl::promise<response>::resolve(error_response);
82
83 return promise;
84}
85
86
87
88#endif
89
90// ========== Engine Events Integration ==========
91
92
93
94// ========== Promise-Based API Implementation ==========
95
97public:
102 // Listener base class automatically removes itself
104 }
105
106 void onEndFrame() override {
107 // Update all async tasks (fetch, timers, etc.) at the end of each frame
109 }
110};
111
115
117 // Auto-register with async system and engine listener on first promise
118 if (mActivePromises.empty()) {
120
121 if (!mEngineListener) {
124 }
125 }
126
127 mActivePromises.push_back(promise);
128}
129
131 // Update all active promises first
132 for (auto& promise : mActivePromises) {
133 if (promise.valid()) {
134 promise.update();
135 }
136 }
137
138 // Then clean up completed/invalid promises in a separate pass
140
141 // Auto-unregister from async system when no more promises
142 if (mActivePromises.empty()) {
144
145 if (mEngineListener) {
147 mEngineListener.reset();
148 }
149 }
150}
151
153 return !mActivePromises.empty();
154}
155
157 return mActivePromises.size();
158}
159
161 return mActivePromises.size();
162}
163
165 // Rebuild vector without completed promises
166 fl::vector<fl::promise<response>> active_promises;
167 for (const auto& promise : mActivePromises) {
168 if (promise.valid() && !promise.is_completed()) {
169 active_promises.push_back(promise);
170 }
171 }
172 mActivePromises = fl::move(active_promises);
173}
174
175// WASM promise management methods removed - no longer needed
176// Promises are now handled directly via shared_ptr capture in callbacks
177
178// ========== Public API Functions ==========
179
181 // Create a new request with GET method
182 fetch_options get_request(url, RequestOptions("GET"));
183
184 // Apply any additional options from the provided request
185 const auto& opts = request.options();
186 get_request.timeout(opts.timeout_ms);
187 for (const auto& header : opts.headers) {
188 get_request.header(header.first, header.second);
189 }
190 if (!opts.body.empty()) {
191 get_request.body(opts.body);
192 }
193
194 return execute_fetch_request(url, get_request);
195}
196
198 // Create a new request with POST method
199 fetch_options post_request(url, RequestOptions("POST"));
200
201 // Apply any additional options from the provided request
202 const auto& opts = request.options();
203 post_request.timeout(opts.timeout_ms);
204 for (const auto& header : opts.headers) {
205 post_request.header(header.first, header.second);
206 }
207 if (!opts.body.empty()) {
208 post_request.body(opts.body);
209 }
210
211 return execute_fetch_request(url, post_request);
212}
213
215 // Create a new request with PUT method
216 fetch_options put_request(url, RequestOptions("PUT"));
217
218 // Apply any additional options from the provided request
219 const auto& opts = request.options();
220 put_request.timeout(opts.timeout_ms);
221 for (const auto& header : opts.headers) {
222 put_request.header(header.first, header.second);
223 }
224 if (!opts.body.empty()) {
225 put_request.body(opts.body);
226 }
227
228 return execute_fetch_request(url, put_request);
229}
230
232 // Create a new request with DELETE method
233 fetch_options delete_request(url, RequestOptions("DELETE"));
234
235 // Apply any additional options from the provided request
236 const auto& opts = request.options();
237 delete_request.timeout(opts.timeout_ms);
238 for (const auto& header : opts.headers) {
239 delete_request.header(header.first, header.second);
240 }
241 if (!opts.body.empty()) {
242 delete_request.body(opts.body);
243 }
244
245 return execute_fetch_request(url, delete_request);
246}
247
249 // Create a new request with HEAD method
250 fetch_options head_request(url, RequestOptions("HEAD"));
251
252 // Apply any additional options from the provided request
253 const auto& opts = request.options();
254 head_request.timeout(opts.timeout_ms);
255 for (const auto& header : opts.headers) {
256 head_request.header(header.first, header.second);
257 }
258 if (!opts.body.empty()) {
259 head_request.body(opts.body);
260 }
261
262 return execute_fetch_request(url, head_request);
263}
264
266 // Create a new request with OPTIONS method
267 fetch_options options_request(url, RequestOptions("OPTIONS"));
268
269 // Apply any additional options from the provided request
270 const auto& opts = request.options();
271 options_request.timeout(opts.timeout_ms);
272 for (const auto& header : opts.headers) {
273 options_request.header(header.first, header.second);
274 }
275 if (!opts.body.empty()) {
276 options_request.body(opts.body);
277 }
278
279 return execute_fetch_request(url, options_request);
280}
281
283 // Create a new request with PATCH method
284 fetch_options patch_request(url, RequestOptions("PATCH"));
285
286 // Apply any additional options from the provided request
287 const auto& opts = request.options();
288 patch_request.timeout(opts.timeout_ms);
289 for (const auto& header : opts.headers) {
290 patch_request.header(header.first, header.second);
291 }
292 if (!opts.body.empty()) {
293 patch_request.body(opts.body);
294 }
295
296 return execute_fetch_request(url, patch_request);
297}
298
300 // Create a fetch_options with the provided options
301 fetch_options request(url, options);
302
303 // Use the helper function to execute the request
304 return execute_fetch_request(url, request);
305}
306
308 // Legacy function - use fl::async_run() for new code
309 // This provides backwards compatibility for existing code
311}
312
316
317// ========== Response Class Method Implementations ==========
318
320 if (!mJsonParsed) {
321 if (is_json() || mBody.find("{") != fl::string::npos || mBody.find("[") != fl::string::npos) {
323 } else {
324 FL_WARN("Response is not JSON: " << mBody);
325 mCachedJson = fl::Json(nullptr); // Not JSON content
326 }
327 mJsonParsed = true;
328 }
329
330 return mCachedJson.has_value() ? *mCachedJson : fl::Json(nullptr);
331}
332
333} // namespace fl
static AsyncManager & instance()
Definition async.cpp:16
void register_runner(async_runner *runner)
Register an async runner.
Definition async.cpp:20
void unregister_runner(async_runner *runner)
Unregister an async runner.
Definition async.cpp:26
static void addListener(Listener *listener, int priority=0)
static void removeListener(Listener *listener)
~FetchEngineListener() override
Definition fetch.cpp:101
void onEndFrame() override
Definition fetch.cpp:106
fl::size active_requests() const
Definition fetch.cpp:160
fl::unique_ptr< FetchEngineListener > mEngineListener
Definition fetch.h:270
static FetchManager & instance()
Definition fetch.cpp:112
void update() override
Update this async runner (called during async pumping)
Definition fetch.cpp:130
void cleanup_completed_promises()
Definition fetch.cpp:164
fl::vector< fl::promise< response > > mActivePromises
Definition fetch.h:269
void register_promise(const fl::promise< response > &promise)
Definition fetch.cpp:116
bool has_active_tasks() const override
Check if this runner has active tasks.
Definition fetch.cpp:152
size_t active_task_count() const override
Get number of active tasks (for debugging/monitoring)
Definition fetch.cpp:156
Internal fetch manager for promise tracking.
Definition fetch.h:253
void push_back(const T &value)
Definition vector.h:552
static T & instance()
Definition singleton.h:11
fetch_options & timeout(int timeout_ms)
Set timeout in milliseconds.
Definition fetch.h:232
fetch_options & body(const fl::string &data)
Set request body.
Definition fetch.h:219
fetch_options & header(const fl::string &name, const fl::string &value)
Add header.
Definition fetch.h:213
const RequestOptions & options() const
Get the options for this request.
Definition fetch.h:241
Fetch options builder (fluent interface)
Definition fetch.h:200
static promise< T > create()
Create a pending promise.
Definition promise.h:75
void update()
Update promise state in main loop - should be called periodically This processes pending callbacks wh...
Definition promise.h:148
bool complete_with_value(const T &value)
Complete the promise with a result (used by networking library)
Definition promise.h:197
static promise< T > resolve(const T &value)
Create a resolved promise with value.
Definition promise.h:81
bool valid() const
Check if promise is valid.
Definition promise.h:122
bool is_completed() const
Check if promise is completed (resolved or rejected)
Definition promise.h:154
Promise class that provides fluent .then() and .catch_() semantics This is a lightweight wrapper arou...
Definition promise.h:72
fl::string mBody
Definition fetch.h:149
fl::Json json() const
Response body parsed as JSON (JavaScript-like API)
Definition fetch.cpp:319
void set_body(const fl::string &body)
Definition fetch.h:141
void set_text(const fl::string &body)
Definition fetch.h:140
fl::Json parse_json_body() const
Parse JSON from response body with error handling.
Definition fetch.h:157
bool mJsonParsed
Definition fetch.h:154
fl::optional< fl::Json > mCachedJson
Definition fetch.h:153
bool is_json() const
Check if response appears to contain JSON content.
Definition fetch.h:127
HTTP response class (unified interface)
Definition fetch.h:83
static const fl::size npos
Definition str.h:597
Unified HTTP fetch API for FastLED (cross-platform)
fl::promise< response > fetch_head(const fl::string &url, const fetch_options &request)
HTTP HEAD request.
Definition fetch.cpp:248
constexpr remove_reference< T >::type && move(T &&t) noexcept
Definition move.h:27
fl::promise< response > fetch_delete(const fl::string &url, const fetch_options &request)
HTTP DELETE request.
Definition fetch.cpp:231
fl::promise< response > fetch_http_options(const fl::string &url, const fetch_options &request)
HTTP OPTIONS request.
Definition fetch.cpp:265
fl::enable_if<!fl::is_array< T >::value, unique_ptr< T > >::type make_unique(Args &&... args)
Definition memory.h:42
void fetch_update()
Legacy manual update for fetch promises (use fl::async_run() for new code)
Definition fetch.cpp:307
fl::promise< response > fetch_request(const fl::string &url, const RequestOptions &options)
Generic request with options (like fetch(url, options))
Definition fetch.cpp:299
fl::promise< response > fetch_put(const fl::string &url, const fetch_options &request)
HTTP PUT request.
Definition fetch.cpp:214
fl::size fetch_active_requests()
Get number of active requests.
Definition fetch.cpp:313
fl::promise< response > execute_fetch_request(const fl::string &url, const fetch_options &request)
Internal helper to execute a fetch request and return a promise.
Definition fetch.cpp:72
fl::promise< response > fetch_patch(const fl::string &url, const fetch_options &request)
HTTP PATCH request.
Definition fetch.cpp:282
void async_run()
Run all registered async tasks once.
Definition async.cpp:63
fl::function< void(const response &)> FetchCallback
Callback type for simple fetch responses (backward compatible)
Definition fetch.h:186
fl::promise< response > fetch_post(const fl::string &url, const fetch_options &request)
HTTP POST request.
Definition fetch.cpp:197
HeapVector< T, Allocator > vector
Definition vector.h:1214
void fetch(const fl::string &url, const FetchCallback &callback)
Make an HTTP GET request (cross-platform, backward compatible)
Definition fetch.cpp:63
fl::promise< response > fetch_get(const fl::string &url, const fetch_options &request)
HTTP GET request.
Definition fetch.cpp:180
IMPORTANT!
Definition crgb.h:20
Generic asynchronous task management for FastLED.
Request options (matches JavaScript fetch RequestInit)
Definition fetch.h:189
#define FL_WARN
Definition warn.h:12