Merge pull request #24 from navi-commons/NTP-15943-callId-fix

NTP-15943 | Transfer Call undefined callId fix
This commit is contained in:
Varnit Goyal
2025-01-02 17:22:42 +05:30
committed by GitHub
3 changed files with 127 additions and 86 deletions

0
.npmrc Normal file
View File

View File

@@ -64,94 +64,134 @@ export function parseQuerystring(url: string): Record<string, any> {
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");
let res = null;
for (const part of parts) {
try {
const jsonData = JSON.parse(part.trim());
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})
);
sendCallStatusMessage(res);
.split("--DON'T_PANIC!_more_will_follow\r\n")
.map((part) => {
try {
return JSON.parse(part.trim());
} catch {
return null; // Ignore parsing errors
}
if (jsonData?.pushType === pushResponseTypes.UserCallModelUpdatedPush) {
res = jsonData;
sendCallStatusMessage(res);
}
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 erroronous condition
if (payload?.isOnBreak) {
window.postMessage({
type: MessagingType.ON_AMEYO_AGENT_ON_BREAK,
data: {
breakReason: 'ameyo is errorounous',
}
});
}
}
if (jsonData?.pushType == pushResponseTypes.UserLoggedOffPush) {
const payload = jsonData?.data;
})
.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_FORCED_LOGOUT,
data: {}
type: MessagingType.ON_AMEYO_CALL_TRANSFER,
data: payload
})
}
} catch (e) {
/* empty */
}
}
if (jsonData?.pushType === pushResponseTypes.UserCCRuntimeUpdatedPush) {
const payload = jsonData?.data;
//handle ameyo erroronous condition
if (payload?.isOnBreak) {
window.postMessage({
type: MessagingType.ON_AMEYO_AGENT_ON_BREAK,
data: {
breakReason: 'ameyo is errorounous',
}
});
}
}
if (jsonData?.pushType == pushResponseTypes.UserLoggedOffPush) {
const payload = jsonData?.data;
window.postMessage({
type: MessagingType.ON_AMEYO_FORCED_LOGOUT,
data: {}
})
}
} )
}
const sendCallStatusMessage = res => {
let message = null;
const data = JSON.parse(
localStorage.getItem('revEngCustomerInfo') || '{}'
);
if (res?.data?.status === 'ringing') {
message = {
type: MessagingType.ON_AMEYO_CALL_INCOMING,
data
};
} else if (res?.data?.status === 'connected') {
message = {
type: MessagingType.ON_AMEYO_CALL_ACCEPTED,
data
};
} else if (res?.data?.status === 'hungup') {
message = {
type: MessagingType.ON_AMEYO_CALL_DISCONNECTED,
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) {
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);
}
if (message) window.postMessage(message);
};
function createRequestObject() {

View File

@@ -108,7 +108,7 @@ class AmeyoAdapter implements IAdapter {
this._initializeAmeyo();
this.metricProcessor = metricProcessor;
this.clickStreamProcessor = clickStreamProcessor;
this.metricProcessor.pushCounterMetric({metricName: 'initSdk', flow: "sdk_init_count"})
this.metricProcessor?.pushCounterMetric({metricName: 'initSdk', flow: "sdk_init_count"})
}
@@ -119,7 +119,7 @@ class AmeyoAdapter implements IAdapter {
loadCredentials({accountName, userName, domain, password});
loadCallOptions();
sipRegister({domain: domainOnly, port});
this.metricProcessor.pushCounterMetric({metricName: 'sipStackInitialised',flow: 'ameyo-sip-stack_init_count'})
this.metricProcessor?.pushCounterMetric({metricName: 'sipStackInitialised',flow: 'ameyo-sip-stack_init_count'})
}
@@ -136,12 +136,12 @@ class AmeyoAdapter implements IAdapter {
_onListenForCorsBypassResponse = (payload: GenericObject) => {
if(payload?.data?.requestKey !== RequestKeys.AMEYO_HEARTBEAT && !payload?.data?.err) {
this.metricProcessor.pushCounterMetric({
this.metricProcessor?.pushCounterMetric({
metricName: `ameyo-api-call-count`,
flow: 'api-call-count',
subFlow: payload?.data?.requestKey
})
this.metricProcessor.pushHistogramMetric({
this.metricProcessor?.pushHistogramMetric({
metricName: `ameyo-api-latency-${payload?.data?.requestKey}`,
flow: 'api-latency',
subFlow: payload?.data?.requestKey,
@@ -150,9 +150,9 @@ class AmeyoAdapter implements IAdapter {
}
if(payload?.data?.err) {
this.clickStreamProcessor.sendClickStreamEvent({type: 'api-error', data: payload?.data?.err})
this.metricProcessor.pushCounterMetric({metricName: `ameyo-api-err-count`, flow: 'api-error-count', subFlow: payload?.data?.requestKey})
this.clickStreamProcessor.sendClickStreamEvent({type: 'api-error', err: payload?.data?.err})
this.clickStreamProcessor?.sendClickStreamEvent({type: 'api-error', data: payload?.data?.err})
this.metricProcessor?.pushCounterMetric({metricName: `ameyo-api-err-count`, flow: 'api-error-count', subFlow: payload?.data?.requestKey})
this.clickStreamProcessor?.sendClickStreamEvent({type: 'api-error', err: payload?.data?.err})
}
if (payload?.data?.requestKey === RequestKeys.AMEYO_LOGIN) {
@@ -305,6 +305,7 @@ class AmeyoAdapter implements IAdapter {
rejectCall() {
sipHangUp();
localStorage.removeItem('revEngCustomerInfo');
}
disposeCall() {