Reconexion automatica en el cliente cuando falla la conexion WebSocket

- Retry con backoff (hasta 3 intentos, delay incremental)
- Suprimir errores de consola durante reintentos
- Mostrar estado "Reconectando" en el widget
- Si todos los reintentos fallan, limpiar sesion y mostrar form de token
This commit is contained in:
2026-02-13 03:05:55 -06:00
parent 4fa3ba9517
commit 480d4d618e
3 changed files with 65 additions and 19 deletions

View File

@@ -26,6 +26,10 @@
this.registeredTools = /* @__PURE__ */ new Set(); this.registeredTools = /* @__PURE__ */ new Set();
this.registeredPrompts = /* @__PURE__ */ new Set(); this.registeredPrompts = /* @__PURE__ */ new Set();
this.registeredResources = /* @__PURE__ */ new Set(); this.registeredResources = /* @__PURE__ */ new Set();
this._reconnectAttempts = 0;
this._maxReconnectAttempts = 3;
this._reconnectDelay = 1e3;
this._lastConnectionToken = null;
this.SESSION_STORAGE_KEY = "webmcp_token"; this.SESSION_STORAGE_KEY = "webmcp_token";
this.TOOLS_STORAGE_KEY = "webmcp_tools"; this.TOOLS_STORAGE_KEY = "webmcp_tools";
this.PROMPTS_STORAGE_KEY = "webmcp_prompts"; this.PROMPTS_STORAGE_KEY = "webmcp_prompts";
@@ -739,6 +743,7 @@
this._updateStatus("disconnected", "Error: No token provided"); this._updateStatus("disconnected", "Error: No token provided");
return; return;
} }
this._lastConnectionToken = connectionToken;
this._updateStatus("connecting", "Connecting..."); this._updateStatus("connecting", "Connecting...");
try { try {
if (!this._processConnectionToken(connectionToken)) { if (!this._processConnectionToken(connectionToken)) {
@@ -884,6 +889,7 @@
} }
this.socket.addEventListener("open", () => { this.socket.addEventListener("open", () => {
this.isConnected = true; this.isConnected = true;
this._reconnectAttempts = 0;
this._updateStatus("connected", `Connected to ${this.currentChannel}`); this._updateStatus("connected", `Connected to ${this.currentChannel}`);
this._updateConnectionUI(true); this._updateConnectionUI(true);
console.log("WebMCP connection established"); console.log("WebMCP connection established");
@@ -891,18 +897,31 @@
}); });
this.socket.addEventListener("close", (event) => { this.socket.addEventListener("close", (event) => {
this.isConnected = false; this.isConnected = false;
console.log(`Connection closed: ${event.code} ${event.reason}`);
if (event.code === 1e3) {
this._updateStatus("disconnected", "Disconnected");
this._updateConnectionUI(false);
return;
}
if (this._reconnectAttempts < this._maxReconnectAttempts && this._lastConnectionToken) {
this._reconnectAttempts++;
const delay = this._reconnectDelay * this._reconnectAttempts;
console.log(`Reconnecting (attempt ${this._reconnectAttempts}/${this._maxReconnectAttempts}) in ${delay}ms...`);
this._updateStatus("connecting", `Reconectando (${this._reconnectAttempts}/${this._maxReconnectAttempts})...`);
setTimeout(() => {
this.connect(this._lastConnectionToken);
}, delay);
return;
}
this._updateStatus("disconnected", "Disconnected"); this._updateStatus("disconnected", "Disconnected");
this._updateConnectionUI(false); this._updateConnectionUI(false);
console.log(`Connection closed: ${event.code} ${event.reason}`);
if (event.code === 1001 || event.code === 401) {
this._updateStatus("disconnected", "Authorization failed");
this.currentToken = ""; this.currentToken = "";
this.currentServer = ""; this.currentServer = "";
this.currentChannel = ""; this.currentChannel = "";
sessionStorage.removeItem(this.SESSION_STORAGE_KEY); sessionStorage.removeItem(this.SESSION_STORAGE_KEY);
}
}); });
this.socket.addEventListener("error", () => { this.socket.addEventListener("error", () => {
if (this._reconnectAttempts > 0) return;
console.error("WebSocket error"); console.error("WebSocket error");
if (this.isConnected) { if (this.isConnected) {
this._updateStatus("disconnected", "Connection error occurred"); this._updateStatus("disconnected", "Connection error occurred");

File diff suppressed because one or more lines are too long

View File

@@ -34,6 +34,10 @@ class WebMCP {
this.registeredTools = new Set(); this.registeredTools = new Set();
this.registeredPrompts = new Set(); this.registeredPrompts = new Set();
this.registeredResources = new Set(); this.registeredResources = new Set();
this._reconnectAttempts = 0;
this._maxReconnectAttempts = 3;
this._reconnectDelay = 1000;
this._lastConnectionToken = null;
// Storage keys for sessionStorage // Storage keys for sessionStorage
this.SESSION_STORAGE_KEY = 'webmcp_token'; this.SESSION_STORAGE_KEY = 'webmcp_token';
@@ -924,6 +928,9 @@ class WebMCP {
return; return;
} }
// Store for reconnection attempts
this._lastConnectionToken = connectionToken;
// Update UI to show connecting state // Update UI to show connecting state
this._updateStatus('connecting', 'Connecting...'); this._updateStatus('connecting', 'Connecting...');
@@ -1137,6 +1144,7 @@ class WebMCP {
// Set up socket open handler // Set up socket open handler
this.socket.addEventListener('open', () => { this.socket.addEventListener('open', () => {
this.isConnected = true; this.isConnected = true;
this._reconnectAttempts = 0;
this._updateStatus('connected', `Connected to ${this.currentChannel}`); this._updateStatus('connected', `Connected to ${this.currentChannel}`);
this._updateConnectionUI(true); this._updateConnectionUI(true);
console.log('WebMCP connection established'); console.log('WebMCP connection established');
@@ -1146,22 +1154,41 @@ class WebMCP {
// Set up socket close handler // Set up socket close handler
this.socket.addEventListener('close', (event) => { this.socket.addEventListener('close', (event) => {
this.isConnected = false; this.isConnected = false;
this._updateStatus('disconnected', 'Disconnected');
this._updateConnectionUI(false);
console.log(`Connection closed: ${event.code} ${event.reason}`); console.log(`Connection closed: ${event.code} ${event.reason}`);
// Check if it was an authorization error // Normal closure — no retry
if (event.code === 1001 || event.code === 401) { if (event.code === 1000) {
this._updateStatus('disconnected', 'Authorization failed'); this._updateStatus('disconnected', 'Disconnected');
this._updateConnectionUI(false);
return;
}
// Abnormal closure — try to reconnect
if (this._reconnectAttempts < this._maxReconnectAttempts && this._lastConnectionToken) {
this._reconnectAttempts++;
const delay = this._reconnectDelay * this._reconnectAttempts;
console.log(`Reconnecting (attempt ${this._reconnectAttempts}/${this._maxReconnectAttempts}) in ${delay}ms...`);
this._updateStatus('connecting', `Reconectando (${this._reconnectAttempts}/${this._maxReconnectAttempts})...`);
setTimeout(() => {
this.connect(this._lastConnectionToken);
}, delay);
return;
}
// Max retries exceeded or no token — give up
this._updateStatus('disconnected', 'Disconnected');
this._updateConnectionUI(false);
this.currentToken = ''; this.currentToken = '';
this.currentServer = ''; this.currentServer = '';
this.currentChannel = ''; this.currentChannel = '';
sessionStorage.removeItem(this.SESSION_STORAGE_KEY); sessionStorage.removeItem(this.SESSION_STORAGE_KEY);
}
}); });
// Set up socket error handler // Set up socket error handler
this.socket.addEventListener('error', () => { this.socket.addEventListener('error', () => {
// Suppress noisy errors during reconnection attempts
if (this._reconnectAttempts > 0) return;
console.error('WebSocket error'); console.error('WebSocket error');
if (this.isConnected) { if (this.isConnected) {