diff --git a/package.json b/package.json index 3e53dd596..fe2ab47f6 100644 --- a/package.json +++ b/package.json @@ -154,8 +154,8 @@ "is-node-process": "^1.2.0", "outvariant": "^1.4.3", "path-to-regexp": "^6.3.0", - "socket.io": "^4.6.1", - "socket.io-client": "^4.6.1", + "socket.io": "^4.8.1", + "socket.io-client": "^4.8.1", "strict-event-emitter": "^0.5.1", "type-fest": "^4.26.1", "yargs": "^17.7.2" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 61ba89b29..cfde86100 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -54,10 +54,10 @@ importers: specifier: ^6.3.0 version: 6.3.0 socket.io: - specifier: ^4.6.1 - version: 4.7.5 + specifier: ^4.8.1 + version: 4.8.1 socket.io-client: - specifier: ^4.6.1 + specifier: ^4.8.1 version: 4.8.1 strict-event-emitter: specifier: ^0.5.1 @@ -2133,10 +2133,6 @@ packages: resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} engines: {node: '>=6.6.0'} - cookie@0.4.2: - resolution: {integrity: sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==} - engines: {node: '>= 0.6'} - cookie@0.6.0: resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} engines: {node: '>= 0.6'} @@ -2429,8 +2425,8 @@ packages: resolution: {integrity: sha512-RcyUFKA93/CXH20l4SoVvzZfrSDMOTUS3bWVpTt2FuFP+XYrL8i8oonHP7WInRyVHXh0n/ORtoeiE1os+8qkSw==} engines: {node: '>=10.0.0'} - engine.io@6.5.4: - resolution: {integrity: sha512-KdVSDKhVKyOi+r5uEabrDLZw2qXStVvCsEB/LN3mw4WFi6Gx50jTyuxYVCwAAC0U46FdnzP/ScKRBTXb/NiEOg==} + engine.io@6.6.2: + resolution: {integrity: sha512-gmNvsYi9C8iErnZdVcJnvCpSKbWTt1E8+JZo8b+daLninywUWi5NQ5STSHZ9rFjFO7imNcvb8Pc5pe/wMR5xEw==} engines: {node: '>=10.2.0'} enhanced-resolve@5.17.1: @@ -4370,8 +4366,8 @@ packages: resolution: {integrity: sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==} engines: {node: '>=10.0.0'} - socket.io@4.7.5: - resolution: {integrity: sha512-DmeAkF6cwM9jSfmp6Dr/5/mfMwb5Z5qRrSXLpo3Fq5SqyU8CMF15jIN4ZhfSwu35ksM1qmHZDQ/DK5XTccSTvA==} + socket.io@4.8.1: + resolution: {integrity: sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==} engines: {node: '>=10.2.0'} sonic-boom@2.8.0: @@ -5970,7 +5966,7 @@ snapshots: cors: 2.8.5 express: 4.19.2 outvariant: 1.4.3 - socket.io: 4.7.5 + socket.io: 4.8.1 transitivePeerDependencies: - bufferutil - supports-color @@ -7199,8 +7195,6 @@ snapshots: cookie-signature@1.2.2: {} - cookie@0.4.2: {} - cookie@0.6.0: {} cookie@0.7.1: {} @@ -7460,18 +7454,18 @@ snapshots: engine.io-parser@5.2.2: {} - engine.io@6.5.4: + engine.io@6.6.2: dependencies: '@types/cookie': 0.4.1 '@types/cors': 2.8.17 '@types/node': 18.19.28 accepts: 1.3.8 base64id: 2.0.0 - cookie: 0.4.2 + cookie: 0.7.2 cors: 2.8.5 debug: 4.3.7 engine.io-parser: 5.2.2 - ws: 8.11.0 + ws: 8.17.1 transitivePeerDependencies: - bufferutil - supports-color @@ -9718,13 +9712,13 @@ snapshots: transitivePeerDependencies: - supports-color - socket.io@4.7.5: + socket.io@4.8.1: dependencies: accepts: 1.3.8 base64id: 2.0.0 cors: 2.8.5 debug: 4.3.7 - engine.io: 6.5.4 + engine.io: 6.6.2 socket.io-adapter: 2.5.4 socket.io-parser: 4.2.4 transitivePeerDependencies: diff --git a/src/core/handlers/RemoteRequestHandler.ts b/src/core/handlers/RemoteRequestHandler.ts index 1a7985f44..fdc92df60 100644 --- a/src/core/handlers/RemoteRequestHandler.ts +++ b/src/core/handlers/RemoteRequestHandler.ts @@ -40,6 +40,10 @@ export class RemoteRequestHandler extends RequestHandler< resolver() {}, }) + console.log('[RemoteRequestHandler] constructor', { + contextId: args.contextId, + }) + this.socket = args.socket this.contextId = args.contextId } @@ -77,6 +81,21 @@ export class RemoteRequestHandler extends RequestHandler< responsePromise.resolve(undefined) }) + console.log( + '[RemoteRequestHandler] sending request to remote...', + new Date(), + ) + + // this.socket.send(JSON.stringify({ a: { b: { c: 1 } } })) + // this.socket.emit( + // 'foo', + // JSON.stringify({ + // requestId: createRequestId(), + // contextId: this.contextId, + // serializeRequest: await serializeRequest(args.request), + // }), + // ) + /** * @note Remote request handler is special. * It cannot await the mocked response from the remote process in @@ -86,23 +105,31 @@ export class RemoteRequestHandler extends RequestHandler< * Instead, the remote handler await the mocked response during the * parsing phase since that's the only async phase before predicate. */ - this.socket.emit('request', { - requestId: createRequestId(), - serializedRequest: await serializeRequest(args.request), - contextId: this.contextId, - }) + debugger + this.socket.emit( + 'request', + { + requestId: createRequestId(), + serializedRequest: await serializeRequest(args.request), + contextId: this.contextId, + }, + (serializedResponse) => { + // Wait for the remote server to acknowledge this request with + // a response before continuing with the request handling. + responsePromise.resolve( + serializedResponse + ? deserializeResponse(serializedResponse) + : undefined, + ) + }, + ) /** * @todo Handle timeouts. * @todo Handle socket errors. */ - this.socket.on('response', ({ serializedResponse }) => { - responsePromise.resolve( - serializedResponse - ? deserializeResponse(serializedResponse) - : undefined, - ) - }) + + console.log('[RemoteRequestHandler] waiting for response from remote...') return { ...parsedResult, diff --git a/src/core/utils/request/serializeUtils.ts b/src/core/utils/request/serializeUtils.ts index 7e85913f9..abf3f6275 100644 --- a/src/core/utils/request/serializeUtils.ts +++ b/src/core/utils/request/serializeUtils.ts @@ -6,7 +6,7 @@ export interface SerializedRequest { method: string url: string headers: Array<[string, string]> - body?: ArrayBuffer + body: ArrayBuffer | undefined } export interface SerializedResponse { @@ -14,7 +14,7 @@ export interface SerializedResponse { status: number statusText?: string headers: Array<[string, string]> - body?: ArrayBuffer + body: ArrayBuffer | undefined } /** diff --git a/src/node/SetupServerApi.ts b/src/node/SetupServerApi.ts index 9cba30537..f61b3cad4 100644 --- a/src/node/SetupServerApi.ts +++ b/src/node/SetupServerApi.ts @@ -150,8 +150,6 @@ export class SetupServerApi this.handlersController.currentHandlers, { apply: (target, thisArg, args) => { - console.log('.currentHandlers()...') - return Array.prototype.concat( new RemoteRequestHandler({ socket, @@ -176,6 +174,8 @@ export class SetupServerApi return } + console.log('[setupSever] beforeRequest', request.method, request.url) + // Before the first request gets handled, await the sync server connection. // This way we ensure that all the requests go through the `RemoteRequestHandler`. await Promise.race([ @@ -185,10 +185,12 @@ export class SetupServerApi setTimeout(resolve, 1000) }), ]) + + console.log('[setupServer] beforeRequest COMPLETE!') } // Forward all life-cycle events from this process to the remote. - this.forwardLifeCycleEvents() + // this.forwardLifeCycleEvents() } } diff --git a/src/node/setupRemoteServer.ts b/src/node/setupRemoteServer.ts index 88ba97fab..3a5beb086 100644 --- a/src/node/setupRemoteServer.ts +++ b/src/node/setupRemoteServer.ts @@ -75,15 +75,16 @@ export interface SetupRemoteServer { } export interface SyncServerEventsMap { - request: (args: { - serializedRequest: SerializedRequest - requestId: string - contextId?: string - }) => Promise | void + request: ( + args: { + serializedRequest: SerializedRequest + requestId: string + contextId?: string + }, + callback: (serializedResponse: SerializedResponse | undefined) => void, + ) => void - response: (args: { - serializedResponse?: SerializedResponse - }) => Promise | void + foo: (data: string) => void lifeCycleEventForward: ( type: Type, @@ -140,12 +141,38 @@ export class SetupRemoteServerApi .once('SIGTERM', () => closeSyncServer(server)) .once('SIGINT', () => closeSyncServer(server)) + server.on('close', () => console.log('SERVER CLOSE')) + server.on('error', () => console.log('SERVER ERROR')) + server.on('connection', async (socket) => { + console.log('[setupRemoteServer] ws client connected!') + + socket.on('error', (error) => { + console.log('[setupRemoteServer] ws client ERROR!', error) + }) + + socket.addListener('message', (data) => console.log('ANY DATA:', data)) + + console.log('ADD REQUEST LISTENER', new Date()) + + socket.on('foo', (data) => { + console.log('FOO RECEIVED!', data) + }) + socket.on( 'request', - async ({ requestId, serializedRequest, contextId }) => { + async ({ contextId, requestId, serializedRequest }, callback) => { + console.log('[setupRemoteServer] REQUEST event') + const request = deserializeRequest(serializedRequest) + console.log( + '[setupRemoteServer] REQUEST', + request.method, + request.url, + { contextId }, + ) + // By default, get the handlers from the current context. let allHandlers = this.handlersController.currentHandlers() @@ -173,11 +200,12 @@ export class SetupRemoteServerApi const context = getContext() allHandlers = context.handlers } + const handlers = allHandlers.filter(isHandlerKind('RequestHandler')) const response = await handleRequest( request, requestId, - allHandlers.filter(isHandlerKind('RequestHandler')), + handlers, /** * @todo Support resolve options from the `.listen()` call. */ @@ -185,11 +213,9 @@ export class SetupRemoteServerApi dummyEmitter, ) - socket.emit('response', { - serializedResponse: response - ? await serializeResponse(response) - : undefined, - }) + console.log({ handlers, response }) + + callback(response ? await serializeResponse(response) : undefined) }, ) @@ -255,6 +281,7 @@ async function createSyncServer( const httpServer = http.createServer() const ws = new WebSocketServer(httpServer, { transports: ['websocket'], + httpCompression: false, cors: { /** * @todo Set the default `origin` to localhost for security reasons. @@ -330,7 +357,7 @@ export async function createSyncClient(args: { port: number }) { // the user is expected to enable remote interception // before the actual application with "setupServer". timeout: 500, - reconnection: true, + reconnection: false, extraHeaders: { // Bypass the internal WebSocket connection requests // to exclude them from the request lookup altogether. @@ -339,11 +366,14 @@ export async function createSyncClient(args: { port: number }) { }, }) - socket.on('connect', () => { + socket.once('connect', () => { + console.log('[setupServer] ws client connected!', new Date()) + connectionPromise.resolve(socket) }) socket.io.once('error', (error) => { + console.log('[setupServer] ws client error!', error) connectionPromise.reject(error) })