Skip to content

Commit c6ab95d

Browse files
authored
Fix cleanup of autodetect event handlers (#4664)
* Fix cleanup of autodetect handlers * Keep onClosed firing by delaying listener removal * Wrap serial.disconnect in try/catch/finally to guarantee cleanup on errors * Guard against undefined TABS.firmware_flasher (runtime TypeError) * Avoid disconnecting existing sessions and stale listeners; only cleanup if a connect was attempted. Move listener registration to just-in-time. * Fix the undefined this.logHead reference
1 parent c4f6137 commit c6ab95d

File tree

1 file changed

+54
-44
lines changed

1 file changed

+54
-44
lines changed

src/js/utils/AutoDetect.js

Lines changed: 54 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -33,42 +33,43 @@ class AutoDetect {
3333
MSP.read(event.detail);
3434
}
3535

36-
verifyBoard() {
36+
async verifyBoard() {
3737
const port = PortHandler.portPicker.selectedPort;
38-
const isLoaded = TABS.firmware_flasher.targets ? Object.keys(TABS.firmware_flasher.targets).length > 0 : false;
39-
40-
if (!PortHandler.portAvailable) {
41-
gui_log(i18n.getMessage("firmwareFlasherNoValidPort"));
42-
return;
43-
}
44-
45-
if (!isLoaded) {
46-
gui_log(i18n.getMessage("firmwareFlasherNoTargetsLoaded"));
47-
return;
48-
}
49-
50-
if (serial.connected || serial.connectionId) {
51-
console.warn(
52-
"Attempting to connect while there still is a connection",
53-
serial.connected,
54-
serial.connectionId,
55-
serial.openCanceled,
56-
);
57-
serial.disconnect();
58-
return;
59-
}
60-
61-
gui_log(i18n.getMessage("firmwareFlasherDetectBoardQuery"));
6238

6339
if (!port.startsWith("virtual")) {
64-
serial.addEventListener("connect", this.boundHandleConnect, { once: true });
65-
serial.addEventListener("disconnect", this.boundHandleDisconnect, { once: true });
66-
67-
console.log("Connecting to serial port", port, serial.connected, serial.connectionId);
68-
69-
serial.connect(port, { baudRate: PortHandler.portPicker.selectedBauds || 115200 });
70-
} else {
71-
gui_log(i18n.getMessage("serialPortOpenFail"));
40+
// Safely check firmware_flasher.targets (use optional chaining so this doesn't throw when undefined)
41+
const isLoaded = TABS.firmware_flasher?.targets
42+
? Object.keys(TABS.firmware_flasher.targets).length > 0
43+
: false;
44+
let result = false;
45+
let attempted = false;
46+
47+
try {
48+
if (!PortHandler.portAvailable) {
49+
gui_log(i18n.getMessage("firmwareFlasherNoValidPort"));
50+
} else if (!isLoaded) {
51+
gui_log(i18n.getMessage("firmwareFlasherNoTargetsLoaded"));
52+
} else if (serial.connected || serial.connectionId) {
53+
console.warn("Attempting to connect while there still is a connection", serial.connected);
54+
gui_log(i18n.getMessage("serialPortOpenFail"));
55+
} else {
56+
// We're about to attempt a connection: register listeners just-in-time
57+
attempted = true;
58+
serial.addEventListener("connect", this.boundHandleConnect, { once: true });
59+
serial.addEventListener("disconnect", this.boundHandleDisconnect, { once: true });
60+
61+
console.log("Connecting to serial port", port);
62+
gui_log(i18n.getMessage("firmwareFlasherDetectBoardQuery"));
63+
result = await serial.connect(port, { baudRate: PortHandler.portPicker.selectedBauds || 115200 });
64+
}
65+
} catch (error) {
66+
console.error("Failed to connect:", error);
67+
} finally {
68+
// Only run cleanup when we actually attempted a connection and it failed
69+
if (attempted && !result) {
70+
this.cleanup();
71+
}
72+
}
7273
}
7374
}
7475

@@ -116,17 +117,7 @@ class AutoDetect {
116117
);
117118
}
118119

119-
// Remove event listeners using stored references
120-
serial.removeEventListener("receive", this.boundHandleSerialReceive);
121-
serial.removeEventListener("connect", this.boundHandleConnect);
122-
serial.removeEventListener("disconnect", this.boundHandleDisconnect);
123-
124-
// Clean up MSP listeners
125-
MSP.clearListeners();
126-
MSP.disconnect_cleanup();
127-
128-
// Disconnect without passing onClosed as a callback
129-
serial.disconnect();
120+
this.cleanup();
130121
}
131122

132123
async getBoardInfo() {
@@ -195,6 +186,25 @@ class AutoDetect {
195186
gui_log(i18n.getMessage("serialPortOpenFail"));
196187
}
197188
}
189+
190+
async cleanup() {
191+
// Disconnect first, so the once-registered disconnect handler can fire
192+
try {
193+
await serial.disconnect();
194+
} catch (error) {
195+
// Log the error with context but continue to run cleanup
196+
console.error("Serial disconnection failed:", error);
197+
} finally {
198+
// Remove event listeners using stored references (disconnect listener is once-registered and already removed)
199+
serial.removeEventListener("receive", this.boundHandleSerialReceive);
200+
serial.removeEventListener("connect", this.boundHandleConnect);
201+
// Do NOT remove disconnect listener, as it is once-registered and will be auto-removed
202+
203+
// Clean up MSP listeners after disconnect (always run)
204+
MSP.clearListeners();
205+
MSP.disconnect_cleanup();
206+
}
207+
}
198208
}
199209

200210
export default new AutoDetect();

0 commit comments

Comments
 (0)