feat: aligner event handler Socket.IO sur le contrat snake_case (#20)

- Ecouter call_event au lieu de ipbx_event
- Lire event_code, queue_name, terminal en snake_case
- handleCallPickedUp/handleCallHungUp utilisent event.queue_name
- renderer.js lit data.queue_name
- 3 tests unitaires ajoutés dans socketio-adapter.test.js
This commit is contained in:
Pierre Marx
2026-03-19 12:32:30 -04:00
parent 78105f84d1
commit 72514cc578
4 changed files with 70 additions and 11 deletions

View File

@@ -43,7 +43,7 @@ bun test # 8 tests unitaires socketio-adapter
- **Sessions webview isolées** : partition Electron unique par centre, auto-connexion via preload script
- **Socket.IO reconnexion** : illimitée (2s→10s backoff)
- **IPC principal** : `login-agent`, `get-terminal-list`, `server-status`, `switch-to-center`, `release-center`
- **Protocole serveur** : auth au handshake, events `login_ok`/`login_error`/`ipbx_event`/`logout``logout_ok`
- **Protocole serveur** : auth au handshake, events `login_ok`/`login_error`/`call_event`/`logout``logout_ok` (champs snake_case : `event_code`, `queue_name`, `terminal`)
- **Terminaux** : REST `GET /terminals?provider=RDVPREM` (pas Socket.IO)
- **Logs** : `~/.simpleconnect-ng/socketio.log`
- **Notes** : sauvegarde auto après 2s d'inactivité, 50 versions, sync localStorage + fichier

18
main.js
View File

@@ -208,19 +208,19 @@ function handleCallPickedUp(event) {
if (!mainWindow || !agentConnectionInfo) return;
const centres = processApplicationUrls(agentConnectionInfo.connList);
const centre = centres.find(c => c.queueName === event.queueName);
const centre = centres.find(c => c.queueName === event.queue_name);
if (centre) {
log(`Basculement vers le centre: ${centre.nom}`);
mainWindow.webContents.send('switch-to-center', {
centreId: centre.id,
centreName: centre.nom,
queueName: event.queueName,
queue_name: event.queue_name,
terminal: event.terminal,
eventType: 'call_pickup'
});
} else {
log(`${c.yellow}Aucun centre trouvé pour la file: ${event.queueName}${c.reset}`);
log(`${c.yellow}Aucun centre trouvé pour la file: ${event.queue_name}${c.reset}`);
}
}
@@ -228,9 +228,9 @@ function handleCallPickedUp(event) {
function handleCallHungUp(event) {
if (!mainWindow) return;
log(`Fin d'appel sur la file: ${event.queueName}`);
log(`Fin d'appel sur la file: ${event.queue_name}`);
mainWindow.webContents.send('release-center', {
queueName: event.queueName,
queue_name: event.queue_name,
terminal: event.terminal,
eventType: 'call_hangup'
});
@@ -245,9 +245,9 @@ function setupEventHandlers() {
serviceProvider: config.socketio.serviceProvider
});
// Ecouter les evenements d'appels IPBX
adapter.on('ipbx_event', (data) => {
log('ipbx_event recu', data);
// Ecouter les evenements d'appels IPBX (contrat snake_case du serveur)
adapter.on('call_event', (data) => {
log('call_event recu', data);
if (!agentConnectionInfo) return;
@@ -257,7 +257,7 @@ function setupEventHandlers() {
return;
}
switch (data.eventCode) {
switch (data.event_code) {
case 1:
handleCallPickedUp(data);
break;

View File

@@ -153,7 +153,7 @@ document.addEventListener('DOMContentLoaded', async () => {
// Écouter la libération de centre après raccrochage
ipcRenderer.on('release-center', (event, data) => {
console.log('Libération de la file:', data.queueName);
console.log('Libération de la file:', data.queue_name);
// Mettre à jour le statut
updateAgentStatus('DISPONIBLE');

View File

@@ -128,4 +128,63 @@ describe("SocketIOAdapter", () => {
expect(states).toEqual(["connecting", "connected", "reconnecting", "connected"]);
});
test("on('call_event') recoit les champs snake_case du serveur", async () => {
const received = [];
adapter.on('call_event', (data) => received.push(data));
const p = adapter.connect("1234", "pass", "2001");
socket._fire("login_ok", { accessCode: "1234" });
await p;
// Le serveur envoie un call_event avec champs snake_case
socket._fire("call_event", {
event_code: 1,
queue_name: "FILE_CENTRE_A",
terminal: "2001",
});
expect(received).toHaveLength(1);
expect(received[0].event_code).toBe(1);
expect(received[0].queue_name).toBe("FILE_CENTRE_A");
expect(received[0].terminal).toBe("2001");
});
test("on('call_event') enregistré avant connect() est dispatché après connexion", async () => {
const received = [];
// Enregistrer le handler AVANT connect (comme le fait main.js)
adapter.on('call_event', (data) => received.push(data));
const p = adapter.connect("1234", "pass", "2001");
socket._fire("login_ok", { accessCode: "1234" });
await p;
// Le serveur envoie un call_event
socket._fire("call_event", {
event_code: 2,
queue_name: "FILE_CENTRE_B",
terminal: "2001",
});
expect(received).toHaveLength(1);
expect(received[0].event_code).toBe(2);
expect(received[0].queue_name).toBe("FILE_CENTRE_B");
});
test("off('call_event') supprime le handler", async () => {
const received = [];
adapter.on('call_event', (data) => received.push(data));
const p = adapter.connect("1234", "pass", "2001");
socket._fire("login_ok", { accessCode: "1234" });
await p;
// Supprimer le handler
adapter.off('call_event');
// L'event ne devrait plus être capté
socket._fire("call_event", { event_code: 1, queue_name: "FILE", terminal: "2001" });
expect(received).toHaveLength(0);
});
});