Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/platform/web/js/libs/library_godot_fetch.js
10279 views
1
/**************************************************************************/
2
/* library_godot_fetch.js */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
const GodotFetch = {
32
$GodotFetch__deps: ['$IDHandler', '$GodotRuntime'],
33
$GodotFetch: {
34
35
onread: function (id, result) {
36
const obj = IDHandler.get(id);
37
if (!obj) {
38
return;
39
}
40
if (result.value) {
41
obj.chunks.push(result.value);
42
}
43
obj.reading = false;
44
obj.done = result.done;
45
},
46
47
onresponse: function (id, response) {
48
const obj = IDHandler.get(id);
49
if (!obj) {
50
return;
51
}
52
let chunked = false;
53
response.headers.forEach(function (value, header) {
54
const v = value.toLowerCase().trim();
55
const h = header.toLowerCase().trim();
56
if (h === 'transfer-encoding' && v === 'chunked') {
57
chunked = true;
58
}
59
});
60
obj.status = response.status;
61
obj.response = response;
62
// `body` can be null per spec (for example, in cases where the request method is HEAD).
63
// As of the time of writing, Chromium (127.0.6533.72) does not follow the spec but Firefox (131.0.3) does.
64
// See godotengine/godot#76825 for more information.
65
// See Chromium revert (of the change to follow the spec):
66
// https://chromium.googlesource.com/chromium/src/+/135354b7bdb554cd03c913af7c90aceead03c4d4
67
obj.reader = response.body?.getReader();
68
obj.chunked = chunked;
69
},
70
71
onerror: function (id, err) {
72
GodotRuntime.error(err);
73
const obj = IDHandler.get(id);
74
if (!obj) {
75
return;
76
}
77
obj.error = err;
78
},
79
80
create: function (method, url, headers, body) {
81
const obj = {
82
request: null,
83
response: null,
84
reader: null,
85
error: null,
86
done: false,
87
reading: false,
88
status: 0,
89
chunks: [],
90
};
91
const id = IDHandler.add(obj);
92
const init = {
93
method: method,
94
headers: headers,
95
body: body,
96
};
97
obj.request = fetch(url, init);
98
obj.request.then(GodotFetch.onresponse.bind(null, id)).catch(GodotFetch.onerror.bind(null, id));
99
return id;
100
},
101
102
free: function (id) {
103
const obj = IDHandler.get(id);
104
if (!obj) {
105
return;
106
}
107
IDHandler.remove(id);
108
if (!obj.request) {
109
return;
110
}
111
// Try to abort
112
obj.request.then(function (response) {
113
response.abort();
114
}).catch(function (e) { /* nothing to do */ });
115
},
116
117
read: function (id) {
118
const obj = IDHandler.get(id);
119
if (!obj) {
120
return;
121
}
122
if (obj.reader && !obj.reading) {
123
if (obj.done) {
124
obj.reader = null;
125
return;
126
}
127
obj.reading = true;
128
obj.reader.read().then(GodotFetch.onread.bind(null, id)).catch(GodotFetch.onerror.bind(null, id));
129
} else if (obj.reader == null && obj.response.body == null) {
130
// Emulate a stream closure to maintain the request lifecycle.
131
obj.reading = true;
132
GodotFetch.onread(id, { value: undefined, done: true });
133
}
134
},
135
},
136
137
godot_js_fetch_create__proxy: 'sync',
138
godot_js_fetch_create__sig: 'iiiiiii',
139
godot_js_fetch_create: function (p_method, p_url, p_headers, p_headers_size, p_body, p_body_size) {
140
const method = GodotRuntime.parseString(p_method);
141
const url = GodotRuntime.parseString(p_url);
142
const headers = GodotRuntime.parseStringArray(p_headers, p_headers_size);
143
const body = p_body_size ? GodotRuntime.heapSlice(HEAP8, p_body, p_body_size) : null;
144
return GodotFetch.create(method, url, headers.map(function (hv) {
145
const idx = hv.indexOf(':');
146
if (idx <= 0) {
147
return [];
148
}
149
return [
150
hv.slice(0, idx).trim(),
151
hv.slice(idx + 1).trim(),
152
];
153
}).filter(function (v) {
154
return v.length === 2;
155
}), body);
156
},
157
158
godot_js_fetch_state_get__proxy: 'sync',
159
godot_js_fetch_state_get__sig: 'ii',
160
godot_js_fetch_state_get: function (p_id) {
161
const obj = IDHandler.get(p_id);
162
if (!obj) {
163
return -1;
164
}
165
if (obj.error) {
166
return -1;
167
}
168
if (!obj.response) {
169
return 0;
170
}
171
// If the reader is nullish, but there is no body, and the request is not marked as done,
172
// the same status should be returned as though the request is currently being read
173
// so that the proper lifecycle closure can be handled in `read()`.
174
if (obj.reader || (obj.response.body == null && !obj.done)) {
175
return 1;
176
}
177
if (obj.done) {
178
return 2;
179
}
180
return -1;
181
},
182
183
godot_js_fetch_http_status_get__proxy: 'sync',
184
godot_js_fetch_http_status_get__sig: 'ii',
185
godot_js_fetch_http_status_get: function (p_id) {
186
const obj = IDHandler.get(p_id);
187
if (!obj || !obj.response) {
188
return 0;
189
}
190
return obj.status;
191
},
192
193
godot_js_fetch_read_headers__proxy: 'sync',
194
godot_js_fetch_read_headers__sig: 'iiii',
195
godot_js_fetch_read_headers: function (p_id, p_parse_cb, p_ref) {
196
const obj = IDHandler.get(p_id);
197
if (!obj || !obj.response) {
198
return 1;
199
}
200
const cb = GodotRuntime.get_func(p_parse_cb);
201
const arr = [];
202
obj.response.headers.forEach(function (v, h) {
203
arr.push(`${h}:${v}`);
204
});
205
const c_ptr = GodotRuntime.allocStringArray(arr);
206
cb(arr.length, c_ptr, p_ref);
207
GodotRuntime.freeStringArray(c_ptr, arr.length);
208
return 0;
209
},
210
211
godot_js_fetch_read_chunk__proxy: 'sync',
212
godot_js_fetch_read_chunk__sig: 'iiii',
213
godot_js_fetch_read_chunk: function (p_id, p_buf, p_buf_size) {
214
const obj = IDHandler.get(p_id);
215
if (!obj || !obj.response) {
216
return 0;
217
}
218
let to_read = p_buf_size;
219
const chunks = obj.chunks;
220
while (to_read && chunks.length) {
221
const chunk = obj.chunks[0];
222
if (chunk.length > to_read) {
223
GodotRuntime.heapCopy(HEAP8, chunk.slice(0, to_read), p_buf);
224
chunks[0] = chunk.slice(to_read);
225
to_read = 0;
226
} else {
227
GodotRuntime.heapCopy(HEAP8, chunk, p_buf);
228
to_read -= chunk.length;
229
chunks.pop();
230
}
231
}
232
if (!chunks.length) {
233
GodotFetch.read(p_id);
234
}
235
return p_buf_size - to_read;
236
},
237
238
godot_js_fetch_is_chunked__proxy: 'sync',
239
godot_js_fetch_is_chunked__sig: 'ii',
240
godot_js_fetch_is_chunked: function (p_id) {
241
const obj = IDHandler.get(p_id);
242
if (!obj || !obj.response) {
243
return -1;
244
}
245
return obj.chunked ? 1 : 0;
246
},
247
248
godot_js_fetch_free__proxy: 'sync',
249
godot_js_fetch_free__sig: 'vi',
250
godot_js_fetch_free: function (id) {
251
GodotFetch.free(id);
252
},
253
};
254
255
autoAddDeps(GodotFetch, '$GodotFetch');
256
mergeInto(LibraryManager.library, GodotFetch);
257
258