Files
call-sdk/packages/adapter-ameyo/lib/assets/js/ajaxClient.ts
2025-01-06 15:21:23 +05:30

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');
}
}