Skip to content

Commit

Permalink
feat(calling): move apis, listeners from calling client to line
Browse files Browse the repository at this point in the history
  • Loading branch information
ShreyasSharma28 committed Sep 13, 2023
1 parent 0b42a95 commit f3e448f
Show file tree
Hide file tree
Showing 13 changed files with 409 additions and 197 deletions.
8 changes: 4 additions & 4 deletions docs/samples/calling/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -295,13 +295,13 @@ function toggleDisplay(elementId, status) {
}
}

const callNotifyEvent = new CustomEvent('callingClient:incoming_call', {
const callNotifyEvent = new CustomEvent('line:incoming_call', {
detail: {
callObject: call,
},
});

callListener.addEventListener('callingClient:incoming_call', (myEvent) => {
callListener.addEventListener('line:incoming_call', (myEvent) => {
console.log('Received incoming call');
answerElm.disabled = false;
const callerDisplay = myEvent.detail.callObject.getCallerInfo();
Expand Down Expand Up @@ -331,7 +331,7 @@ function createDevice() {
});

// Start listening for incoming calls
callingClient.on('callingClient:incoming_call', (callObj) => {
line.on('line:incoming_call', (callObj) => {
call = callObj;
call.on('call:caller_id', (CallerIdEmitter) => {
callDetailsElm.innerText = `Name: ${CallerIdEmitter.callerId.name}, Number: ${CallerIdEmitter.callerId.num}, Avatar: ${CallerIdEmitter.callerId.avatarSrc}, UserId: ${CallerIdEmitter.callerId.id}`;
Expand Down Expand Up @@ -452,7 +452,7 @@ function createCall(e) {
console.log(destination.value);

console.log(destination.value);
call = callingClient.makeCall({
call = line.makeCall({
type: 'uri',
address: destination.value,
});
Expand Down
126 changes: 45 additions & 81 deletions packages/calling/src/CallingClient/CallingClient.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
import {Mutex} from 'async-mutex';
import {LOGGER} from '../Logger/types';
import {getTestUtilsWebex, getMockRequestTemplate, getMockDeviceInfo} from '../common/testUtil';
import {
getTestUtilsWebex,
getMockRequestTemplate,
getMockDeviceInfo,
getMobiusDiscoveryResponse,
} from '../common/testUtil';
import {
CallDirection,
CallType,
IDeviceInfo,
MobiusStatus,
ServiceIndicator,
WebexRequestPayload,
Expand All @@ -23,7 +30,7 @@ import {
SPARK_USER_AGENT,
} from './constants';
import {MOCK_MULTIPLE_SESSIONS_EVENT, MOCK_SESSION_EVENT} from './callRecordFixtures';
import {ILine} from './line/types';
import {ILine, LineStatus} from './line/types';
import {
ipPayload,
regionBody,
Expand All @@ -34,6 +41,9 @@ import {
uri,
myIP,
} from './callingClientFixtures';
import Line from './line';
import {filterMobiusUris} from '../common/Utils';
import {URL} from './registration/registerFixtures';

describe('CallingClient Tests', () => {
// Common initializers
Expand Down Expand Up @@ -571,10 +581,32 @@ describe('CallingClient Tests', () => {

// Calling related test cases
describe('Calling tests', () => {
let callingClient: ICallingClient;
const mutex = new Mutex();
const userId = webex.internal.device.userId;
const clientDeviceUri = webex.internal.device.url;
const mobiusUris = filterMobiusUris(getMobiusDiscoveryResponse(), URL);
const primaryMobiusUris = jest.fn(() => mobiusUris.primary);
const backupMobiusUris = jest.fn(() => mobiusUris.backup);

let callingClient;
let line: Line;

beforeAll(async () => {
callingClient = await createClient(webex, {logger: {level: LOGGER.INFO}});
callingClient = await createClient(webex);
line = new Line(
userId,
clientDeviceUri,
LineStatus.ACTIVE,
mutex,
primaryMobiusUris(),
backupMobiusUris(),
LOGGER.INFO
);
const calls = Object.values(callManager.getActiveCalls());

calls.forEach((call) => {
call.end();
});
});

afterAll(() => {
Expand All @@ -588,85 +620,17 @@ describe('CallingClient Tests', () => {
);
});

it('Return a successful call object while making call', () => {
const call = callingClient.makeCall({address: '5003', type: CallType.URI});

expect(call).toBeTruthy();
expect(callingClient.getCall(call ? call.getCorrelationId() : '')).toBe(call);
expect(call ? call['direction'] : undefined).toStrictEqual(CallDirection.OUTBOUND);
call?.end();
});

it('Return a successful call object while making call to FAC codes', () => {
const call = callingClient.makeCall({address: '*25', type: CallType.URI});

expect(call).toBeTruthy();
expect(call ? call['direction'] : undefined).toStrictEqual(CallDirection.OUTBOUND);
call?.end();
});

it('Remove spaces from dialled number while making call', () => {
const call = callingClient.makeCall({address: '+91 123 456 7890', type: CallType.URI});

expect(call).toBeTruthy();
expect(call ? call['direction'] : undefined).toStrictEqual(CallDirection.OUTBOUND);
expect(call ? call['destination']['address'] : undefined).toStrictEqual('tel:+911234567890');
call?.end();
});

it('Remove hyphen from dialled number while making call', () => {
const call = callingClient.makeCall({address: '123-456-7890', type: CallType.URI});

expect(call).toBeTruthy();
expect(call ? call['direction'] : undefined).toStrictEqual(CallDirection.OUTBOUND);
expect(call ? call['destination']['address'] : undefined).toStrictEqual('tel:1234567890');
call?.end();
});

it('attempt to create call with incorrect number format 1', (done) => {
// There may be other listeners , which may create race
callingClient.removeAllListeners(EVENT_KEYS.ERROR);
const createCallSpy = jest.spyOn(callManager, 'createCall');

callingClient.on(EVENT_KEYS.ERROR, (error) => {
expect(error.message).toBe(
'An invalid phone number was detected. Check the number and try again.'
);
done();
});
try {
const call = callingClient.makeCall({address: 'select#$@^^', type: CallType.URI});

expect(call).toBeUndefined();
expect(createCallSpy).toBeCalledTimes(0);
} catch (error) {
done(error);
}
expect.assertions(3);
it('returns undefined when there is no connected call', () => {
line.register();
line.makeCall({address: '123456', type: CallType.URI});
expect(callingClient.getConnectedCall()).toEqual(undefined);
});

it('attempt to create call with incorrect number format 2', (done) => {
expect.assertions(3);
// There may be other listeners , which may create race
callingClient.removeAllListeners(EVENT_KEYS.ERROR);
const createCallSpy = jest.spyOn(callManager, 'createCall');

callingClient.on(EVENT_KEYS.ERROR, (error) => {
expect(error.message).toBe(
'An invalid phone number was detected. Check the number and try again.'
);
done();
});

try {
const call = callingClient.makeCall({address: '+1@8883332505', type: CallType.URI});

expect(call).toBeUndefined();
expect(createCallSpy).toBeCalledTimes(0);
} catch (error) {
done(error);
}
expect.assertions(3);
it('returns the connected call', () => {
line.register();
const call1 = line.makeCall({address: '5893', type: CallType.URI});
jest.spyOn(call1, 'isConnected').mockReturnValue(true);
expect(callingClient.getConnectedCall()).toEqual(call1);
});
});

Expand Down
106 changes: 34 additions & 72 deletions packages/calling/src/CallingClient/CallingClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ import log from '../Logger';
import {getCallManager} from './calling/callManager';
import {
CALLING_CLIENT_FILE,
VALID_PHONE,
CALLS_CLEARED_HANDLER_UTIL,
CALLING_USER_AGENT,
CISCO_DEVICE_URL,
Expand Down Expand Up @@ -110,7 +109,6 @@ export class CallingClient extends Eventing<CallingClientEventTypes> implements

log.setLogger(logLevel, CALLING_CLIENT_FILE);

this.incomingCallListener();
this.registerCallsClearedListener();
}

Expand All @@ -123,21 +121,6 @@ export class CallingClient extends Eventing<CallingClientEventTypes> implements
this.detectNetworkChange();
}

/**
* An Incoming Call listener.
*/
private incomingCallListener() {
const logContext = {
file: CALLING_CLIENT_FILE,
method: this.incomingCallListener.name,
};

log.log('Listening for incoming calls... ', logContext);
this.callManager.on(EVENT_KEYS.INCOMING_CALL, (callObj: ICall) => {
this.emit(EVENT_KEYS.INCOMING_CALL, callObj);
});
}

/**
* Register callbacks for network changes.
*/
Expand Down Expand Up @@ -375,61 +358,6 @@ export class CallingClient extends Eventing<CallingClientEventTypes> implements
return log.getLogLevel();
}

/**
* @param callId -.
* @param correlationId -.
*/
public getCall = (correlationId: CorrelationId): ICall => {
return this.callManager.getCall(correlationId);
};

/**
* @param dest -.
*/
public makeCall = (dest: CallDetails): ICall | undefined => {
let call;

// this is a temporary logic to get registration obj
// it will change once we have proper lineId and multiple lines as well
const {registration} = Object.values(this.lineDict)[0];

if (dest) {
const match = dest.address.match(VALID_PHONE);

if (match && match[0].length === dest.address.length) {
const sanitizedNumber = dest.address
.replace(/[^[*+]\d#]/gi, '')
.replace(/\s+/gi, '')
.replace(/-/gi, '');
const formattedDest = {
type: dest.type,
address: `tel:${sanitizedNumber}`,
};

call = this.callManager.createCall(
formattedDest,
CallDirection.OUTBOUND,
registration.getDeviceInfo().device?.deviceId as string
);
log.log(`New call created, callId: ${call.getCallId()}`, {});
} else {
log.warn('Invalid phone number detected', {});
const err = new CallingClientError(
'An invalid phone number was detected. Check the number and try again.',
{},
ERROR_TYPE.CALL_ERROR,
MobiusStatus.ACTIVE
);

this.emit(EVENT_KEYS.ERROR, err);
}

return call;
}

return undefined;
};

/**
*
*/
Expand Down Expand Up @@ -491,6 +419,40 @@ export class CallingClient extends Eventing<CallingClientEventTypes> implements
public getLines(): Record<string, ILine> {
return this.lineDict;
}

/**
*
*/
public getActiveCalls(): Record<string, ICall[]> {
const activeCalls = {};
const allCalls = this.callManager.getActiveCalls();
Object.keys(this.lineDict).forEach((deviceId) => {
const {lineId} = this.lineDict[deviceId];
activeCalls[lineId] = [];
Object.keys(allCalls).forEach((correlationId) => {
if (allCalls[correlationId].getLineId() === lineId) {
activeCalls[lineId].push(allCalls[correlationId]);
}
});
});

return activeCalls;
}

/**
*
*/
public getConnectedCall(): ICall | undefined {
let connectCall;
const allCalls = this.callManager.getActiveCalls();
Object.keys(allCalls).forEach((correlationId) => {
if (allCalls[correlationId].isConnected() && !allCalls[correlationId].isHeld()) {
connectCall = allCalls[correlationId];
}
});

return connectCall;
}
}

/**
Expand Down
Loading

0 comments on commit f3e448f

Please sign in to comment.