Add RestSocketAdapter that uses: - REST API for actions (login, logout, terminals) - Socket.IO for real-time events (IpbxEvent) ConnectionManager now tries SignalR first (.NET server), then falls back to REST+SocketIO (Python server). This enables the client to work with both servers during migration.
134 lines
4.0 KiB
JavaScript
134 lines
4.0 KiB
JavaScript
/**
|
|
* Gestionnaire de connexion avec fallback SignalR → REST + Socket.IO
|
|
*
|
|
* 1. Essaie d'abord SignalR (serveur .NET legacy)
|
|
* 2. Si SignalR échoue, bascule sur REST + Socket.IO (serveur Python)
|
|
*/
|
|
|
|
const signalR = require('@microsoft/signalr');
|
|
const RestSocketAdapter = require('./rest-socket-adapter');
|
|
|
|
class ConnectionManager {
|
|
constructor(serverUrl, options = {}) {
|
|
this.serverUrl = serverUrl;
|
|
this.options = options;
|
|
this.connection = null;
|
|
this.connectionType = 'none'; // 'none', 'SignalR', 'REST+SocketIO'
|
|
}
|
|
|
|
/**
|
|
* Établit la connexion en essayant SignalR puis REST + Socket.IO
|
|
*/
|
|
async connect() {
|
|
console.log('🔌 Tentative de connexion au serveur...');
|
|
|
|
// 1. Essayer SignalR d'abord (serveur .NET)
|
|
try {
|
|
console.log('📡 Essai avec SignalR...');
|
|
this.connection = this._createSignalRConnection();
|
|
await this.connection.start();
|
|
this.connectionType = 'SignalR';
|
|
console.log('✅ Connexion SignalR établie (serveur .NET)');
|
|
return this.connection;
|
|
} catch (signalRError) {
|
|
console.warn('⚠️ SignalR indisponible:', signalRError.message);
|
|
console.log('🔄 Basculement vers REST + Socket.IO...');
|
|
}
|
|
|
|
// 2. Fallback vers REST + Socket.IO (serveur Python)
|
|
try {
|
|
this.connection = new RestSocketAdapter(this.serverUrl, this.options);
|
|
await this.connection.start();
|
|
this.connectionType = 'REST+SocketIO';
|
|
console.log('✅ Connexion REST + Socket.IO établie (serveur Python)');
|
|
return this.connection;
|
|
} catch (restError) {
|
|
console.error('❌ REST + Socket.IO indisponible:', restError.message);
|
|
throw new Error('Impossible de se connecter (SignalR et REST+SocketIO ont échoué)');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Crée une connexion SignalR
|
|
*/
|
|
_createSignalRConnection() {
|
|
let url = this.serverUrl;
|
|
if (!url.startsWith('http://') && !url.startsWith('https://')) {
|
|
url = `http://${url}`;
|
|
}
|
|
if (!url.includes('/signalR')) {
|
|
url = `${url}/signalR`;
|
|
}
|
|
|
|
console.log(`📡 URL SignalR: ${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,
|
|
isSignalR: this.connectionType === 'SignalR',
|
|
isRestSocketIO: this.connectionType === 'REST+SocketIO',
|
|
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);
|
|
}
|
|
|
|
/**
|
|
* Méthode helper pour retirer un handler d'événement
|
|
*/
|
|
off(eventName) {
|
|
if (this.connection && this.connection.off) {
|
|
this.connection.off(eventName);
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = ConnectionManager;
|