PageSourceSearch

https://www.bahraingp.com/app/plugins/bic-avaya/assets/js/bic-avaya-chat-socket.js?ver=1.0.0

js bahraingp.com collected 2026-10-02 07:41:16 UTC 11,846 bytes, 352 lines download raw bytes

1/**
2 * BIC Avaya - Chat WebSocket Handler
3 *
4 * Manages WebSocket connection for live chat.
5 *
6 * @package BIC_Avaya
7 */
8
9(function($, window) {
10    'use strict';
11
12    if (typeof bicAvayaChatConfig === 'undefined') {
13        bicAvayaLog.error('Chat config not loaded');
14        return;
15    }
16
17    /**
18     * WebSocket manager
19     */
20    window.bicAvayaChatSocket = {
21        socket: null,
22        retryCount: 0,
23        pingInterval: null,
24        dontRetryConnection: false,
25        isConnected: false,
26        messageHandlers: {},
27
28        /**
29         * Connect to the WebSocket server
30         */
31        connect: function() {
32            var self = this;
33
34            if (this.socket && this.socket.readyState === WebSocket.OPEN) {
35                bicAvayaLog.debug('WebSocket already connected');
36                return;
37            }
38
39            bicAvayaLog.debug('Connecting to WebSocket:', bicAvayaChatConfig.webSocketUrl);
40
41            try {
42                this.socket = new WebSocket(bicAvayaChatConfig.webSocketUrl);
43
44                this.socket.onopen = function() {
45                    bicAvayaLog.info('✓ WebSocket connection established');
46                    bicAvayaLog.debug('Ready state:', self.socket.readyState);
47                    self.isConnected = true;
48                    self.retryCount = 0;
49                    self.startPing();
50                    self.trigger('connected');
51                };
52
53                this.socket.onclose = function(event) {
54                    bicAvayaLog.debug('WebSocket closed', event.code, event.reason);
55                    self.isConnected = false;
56                    self.stopPing();
57                    self.trigger('disconnected');
58
59                    // Auto-reconnect unless explicitly closed or max retries reached
60                    if (!self.dontRetryConnection && event.code !== 1000) {
61                        self.scheduleReconnect();
62                    }
63                };
64
65                this.socket.onerror = function(error) {
66                    bicAvayaLog.error('WebSocket error:', error);
67                    self.trigger('error', error);
68                };
69
70                this.socket.onmessage = function(event) {
71                    self.handleMessage(event.data);
72                };
73
74            } catch (e) {
75                bicAvayaLog.error('Failed to create WebSocket:', e);
76                this.scheduleReconnect();
77            }
78        },
79
80        /**
81         * Disconnect from the WebSocket server
82         */
83        disconnect: function() {
84            this.dontRetryConnection = true;
85            this.stopPing();
86
87            if (this.socket) {
88                this.socket.close(1000, 'User closed chat');
89                this.socket = null;
90            }
91
92            this.isConnected = false;
93            bicAvayaLog.debug('WebSocket disconnected');
94        },
95
96        /**
97         * Schedule a reconnection attempt
98         */
99        scheduleReconnect: function() {
100            var self = this;
101
102            if (this.retryCount >= bicAvayaChatConfig.maxRetries) {
103                bicAvayaLog.error('Max reconnection attempts reached');
104                this.trigger('maxRetriesReached');
105                return;
106            }
107
108            this.retryCount++;
109            bicAvayaLog.debug('Scheduling reconnect attempt', this.retryCount);
110
111            setTimeout(function() {
112                if (!self.dontRetryConnection) {
113                    self.connect();
114                }
115            }, bicAvayaChatConfig.retryInterval);
116        },
117
118        /**
119         * Send a message through the WebSocket
120         */
121        send: function(message) {
122            if (!this.socket || this.socket.readyState !== WebSocket.OPEN) {
123                bicAvayaLog.error('Cannot send message - WebSocket not connected');
124                return false;
125            }
126
127            var messageStr = typeof message === 'string' ? message : JSON.stringify(message);
128
129            bicAvayaLog.info('→ Sending WebSocket message:', message);
130            bicAvayaLog.debug('→ JSON string:', messageStr);
131            this.socket.send(messageStr);
132            return true;
133        },
134
135        /**
136         * Handle incoming WebSocket message
137         */
138        handleMessage: function(data) {
139            bicAvayaLog.info('← Received WebSocket message (raw):', data);
140
141            try {
142                var message = JSON.parse(data);
143                bicAvayaLog.info('← Parsed message object:', message);
144
145                var type = message.type || message.messageType;
146                bicAvayaLog.info('← Detected message type: "' + type + '"');
147                bicAvayaLog.info('← Expected NEW_CHAT_ACK type: "' + bicAvayaChatConfig.messageTypes.NEW_CHAT_ACK + '"');
148                bicAvayaLog.info('← Type match:', type === bicAvayaChatConfig.messageTypes.NEW_CHAT_ACK);
149
150                switch (type) {
151                    case bicAvayaChatConfig.messageTypes.NEW_CHAT_ACK:
152                        bicAvayaLog.info('✓✓✓ Matched NEW_CHAT_ACK - triggering chatCreated event ✓✓✓');
153                        this.trigger('chatCreated', message);
154                        break;
155
156                    case bicAvayaChatConfig.messageTypes.ACK:
157                        bicAvayaLog.debug('✓ Acknowledgement received');
158                        this.trigger('acknowledgement', message);
159                        break;
160
161                    case bicAvayaChatConfig.messageTypes.ERROR:
162                        bicAvayaLog.error('✗ Server error:', message.body);
163                        this.trigger('chatError', message);
164                        break;
165
166                    case bicAvayaChatConfig.messageTypes.NOTIFICATION:
167                        bicAvayaLog.debug('← Notification:', message.body && message.body.method);
168                        this.handleNotification(message);
169                        break;
170
171                    default:
172                        bicAvayaLog.warn('← Unknown/unhandled message type: "' + type + '"');
173                        bicAvayaLog.warn('← Full message:', message);
174                        this.trigger('message', message);
175                }
176            } catch (e) {
177                bicAvayaLog.error('Failed to parse message:', e, data);
178            }
179        },
180
181        /**
182         * Handle notification messages
183         */
184        handleNotification: function(message) {
185            var body = message.body || {};
186            var method = body.method;
187
188            bicAvayaLog.debug('← Notification method: "' + method + '"');
189
190            switch (method) {
191                case 'requestChat':
192                    // Chat successfully created - this is the acknowledgement
193                    bicAvayaLog.info('✓✓✓ Chat created via notification (requestChat) ✓✓✓');
194                    this.trigger('chatCreated', message);
195                    break;
196
197                case 'newMessage':
198                    // Agent sent a message
199                    this.trigger('agentMessage', {
200                        message: body.message,
201                        displayName: body.displayName || 'Agent',
202                        timestamp: body.timestamp
203                    });
204                    break;
205
206                case 'newParticipant':
207                    // Agent joined
208                    this.trigger('participants', {
209                        participants: body.participants || [],
210                        displayName: body.displayName,
211                        agentId: body.agentId
212                    });
213                    break;
214
215                case 'N':
216                case 'N_PLAIN':
217                case 'N_RICH':
218                    this.trigger('agentMessage', {
219                        message: body.value,
220                        displayName: body.displayName || 'Agent',
221                        isRich: method === 'N_RICH'
222                    });
223                    break;
224
225                case 'N_AGENT_TYPING_START':
226                    this.trigger('agentTyping', { isTyping: true });
227                    break;
228
229                case 'N_AGENT_TYPING_STOP':
230                    this.trigger('agentTyping', { isTyping: false });
231                    break;
232
233                case 'isTyping':
234                    // Handle isTyping notifications from agent
235                    if (body.isTyping === true) {
236                        this.trigger('agentTyping', { isTyping: true });
237                    } else if (body.isTyping === false) {
238                        this.trigger('agentTyping', { isTyping: false });
239                    }
240                    break;
241
242                case 'N_QUEUE_POSITION':
243                    this.trigger('queuePosition', { position: body.value });
244                    break;
245
246                case 'N_PARTICIPANTS':
247                    this.trigger('participants', { participants: body.value });
248                    break;
249
250                case 'N_END_CHAT':
251                case 'N_CLOSE':
252                case 'closeConversation':
253                    this.trigger('chatEnded', { reason: body.value || 'Chat ended' });
254                    break;
255
256                case 'N_PAGE_PUSH':
257                    this.trigger('pagePush', { url: body.value });
258                    break;
259
260                case 'ping':
261                    // Ping response - ignore
262                    break;
263
264                default:
265                    bicAvayaLog.debug('Unknown notification method:', method);
266                    this.trigger('notification', message);
267            }
268        },
269
270        /**
271         * Start ping interval to keep connection alive
272         */
273        startPing: function() {
274            var self = this;
275            this.stopPing();
276
277            this.pingInterval = setInterval(function() {
278                if (self.isConnected) {
279                    self.send({
280                        apiVersion: '1.0',
281                        type: 'request',
282                        body: {
283                            method: 'ping'
284                        }
285                    });
286                }
287            }, bicAvayaChatConfig.pingTimer);
288        },
289
290        /**
291         * Stop ping interval
292         */
293        stopPing: function() {
294            if (this.pingInterval) {
295                clearInterval(this.pingInterval);
296                this.pingInterval = null;
297            }
298        },
299
300        /**
301         * Register an event handler
302         */
303        on: function(event, handler) {
304            if (!this.messageHandlers[event]) {
305                this.messageHandlers[event] = [];
306            }
307            this.messageHandlers[event].push(handler);
308        },
309
310        /**
311         * Remove an event handler
312         */
313        off: function(event, handler) {
314            if (!this.messageHandlers[event]) return;
315
316            if (handler) {
317                this.messageHandlers[event] = this.messageHandlers[event].filter(function(h) {
318                    return h !== handler;
319                });
320            } else {
321                delete this.messageHandlers[event];
322            }
323        },
324
325        /**
326         * Trigger an event
327         */
328        trigger: function(event, data) {
329            var handlers = this.messageHandlers[event];
330            if (!handlers) return;
331
332            handlers.forEach(function(handler) {
333                try {
334                    handler(data);
335                } catch (e) {
336                    bicAvayaLog.error('Error in event handler:', event, e);
337                }
338            });
339        },
340
341        /**
342         * Reset socket state for new chat
343         */
344        reset: function() {
345            this.dontRetryConnection = false;
346            this.retryCount = 0;
347        }
348    };
349
350    bicAvayaLog.debug('Chat socket module loaded');
351
352})(jQuery, window);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.