Skip to content

Commit 10898e4

Browse files
committed
fix(native-messaging): add retry budget and poll for test connection result
- Add MAX_RECONNECT_ATTEMPTS (10) to prevent infinite reconnect loops on unclassified permanent failures. After exhausting retries, state transitions to "error" requiring explicit user action to retry. - Test Connection now polls for up to 5s after triggering reconnect, waiting for the async connection to settle before showing the result.
1 parent 1eca752 commit 10898e4

File tree

2 files changed

+28
-1
lines changed

2 files changed

+28
-1
lines changed

src/entries/background/utils/nativeMessaging.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const INSTANCE_ID_KEY = "ptd_native_instance_id";
66
const ENABLED_KEY = "ptd_native_bridge_enabled";
77
const RECONNECT_BASE_MS = 1000;
88
const RECONNECT_MAX_MS = 30000;
9+
const MAX_RECONNECT_ATTEMPTS = 10;
910

1011
/** Errors that indicate the native host is not installed — no point retrying. */
1112
const FATAL_ERRORS = [
@@ -113,9 +114,19 @@ function disconnect(intentional: boolean) {
113114
function scheduleReconnect() {
114115
clearReconnectTimer();
115116
reconnectAttempt++;
117+
118+
if (reconnectAttempt > MAX_RECONNECT_ATTEMPTS) {
119+
state = "error";
120+
lastError = `Gave up after ${MAX_RECONNECT_ATTEMPTS} reconnect attempts`;
121+
console.debug("[PTD] Native bridge exceeded max reconnect attempts, giving up.");
122+
return;
123+
}
124+
116125
const delay = Math.min(RECONNECT_BASE_MS * 2 ** reconnectAttempt, RECONNECT_MAX_MS);
117126
state = "retrying";
118-
console.debug(`[PTD] Native bridge reconnecting in ${delay}ms (attempt ${reconnectAttempt})...`);
127+
console.debug(
128+
`[PTD] Native bridge reconnecting in ${delay}ms (attempt ${reconnectAttempt}/${MAX_RECONNECT_ATTEMPTS})...`,
129+
);
119130
reconnectTimer = setTimeout(connect, delay);
120131
}
121132

src/entries/options/views/Settings/SetBase/NativeBridgeWindow.vue

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,26 @@ async function toggleEnabled(newValue: boolean) {
7575
}
7676
}
7777
78+
async function waitForSettledState(maxMs = 5000, intervalMs = 500) {
79+
const transientStates: BridgeState[] = ["connecting", "retrying"];
80+
const start = Date.now();
81+
while (Date.now() - start < maxMs) {
82+
await new Promise((r) => setTimeout(r, intervalMs));
83+
await refreshStatus();
84+
if (!transientStates.includes(status.value.state)) {
85+
return;
86+
}
87+
}
88+
}
89+
7890
async function testConnection() {
7991
testLoading.value = true;
8092
try {
8193
status.value = await sendMessage("nativeBridgeReconnect", undefined);
94+
// Poll until state settles (connected/error) or timeout
95+
if (status.value.state === "connecting") {
96+
await waitForSettledState();
97+
}
8298
} catch (e: any) {
8399
console.debug("[PTD] Reconnect failed:", e);
84100
} finally {

0 commit comments

Comments
 (0)