Skip to content

Commit

Permalink
fix: disordered event sequence issue (#34)
Browse files Browse the repository at this point in the history
* fix: disordered event sequence issue

* chore: remove unused code

* chore: lint issue

* chore: add tests

* feat: clear session when drop session with 404

* fix: use partyId as event sequence key

* chore: demo loading issue
  • Loading branch information
embbnux authored Dec 7, 2021
1 parent 88f13e8 commit f5226cf
Show file tree
Hide file tree
Showing 8 changed files with 248 additions and 97 deletions.
2 changes: 1 addition & 1 deletion demo/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ $(function() {
refreshCallList();
});
});
$('.modal').modal('hide');
$loadingModal.modal('hide');
}
if (rcCallControl.ready) {
onInitializedEvent();
Expand Down
1 change: 0 additions & 1 deletion demo/redirect.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
<body>
<p>Loading</p>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/es6-promise/3.2.2/es6-promise.js"></script>
<script type="text/javascript" src="https://cdn.pubnub.com/sdk/javascript/pubnub.4.20.1.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/fetch/0.11.1/fetch.js"></script>
<script type="text/javascript" src="https://unpkg.com/@ringcentral/sdk@latest/dist/ringcentral.js"></script>
<script>
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ringcentral-call-control",
"version": "0.2.5",
"version": "0.2.6",
"main": "lib/index.js",
"license": "MIT",
"repository": {
Expand Down
64 changes: 23 additions & 41 deletions src/Session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ export interface SessionData {
sessionId: string;
creationTime: string;
voiceCallToken?: string;
sequence?: number;
origin: Origin;
}

Expand Down Expand Up @@ -202,36 +201,16 @@ function diffParties(oldParties: Party[], updatedParties: Party[]) {

export class Session extends EventEmitter {
private _data: any;
private _eventPartySequences: any;
private _sdk: RingCentralSDK;
private _accountLevel: boolean;
private _userAgent: string;

constructor(rawData: SessionData, sdk: RingCentralSDK, accountLevel: boolean, userAgent?: string) {
super();
const { sequence, ...data } = rawData;
this._data = data;
this._eventPartySequences = {};
this._data = { ...rawData };
this._sdk = sdk;
this._accountLevel = !!accountLevel;
this._userAgent = userAgent;

this._updatePartiesSequence(this._data.parties, sequence);

this.on('status', ({ party }) => {
this._onPartyUpdated(party);
});
}

_updatePartiesSequence(parties: Party[] = [], sequence?: Number) {
if (!sequence) {
return;
}
parties.forEach((party) => {
if (!this._eventPartySequences[party.id] || this._eventPartySequences[party.id] < sequence) {
this._eventPartySequences[party.id] = sequence;
}
});
}

public onUpdated(data: SessionData) {
Expand All @@ -242,10 +221,6 @@ export class Session extends EventEmitter {
this.emit('status', { party: diff.party });
return;
}
const lastSequence = this._eventPartySequences[diff.party.id]
if (lastSequence && data.sequence < lastSequence) {
return;
}
if (diff.type === 'update') {
const oldPartyIndex = this.parties.findIndex(p => p.id === diff.party.id);
const parties = this.parties.slice(0);
Expand All @@ -260,16 +235,6 @@ export class Session extends EventEmitter {
return;
}
});
this._updatePartiesSequence(data.parties, data.sequence);
}

_onPartyUpdated(party) {
if (
party.status.code === PartyStatusCode.disconnected &&
party.status.reason === 'Pickup'
) {
this._data.parties = this.parties.filter(p => p.id !== party.id);
}
}

public restore(data: SessionData) {
Expand Down Expand Up @@ -369,11 +334,28 @@ export class Session extends EventEmitter {
}

async drop() {
await this._sdk.platform().delete(
`/restapi/v1.0/account/~/telephony/sessions/${this._data.id}`,
null,
this.requestOptions
);
try {
await this._sdk.platform().delete(
`/restapi/v1.0/account/~/telephony/sessions/${this._data.id}`,
null,
this.requestOptions
);
} catch (e) {
if (e && e.response && e.response.status === 404) {
// Force drop session at client side
const disconnectedParty = {
...this.party,
status: {
...this.party.status,
code: PartyStatusCode.disconnected,
},
};
this.saveNewPartyData(disconnectedParty);
this.emit('status', { party: this.party });
return;
}
throw e;
}
}

private saveNewPartyData(rawParty) {
Expand Down
48 changes: 47 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,16 @@ export interface Device {
lastLocationReportTime: string;
}

export interface EventSequenceData {
sequence: number;
updatedAt: number;
telephonySessionId: string;
}

export interface EventSequenceMap {
[key: string]: EventSequenceData;
}

export interface Account {
id: string;
}
Expand Down Expand Up @@ -78,6 +88,7 @@ export class RingCentralCallControl extends EventEmitter {
private _preloadSessions: boolean;
private _preloadDevices: boolean;
private _userAgent: string;
private _eventSequenceMap: EventSequenceMap = {};

constructor({
sdk,
Expand Down Expand Up @@ -141,6 +152,10 @@ export class RingCentralCallControl extends EventEmitter {
if (!telephonySessionId) {
return;
}
const validatedSequence = this.checkSequence(message.body);
if (!validatedSequence) {
return;
}
const existedSession = this._sessionsMap.get(telephonySessionId);
newData.id = telephonySessionId;
newData.extensionId = this.extensionId;
Expand Down Expand Up @@ -179,6 +194,33 @@ export class RingCentralCallControl extends EventEmitter {
}
}

private checkSequence({ sequence, telephonySessionId, parties }) {
let result = true;
const partyId = parties[0] && parties[0].id;
const eventSequenceData = this._eventSequenceMap[partyId];
if (eventSequenceData && eventSequenceData.sequence > sequence) {
result = false;
} else {
this._eventSequenceMap[partyId] = {
sequence,
telephonySessionId,
updatedAt: Date.now(),
};
}
this.cleanExpiredSequenceData();
return result;
}

private cleanExpiredSequenceData() {
Object.keys(this._eventSequenceMap).forEach((partyId) => {
const eventSequenceData = this._eventSequenceMap[partyId];
const existedSession = this._sessionsMap.get(eventSequenceData.telephonySessionId);
if (!existedSession && eventSequenceData.updatedAt + 60000 < Date.now()) {
delete this._eventSequenceMap[partyId];
}
});
}

get sessions(): Session[] {
return Array.from(this._sessionsMap.values());
}
Expand All @@ -193,7 +235,7 @@ export class RingCentralCallControl extends EventEmitter {
await this._sdk.platform().get('/restapi/v1.0/account/~/extension/~', null, this.requestOptions);
this._currentExtension = await response.json();
} catch (e) {
console.error('Fetch presence error', e);
console.error('Fetch extension info error', e);
}
}

Expand Down Expand Up @@ -376,4 +418,8 @@ export class RingCentralCallControl extends EventEmitter {
userAgent: this._userAgent ? `${this._userAgent} ${USER_AGENT}` : USER_AGENT,
};
}

get eventSequenceMap() {
return this._eventSequenceMap;
}
}
Loading

0 comments on commit f5226cf

Please sign in to comment.