yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
emscripten_http_client.cc
Go to the documentation of this file.
1#ifdef __EMSCRIPTEN__
2
4
5#include <emscripten/fetch.h>
6#include <cstring>
7#include <vector>
8
9namespace yaze {
10namespace net {
11
12EmscriptenHttpClient::EmscriptenHttpClient() {
13 // Constructor
14}
15
16EmscriptenHttpClient::~EmscriptenHttpClient() {
17 // Destructor
18}
19
20void EmscriptenHttpClient::OnFetchSuccess(emscripten_fetch_t* fetch) {
21 FetchResult* result = static_cast<FetchResult*>(fetch->userData);
22
23 {
24 std::lock_guard<std::mutex> lock(result->mutex);
25 result->success = true;
26 result->status_code = fetch->status;
27 result->body = std::string(fetch->data, fetch->numBytes);
28
29 // Parse response headers if available
30 // Note: Emscripten fetch API has limited header access due to CORS
31 // Only headers exposed by Access-Control-Expose-Headers are available
32
33 result->completed = true;
34 }
35 result->cv.notify_one();
36
37 emscripten_fetch_close(fetch);
38}
39
40void EmscriptenHttpClient::OnFetchError(emscripten_fetch_t* fetch) {
41 FetchResult* result = static_cast<FetchResult*>(fetch->userData);
42
43 {
44 std::lock_guard<std::mutex> lock(result->mutex);
45 result->success = false;
46 result->status_code = fetch->status;
47
48 if (fetch->status == 0) {
49 result->error_message = "Network error or CORS blocking";
50 } else {
51 result->error_message = "HTTP error: " + std::to_string(fetch->status);
52 }
53
54 result->completed = true;
55 }
56 result->cv.notify_one();
57
58 emscripten_fetch_close(fetch);
59}
60
61void EmscriptenHttpClient::OnFetchProgress(emscripten_fetch_t* fetch) {
62 // Progress callback - can be used for download progress
63 // Not implemented for now
64 (void)fetch; // Suppress unused parameter warning
65}
66
67absl::StatusOr<HttpResponse> EmscriptenHttpClient::PerformFetch(
68 const std::string& method,
69 const std::string& url,
70 const std::string& body,
71 const Headers& headers) {
72
73 // Create result structure
74 FetchResult result;
75
76 // Initialize fetch attributes
77 emscripten_fetch_attr_t attr;
78 emscripten_fetch_attr_init(&attr);
79
80 // Set HTTP method
81 strncpy(attr.requestMethod, method.c_str(), sizeof(attr.requestMethod) - 1);
82 attr.requestMethod[sizeof(attr.requestMethod) - 1] = '\0';
83
84 // Set attributes for synchronous-style operation
85 // We use async fetch with callbacks but wait for completion
86 attr.attributes = EMSCRIPTEN_FETCH_LOAD_TO_MEMORY;
87
88 // Set callbacks
89 attr.onsuccess = OnFetchSuccess;
90 attr.onerror = OnFetchError;
91 attr.onprogress = OnFetchProgress;
92 attr.userData = &result;
93
94 // Set timeout
95 attr.timeoutMSecs = timeout_seconds_ * 1000;
96
97 // Prepare headers
98 std::vector<const char*> header_strings;
99 std::vector<std::string> header_storage;
100
101 for (const auto& [key, value] : headers) {
102 header_storage.push_back(key);
103 header_storage.push_back(value);
104 }
105
106 // Add Content-Type for POST/PUT if not provided
107 if ((method == "POST" || method == "PUT") && !body.empty()) {
108 bool has_content_type = false;
109 for (const auto& [key, value] : headers) {
110 if (key == "Content-Type") {
111 has_content_type = true;
112 break;
113 }
114 }
115 if (!has_content_type) {
116 header_storage.push_back("Content-Type");
117 header_storage.push_back("application/json");
118 }
119 }
120
121 // Convert to C-style array
122 for (const auto& str : header_storage) {
123 header_strings.push_back(str.c_str());
124 }
125 header_strings.push_back(nullptr); // Null-terminate
126
127 if (!header_strings.empty() && header_strings.size() > 1) {
128 attr.requestHeaders = header_strings.data();
129 }
130
131 // Set request body for POST/PUT
132 if (!body.empty() && (method == "POST" || method == "PUT")) {
133 attr.requestData = body.c_str();
134 attr.requestDataSize = body.length();
135 }
136
137 // Perform the fetch
138 emscripten_fetch_t* fetch = emscripten_fetch(&attr, url.c_str());
139
140 if (!fetch) {
141 return absl::InternalError("Failed to initiate fetch request");
142 }
143
144 // Wait for completion (convert async to sync)
145 {
146 std::unique_lock<std::mutex> lock(result.mutex);
147 result.cv.wait(lock, [&result] { return result.completed; });
148 }
149
150 // Check result
151 if (!result.success) {
152 return absl::UnavailableError(result.error_message.empty()
153 ? "Fetch request failed"
154 : result.error_message);
155 }
156
157 // Build response
158 HttpResponse response;
159 response.status_code = result.status_code;
160 response.body = result.body;
161 response.headers = result.headers;
162
163 return response;
164}
165
166absl::StatusOr<HttpResponse> EmscriptenHttpClient::Get(
167 const std::string& url,
168 const Headers& headers) {
169 return PerformFetch("GET", url, "", headers);
170}
171
172absl::StatusOr<HttpResponse> EmscriptenHttpClient::Post(
173 const std::string& url,
174 const std::string& body,
175 const Headers& headers) {
176 return PerformFetch("POST", url, body, headers);
177}
178
179absl::StatusOr<HttpResponse> EmscriptenHttpClient::Put(
180 const std::string& url,
181 const std::string& body,
182 const Headers& headers) {
183 return PerformFetch("PUT", url, body, headers);
184}
185
186absl::StatusOr<HttpResponse> EmscriptenHttpClient::Delete(
187 const std::string& url,
188 const Headers& headers) {
189 return PerformFetch("DELETE", url, "", headers);
190}
191
192} // namespace net
193} // namespace yaze
194
195#endif // __EMSCRIPTEN__
std::map< std::string, std::string > Headers
HTTP headers type definition.
Definition http_client.h:16