Skip to content

Commit 7600d9b

Browse files
committed
feat: add streaming to XHR driver client
1 parent fa96c6d commit 7600d9b

File tree

1 file changed

+67
-0
lines changed

1 file changed

+67
-0
lines changed

src/puter-js/src/lib/utils.js

+67
Original file line numberDiff line numberDiff line change
@@ -268,9 +268,76 @@ async function driverCall_(
268268
if ( settings.responseType ) {
269269
xhr.responseType = settings.responseType;
270270
}
271+
272+
// ===============================================
273+
// TO UNDERSTAND THIS CODE, YOU MUST FIRST
274+
// UNDERSTAND THE FOLLOWING TEXT:
275+
//
276+
// Everything between here and the comment reading
277+
// "=== END OF STREAMING ===" is ONLY for handling
278+
// requests with content type "application/x-ndjson"
279+
// ===============================================
280+
281+
let is_stream = false;
282+
let got_headers = false;
283+
let signal_stream_update = null;
284+
let lastLength = 0;
285+
let response_complete = false;
286+
const parts_received = [];
287+
xhr.onreadystatechange = () => {
288+
if ( got_headers ) return;
289+
got_headers = true;
290+
if ( xhr.readyState >= 2 ) {
291+
if ( xhr.getResponseHeader("Content-Type") !==
292+
'application/x-ndjson'
293+
) return;
294+
is_stream = true;
295+
const Stream = async function* Stream () {
296+
while ( ! response_complete ) {
297+
const tp = new TeePromise();
298+
signal_stream_update = tp.resolve.bind(tp);
299+
await tp;
300+
if ( response_complete ) break;
301+
while ( parts_received.length > 0 ) {
302+
const value = parts_received.pop();
303+
const parts = value.split('\n');
304+
for ( const part of parts ) {
305+
if ( part.trim() === '' ) continue;
306+
yield JSON.parse(part);
307+
}
308+
}
309+
}
310+
}
311+
312+
return resolve_func(Stream());
313+
}
314+
};
315+
316+
xhr.onprogress = function() {
317+
if ( ! signal_stream_update ) return;
318+
319+
const newText = xhr.responseText.slice(lastLength);
320+
lastLength = xhr.responseText.length; // Update lastLength to the current length
321+
322+
parts_received.push(newText);
323+
signal_stream_update();
324+
};
325+
326+
xhr.addEventListener('load', () => {
327+
response_complete = true;
328+
});
329+
330+
// ========================
331+
// === END OF STREAMING ===
332+
// ========================
271333

272334
// load: success or error
273335
xhr.addEventListener('load', async function(response){
336+
response_complete = true;
337+
if ( is_stream ) {
338+
signal_stream_update?.();
339+
return;
340+
}
274341
const resp = await parseResponse(response.target);
275342
// HTTP Error - unauthorized
276343
if(response.status === 401 || resp?.code === "token_auth_failed"){

0 commit comments

Comments
 (0)