* Converts a remote socket to a WebSocket connection. * @param {import("@cloudflare/workers-types").Socket} remoteSocket The remote socket to convert. * @param {import("@cloudflare/workers-types").WebSocket} webSocket The WebSocket to connect to. * @param {ArrayBuffer | null} vlessResponseHead
(remoteSocket, webSocket, vlessResponseHeader, retry, log)
| 582 | * @returns {Promise<void>} A Promise that resolves when the conversion is complete. |
| 583 | */ |
| 584 | async function remoteSocketToWS(remoteSocket, webSocket, vlessResponseHeader, retry, log) { |
| 585 | // remote--> ws |
| 586 | let remoteChunkCount = 0; |
| 587 | let chunks = []; |
| 588 | /** @type {ArrayBuffer | null} */ |
| 589 | let vlessHeader = vlessResponseHeader; |
| 590 | let hasIncomingData = false; // check if remoteSocket has incoming data |
| 591 | await remoteSocket.readable |
| 592 | .pipeTo( |
| 593 | new WritableStream({ |
| 594 | start() { |
| 595 | }, |
| 596 | /** |
| 597 | * |
| 598 | * @param {Uint8Array} chunk |
| 599 | * @param {*} controller |
| 600 | */ |
| 601 | async write(chunk, controller) { |
| 602 | hasIncomingData = true; |
| 603 | remoteChunkCount++; |
| 604 | if (webSocket.readyState !== WS_READY_STATE_OPEN) { |
| 605 | controller.error( |
| 606 | 'webSocket.readyState is not open, maybe close' |
| 607 | ); |
| 608 | } |
| 609 | if (vlessHeader) { |
| 610 | webSocket.send(await new Blob([vlessHeader, chunk]).arrayBuffer()); |
| 611 | vlessHeader = null; |
| 612 | } else { |
| 613 | console.log(`remoteSocketToWS send chunk ${chunk.byteLength}`); |
| 614 | // seems no need rate limit this, CF seems fix this??.. |
| 615 | // if (remoteChunkCount > 20000) { |
| 616 | // // cf one package is 4096 byte(4kb), 4096 * 20000 = 80M |
| 617 | // await delay(1); |
| 618 | // } |
| 619 | webSocket.send(chunk); |
| 620 | } |
| 621 | }, |
| 622 | close() { |
| 623 | log(`remoteConnection!.readable is close with hasIncomingData is ${hasIncomingData}`); |
| 624 | // safeCloseWebSocket(webSocket); // no need server close websocket frist for some case will casue HTTP ERR_CONTENT_LENGTH_MISMATCH issue, client will send close event anyway. |
| 625 | }, |
| 626 | abort(reason) { |
| 627 | console.error(`remoteConnection!.readable abort`, reason); |
| 628 | }, |
| 629 | }) |
| 630 | ) |
| 631 | .catch((error) => { |
| 632 | console.error( |
| 633 | `remoteSocketToWS has exception `, |
| 634 | error.stack || error |
| 635 | ); |
| 636 | safeCloseWebSocket(webSocket); |
| 637 | }); |
| 638 | |
| 639 | // seems is cf connect socket have error, |
| 640 | // 1. Socket.closed will have error |
| 641 | // 2. Socket.readable will be close without any data coming |
no test coverage detected