168 lines
5.2 KiB
JavaScript
168 lines
5.2 KiB
JavaScript
/**
|
|
* 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; |