mirror of
https://github.com/MercuryWorkshop/adrift.git
synced 2025-05-13 14:20:01 -04:00
merge
This commit is contained in:
commit
97dd94c1f0
5 changed files with 148 additions and 48 deletions
|
@ -13,7 +13,14 @@
|
|||
"@types/uuid": "^9.0.2",
|
||||
"bare-client-custom": "file:../bare-client-custom",
|
||||
"firebase": "^10.1.0",
|
||||
<<<<<<< HEAD
|
||||
"protocol": "workspace:*",
|
||||
"uuid": "^9.0.0"
|
||||
=======
|
||||
"protocol": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.4.10"
|
||||
>>>>>>> e51b5d90d4d2d0eba874fc6e5f3397f66fa846e3
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,11 +7,92 @@ import {
|
|||
ReadyStateCallback,
|
||||
WebSocketImpl,
|
||||
} from "bare-client-custom";
|
||||
import { ReadableStream, TransformStream } from "node:stream/web";
|
||||
import { MAX_CHUNK_SIZE } from "protocol";
|
||||
import { Connection } from "./Connection";
|
||||
|
||||
// https://fetch.spec.whatwg.org/#statuses
|
||||
const NULL_BODY_STATUSES = [101, 103, 204, 205, 304];
|
||||
|
||||
/**
|
||||
* given a completely unknown body type, returns a stream that yields Uint8Arrays
|
||||
* below MAX_CHUNK_SIZE.
|
||||
*/
|
||||
function createBodyStream(
|
||||
body: BodyInit | null
|
||||
): ReadableStream<ArrayBuffer | Uint8Array> | null {
|
||||
if (body === null) return null;
|
||||
|
||||
const transformer = () =>
|
||||
new TransformStream({
|
||||
transform: async (
|
||||
chunk: any,
|
||||
controller: TransformStreamDefaultController<Uint8Array>
|
||||
) => {
|
||||
// attempt to transform a couple types into an ArrayBuffer
|
||||
if (typeof chunk === "string") {
|
||||
chunk = new TextEncoder().encode(chunk);
|
||||
}
|
||||
if (chunk instanceof Blob) {
|
||||
chunk = await chunk.arrayBuffer();
|
||||
}
|
||||
if (ArrayBuffer.isView(chunk)) {
|
||||
chunk = chunk.buffer.slice(
|
||||
chunk.byteOffset,
|
||||
chunk.byteOffset + chunk.byteLength
|
||||
);
|
||||
}
|
||||
|
||||
// if none of those worked, give up.
|
||||
if (!(chunk instanceof ArrayBuffer)) {
|
||||
console.error({ chunk });
|
||||
throw new Error("Invalid type read from body stream: " + chunk);
|
||||
}
|
||||
|
||||
let current = null;
|
||||
let remaining = chunk;
|
||||
do {
|
||||
current = remaining.slice(0, MAX_CHUNK_SIZE);
|
||||
remaining = remaining.slice(MAX_CHUNK_SIZE);
|
||||
controller.enqueue(new Uint8Array(current));
|
||||
} while (remaining.byteLength > 0);
|
||||
},
|
||||
});
|
||||
|
||||
if (body instanceof ReadableStream) {
|
||||
return body.pipeThrough(transformer());
|
||||
}
|
||||
|
||||
if (body instanceof ArrayBuffer) {
|
||||
if (body.byteLength == 0) {
|
||||
return null;
|
||||
}
|
||||
let remaining = body;
|
||||
return new ReadableStream({
|
||||
type: "bytes",
|
||||
pull: (controller) => {
|
||||
if (remaining.byteLength <= 0) {
|
||||
return controller.close();
|
||||
}
|
||||
const current = remaining.slice(0, MAX_CHUNK_SIZE);
|
||||
remaining = remaining.slice(MAX_CHUNK_SIZE);
|
||||
controller.enqueue(new Uint8Array(current));
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (body instanceof Blob) {
|
||||
// @ts-expect-error
|
||||
return body.stream().pipeThrough(transformer());
|
||||
}
|
||||
|
||||
if (body instanceof FormData) {
|
||||
throw new Error("formdata todo");
|
||||
}
|
||||
|
||||
throw new Error("Unexpected body type: " + body);
|
||||
}
|
||||
|
||||
export class AdriftBareClient extends Client {
|
||||
constructor(private connection: Connection) {
|
||||
super();
|
||||
|
@ -25,20 +106,15 @@ export class AdriftBareClient extends Client {
|
|||
duplex: string | undefined,
|
||||
signal: AbortSignal | undefined
|
||||
): Promise<BareResponse> {
|
||||
if (
|
||||
body !== null &&
|
||||
typeof body !== "undefined" &&
|
||||
typeof body !== "string"
|
||||
) {
|
||||
console.log({ body });
|
||||
throw new Error("bare-client-custom passed an unexpected body type");
|
||||
}
|
||||
let { payload, body: respRawBody } = await this.connection.httprequest({
|
||||
method,
|
||||
requestHeaders,
|
||||
body,
|
||||
remote,
|
||||
});
|
||||
const bodyStream = createBodyStream(body);
|
||||
let { payload, body: respRawBody } = await this.connection.httprequest(
|
||||
{
|
||||
method,
|
||||
requestHeaders,
|
||||
remote,
|
||||
},
|
||||
bodyStream
|
||||
);
|
||||
const headers = new Headers();
|
||||
for (const [header, values] of Object.entries(payload.headers)) {
|
||||
for (const value of <string[]>values) {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { ReadableStream } from "node:stream/web";
|
||||
import {
|
||||
C2SRequestType,
|
||||
C2SRequestTypes,
|
||||
|
@ -130,8 +131,8 @@ export class Connection {
|
|||
|
||||
async send(
|
||||
requestID: number,
|
||||
data: ArrayBuffer | Blob,
|
||||
type: C2SRequestType
|
||||
type: C2SRequestType,
|
||||
data?: ArrayBuffer | Blob
|
||||
): Promise<void> {
|
||||
let header = new ArrayBuffer(2 + 1);
|
||||
let view = new DataView(header);
|
||||
|
@ -143,21 +144,35 @@ export class Connection {
|
|||
view.setUint8(cursor, type);
|
||||
cursor += 1;
|
||||
|
||||
let buf = await new Blob([header, data]).arrayBuffer();
|
||||
let buf = header;
|
||||
if (data) {
|
||||
buf = await new Blob([header, data]).arrayBuffer();
|
||||
}
|
||||
|
||||
this.transport.send(buf);
|
||||
console.log(buf);
|
||||
}
|
||||
|
||||
httprequest(
|
||||
data: HTTPRequestPayload
|
||||
data: HTTPRequestPayload,
|
||||
body: ReadableStream<ArrayBuffer | Uint8Array> | null
|
||||
): Promise<{ payload: HTTPResponsePayload; body: ArrayBuffer }> {
|
||||
let json = JSON.stringify(data);
|
||||
|
||||
return new Promise(async (resolve) => {
|
||||
let seq = this.nextSeq();
|
||||
this.requestCallbacks[seq] = resolve;
|
||||
await this.send(seq, new Blob([json]), C2SRequestTypes.HTTPRequest);
|
||||
await this.send(seq, C2SRequestTypes.HTTPRequestStart, new Blob([json]));
|
||||
|
||||
if (body) {
|
||||
for await (const chunk of body) {
|
||||
await this.send(
|
||||
seq,
|
||||
C2SRequestTypes.HTTPRequestChunk,
|
||||
new Uint8Array(chunk)
|
||||
);
|
||||
}
|
||||
}
|
||||
await this.send(seq, C2SRequestTypes.HTTPRequestEnd);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -179,8 +194,8 @@ export class Connection {
|
|||
|
||||
this.send(
|
||||
seq,
|
||||
new TextEncoder().encode(payloadJSON),
|
||||
C2SRequestTypes.WSOpen
|
||||
C2SRequestTypes.WSOpen,
|
||||
new TextEncoder().encode(payloadJSON)
|
||||
).catch((e) => {
|
||||
console.error(e);
|
||||
closeWithError();
|
||||
|
@ -206,23 +221,23 @@ export class Connection {
|
|||
if (typeof data === "string") {
|
||||
this.send(
|
||||
seq,
|
||||
new TextEncoder().encode(data),
|
||||
C2SRequestTypes.WSSendText
|
||||
C2SRequestTypes.WSSendText,
|
||||
new TextEncoder().encode(data)
|
||||
).catch(cleanup);
|
||||
return;
|
||||
}
|
||||
if (data instanceof ArrayBuffer) {
|
||||
this.send(seq, data, C2SRequestTypes.WSSendBinary).catch(cleanup);
|
||||
this.send(seq, C2SRequestTypes.WSSendBinary, data).catch(cleanup);
|
||||
return;
|
||||
}
|
||||
if (ArrayBuffer.isView(data)) {
|
||||
this.send(
|
||||
seq,
|
||||
C2SRequestTypes.WSSendBinary,
|
||||
data.buffer.slice(
|
||||
data.byteOffset,
|
||||
data.byteOffset + data.byteLength
|
||||
),
|
||||
C2SRequestTypes.WSSendBinary
|
||||
)
|
||||
).catch(cleanup);
|
||||
return;
|
||||
}
|
||||
|
@ -234,8 +249,8 @@ export class Connection {
|
|||
const payloadJSON = JSON.stringify(payload);
|
||||
this.send(
|
||||
seq,
|
||||
new TextEncoder().encode(payloadJSON),
|
||||
C2SRequestTypes.WSClose
|
||||
C2SRequestTypes.WSClose,
|
||||
new TextEncoder().encode(payloadJSON)
|
||||
).catch((e) => {
|
||||
// At this point there is nothing left to clean up
|
||||
console.error(e);
|
||||
|
|
21
pnpm-lock.yaml
generated
21
pnpm-lock.yaml
generated
|
@ -1,4 +1,4 @@
|
|||
lockfileVersion: '6.1'
|
||||
lockfileVersion: '6.0'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
|
@ -91,8 +91,8 @@ importers:
|
|||
version: link:../bare-client-custom
|
||||
devDependencies:
|
||||
'@tomphttp/bare-client':
|
||||
specifier: file:../bare-client-custom/
|
||||
version: file:bare-client-custom
|
||||
specifier: ^2.2.0-alpha
|
||||
version: 2.2.0-alpha
|
||||
css-tree:
|
||||
specifier: ^2.3.1
|
||||
version: 2.3.1
|
||||
|
@ -178,14 +178,11 @@ importers:
|
|||
protocol:
|
||||
specifier: workspace:*
|
||||
version: link:../protocol
|
||||
uuid:
|
||||
specifier: ^9.0.0
|
||||
version: 9.0.0
|
||||
|
||||
corium:
|
||||
dependencies:
|
||||
'@rollup/browser':
|
||||
specifier: ^3.28.0
|
||||
specifier: ^3.17.2
|
||||
version: 3.28.0
|
||||
'@swc/helpers':
|
||||
specifier: ^0.4.14
|
||||
|
@ -3730,7 +3727,6 @@ packages:
|
|||
|
||||
/@tomphttp/bare-client@2.2.0-alpha:
|
||||
resolution: {integrity: sha512-xhcflOpwr92tkpp8SoDhB3nK3LHMBIjx+vgow37XobQew2k0/mXSxmaU7BsDFpOIa1CcLCEsR8gWn0v7Cy9+7Q==}
|
||||
dev: false
|
||||
|
||||
/@tomphttp/bare-server-node@2.0.1:
|
||||
resolution: {integrity: sha512-L42TC/AldYRFBRZSxhkI0FC5TL8EC/NAsepNC/cWYTTiHQJ7mGg/vdTqNz8ShTYHr6LTHYkuD3/81nhX55SYtA==}
|
||||
|
@ -3783,6 +3779,10 @@ packages:
|
|||
resolution: {integrity: sha512-BG7fQKZ689HIoc5h+6D2Dgq1fABRa0RbBWKBd9SP/MVRVXROflpm5fhwyATX5duFmbStzyzyycPB8qUYKDH3NA==}
|
||||
dev: true
|
||||
|
||||
/@types/crypto-js@4.1.1:
|
||||
resolution: {integrity: sha512-BG7fQKZ689HIoc5h+6D2Dgq1fABRa0RbBWKBd9SP/MVRVXROflpm5fhwyATX5duFmbStzyzyycPB8qUYKDH3NA==}
|
||||
dev: true
|
||||
|
||||
/@types/css-tree@2.0.0:
|
||||
resolution: {integrity: sha512-mY2sXRLBnUPMYw6mkOT+6dABeaNxAEKZz6scE9kQPNJx8fKe1fOsm8Honl7+xFYe6TKX8WNk2+7oMp2vBArJ9Q==}
|
||||
dev: true
|
||||
|
@ -3972,6 +3972,7 @@ packages:
|
|||
|
||||
/@types/uuid@9.0.2:
|
||||
resolution: {integrity: sha512-kNnC1GFBLuhImSnV7w4njQkUiJi0ZXUycu1rUaouPqiKlXkh77JKgdRnTAp1x5eBwcIwbtI+3otwzuIDEuDoxQ==}
|
||||
dev: false
|
||||
|
||||
/@types/webrtc@0.0.36:
|
||||
resolution: {integrity: sha512-tYFarc92EluXU7XyRmWbkQXSbZIOHTdDOudFPal9u/TNTQuouWpIHV/2o9bNAdqvTJFjLJh/zflCOLWbL30tEQ==}
|
||||
|
@ -10906,6 +10907,7 @@ packages:
|
|||
/uuid@9.0.0:
|
||||
resolution: {integrity: sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==}
|
||||
hasBin: true
|
||||
dev: false
|
||||
|
||||
/v8-compile-cache-lib@3.0.1:
|
||||
resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==}
|
||||
|
@ -11371,15 +11373,14 @@ packages:
|
|||
file:bare-client-custom:
|
||||
resolution: {directory: bare-client-custom, type: directory}
|
||||
name: bare-client-custom
|
||||
version: 2.2.0-alpha
|
||||
dependencies:
|
||||
'@types/uuid': 9.0.2
|
||||
uuid: 9.0.0
|
||||
dev: false
|
||||
|
||||
file:corium:
|
||||
resolution: {directory: corium, type: directory}
|
||||
name: corium
|
||||
version: 1.0.0-alpha.2
|
||||
dependencies:
|
||||
'@rollup/browser': 3.28.0
|
||||
'@swc/helpers': 0.4.14
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
export type ObjectValues<T> = T[keyof T];
|
||||
export const C2SRequestTypes = {
|
||||
HTTPRequest: 0,
|
||||
WSOpen: 1,
|
||||
WSClose: 2,
|
||||
WSSendText: 3,
|
||||
WSSendBinary: 4,
|
||||
HTTPRequestStart: 0,
|
||||
HTTPRequestChunk: 1,
|
||||
HTTPRequestEnd: 2,
|
||||
WSOpen: 3,
|
||||
WSClose: 4,
|
||||
WSSendText: 5,
|
||||
WSSendBinary: 6,
|
||||
} as const;
|
||||
export type C2SRequestType = ObjectValues<typeof C2SRequestTypes>;
|
||||
|
||||
|
@ -13,9 +15,9 @@ export const S2CRequestTypes = {
|
|||
HTTPResponseChunk: 1,
|
||||
HTTPResponseEnd: 2,
|
||||
WSOpen: 3,
|
||||
WSDataText: 4,
|
||||
WSDataBinary: 5,
|
||||
WSClose: 6,
|
||||
WSClose: 4,
|
||||
WSDataText: 5,
|
||||
WSDataBinary: 6,
|
||||
WSError: 7,
|
||||
} as const;
|
||||
export type S2CRequestType = ObjectValues<typeof S2CRequestTypes>;
|
||||
|
@ -25,7 +27,6 @@ export type ProtoBareHeaders = Record<string, string | string[]>;
|
|||
export type HTTPRequestPayload = {
|
||||
method: string;
|
||||
requestHeaders: ProtoBareHeaders;
|
||||
body: string | null;
|
||||
remote: URL;
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue