Skip to content

Commit 5c51dc3

Browse files
committed
fix: surface webinspector receive errors to the message iterator
Receive failures were emitted on the unlistened error event and crashed the process. Emit them as errorMessage, stop the iterator, and rethrow the error to the consumer of listenMessage.
1 parent cacdb2d commit 5c51dc3

2 files changed

Lines changed: 41 additions & 2 deletions

File tree

src/services/ios/webinspector/index.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,15 @@ export class WebInspectorService extends BaseService {
105105
}
106106
};
107107

108+
let receiveError: unknown = null;
109+
const errorHandler = (error: unknown) => {
110+
receiveError = error;
111+
stopHandler();
112+
};
113+
108114
this.messageEmitter.on('message', messageHandler);
109115
this.messageEmitter.once('stop', stopHandler);
116+
this.messageEmitter.once('errorMessage', errorHandler);
110117

111118
try {
112119
while (!stopped) {
@@ -133,9 +140,14 @@ export class WebInspectorService extends BaseService {
133140
yield message;
134141
}
135142
}
143+
144+
if (receiveError) {
145+
throw receiveError;
146+
}
136147
} finally {
137148
this.messageEmitter.off('message', messageHandler);
138149
this.messageEmitter.off('stop', stopHandler);
150+
this.messageEmitter.off('errorMessage', errorHandler);
139151
}
140152
}
141153

@@ -160,6 +172,7 @@ export class WebInspectorService extends BaseService {
160172
// Remove all listeners to prevent memory leaks and ensure clean restart
161173
this.messageEmitter.removeAllListeners('message');
162174
this.messageEmitter.removeAllListeners('stop');
175+
this.messageEmitter.removeAllListeners('errorMessage');
163176
}
164177

165178
/**
@@ -382,9 +395,9 @@ export class WebInspectorService extends BaseService {
382395
continue;
383396
}
384397

385-
// For other errors, log and exit
398+
// For other errors, log and end the iterator
386399
log.error('Error receiving message:', error);
387-
this.messageEmitter.emit('error', error);
400+
this.messageEmitter.emit('errorMessage', error);
388401
break;
389402
}
390403
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import assert from 'node:assert/strict';
2+
import {describe, it} from 'node:test';
3+
4+
import WebInspectorService from '../../../src/services/ios/webinspector/index.js';
5+
6+
describe('WebInspectorService', function () {
7+
describe('listenMessage', function () {
8+
it('should throw receive errors to the consumer instead of crashing the process', async function () {
9+
const service = new WebInspectorService('test-udid');
10+
const receiveError = new Error('socket lost');
11+
12+
const fakeConnection = {
13+
receive: async (): Promise<never> => {
14+
throw receiveError;
15+
},
16+
};
17+
(service as unknown as {connection: unknown}).connection = fakeConnection;
18+
19+
await assert.rejects(async () => {
20+
for await (const _ of service.listenMessage()) {
21+
// no messages expected
22+
}
23+
}, /socket lost/);
24+
});
25+
});
26+
});

0 commit comments

Comments
 (0)