Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions enum/ErrorLogs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,5 @@ export enum ErrorLogs {
ESCALATION_FAILED_DUE_TO_ERROR_GETTING_SF_MESSAGES = 'Failure getting Salesforce Messages',
QUEUE_TIME_NOT_SET = 'Start time for escalation queue has not been set',
LIVEAGENT_EMPTY_RESPONSE = 'Empty response from liveagent',
SWITCH_SERVER_ERROR = 'SwitchServer received. The Chat API endpoint is changed. This happens due to a planned org migration or during a Site Switch to a different instance.',
}
46 changes: 44 additions & 2 deletions handlers/InitiateSalesforceSessionHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,15 @@ import { ErrorLogs } from '../enum/ErrorLogs';
import { InfoLogs } from '../enum/InfoLogs';
import { sendDebugLCMessage, sendLCMessage } from '../helperFunctions/LivechatMessageHelpers';
import { getError } from '../helperFunctions/Log';
import { getRoomAssoc, updatePersistentData } from '../helperFunctions/PersistenceHelpers';
import { getGlobalAssoc, getRoomAssoc, updatePersistentData } from '../helperFunctions/PersistenceHelpers';
import { updateRoomCustomFields } from '../helperFunctions/RoomCustomFieldsHelper';
import { getSessionTokens, pullMessages, sendChatRequest } from '../helperFunctions/SalesforceAPIHelpers';
import {
getSalesforceChatAPIEndpoint,
checkAvailability,
getSessionTokens,
pullMessages,
sendChatRequest,
} from '../helperFunctions/SalesforceAPIHelpers';
import { checkForEvent, checkForPostChatUrl, getForEvent, handleChatEstablished } from '../helperFunctions/SalesforceMessageHelpers';
import { CheckAgentStatusCallback } from '../helperFunctions/subscribeHelpers/InitiateSalesforceSessionHelpers/CheckAgentStatusCallback';
import { CheckChatStatus } from '../helperFunctions/subscribeHelpers/InitiateSalesforceSessionHelpers/CheckChatStatusHelper';
Expand Down Expand Up @@ -72,6 +78,42 @@ export class InitiateSalesforceSession {

const assoc = getRoomAssoc(roomId);
await sendDebugLCMessage(this.read, this.modify, this.data.room, InfoLogs.INITIATING_LIVEAGENT_SESSION, this.data.agent);

//Check Availability
await checkAvailability(
this.http,
salesforceChatApiEndpoint,
salesforceOrganisationId,
salesforceDeploymentId,
salesforceButtonId,
roomId,
)
.then(async (response) => {
const responseJSON = JSON.parse(response.content || '{}');
const messagesArray = responseJSON.messages;

const isSwitchServer = checkForEvent(messagesArray, 'SwitchServer');
if (isSwitchServer) {
const switchServerMessage = getForEvent(messagesArray, 'SwitchServer').message;
const { newUrl } = switchServerMessage;
await updatePersistentData(this.read, this.persistence, getGlobalAssoc(), {
isSwitchServer: true,
switchServerUrl: newUrl + '/rest',
});
console.error(ErrorLogs.SWITCH_SERVER_ERROR, JSON.stringify(switchServerMessage));
} else {
await updatePersistentData(this.read, this.persistence, getGlobalAssoc(), {
isSwitchServer: false,
switchServerUrl: null,
});
}
})
.catch(async (error) => {
console.error(ErrorLogs.CHECKING_AVAILABILITY_ERROR, error);
});

salesforceChatApiEndpoint = await getSalesforceChatAPIEndpoint(this.read);

await getSessionTokens(this.http, salesforceChatApiEndpoint, roomId)
.then(async (res) => {
console.log(InfoLogs.LIVEAGENT_SESSION_ID_GENERATED);
Expand Down
2 changes: 1 addition & 1 deletion handlers/LiveAgentSessionHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export class LiveAgentSession {
return;
}

const salesforceChatApiEndpoint = await getSalesforceChatAPIEndpoint(this.read);
const salesforceChatApiEndpoint: string = await getSalesforceChatAPIEndpoint(this.read);
const assoc = getRoomAssoc(this.message.room.id);
const { persistentAffinity, persistentKey } = await retrievePersistentTokens(this.read, assoc);

Expand Down
15 changes: 4 additions & 11 deletions handlers/SalesforceAgentAssignedHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import { IHttp, IModify, IPersistence, IRead } from '@rocket.chat/apps-engine/de
import { IApp } from '@rocket.chat/apps-engine/definition/IApp';
import { ILivechatEventContext } from '@rocket.chat/apps-engine/definition/livechat';
import { AppSettingId } from '../enum/AppSettingId';
import { ErrorLogs } from '../enum/ErrorLogs';
import { InfoLogs } from '../enum/InfoLogs';
import { sendDebugLCMessage, sendLCMessage } from '../helperFunctions/LivechatMessageHelpers';
import { sendLCMessage } from '../helperFunctions/LivechatMessageHelpers';
import { getRoomAssoc, retrievePersistentData, retrievePersistentTokens } from '../helperFunctions/PersistenceHelpers';
import { SubscribeToLiveAgent } from '../helperFunctions/subscribeHelpers/SalesforceAgentAssignedHelpers/SubscribeToLiveAgentHelper';
import { getSalesforceChatAPIEndpoint } from '../helperFunctions/SalesforceAPIHelpers';
import { getAppSettingValue } from '../lib/Settings';

export class SalesforceAgentAssigned {
Expand All @@ -31,15 +31,8 @@ export class SalesforceAgentAssigned {
const salesforceAgentName = (await retrievePersistentData(this.read, assoc)).salesforceAgentName;
const technicalDifficultyMessage: string = await getAppSettingValue(this.read, AppSettingId.TECHNICAL_DIFFICULTY_MESSAGE);

let salesforceChatApiEndpoint: string = await getAppSettingValue(this.read, AppSettingId.SALESFORCE_CHAT_API_ENDPOINT);
try {
salesforceChatApiEndpoint = salesforceChatApiEndpoint.replace(/\/?$/, '/');
} catch (error) {
await sendLCMessage(this.read, this.modify, this.data.room, technicalDifficultyMessage, this.data.agent);
await sendDebugLCMessage(this.read, this.modify, this.data.room, ErrorLogs.SALESFORCE_CHAT_API_NOT_FOUND, this.data.agent);
console.error(ErrorLogs.SALESFORCE_CHAT_API_NOT_FOUND, error);
return;
Comment on lines -38 to -41

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are not sending technical difficulty message anymore post this change. Is this expected behaviour?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we are not sending technicalDifficultyMessage. It's redundant. In the try-catch we are only doing string replacement. Also, we are not having access to all the parameters of sendMessage fn everywhere.

}
const salesforceChatApiEndpoint: string = await getSalesforceChatAPIEndpoint(this.read);

const LAChatEndedMessage: string = await getAppSettingValue(this.read, AppSettingId.LIVEAGENT_CHAT_ENDED_MESSAGE);
const connectedToAgentMessage = `${InfoLogs.CONNECTING_TO_SALESFORCE_LIVEAGENT} ${salesforceAgentName}.`;
await sendLCMessage(this.read, this.modify, this.data.room, connectedToAgentMessage, this.data.agent);
Expand Down
15 changes: 15 additions & 0 deletions helperFunctions/PersistenceHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { RocketChatAssociationModel, RocketChatAssociationRecord } from '@rocket

export const getRoomAssoc = (rid: string) => new RocketChatAssociationRecord(RocketChatAssociationModel.MISC, `SFLAIA-${rid}`);

export const getGlobalAssoc = () => new RocketChatAssociationRecord(RocketChatAssociationModel.MISC, `SF-GLOBAL-PERSISTENCE`);

export async function retrievePersistentTokens(read: IRead, assoc: RocketChatAssociationRecord) {
try {
const awayDatas = await read.getPersistenceReader().readByAssociation(assoc);
Expand Down Expand Up @@ -63,6 +65,19 @@ export async function retrievePersistentData(read: IRead, assoc: RocketChatAssoc
}
}

export async function getPersistentData(read: IRead, assoc: RocketChatAssociationRecord) {
try {
const asocData = await read.getPersistenceReader().readByAssociation(assoc);
if (asocData[0]) {
const contentStringified = JSON.stringify(asocData[0]);
const data = JSON.parse(contentStringified);
return data;
}
} catch (error) {
throw new Error(error);
}
}

export async function updatePersistentData(read: IRead, persistence: IPersistence, assoc: RocketChatAssociationRecord, data: object) {
try {
const persistentData = await retrievePersistentData(read, assoc);
Expand Down
39 changes: 38 additions & 1 deletion helperFunctions/SalesforceAPIHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { AppSettingId } from '../enum/AppSettingId';
import { ErrorLogs } from '../enum/ErrorLogs';
import { getError } from '../helperFunctions/Log';
import { getAppSettingValue } from '../lib/Settings';
import { getGlobalAssoc, getPersistentData } from './PersistenceHelpers';

export const validateResponse = (roomId: string, response) => {
console.log(
Expand All @@ -17,7 +18,16 @@ export const validateResponse = (roomId: string, response) => {
};

export async function getSalesforceChatAPIEndpoint(read: IRead): Promise<string> {
let salesforceChatApiEndpoint: string = await getAppSettingValue(read, AppSettingId.SALESFORCE_CHAT_API_ENDPOINT);
let salesforceChatApiEndpoint: string;

const { isSwitchServer, switchServerUrl } = await getPersistentData(read, getGlobalAssoc());

if (isSwitchServer) {
salesforceChatApiEndpoint = switchServerUrl;
} else {
salesforceChatApiEndpoint = await getAppSettingValue(read, AppSettingId.SALESFORCE_CHAT_API_ENDPOINT);
}

try {
salesforceChatApiEndpoint = salesforceChatApiEndpoint.replace(/\/?$/, '/');
} catch (error) {
Expand All @@ -27,6 +37,33 @@ export async function getSalesforceChatAPIEndpoint(read: IRead): Promise<string>
return salesforceChatApiEndpoint;
}

export async function checkAvailability(
http: IHttp,
liveAgentUrl: string,
orgId: string,
deploymentId: string,
buttonId: string,
roomId: string,
) {
try {
const availabilityEndpoint =
liveAgentUrl + `Visitor/Availability?org_id=${orgId}&deployment_id=${deploymentId}&Availability.ids=${buttonId}`;

const checkAvailabilityHttpRequest: IHttpRequest = {
headers: {
'X-LIVEAGENT-API-VERSION': '49',
},
};

const response = await http.get(availabilityEndpoint, checkAvailabilityHttpRequest);
validateResponse(roomId, response);
return response;
} catch (error) {
console.error(ErrorLogs.CHECKING_AVAILABILITY_ERROR, error);
throw new Error(error);
}
}

export async function getSessionTokens(http: IHttp, liveAgentUrl: string, roomId: string) {
const generateTokenEndpoint = liveAgentUrl + 'System/SessionId';
const generateSessionIdHttpRequest: IHttpRequest = {
Expand Down
2 changes: 1 addition & 1 deletion lib/LivechatRoomClosedHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export class LivechatRoomClosedClass {
public async closeChatFromSalesforce() {
const { customFields, id: rid } = this.room;
const { persistentAffinity, persistentKey } = await retrievePersistentTokens(this.read, getRoomAssoc(rid));
const salesforceChatApiEndpoint = await getSalesforceChatAPIEndpoint(this.read);
const salesforceChatApiEndpoint: string = await getSalesforceChatAPIEndpoint(this.read);

if (persistentAffinity !== null && persistentKey !== null) {
let reason = '';
Expand Down
12 changes: 2 additions & 10 deletions lib/OnUserTypingHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@ import { IHttp, IPersistence, IRead } from '@rocket.chat/apps-engine/definition/
import { IApp } from '@rocket.chat/apps-engine/definition/IApp';
import { ILivechatRoom } from '@rocket.chat/apps-engine/definition/livechat';
import { IRoomUserTypingContext } from '@rocket.chat/apps-engine/definition/rooms';
import { AppSettingId } from '../enum/AppSettingId';
import { ErrorLogs } from '../enum/ErrorLogs';
import { getRoomAssoc, retrievePersistentData } from '../helperFunctions/PersistenceHelpers';
import { chasitorSneakPeak, chasitorTyping } from '../helperFunctions/SalesforceAPIHelpers';
import { getAppSettingValue } from '../lib/Settings';
import { getSalesforceChatAPIEndpoint, chasitorSneakPeak, chasitorTyping } from '../helperFunctions/SalesforceAPIHelpers';

export class OnUserTypingHandler {
constructor(
Expand Down Expand Up @@ -35,13 +33,7 @@ export class OnUserTypingHandler {
return;
}

let salesforceChatApiEndpoint: string = await getAppSettingValue(this.read, AppSettingId.SALESFORCE_CHAT_API_ENDPOINT);
try {
salesforceChatApiEndpoint = salesforceChatApiEndpoint.replace(/\/?$/, '/');
} catch (error) {
console.error(ErrorLogs.SALESFORCE_CHAT_API_NOT_FOUND);
return;
}
const salesforceChatApiEndpoint: string = await getSalesforceChatAPIEndpoint(this.read);
const assoc = getRoomAssoc(this.data.roomId);
const { persistentAffinity, persistentKey, sneakPeekEnabled } = await retrievePersistentData(this.read, assoc);

Expand Down