439 lines
14 KiB
TypeScript
439 lines
14 KiB
TypeScript
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
//@ts-nocheck
|
|
|
|
|
|
import messagingType from "../../../types/MessagingType.ts";
|
|
import {parse} from "path";
|
|
|
|
export enum MessagingType {
|
|
ON_AMEYO_CALL_INCOMING = 'onAmeyoCallIncoming',
|
|
ON_AMEYO_CALL_ACCEPTED = 'onAmeyoCallAccepted',
|
|
ON_AMEYO_CALL_DISCONNECTED = 'onAmeyoCallDisconnected',
|
|
ON_AMEYO_AGENT_ON_BREAK = 'onAmeyoAgentOnBreak',
|
|
ON_AMEYO_FORCED_LOGOUT = 'onAmeyoForcedLogout',
|
|
ON_AMEYO_CALL_TRANSFER = 'onAmeyoCallTransfer',
|
|
ON_AMEYO_AVAILABILITY_CHANGE = 'onAmeyoAvailabilityChange'
|
|
|
|
}
|
|
|
|
|
|
let pushConnectionIndex = 0;
|
|
const pushHistory = [];
|
|
let sizeOfHistory = 5;
|
|
|
|
let isConnectionEstablished = false;
|
|
let shouldStopConnection = false;
|
|
|
|
let isAttempting = false;
|
|
|
|
let connStart;
|
|
let connEnd;
|
|
let conAttemptFailed = 0;
|
|
|
|
let reConnectionCount = 0;
|
|
|
|
let baseUrl;
|
|
let sessionId;
|
|
|
|
let pushConnectionHealthTimer = null;
|
|
let lastPushReceivedTime = '';
|
|
const monitorPushTime = 60 * 1000;
|
|
|
|
//call the above function to create the XMLHttpRequest object
|
|
let http = createRequestObject();
|
|
|
|
enum pushResponseTypes {
|
|
UserCallModelUpdatedPush = 'UserCallModelUpdatedPush',
|
|
CustomerCallMemberUpdatedPush = 'CustomerCallMemberUpdatedPush',
|
|
UserCallMemberUpdatedPush = 'UserCallMemberUpdatedPush',
|
|
CRMCreateNotifyPush = 'CRMCreateNotifyPush',
|
|
UserCCRuntimeUpdatedPush = 'UserCCRuntimeUpdatedPush',
|
|
UserLoggedOffPush = 'UserLoggedOffPush'
|
|
}
|
|
|
|
export function parseQuerystring(url: string): Record<string, any> {
|
|
const foo = url?.split('?')?.[1]?.split('&') || [];
|
|
const dict = {};
|
|
let elem = [];
|
|
for (let i = foo.length - 1; i >= 0; i--) {
|
|
elem = foo[i].split('=');
|
|
dict[elem[0]] = elem[1];
|
|
}
|
|
return dict || {};
|
|
}
|
|
|
|
function extractUserCallModelUpdatedPush(rawResponse) {
|
|
const parts = rawResponse
|
|
.replaceAll(`Content-type: application/json ; charset: utf-8\r\n\r\n`, '')
|
|
.split("--DON'T_PANIC!_more_will_follow\r\n")
|
|
.map((part) => {
|
|
try {
|
|
return JSON.parse(part.trim());
|
|
} catch {
|
|
return null; // Ignore parsing errors
|
|
}
|
|
})
|
|
.filter(Boolean); // Remove null values
|
|
|
|
// Prioritize CRMCreateNotifyPush and keep the rest
|
|
const sortedParts = [
|
|
...parts.filter(part => part?.pushType === pushResponseTypes.CRMCreateNotifyPush),
|
|
...parts.filter(part => part?.pushType !== pushResponseTypes.CRMCreateNotifyPush),
|
|
];
|
|
|
|
sortedParts.forEach(jsonData => {
|
|
if (jsonData?.pushType === pushResponseTypes.CRMCreateNotifyPush) {
|
|
const crtObjectId = jsonData?.data?.crtObjectId;
|
|
const parsedObject = parseQuerystring(jsonData?.data?.crmURL);
|
|
let userCRTObjectId = parsedObject?.userCrtObjectId?.replace('%40', '@');
|
|
userCRTObjectId = userCRTObjectId.replace('%40', '@');
|
|
const phoneNumber = parsedObject?.phone;
|
|
const lan = parsedObject?.loanaccountnumber;
|
|
const callId = parsedObject?.unique_id || parsedObject?.callid;
|
|
localStorage.setItem(
|
|
'revEngCustomerInfo',
|
|
JSON.stringify({phoneNumber, lan, crtObjectId, userCRTObjectId, callId})
|
|
);
|
|
}
|
|
if (jsonData?.pushType === pushResponseTypes.UserCallModelUpdatedPush) {
|
|
sendCallStatusMessage(jsonData);
|
|
}
|
|
if (jsonData?.pushType === pushResponseTypes.CustomerCallMemberUpdatedPush) {
|
|
const payload = jsonData?.data;
|
|
// handle for transfer call
|
|
if (payload?.isDisposing &&
|
|
payload?.status === 'hungup')
|
|
sendCallStatusMessage(jsonData);
|
|
}
|
|
if (jsonData?.pushType === pushResponseTypes.UserCallMemberUpdatedPush) {
|
|
const payload = jsonData?.data;
|
|
const validStatuses = ["ringing", "connected", "hungup"];
|
|
// handle for transfer call
|
|
if (payload?.associationType === 'transfer.association' && validStatuses.includes(payload?.status)) {
|
|
window.postMessage({
|
|
type: MessagingType.ON_AMEYO_CALL_TRANSFER,
|
|
data: payload
|
|
})
|
|
}
|
|
}
|
|
if (jsonData?.pushType === pushResponseTypes.UserCCRuntimeUpdatedPush) {
|
|
const payload = jsonData?.data;
|
|
//handle ameyo availablility changes
|
|
window.postMessage({
|
|
type: messagingType.ON_AMEYO_AVAILABILITY_CHANGE,
|
|
data:{
|
|
isOnBreak: payload?.isOnBreak,
|
|
reason: payload?.statusDescription
|
|
}
|
|
})
|
|
}
|
|
if (jsonData?.pushType == pushResponseTypes.UserLoggedOffPush) {
|
|
const payload = jsonData?.data;
|
|
window.postMessage({
|
|
type: MessagingType.ON_AMEYO_FORCED_LOGOUT,
|
|
data: {}
|
|
})
|
|
}
|
|
} )
|
|
}
|
|
|
|
const sendCallStatusMessage = (res) => {
|
|
try {
|
|
const status = res?.data?.status;
|
|
|
|
const getCustomerInfo = () =>
|
|
JSON.parse(localStorage.getItem('revEngCustomerInfo') || '{}');
|
|
|
|
const sendConnectedMessage = (retryCount = 3) => {
|
|
/* The callId is received after the call is connected.
|
|
* Since callId is essential and cannot be null,
|
|
* this retry mechanism ensures we wait until it becomes available. */
|
|
const data = getCustomerInfo();
|
|
if (data?.callId || data?.phoneNumber) {
|
|
const message = {
|
|
type: MessagingType.ON_AMEYO_CALL_ACCEPTED,
|
|
data,
|
|
};
|
|
window.postMessage(message);
|
|
} else if (retryCount > 0) {
|
|
setTimeout(() => sendConnectedMessage(retryCount - 1), 100);
|
|
} else {
|
|
console.warn('Unable to send ON_AMEYO_CALL_ACCEPTED: callId not found.');
|
|
}
|
|
};
|
|
|
|
switch (status) {
|
|
case 'ringing': {
|
|
const data = getCustomerInfo();
|
|
const message = {
|
|
type: MessagingType.ON_AMEYO_CALL_INCOMING,
|
|
data,
|
|
};
|
|
window.postMessage(message);
|
|
break;
|
|
}
|
|
case 'connected': {
|
|
sendConnectedMessage();
|
|
break;
|
|
}
|
|
case 'hungup': {
|
|
const data = getCustomerInfo();
|
|
const message = {
|
|
type: MessagingType.ON_AMEYO_CALL_DISCONNECTED,
|
|
data,
|
|
};
|
|
window.postMessage(message);
|
|
localStorage.removeItem('revEngCustomerInfo');
|
|
break;
|
|
}
|
|
default:
|
|
console.warn(`Unhandled call status: ${status}`);
|
|
}
|
|
} catch (error) {
|
|
console.error('Error in sendCallStatusMessage:', error);
|
|
}
|
|
};
|
|
|
|
function createRequestObject() {
|
|
let tmpXmlHttpObject;
|
|
|
|
// depending on what the browser supports, use the right way to create the
|
|
// XMLHttpRequest object
|
|
if (window.XMLHttpRequest) {
|
|
// Mozilla, Safari would use this method ...
|
|
tmpXmlHttpObject = new XMLHttpRequest();
|
|
} else if (window.ActiveXObject) {
|
|
// IE would use this method ...
|
|
tmpXmlHttpObject = new ActiveXObject('Microsoft.XMLHTTP');
|
|
}
|
|
|
|
return tmpXmlHttpObject;
|
|
}
|
|
|
|
//This is called after login to start attempting push connection through post request
|
|
export function establishPushConnection(url, session) {
|
|
baseUrl = url;
|
|
sessionId = session;
|
|
makePostRequest(baseUrl, sessionId);
|
|
}
|
|
|
|
//This should be after logout to stop re-establishing push connection
|
|
function stopPushConnection() {
|
|
shouldStopConnection = true;
|
|
if (http) {
|
|
http.abort();
|
|
}
|
|
}
|
|
|
|
function reset() {
|
|
pushConnectionIndex = 0;
|
|
sizeOfHistory = 5;
|
|
isConnectionEstablished = false;
|
|
shouldStopConnection = false;
|
|
isAttempting = false;
|
|
conAttemptFailed = 0;
|
|
reConnectionCount = 0;
|
|
}
|
|
|
|
function processResponse() {
|
|
// check if the response has been received from the server
|
|
if (http.readyState == 3 || http.readyState == 4) {
|
|
reConnectionCount = 0;
|
|
|
|
if (http.status == 200) {
|
|
changeConnectionEstablishState(true);
|
|
}
|
|
// read and assign the response from the server
|
|
const pushResponse = http.responseText.substring(pushConnectionIndex, http.responseText.length);
|
|
pushConnectionIndex = http.responseText.length;
|
|
|
|
// process push received one at a time
|
|
processPush(pushResponse);
|
|
|
|
// in this case simply assign the response to the contents of the <div>
|
|
// on the page.
|
|
// document.getElementById('description').innerHTML = http.responseText;
|
|
|
|
const currentTime = new Date();
|
|
lastPushReceivedTime = currentTime.getTime();
|
|
}
|
|
|
|
// Note :This sample does not consider content boundary in the multipart
|
|
// response
|
|
}
|
|
|
|
function processPush(pushResponse) {
|
|
extractUserCallModelUpdatedPush(pushResponse);
|
|
//ajaxRequest.handleIntermediateResponse(pushResponse);
|
|
}
|
|
|
|
function makePostRequest(url, session) {
|
|
if (shouldStopConnection == true) {
|
|
console.log('should stop connection');
|
|
return;
|
|
}
|
|
|
|
reConnectionCount++;
|
|
if (reConnectionCount > 10) {
|
|
console.log('reconnection count reached not reconnecting');
|
|
return;
|
|
}
|
|
|
|
if (isConnectionEstablished) {
|
|
console.log('connection is already established , so not establishing a connection');
|
|
return;
|
|
}
|
|
|
|
if (conAttemptFailed > 5) {
|
|
console.log('continous attempt failed limit reached');
|
|
console.error('Unable to connect to the server. Please login after some time.');
|
|
return;
|
|
}
|
|
|
|
if (isAttempting) {
|
|
return;
|
|
} else {
|
|
isAttempting = true;
|
|
}
|
|
|
|
connStart = new Date();
|
|
|
|
http = createRequestObject();
|
|
|
|
const listenerName = `webcore_${Date.now()}`; //window.listenerName ;
|
|
window.listenerName = listenerName;
|
|
let lastProcessedSeq = -1; //window.lastProcessedPush;
|
|
|
|
let finalUrl = url;
|
|
const tempSession = session;
|
|
|
|
if (typeof lastProcessedSeq == 'undefined' || lastProcessedSeq == null) {
|
|
lastProcessedSeq = -1;
|
|
}
|
|
|
|
if (typeof pushConnectionHealthTimer != 'undefined' && pushConnectionHealthTimer != null) {
|
|
clearInterval(pushConnectionHealthTimer);
|
|
pushConnectionHealthTimer = null;
|
|
}
|
|
|
|
finalUrl = finalUrl + '&listener-name=' + listenerName + '&lastProcessedPush=' + lastProcessedSeq;
|
|
console.log(
|
|
'going to create push connection with seq:- ' +
|
|
lastProcessedSeq +
|
|
' listener name:- ' +
|
|
listenerName
|
|
);
|
|
console.log('final url ', finalUrl);
|
|
// make a connection to the server ... specifying that you intend to make a
|
|
// GET request
|
|
// to the server. Specifiy the page name and the URL parameters to send
|
|
http.open('POST', finalUrl, true);
|
|
http.setRequestHeader('sessionId', tempSession);
|
|
pushConnectionIndex = 0;
|
|
// assign a handler for the response Origin null is not allowed by
|
|
// Access-Control-Allow-Origin.
|
|
http.onreadystatechange = processResponse;
|
|
|
|
http.addEventListener('loadend', function checkPushEventHealth(e) {
|
|
connEnd = new Date();
|
|
const seconds = (connEnd.getTime() - connStart.getTime()) / 1000;
|
|
|
|
if (seconds < 5) {
|
|
conAttemptFailed++;
|
|
} else {
|
|
conAttemptFailed = 0;
|
|
}
|
|
|
|
isAttempting = false;
|
|
changeConnectionEstablishState(false);
|
|
makePostRequest(baseUrl, sessionId);
|
|
});
|
|
http.addEventListener('loadstart', function createCheckPushHealthTimer() {
|
|
if (typeof pushConnectionHealthTimer == 'undefined' || pushConnectionHealthTimer == null) {
|
|
pushConnectionHealthTimer = window.setInterval(
|
|
function () {
|
|
checkAjaxPushConnectionHealth();
|
|
},
|
|
3 * 1000 // 3 seconds
|
|
);
|
|
}
|
|
});
|
|
// actually send the request to the server
|
|
http.send();
|
|
}
|
|
|
|
function checkAjaxPushConnectionHealth() {
|
|
if (typeof http == 'undefined' || http == null) {
|
|
return;
|
|
}
|
|
const time = new Date();
|
|
const timeDiff = time.getTime() - lastPushReceivedTime;
|
|
if (timeDiff >= monitorPushTime) {
|
|
resetConn();
|
|
}
|
|
}
|
|
|
|
function resetConn() {
|
|
console.log('going to reset connection');
|
|
if (http) {
|
|
http.abort();
|
|
}
|
|
}
|
|
|
|
function makeConnectionEstablishHistory(isEstablished) {
|
|
const connectionRecord = new Object();
|
|
connectionRecord.state = isEstablished;
|
|
connectionRecord.dateAdded = new Date();
|
|
|
|
console.log(
|
|
'push connection state changed to ' +
|
|
connectionRecord.state +
|
|
' at ' +
|
|
connectionRecord.dateAdded
|
|
);
|
|
addRecordInHistory(connectionRecord);
|
|
}
|
|
|
|
function addRecordInHistory(record) {
|
|
if (pushHistory != null && record != null) {
|
|
if (pushHistory.length > sizeOfHistory) {
|
|
pushHistory.pop(0);
|
|
}
|
|
pushHistory.push(record);
|
|
}
|
|
}
|
|
|
|
function getPushConnectionHistory() {
|
|
let pushConnectionString = '';
|
|
if (pushHistory != null) {
|
|
for (index = 0; index < pushHistory.length; index++) {
|
|
const connectionRecord = pushHistory[index];
|
|
pushConnectionString =
|
|
pushConnectionString +
|
|
'push connection state changed to ' +
|
|
connectionRecord.state +
|
|
' at ' +
|
|
connectionRecord.dateAdded +
|
|
' \n ';
|
|
}
|
|
}
|
|
return pushConnectionString;
|
|
}
|
|
|
|
/**
|
|
* change state of the connection establish. ignore if same state event came.
|
|
*
|
|
* @param isEstablished
|
|
*/
|
|
function changeConnectionEstablishState(isEstablished) {
|
|
try {
|
|
if (isConnectionEstablished == isEstablished) {
|
|
} else {
|
|
isConnectionEstablished = isEstablished;
|
|
makeConnectionEstablishHistory(isEstablished);
|
|
}
|
|
} catch (err) {
|
|
console.log('unable to log connection establish history');
|
|
}
|
|
}
|