Merge pull request 'socketio-fallback-signalR' (#1) from socketio-fallback-signalR into main
Reviewed-on: pierre/SimpleConnect-client-electron#1
This commit is contained in:
117
connection-manager.js
Normal file
117
connection-manager.js
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
/**
|
||||||
|
* Gestionnaire de connexion avec fallback SignalR → WebSocket
|
||||||
|
* Essaie d'abord SignalR, puis bascule sur WebSocket si nécessaire
|
||||||
|
*/
|
||||||
|
|
||||||
|
const signalR = require('@microsoft/signalr');
|
||||||
|
const WebSocketAdapter = require('./websocket-adapter');
|
||||||
|
|
||||||
|
class ConnectionManager {
|
||||||
|
constructor(serverUrl, options = {}) {
|
||||||
|
this.serverUrl = serverUrl;
|
||||||
|
this.options = options;
|
||||||
|
this.connection = null;
|
||||||
|
this.isUsingWebSocketFallback = false;
|
||||||
|
this.connectionType = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Établit la connexion en essayant SignalR puis WebSocket
|
||||||
|
*/
|
||||||
|
async connect() {
|
||||||
|
console.log('🔌 Tentative de connexion au serveur...');
|
||||||
|
|
||||||
|
// 1. Essayer SignalR d'abord
|
||||||
|
try {
|
||||||
|
console.log('📡 Essai avec SignalR...');
|
||||||
|
this.connection = await this.createSignalRConnection();
|
||||||
|
await this.connection.start();
|
||||||
|
this.connectionType = 'SignalR';
|
||||||
|
this.isUsingWebSocketFallback = false;
|
||||||
|
console.log('✅ Connexion SignalR établie');
|
||||||
|
return this.connection;
|
||||||
|
} catch (signalRError) {
|
||||||
|
console.warn('⚠️ SignalR indisponible:', signalRError.message);
|
||||||
|
console.log('🔄 Basculement vers WebSocket...');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Fallback vers WebSocket
|
||||||
|
try {
|
||||||
|
this.connection = new WebSocketAdapter(this.serverUrl, this.options);
|
||||||
|
await this.connection.start();
|
||||||
|
this.connectionType = 'WebSocket';
|
||||||
|
this.isUsingWebSocketFallback = true;
|
||||||
|
console.log('✅ Connexion WebSocket établie (mode fallback)');
|
||||||
|
return this.connection;
|
||||||
|
} catch (wsError) {
|
||||||
|
console.error('❌ Impossible de se connecter (SignalR et WebSocket ont échoué)');
|
||||||
|
throw wsError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crée une connexion SignalR
|
||||||
|
*/
|
||||||
|
createSignalRConnection() {
|
||||||
|
const url = `http://${this.serverUrl}/signalR`;
|
||||||
|
console.log(`Creating SignalR connection to: ${url}`);
|
||||||
|
|
||||||
|
return new signalR.HubConnectionBuilder()
|
||||||
|
.withUrl(url)
|
||||||
|
.withAutomaticReconnect([0, 2000, 5000, 10000])
|
||||||
|
.configureLogging(signalR.LogLevel.Information)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retourne la connexion active
|
||||||
|
*/
|
||||||
|
getConnection() {
|
||||||
|
return this.connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Déconnecte proprement
|
||||||
|
*/
|
||||||
|
async disconnect() {
|
||||||
|
if (this.connection) {
|
||||||
|
await this.connection.stop();
|
||||||
|
this.connection = null;
|
||||||
|
this.connectionType = 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Informations sur la connexion
|
||||||
|
*/
|
||||||
|
getConnectionInfo() {
|
||||||
|
return {
|
||||||
|
type: this.connectionType,
|
||||||
|
isWebSocketFallback: this.isUsingWebSocketFallback,
|
||||||
|
isConnected: this.connection && this.connection.state === 'Connected',
|
||||||
|
serverUrl: this.serverUrl
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Méthode helper pour invoquer des méthodes sur la connexion
|
||||||
|
*/
|
||||||
|
async invoke(methodName, ...args) {
|
||||||
|
if (!this.connection) {
|
||||||
|
throw new Error('Pas de connexion active');
|
||||||
|
}
|
||||||
|
return this.connection.invoke(methodName, ...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Méthode helper pour écouter des événements
|
||||||
|
*/
|
||||||
|
on(eventName, handler) {
|
||||||
|
if (!this.connection) {
|
||||||
|
throw new Error('Pas de connexion active');
|
||||||
|
}
|
||||||
|
this.connection.on(eventName, handler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = ConnectionManager;
|
||||||
@@ -1,5 +1,34 @@
|
|||||||
# Changelog - SimpleConnect Electron
|
# Changelog - SimpleConnect Electron
|
||||||
|
|
||||||
|
## [1.3.0] - 2025-09-12
|
||||||
|
|
||||||
|
### Ajouté
|
||||||
|
- **Support dual SignalR/SocketIO avec fallback automatique** : Compatibilité totale avec backends .NET et Python
|
||||||
|
- ConnectionManager qui essaie d'abord SignalR puis bascule sur SocketIO
|
||||||
|
- WebSocketAdapter qui émule l'API SignalR complète avec socket.io-client
|
||||||
|
- Abstraction totale : même API peu importe le protocole utilisé
|
||||||
|
- Détection automatique du type de serveur disponible
|
||||||
|
- Messages de statut indiquant le type de connexion active (SignalR ou WebSocket)
|
||||||
|
|
||||||
|
### Modifié
|
||||||
|
- **Architecture de connexion refactorisée** : Système modulaire avec adaptateurs
|
||||||
|
- Nouveau module `connection-manager.js` pour gérer la stratégie de fallback
|
||||||
|
- Nouveau module `websocket-adapter.js` pour l'émulation SignalR avec SocketIO
|
||||||
|
- Code principal simplifié grâce à l'abstraction de connexion
|
||||||
|
- Meilleure gestion des erreurs et reconnexion automatique
|
||||||
|
|
||||||
|
### Technique
|
||||||
|
- Ajout de la dépendance `socket.io-client` v4.8.1
|
||||||
|
- Pattern Adapter pour unifier les APIs SignalR et SocketIO
|
||||||
|
- Gestion des promesses pour les invocations asynchrones
|
||||||
|
- Mapping automatique des événements entre les deux protocoles
|
||||||
|
- Conservation de la compatibilité ascendante avec les serveurs existants
|
||||||
|
|
||||||
|
### Documentation
|
||||||
|
- Support confirmé pour les backends Python/FastAPI avec SocketIO
|
||||||
|
- Migration transparente entre serveurs .NET et Python
|
||||||
|
- Logs détaillés du type de connexion utilisé
|
||||||
|
|
||||||
## [1.2.16] - 2025-09-05
|
## [1.2.16] - 2025-09-05
|
||||||
|
|
||||||
### Ajouté
|
### Ajouté
|
||||||
|
|||||||
105
main.js
105
main.js
@@ -3,6 +3,7 @@ const path = require('path');
|
|||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const os = require('os');
|
const os = require('os');
|
||||||
const signalR = require('@microsoft/signalr');
|
const signalR = require('@microsoft/signalr');
|
||||||
|
const ConnectionManager = require('./connection-manager');
|
||||||
|
|
||||||
let mainWindow;
|
let mainWindow;
|
||||||
let config;
|
let config;
|
||||||
@@ -87,58 +88,25 @@ function createWindow() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// === GESTION SIGNALR ===
|
// === GESTION SIGNALR/WEBSOCKET ===
|
||||||
function initializeSignalR() {
|
function initializeSignalR() {
|
||||||
if (!config.signalR || !config.signalR.enabled) {
|
if (!config.signalR || !config.signalR.enabled) {
|
||||||
console.log('SignalR désactivé dans la configuration');
|
console.log('SignalR/WebSocket désactivé dans la configuration');
|
||||||
signalRStatus = 'disabled';
|
signalRStatus = 'disabled';
|
||||||
sendSignalRStatus();
|
sendSignalRStatus();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Créer la connexion SignalR
|
// Utiliser le ConnectionManager avec fallback automatique SignalR → WebSocket
|
||||||
signalRConnection = new signalR.HubConnectionBuilder()
|
const connectionManager = new ConnectionManager(config.ServerIp || config.signalR.serverUrl.replace('http://', '').replace('/signalR', ''));
|
||||||
.withUrl(config.signalR.serverUrl)
|
|
||||||
.withAutomaticReconnect([0, 2000, 5000, 10000, 30000])
|
|
||||||
.configureLogging(signalR.LogLevel.Information)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
// Gérer les changements d'état
|
// La connexion sera établie plus tard avec fallback automatique
|
||||||
signalRConnection.onreconnecting(() => {
|
signalRConnection = connectionManager;
|
||||||
console.log('SignalR: Reconnexion en cours...');
|
|
||||||
logSignalR('🔄 SignalR en reconnexion...', {
|
|
||||||
previousStatus: signalRStatus,
|
|
||||||
timestamp: new Date().toISOString()
|
|
||||||
});
|
|
||||||
signalRStatus = 'connecting';
|
|
||||||
sendSignalRStatus();
|
|
||||||
});
|
|
||||||
|
|
||||||
signalRConnection.onreconnected(() => {
|
// Les handlers d'état seront configurés après la connexion
|
||||||
console.log('SignalR: Reconnecté');
|
|
||||||
logSignalR('🔗 SignalR reconnecté avec succès', {
|
|
||||||
connectionId: signalRConnection.connectionId,
|
|
||||||
timestamp: new Date().toISOString()
|
|
||||||
});
|
|
||||||
signalRStatus = 'connected';
|
|
||||||
sendSignalRStatus();
|
|
||||||
});
|
|
||||||
|
|
||||||
signalRConnection.onclose(() => {
|
// Démarrer la connexion (les handlers seront configurés après)
|
||||||
console.log('SignalR: Connexion fermée');
|
|
||||||
logSignalR('🔌 SignalR déconnecté', {
|
|
||||||
lastConnectionId: signalRConnection.connectionId,
|
|
||||||
timestamp: new Date().toISOString()
|
|
||||||
});
|
|
||||||
signalRStatus = 'disconnected';
|
|
||||||
sendSignalRStatus();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Configurer les méthodes SignalR
|
|
||||||
setupSignalRMethods();
|
|
||||||
|
|
||||||
// Démarrer la connexion
|
|
||||||
startSignalRConnection();
|
startSignalRConnection();
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -148,7 +116,14 @@ function initializeSignalR() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupSignalRMethods() {
|
function setupSignalRHandlers() {
|
||||||
|
// Configuration des handlers après la connexion
|
||||||
|
const connection = signalRConnection.getConnection();
|
||||||
|
if (!connection) {
|
||||||
|
console.error('Pas de connexion active pour configurer les handlers');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// === LOGGER UNIVERSEL POUR TOUS LES MESSAGES SIGNALR ===
|
// === LOGGER UNIVERSEL POUR TOUS LES MESSAGES SIGNALR ===
|
||||||
// Intercepter TOUS les messages reçus du serveur pour découvrir les événements disponibles
|
// Intercepter TOUS les messages reçus du serveur pour découvrir les événements disponibles
|
||||||
|
|
||||||
@@ -185,7 +160,7 @@ function setupSignalRMethods() {
|
|||||||
|
|
||||||
// Écouter tous les événements possibles et logger ce qu'on reçoit
|
// Écouter tous les événements possibles et logger ce qu'on reçoit
|
||||||
possibleEvents.forEach(eventName => {
|
possibleEvents.forEach(eventName => {
|
||||||
signalRConnection.on(eventName, (...args) => {
|
connection.on(eventName, (...args) => {
|
||||||
// Logger dans la console avec formatage
|
// Logger dans la console avec formatage
|
||||||
console.log('═══════════════════════════════════════════════════════════');
|
console.log('═══════════════════════════════════════════════════════════');
|
||||||
console.log(`📨 MESSAGE SIGNALR REÇU: ${eventName}`);
|
console.log(`📨 MESSAGE SIGNALR REÇU: ${eventName}`);
|
||||||
@@ -323,18 +298,28 @@ async function startSignalRConnection() {
|
|||||||
try {
|
try {
|
||||||
signalRStatus = 'connecting';
|
signalRStatus = 'connecting';
|
||||||
sendSignalRStatus();
|
sendSignalRStatus();
|
||||||
logSignalR('🔌 Tentative de connexion SignalR...', {
|
logSignalR('🔌 Tentative de connexion au serveur...', {
|
||||||
serverUrl: config.signalR.serverUrl,
|
serverUrl: config.ServerIp || config.signalR.serverUrl,
|
||||||
status: 'connecting'
|
status: 'connecting'
|
||||||
});
|
});
|
||||||
|
|
||||||
await signalRConnection.start();
|
// Le ConnectionManager gère le fallback automatiquement
|
||||||
console.log('SignalR: Connexion établie');
|
const connection = await signalRConnection.connect();
|
||||||
logSignalR('✅ Connexion SignalR établie avec succès', {
|
|
||||||
connectionId: signalRConnection.connectionId,
|
// Déterminer quel type de connexion a réussi
|
||||||
|
const connectionInfo = signalRConnection.getConnectionInfo();
|
||||||
|
|
||||||
|
console.log(`Connexion établie via ${connectionInfo.type}`);
|
||||||
|
logSignalR(`✅ Connexion établie avec succès (${connectionInfo.type})`, {
|
||||||
|
connectionType: connectionInfo.type,
|
||||||
|
isWebSocketFallback: connectionInfo.isWebSocketFallback,
|
||||||
status: 'connected',
|
status: 'connected',
|
||||||
serverUrl: config.signalR.serverUrl
|
serverUrl: connectionInfo.serverUrl
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Maintenant configurer les handlers sur la connexion active
|
||||||
|
setupSignalRHandlers();
|
||||||
|
|
||||||
signalRStatus = 'connected';
|
signalRStatus = 'connected';
|
||||||
sendSignalRStatus();
|
sendSignalRStatus();
|
||||||
|
|
||||||
@@ -403,10 +388,9 @@ app.on('window-all-closed', async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Arrêter SignalR
|
// Ne pas appeler disconnect() pour éviter l'envoi du CloseMessage
|
||||||
if (signalRConnection) {
|
// Le serveur .NET ne supporte pas ce message
|
||||||
await signalRConnection.stop();
|
// On laisse la connexion se fermer naturellement avec l'application
|
||||||
}
|
|
||||||
|
|
||||||
if (process.platform !== 'darwin') {
|
if (process.platform !== 'darwin') {
|
||||||
app.quit();
|
app.quit();
|
||||||
@@ -655,15 +639,10 @@ ipcMain.handle('logout', async () => {
|
|||||||
|
|
||||||
// Handler pour quitter l'application proprement
|
// Handler pour quitter l'application proprement
|
||||||
ipcMain.handle('quit-app', async () => {
|
ipcMain.handle('quit-app', async () => {
|
||||||
// Fermer la connexion SignalR si elle existe
|
// Ne pas appeler disconnect() pour éviter l'envoi du CloseMessage
|
||||||
if (signalRConnection) {
|
// Le serveur .NET ne supporte pas ce message
|
||||||
try {
|
// On laisse la connexion se fermer naturellement avec l'application
|
||||||
await signalRConnection.stop();
|
// (comme le fait le client de prod)
|
||||||
console.log('Connexion SignalR fermée');
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Erreur lors de la fermeture de SignalR:', error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Quitter l'application
|
// Quitter l'application
|
||||||
app.quit();
|
app.quit();
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "simpleconnect-electron",
|
"name": "simpleconnect-electron",
|
||||||
"version": "1.2.16",
|
"version": "1.3.0",
|
||||||
"description": "Application de gestion centralisée des plannings médicaux pour centres d'appels",
|
"description": "Application de gestion centralisée des plannings médicaux pour centres d'appels",
|
||||||
"main": "main.js",
|
"main": "main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -86,6 +86,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@microsoft/signalr": "^9.0.6",
|
"@microsoft/signalr": "^9.0.6",
|
||||||
"choices.js": "^11.1.0"
|
"choices.js": "^11.1.0",
|
||||||
|
"socket.io-client": "^4.8.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
168
websocket-adapter.js
Normal file
168
websocket-adapter.js
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
/**
|
||||||
|
* Adaptateur WebSocket pour fallback quand SignalR n'est pas disponible
|
||||||
|
* Émule l'API SignalR avec SocketIO
|
||||||
|
*/
|
||||||
|
|
||||||
|
const io = require('socket.io-client');
|
||||||
|
|
||||||
|
class WebSocketAdapter {
|
||||||
|
constructor(serverUrl, options = {}) {
|
||||||
|
// Nettoyer l'URL et s'assurer qu'elle est valide
|
||||||
|
this.serverUrl = serverUrl;
|
||||||
|
if (this.serverUrl.includes('/signalR')) {
|
||||||
|
this.serverUrl = this.serverUrl.replace('/signalR', '');
|
||||||
|
}
|
||||||
|
// S'assurer qu'on a le protocole
|
||||||
|
if (!this.serverUrl.startsWith('http://') && !this.serverUrl.startsWith('https://')) {
|
||||||
|
this.serverUrl = `http://${this.serverUrl}`;
|
||||||
|
}
|
||||||
|
this.socket = null;
|
||||||
|
this.connected = false;
|
||||||
|
this.handlers = new Map();
|
||||||
|
this.options = options;
|
||||||
|
this.pendingInvocations = new Map();
|
||||||
|
this.invocationId = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Émule connection.start() de SignalR
|
||||||
|
*/
|
||||||
|
async start() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
console.log(`🔄 Connexion WebSocket à ${this.serverUrl}...`);
|
||||||
|
|
||||||
|
// Se connecter avec SocketIO
|
||||||
|
this.socket = io(this.serverUrl, {
|
||||||
|
transports: ['websocket'],
|
||||||
|
reconnection: true,
|
||||||
|
reconnectionAttempts: 5,
|
||||||
|
reconnectionDelay: 2000,
|
||||||
|
...this.options
|
||||||
|
});
|
||||||
|
|
||||||
|
this.socket.on('connect', () => {
|
||||||
|
console.log('✅ WebSocket connecté (mode fallback)');
|
||||||
|
this.connected = true;
|
||||||
|
|
||||||
|
// Émuler l'événement 'connected' de SignalR
|
||||||
|
if (this.handlers.has('connected')) {
|
||||||
|
this.handlers.get('connected')({ connectionId: this.socket.id });
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.socket.on('connect_error', (error) => {
|
||||||
|
console.error('❌ Erreur connexion WebSocket:', error.message);
|
||||||
|
reject(error);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.socket.on('disconnect', (reason) => {
|
||||||
|
console.log('🔌 WebSocket déconnecté:', reason);
|
||||||
|
this.connected = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Timeout de connexion
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!this.connected) {
|
||||||
|
reject(new Error('Timeout de connexion WebSocket'));
|
||||||
|
}
|
||||||
|
}, 10000);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Émule connection.stop() de SignalR
|
||||||
|
*/
|
||||||
|
async stop() {
|
||||||
|
if (this.socket) {
|
||||||
|
this.socket.disconnect();
|
||||||
|
this.connected = false;
|
||||||
|
console.log('🛑 WebSocket fermé');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Émule connection.invoke() de SignalR
|
||||||
|
*/
|
||||||
|
async invoke(methodName, ...args) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (!this.connected) {
|
||||||
|
reject(new Error('WebSocket non connecté'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const invocationId = ++this.invocationId;
|
||||||
|
console.log(`📤 WebSocket invoke: ${methodName}`, args);
|
||||||
|
|
||||||
|
// Stocker la promesse pour la résolution
|
||||||
|
this.pendingInvocations.set(invocationId, { resolve, reject });
|
||||||
|
|
||||||
|
// Émuler le format SignalR mais utiliser l'API SocketIO
|
||||||
|
// SocketIO utilise emit avec un callback pour les réponses
|
||||||
|
this.socket.emit(methodName, ...args, (response) => {
|
||||||
|
console.log(`📥 WebSocket response for ${methodName}:`, response);
|
||||||
|
|
||||||
|
const pending = this.pendingInvocations.get(invocationId);
|
||||||
|
if (pending) {
|
||||||
|
pending.resolve(response);
|
||||||
|
this.pendingInvocations.delete(invocationId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Timeout pour éviter les promesses pendantes
|
||||||
|
setTimeout(() => {
|
||||||
|
const pending = this.pendingInvocations.get(invocationId);
|
||||||
|
if (pending) {
|
||||||
|
pending.reject(new Error(`Timeout invoking ${methodName}`));
|
||||||
|
this.pendingInvocations.delete(invocationId);
|
||||||
|
}
|
||||||
|
}, 30000);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Émule connection.on() de SignalR
|
||||||
|
*/
|
||||||
|
on(eventName, handler) {
|
||||||
|
console.log(`👂 WebSocket listener ajouté: ${eventName}`);
|
||||||
|
this.handlers.set(eventName, handler);
|
||||||
|
|
||||||
|
// Mapper les événements SocketIO vers les handlers
|
||||||
|
if (this.socket) {
|
||||||
|
this.socket.on(eventName, (...args) => {
|
||||||
|
console.log(`📨 WebSocket event reçu: ${eventName}`, args);
|
||||||
|
handler(eventName, args);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Émule connection.off() de SignalR
|
||||||
|
*/
|
||||||
|
off(eventName) {
|
||||||
|
this.handlers.delete(eventName);
|
||||||
|
if (this.socket) {
|
||||||
|
this.socket.off(eventName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* État de la connexion (émule SignalR HubConnectionState)
|
||||||
|
*/
|
||||||
|
get state() {
|
||||||
|
if (this.connected) {
|
||||||
|
return 'Connected';
|
||||||
|
}
|
||||||
|
return 'Disconnected';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifier si la connexion utilise WebSocket (toujours vrai pour cet adaptateur)
|
||||||
|
*/
|
||||||
|
get isWebSocketFallback() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = WebSocketAdapter;
|
||||||
Reference in New Issue
Block a user