Skip to content

Commit 9668098

Browse files
committed
WIP: keep debugging get-port, now with inline emits for events
1 parent 808b9b4 commit 9668098

File tree

1 file changed

+54
-20
lines changed

1 file changed

+54
-20
lines changed

src/server/mockttp-server.ts

Lines changed: 54 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -141,22 +141,26 @@ async function findFreePort(startPort: number, endPort: number): Promise<number>
141141
for (let port = startPort; port <= endPort; port++) {
142142
try {
143143
for (const host of hosts) {
144-
await new Promise<void>((resolve, reject) => {
145-
const server = net.createServer();
146-
server.unref();
147-
server.once('error', reject);
148-
server.once('listening', () => server.close(() => resolve()));
149-
if (host !== undefined) {
150-
server.listen(port, host);
151-
} else {
152-
server.listen(port);
153-
}
154-
});
144+
try {
145+
await new Promise<void>((resolve, reject) => {
146+
const server = net.createServer();
147+
server.unref();
148+
server.once('error', reject);
149+
server.once('listening', () => server.close(() => resolve()));
150+
if (host !== undefined) {
151+
server.listen(port, host);
152+
} else {
153+
server.listen(port);
154+
}
155+
});
156+
} catch (e: any) {
157+
if (e.code === 'EADDRNOTAVAIL' || e.code === 'EINVAL') continue;
158+
throw e; // EADDRINUSE/EACCES or other → port unavailable
159+
}
155160
}
156161
return port;
157162
} catch (e: any) {
158-
if (e.code !== 'EADDRINUSE' && e.code !== 'EACCES' &&
159-
e.code !== 'EADDRNOTAVAIL' && e.code !== 'EINVAL') throw e;
163+
if (e.code !== 'EADDRINUSE' && e.code !== 'EACCES') throw e;
160164
}
161165
}
162166
throw new Error(`No open ports between ${startPort} and ${endPort}`);
@@ -750,14 +754,18 @@ export class MockttpServer extends AbstractMockttp implements Mockttp {
750754
const request = this.preprocessRequest(rawRequest, 'request');
751755
if (request === null) return; // Preprocessing failed - don't handle this
752756

757+
// Capture the emitter at the start of request handling, so that all events for this
758+
// request are emitted to the same emitter, even if the server is reset mid-request.
759+
const emitter = this.eventEmitter;
760+
753761
if (this.debug) console.log(`Handling request for ${rawRequest.url}`);
754762

755763
let result: 'responded' | 'aborted' | null = null;
756764
const abort = (error?: Error) => {
757765
if (result === null) {
758766
result = 'aborted';
759767
request.timingEvents.abortedTimestamp = now();
760-
this.announceAbortAsync(request, error);
768+
this.announceAbortAsync(request);
761769
}
762770
}
763771
request.once('aborted', abort);
@@ -774,13 +782,29 @@ export class MockttpServer extends AbstractMockttp implements Mockttp {
774782
request.tags,
775783
{
776784
maxSize: this.maxBodySize,
777-
onWriteHead: () => this.announceInitialResponseAsync(response),
778-
onBodyData: this.eventEmitter.listenerCount('response-body-data') > 0
779-
? this.announceBodyDataAsync.bind(this, 'response')
785+
onWriteHead: () => {
786+
if (emitter.listenerCount('response-initiated') === 0) return;
787+
setImmediate(() => {
788+
const initiatedRes = buildInitiatedResponse(response);
789+
emitter.emit('response-initiated', Object.assign(
790+
initiatedRes,
791+
{
792+
timingEvents: _.clone(initiatedRes.timingEvents),
793+
tags: _.clone(initiatedRes.tags)
794+
}
795+
));
796+
});
797+
},
798+
onBodyData: emitter.listenerCount('response-body-data') > 0
799+
? (id: string, eventTimestamp: number, content: Uint8Array, isEnded: boolean) => {
800+
setImmediate(() => {
801+
emitter.emit('response-body-data', { id, content, isEnded, eventTimestamp });
802+
});
803+
}
780804
: undefined
781805
}
782806
);
783-
const hasResponseListener = this.eventEmitter.listenerCount('response') > 0;
807+
const hasResponseListener = emitter.listenerCount('response') > 0;
784808
if (hasResponseListener) {
785809
// Start buffering response body if there's somebody who
786810
// might want to hear about it later
@@ -812,7 +836,7 @@ export class MockttpServer extends AbstractMockttp implements Mockttp {
812836
record: this.recordTraffic,
813837
debug: this.debug,
814838
keyLogStream: this.keyLogStream,
815-
emitEventCallback: (this.eventEmitter.listenerCount('rule-event') !== 0)
839+
emitEventCallback: (emitter.listenerCount('rule-event') !== 0)
816840
? (type, event) => this.announceRuleEventAsync(request.id, nextRule!.id, type, event)
817841
: undefined
818842
});
@@ -858,7 +882,17 @@ export class MockttpServer extends AbstractMockttp implements Mockttp {
858882
}
859883

860884
if (result === 'responded' && hasResponseListener) {
861-
this.announceResponseAsync(response);
885+
// Use captured emitter for response announcement too
886+
waitForCompletedResponse(response)
887+
.then((res: CompletedResponse) => {
888+
setImmediate(() => {
889+
emitter.emit('response', Object.assign(res, {
890+
timingEvents: _.clone(res.timingEvents),
891+
tags: _.clone(res.tags)
892+
}));
893+
});
894+
})
895+
.catch(console.error);
862896
}
863897
}
864898

0 commit comments

Comments
 (0)