2019-10-30 05:45:47 +08:00
|
|
|
/**
|
2022-10-18 23:19:24 +08:00
|
|
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
2019-10-30 05:45:47 +08:00
|
|
|
*
|
|
|
|
|
* This source code is licensed under the MIT license found in the
|
|
|
|
|
* LICENSE file in the root directory of this source tree.
|
|
|
|
|
*
|
|
|
|
|
* @flow
|
|
|
|
|
*/
|
|
|
|
|
|
2022-09-15 08:20:33 +08:00
|
|
|
import type {Thenable} from 'shared/ReactTypes.js';
|
|
|
|
|
|
2020-03-26 02:47:55 +08:00
|
|
|
import type {Response as FlightResponse} from 'react-client/src/ReactFlightClientStream';
|
2019-10-30 05:45:47 +08:00
|
|
|
|
2022-05-28 04:16:24 +08:00
|
|
|
import type {BundlerConfig} from './ReactFlightClientWebpackBundlerConfig';
|
|
|
|
|
|
2019-10-30 05:45:47 +08:00
|
|
|
import {
|
2019-11-02 07:05:07 +08:00
|
|
|
createResponse,
|
2022-09-15 08:20:33 +08:00
|
|
|
getRoot,
|
2019-11-02 07:05:07 +08:00
|
|
|
reportGlobalError,
|
|
|
|
|
processStringChunk,
|
|
|
|
|
processBinaryChunk,
|
2020-03-11 05:55:04 +08:00
|
|
|
close,
|
|
|
|
|
} from 'react-client/src/ReactFlightClientStream';
|
2019-10-30 05:45:47 +08:00
|
|
|
|
2023-02-10 08:45:05 +08:00
|
|
|
type CallServerCallback = <A, T>(
|
|
|
|
|
{filepath: string, name: string},
|
|
|
|
|
args: A,
|
|
|
|
|
) => Promise<T>;
|
|
|
|
|
|
2022-09-10 04:03:48 +08:00
|
|
|
export type Options = {
|
2022-05-28 04:16:24 +08:00
|
|
|
moduleMap?: BundlerConfig,
|
2023-02-10 08:45:05 +08:00
|
|
|
callServer?: CallServerCallback,
|
2022-09-10 04:03:48 +08:00
|
|
|
};
|
2022-05-28 04:16:24 +08:00
|
|
|
|
2020-04-04 05:58:02 +08:00
|
|
|
function startReadingFromStream(
|
|
|
|
|
response: FlightResponse,
|
2020-03-26 02:47:55 +08:00
|
|
|
stream: ReadableStream,
|
|
|
|
|
): void {
|
2020-04-02 03:35:52 +08:00
|
|
|
const reader = stream.getReader();
|
2023-02-10 06:07:39 +08:00
|
|
|
function progress({
|
|
|
|
|
done,
|
|
|
|
|
value,
|
|
|
|
|
}: {
|
|
|
|
|
done: boolean,
|
|
|
|
|
value: ?any,
|
|
|
|
|
...
|
|
|
|
|
}): void | Promise<void> {
|
2019-11-02 07:05:07 +08:00
|
|
|
if (done) {
|
2020-03-11 05:55:04 +08:00
|
|
|
close(response);
|
2019-11-02 07:05:07 +08:00
|
|
|
return;
|
|
|
|
|
}
|
2020-04-02 03:35:52 +08:00
|
|
|
const buffer: Uint8Array = (value: any);
|
2019-11-07 01:48:34 +08:00
|
|
|
processBinaryChunk(response, buffer);
|
2023-01-31 21:25:05 +08:00
|
|
|
return reader.read().then(progress).catch(error);
|
2019-11-02 07:05:07 +08:00
|
|
|
}
|
2023-01-10 04:46:48 +08:00
|
|
|
function error(e: any) {
|
2019-11-02 07:05:07 +08:00
|
|
|
reportGlobalError(response, e);
|
|
|
|
|
}
|
2023-01-31 21:25:05 +08:00
|
|
|
reader.read().then(progress).catch(error);
|
2019-11-02 07:05:07 +08:00
|
|
|
}
|
|
|
|
|
|
2022-09-15 08:20:33 +08:00
|
|
|
function createFromReadableStream<T>(
|
2022-05-28 04:16:24 +08:00
|
|
|
stream: ReadableStream,
|
|
|
|
|
options?: Options,
|
2022-09-15 08:20:33 +08:00
|
|
|
): Thenable<T> {
|
2022-05-28 04:16:24 +08:00
|
|
|
const response: FlightResponse = createResponse(
|
|
|
|
|
options && options.moduleMap ? options.moduleMap : null,
|
2023-02-10 08:45:05 +08:00
|
|
|
options && options.callServer ? options.callServer : undefined,
|
2022-05-28 04:16:24 +08:00
|
|
|
);
|
2019-11-02 07:05:07 +08:00
|
|
|
startReadingFromStream(response, stream);
|
2022-09-15 08:20:33 +08:00
|
|
|
return getRoot(response);
|
2019-11-02 07:05:07 +08:00
|
|
|
}
|
|
|
|
|
|
2022-09-15 08:20:33 +08:00
|
|
|
function createFromFetch<T>(
|
2019-11-02 07:05:07 +08:00
|
|
|
promiseForResponse: Promise<Response>,
|
2022-05-28 04:16:24 +08:00
|
|
|
options?: Options,
|
2022-09-15 08:20:33 +08:00
|
|
|
): Thenable<T> {
|
2022-05-28 04:16:24 +08:00
|
|
|
const response: FlightResponse = createResponse(
|
|
|
|
|
options && options.moduleMap ? options.moduleMap : null,
|
2023-02-10 08:45:05 +08:00
|
|
|
options && options.callServer ? options.callServer : undefined,
|
2022-05-28 04:16:24 +08:00
|
|
|
);
|
2019-11-02 07:05:07 +08:00
|
|
|
promiseForResponse.then(
|
2023-01-31 21:25:05 +08:00
|
|
|
function (r) {
|
2019-11-02 07:05:07 +08:00
|
|
|
startReadingFromStream(response, (r.body: any));
|
2019-10-30 05:45:47 +08:00
|
|
|
},
|
2023-01-31 21:25:05 +08:00
|
|
|
function (e) {
|
2019-11-02 07:05:07 +08:00
|
|
|
reportGlobalError(response, e);
|
2019-10-30 05:45:47 +08:00
|
|
|
},
|
2019-11-02 07:05:07 +08:00
|
|
|
);
|
2022-09-15 08:20:33 +08:00
|
|
|
return getRoot(response);
|
2019-11-02 07:05:07 +08:00
|
|
|
}
|
|
|
|
|
|
2022-09-15 08:20:33 +08:00
|
|
|
function createFromXHR<T>(
|
2022-05-28 04:16:24 +08:00
|
|
|
request: XMLHttpRequest,
|
|
|
|
|
options?: Options,
|
2022-09-15 08:20:33 +08:00
|
|
|
): Thenable<T> {
|
2022-05-28 04:16:24 +08:00
|
|
|
const response: FlightResponse = createResponse(
|
|
|
|
|
options && options.moduleMap ? options.moduleMap : null,
|
2023-02-10 08:45:05 +08:00
|
|
|
options && options.callServer ? options.callServer : undefined,
|
2022-05-28 04:16:24 +08:00
|
|
|
);
|
2019-11-02 07:05:07 +08:00
|
|
|
let processedLength = 0;
|
|
|
|
|
function progress(e: ProgressEvent): void {
|
2020-04-02 03:35:52 +08:00
|
|
|
const chunk = request.responseText;
|
2019-11-02 07:05:07 +08:00
|
|
|
processStringChunk(response, chunk, processedLength);
|
|
|
|
|
processedLength = chunk.length;
|
|
|
|
|
}
|
|
|
|
|
function load(e: ProgressEvent): void {
|
|
|
|
|
progress(e);
|
2020-03-11 05:55:04 +08:00
|
|
|
close(response);
|
2019-11-02 07:05:07 +08:00
|
|
|
}
|
|
|
|
|
function error(e: ProgressEvent): void {
|
|
|
|
|
reportGlobalError(response, new TypeError('Network error'));
|
|
|
|
|
}
|
|
|
|
|
request.addEventListener('progress', progress);
|
|
|
|
|
request.addEventListener('load', load);
|
|
|
|
|
request.addEventListener('error', error);
|
|
|
|
|
request.addEventListener('abort', error);
|
|
|
|
|
request.addEventListener('timeout', error);
|
2022-09-15 08:20:33 +08:00
|
|
|
return getRoot(response);
|
2019-10-30 05:45:47 +08:00
|
|
|
}
|
|
|
|
|
|
2020-03-26 02:47:55 +08:00
|
|
|
export {createFromXHR, createFromFetch, createFromReadableStream};
|