* 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} vlessResponseHeader
(remoteSocket, webSocket, vlessResponseHeader, retry, log)
| 506 | * @returns {Promise<void>} A Promise that resolves when the conversion is complete. |
| 507 | */ |
| 508 | async function remoteSocketToWS(remoteSocket, webSocket, vlessResponseHeader, retry, log) { |
| 509 | // remote--> ws |
| 510 | let remoteChunkCount = 0; |
| 511 | let chunks = []; |
| 512 | /** @type {ArrayBuffer | null} */ |
| 513 | let vlessHeader = vlessResponseHeader; |
| 514 | let hasIncomingData = false; // check if remoteSocket has incoming data |
| 515 | await remoteSocket.readable |
| 516 | .pipeTo( |
| 517 | new WritableStream({ |
| 518 | start() { |
| 519 | }, |
| 520 | /** |
| 521 | * |
| 522 | * @param {Uint8Array} chunk |
| 523 | * @param {*} controller |
| 524 | */ |
| 525 | async write(chunk, controller) { |
| 526 | hasIncomingData = true; |
| 527 | remoteChunkCount++; |
| 528 | if (webSocket.readyState !== WS_READY_STATE_OPEN) { |
| 529 | controller.error( |
| 530 | 'webSocket.readyState is not open, maybe close' |
| 531 | ); |
| 532 | } |
| 533 | if (vlessHeader) { |
| 534 | webSocket.send(await new Blob([vlessHeader, chunk]).arrayBuffer()); |
| 535 | vlessHeader = null; |
| 536 | } else { |
| 537 | // console.log(`remoteSocketToWS send chunk ${chunk.byteLength}`); |
| 538 | // seems no need rate limit this, CF seems fix this??.. |
| 539 | // if (remoteChunkCount > 20000) { |
| 540 | // // cf one package is 4096 byte(4kb), 4096 * 20000 = 80M |
| 541 | // await delay(1); |
| 542 | // } |
| 543 | webSocket.send(chunk); |
| 544 | } |
| 545 | }, |
| 546 | close() { |
| 547 | log(`remoteConnection!.readable is close with hasIncomingData is ${hasIncomingData}`); |
| 548 | // 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. |
| 549 | }, |
| 550 | abort(reason) { |
| 551 | console.error(`remoteConnection!.readable abort`, reason); |
| 552 | }, |
| 553 | }) |
| 554 | ) |
| 555 | .catch((error) => { |
| 556 | console.error( |
| 557 | `remoteSocketToWS has exception `, |
| 558 | error.stack || error |
| 559 | ); |
| 560 | safeCloseWebSocket(webSocket); |
| 561 | }); |
| 562 | |
| 563 | // seems is cf connect socket have error, |
| 564 | // 1. Socket.closed will have error |
| 565 | // 2. Socket.readable will be close without any data coming |
no test coverage detected