-
Notifications
You must be signed in to change notification settings - Fork 46.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Flight] Split Streaming from Relay Implemenation (#18260)
* Add ReactFlightServerConfig intermediate This just forwards to the stream version of Flight which is itself forked between Node and W3C streams. The dom-relay goes directly to the Relay config though which allows it to avoid the stream part of Flight. * Separate streaming protocol into the Stream config * Split streaming parts into the ReactFlightServerConfigStream This decouples it so that the Relay implementation doesn't have to encode the JSON to strings. Instead it can be fed the values as JSON objects and do its own encoding. * Split FlightClient into a basic part and a stream part Same split as the server. * Expose lower level async hooks to Relay This requires an external helper file that we'll wire up internally.
- Loading branch information
1 parent
160505b
commit 99d7371
Showing
26 changed files
with
615 additions
and
269 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,4 +7,4 @@ | |
* @flow | ||
*/ | ||
|
||
export * from './src/ReactFlightClient'; | ||
export * from './src/ReactFlightClientStream'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
/** | ||
* Copyright (c) Facebook, Inc. and its affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
* | ||
* @flow | ||
*/ | ||
|
||
import type {Response as ResponseBase, JSONValue} from './ReactFlightClient'; | ||
|
||
import type {StringDecoder} from './ReactFlightClientHostConfig'; | ||
|
||
import { | ||
createResponse as createResponseImpl, | ||
resolveModelChunk, | ||
resolveErrorChunk, | ||
parseModelFromJSON, | ||
} from './ReactFlightClient'; | ||
|
||
import { | ||
supportsBinaryStreams, | ||
createStringDecoder, | ||
readPartialStringChunk, | ||
readFinalStringChunk, | ||
} from './ReactFlightClientHostConfig'; | ||
|
||
export type ReactModelRoot<T> = {| | ||
model: T, | ||
|}; | ||
|
||
type Response = ResponseBase & { | ||
fromJSON: (key: string, value: JSONValue) => any, | ||
stringDecoder: StringDecoder, | ||
}; | ||
|
||
export function createResponse(): Response { | ||
let response: Response = (createResponseImpl(): any); | ||
response.fromJSON = function(key: string, value: JSONValue) { | ||
return parseModelFromJSON(response, this, key, value); | ||
}; | ||
if (supportsBinaryStreams) { | ||
response.stringDecoder = createStringDecoder(); | ||
} | ||
return response; | ||
} | ||
|
||
function processFullRow(response: Response, row: string): void { | ||
if (row === '') { | ||
return; | ||
} | ||
let tag = row[0]; | ||
switch (tag) { | ||
case 'J': { | ||
let colon = row.indexOf(':', 1); | ||
let id = parseInt(row.substring(1, colon), 16); | ||
let json = row.substring(colon + 1); | ||
let model = JSON.parse(json, response.fromJSON); | ||
resolveModelChunk(response, id, model); | ||
return; | ||
} | ||
case 'E': { | ||
let colon = row.indexOf(':', 1); | ||
let id = parseInt(row.substring(1, colon), 16); | ||
let json = row.substring(colon + 1); | ||
let errorInfo = JSON.parse(json); | ||
resolveErrorChunk(response, id, errorInfo.message, errorInfo.stack); | ||
return; | ||
} | ||
default: { | ||
// Assume this is the root model. | ||
let model = JSON.parse(row, response.fromJSON); | ||
resolveModelChunk(response, 0, model); | ||
return; | ||
} | ||
} | ||
} | ||
|
||
export function processStringChunk( | ||
response: Response, | ||
chunk: string, | ||
offset: number, | ||
): void { | ||
let linebreak = chunk.indexOf('\n', offset); | ||
while (linebreak > -1) { | ||
let fullrow = response.partialRow + chunk.substring(offset, linebreak); | ||
processFullRow(response, fullrow); | ||
response.partialRow = ''; | ||
offset = linebreak + 1; | ||
linebreak = chunk.indexOf('\n', offset); | ||
} | ||
response.partialRow += chunk.substring(offset); | ||
} | ||
|
||
export function processBinaryChunk( | ||
response: Response, | ||
chunk: Uint8Array, | ||
): void { | ||
if (!supportsBinaryStreams) { | ||
throw new Error("This environment don't support binary chunks."); | ||
} | ||
let stringDecoder = response.stringDecoder; | ||
let linebreak = chunk.indexOf(10); // newline | ||
while (linebreak > -1) { | ||
let fullrow = | ||
response.partialRow + | ||
readFinalStringChunk(stringDecoder, chunk.subarray(0, linebreak)); | ||
processFullRow(response, fullrow); | ||
response.partialRow = ''; | ||
chunk = chunk.subarray(linebreak + 1); | ||
linebreak = chunk.indexOf(10); // newline | ||
} | ||
response.partialRow += readPartialStringChunk(stringDecoder, chunk); | ||
} | ||
|
||
export {reportGlobalError, close, getModelRoot} from './ReactFlightClient'; |
Oops, something went wrong.