ringcentral-call-control
Version:
[](https://coveralls.io/github/ringcentral/ringcentral-call-control-js?branch=master) [ || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (g && (g = 0, op[0] && (_ = 0)), _) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.RingCentralCallControl = void 0;
var events_1 = require("events");
var formatParty_1 = require("./formatParty");
var helper_1 = require("./helper");
var Session_1 = require("./Session");
var userAgent_1 = require("./userAgent");
var RingCentralCallControl = /** @class */ (function (_super) {
__extends(RingCentralCallControl, _super);
function RingCentralCallControl(_a) {
var sdk = _a.sdk, accountLevel = _a.accountLevel, _b = _a.preloadSessions, preloadSessions = _b === void 0 ? true : _b, _c = _a.preloadDevices, preloadDevices = _c === void 0 ? true : _c, extensionInfo = _a.extensionInfo, userAgent = _a.userAgent;
var _this = _super.call(this) || this;
_this._eventSequenceMap = {};
_this._accountLevel = !!accountLevel;
_this._sdk = sdk;
_this._userAgent = userAgent;
_this._sessionsMap = new Map;
_this._devices = [];
_this._ready = false;
_this._initializePromise = null;
_this._preloadSessions = preloadSessions;
_this._preloadDevices = preloadDevices;
_this._currentExtension = extensionInfo;
_this.initialize();
return _this;
}
RingCentralCallControl.prototype.initialize = function () {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (this._ready) {
return [2 /*return*/];
}
if (!this._initializePromise) {
this._initializePromise = this._initialize();
}
return [4 /*yield*/, this._initializePromise];
case 1:
_a.sent();
this._initializePromise = null;
return [2 /*return*/];
}
});
});
};
RingCentralCallControl.prototype._initialize = function () {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!!this._currentExtension) return [3 /*break*/, 2];
return [4 /*yield*/, this.loadCurrentExtension()];
case 1:
_a.sent();
_a.label = 2;
case 2:
if (!this._preloadSessions) return [3 /*break*/, 4];
return [4 /*yield*/, this.preloadSessions()];
case 3:
_a.sent();
_a.label = 4;
case 4:
if (!this._preloadDevices) return [3 /*break*/, 6];
return [4 /*yield*/, this.loadDevices()];
case 5:
_a.sent();
_a.label = 6;
case 6:
this._ready = true;
this.emit('initialized');
return [2 /*return*/];
}
});
});
};
RingCentralCallControl.prototype.onNotificationEvent = function (message) {
var _this = this;
if (message.event.indexOf('/telephony/sessions') === -1) {
return;
}
var _a = message.body, eventTime = _a.eventTime, telephonySessionId = _a.telephonySessionId, newData = __rest(_a, ["eventTime", "telephonySessionId"]);
if (!telephonySessionId) {
return;
}
var validatedSequence = this.checkSequence(message.body);
if (!validatedSequence) {
return;
}
var existedSession = this._sessionsMap.get(telephonySessionId);
newData.id = telephonySessionId;
newData.extensionId = this.extensionId;
newData.accountId = this.accountId;
newData.parties = newData.parties.map(function (p) { return (0, formatParty_1.formatParty)(p); });
if (!existedSession) {
var disconnectedParties = newData.parties.filter(function (p) { return p.status.code === 'Disconnected'; });
if (disconnectedParties.length === newData.parties.length) {
return;
}
// use first event's eventTime as session creationTime
newData.creationTime = eventTime;
// if new session is the inbound leg of ringout call then abandon it
var checkResult = (0, helper_1.ringOutInboundLegCheck)(newData, this.sessions);
if (checkResult.isRingOutInboundLeg) {
return;
}
if (!checkResult.isRingOutInboundLeg && checkResult.legSessionId) {
// if find an inbound leg then remove it from sessions
this._sessionsMap.delete(checkResult.legSessionId);
}
var newSession_1 = new Session_1.Session(newData, this._sdk, this._accountLevel);
newSession_1.on('status', function () {
_this.onSessionStatusUpdated(newSession_1);
});
this._sessionsMap.set(telephonySessionId, newSession_1);
if (newSession_1.party) {
this.emit('new', newSession_1);
}
return;
}
var party = existedSession.party;
existedSession.onUpdated(newData);
if (!party && existedSession.party) {
this.emit('new', existedSession);
}
};
RingCentralCallControl.prototype.checkSequence = function (_a) {
var sequence = _a.sequence, telephonySessionId = _a.telephonySessionId, parties = _a.parties;
var result = true;
var partyId = parties[0] && parties[0].id;
var eventSequenceData = this._eventSequenceMap[partyId];
if (eventSequenceData && eventSequenceData.sequence > sequence) {
result = false;
}
else {
this._eventSequenceMap[partyId] = {
sequence: sequence,
telephonySessionId: telephonySessionId,
updatedAt: Date.now(),
};
}
this.cleanExpiredSequenceData();
return result;
};
RingCentralCallControl.prototype.cleanExpiredSequenceData = function () {
var _this = this;
Object.keys(this._eventSequenceMap).forEach(function (partyId) {
var eventSequenceData = _this._eventSequenceMap[partyId];
var existedSession = _this._sessionsMap.get(eventSequenceData.telephonySessionId);
if (!existedSession && eventSequenceData.updatedAt + 60000 < Date.now()) {
delete _this._eventSequenceMap[partyId];
}
});
};
Object.defineProperty(RingCentralCallControl.prototype, "sessions", {
get: function () {
return Array.from(this._sessionsMap.values());
},
enumerable: false,
configurable: true
});
Object.defineProperty(RingCentralCallControl.prototype, "sessionsMap", {
get: function () {
return this._sessionsMap;
},
enumerable: false,
configurable: true
});
RingCentralCallControl.prototype.loadCurrentExtension = function () {
return __awaiter(this, void 0, void 0, function () {
var response, _a, e_1;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
_b.trys.push([0, 3, , 4]);
return [4 /*yield*/, this._sdk.platform().get('/restapi/v1.0/account/~/extension/~', undefined, this.requestOptions)];
case 1:
response = _b.sent();
_a = this;
return [4 /*yield*/, response.json()];
case 2:
_a._currentExtension = _b.sent();
return [3 /*break*/, 4];
case 3:
e_1 = _b.sent();
console.error('Fetch extension info error', e_1);
return [3 /*break*/, 4];
case 4: return [2 /*return*/];
}
});
});
};
RingCentralCallControl.prototype.preloadSessions = function () {
return __awaiter(this, void 0, void 0, function () {
var activeCalls;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.loadActiveCalls()];
case 1:
activeCalls = _a.sent();
return [4 /*yield*/, this.loadSessions(activeCalls)];
case 2:
_a.sent();
return [2 /*return*/];
}
});
});
};
RingCentralCallControl.prototype.loadActiveCalls = function () {
return __awaiter(this, void 0, void 0, function () {
var presenceUrl, response, data, presences, activeCalls_1, e_2;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
presenceUrl = '/restapi/v1.0/account/~/extension/~/presence?detailedTelephonyState=true&sipData=true';
if (this._accountLevel) {
presenceUrl = '/restapi/v1.0/account/~/presence?detailedTelephonyState=true&sipData=true';
}
_a.label = 1;
case 1:
_a.trys.push([1, 4, , 5]);
return [4 /*yield*/, this._sdk.platform().get(presenceUrl, undefined, this.requestOptions)];
case 2:
response = _a.sent();
return [4 /*yield*/, response.json()];
case 3:
data = _a.sent();
if (this._accountLevel) {
presences = data.records;
activeCalls_1 = [];
presences.forEach(function (presence) {
if (presence.activeCalls) {
activeCalls_1 = activeCalls_1.concat(presence.activeCalls);
}
});
return [2 /*return*/, activeCalls_1];
}
return [2 /*return*/, data.activeCalls || []];
case 4:
e_2 = _a.sent();
console.error('Fetch presence error', e_2);
return [2 /*return*/, []];
case 5: return [2 /*return*/];
}
});
});
};
RingCentralCallControl.prototype.loadSessions = function (activeCalls) {
return __awaiter(this, void 0, void 0, function () {
var e_3;
var _this = this;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (activeCalls.length === 0) {
return [2 /*return*/];
}
_a.label = 1;
case 1:
_a.trys.push([1, 3, , 4]);
return [4 /*yield*/, Promise.all(activeCalls.map(function (activeCall) { return __awaiter(_this, void 0, void 0, function () {
var response, data, session;
var _this = this;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this._sdk.platform().get("/restapi/v1.0/account/~/telephony/sessions/".concat(activeCall.telephonySessionId), undefined, this.requestOptions)];
case 1:
response = _a.sent();
return [4 /*yield*/, response.json()];
case 2:
data = _a.sent();
data.extensionId = this.extensionId;
data.accountId = this.accountId;
data.parties = data.parties.map(function (p) { return (0, formatParty_1.formatParty)(p); });
// since call session status API not provide the `sessionId`, so pick from presence here.
data.sessionId = activeCall.sessionId;
session = new Session_1.Session(data, this._sdk, this._accountLevel);
this._sessionsMap.set(activeCall.telephonySessionId, session);
session.on('status', function () {
_this.onSessionStatusUpdated(session);
});
return [2 /*return*/];
}
});
}); }))];
case 2:
_a.sent();
return [3 /*break*/, 4];
case 3:
e_3 = _a.sent();
console.error('load sessions error', e_3);
return [3 /*break*/, 4];
case 4: return [2 /*return*/];
}
});
});
};
RingCentralCallControl.prototype.restoreSessions = function (sessionDatas) {
var _this = this;
var oldSessionMap = this._sessionsMap;
this._sessionsMap = new Map();
sessionDatas.forEach(function (sessionData) {
if (oldSessionMap.get(sessionData.id)) {
var oldSession = oldSessionMap.get(sessionData.id);
oldSession.restore(sessionData);
_this._sessionsMap.set(sessionData.id, oldSession);
return;
}
_this._sessionsMap.set(sessionData.id, new Session_1.Session(sessionData, _this._sdk, _this._accountLevel));
});
};
RingCentralCallControl.prototype.loadDevices = function () {
return __awaiter(this, void 0, void 0, function () {
var response, data, e_4;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
_a.trys.push([0, 3, , 4]);
return [4 /*yield*/, this._sdk.platform().get('/restapi/v1.0/account/~/extension/~/device', undefined, this.requestOptions)];
case 1:
response = _a.sent();
return [4 /*yield*/, response.json()];
case 2:
data = _a.sent();
this._devices = data.records || [];
return [3 /*break*/, 4];
case 3:
e_4 = _a.sent();
console.error('Fetch presence error', e_4);
return [3 /*break*/, 4];
case 4: return [2 /*return*/];
}
});
});
};
RingCentralCallControl.prototype.onSessionStatusUpdated = function (session) {
var party = session.party;
if (party &&
party.status.code === Session_1.PartyStatusCode.disconnected &&
party.status.reason !== 'Pickup' && // don't end when call switched
party.status.reason !== 'CallSwitch' // don't end when call switched
) {
this._sessionsMap.delete(session.id);
}
};
RingCentralCallControl.prototype.refreshDevices = function () {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.loadDevices()];
case 1:
_a.sent();
return [2 /*return*/];
}
});
});
};
RingCentralCallControl.prototype.createCall = function (deviceId, to) {
return __awaiter(this, void 0, void 0, function () {
var response, sessionData, session;
var _this = this;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this._sdk.platform().post('/restapi/v1.0/account/~/telephony/call-out', {
from: { deviceId: deviceId },
to: to,
}, undefined, this.requestOptions)];
case 1:
response = _a.sent();
return [4 /*yield*/, response.json()];
case 2:
sessionData = (_a.sent()).session;
sessionData.extensionId = this.extensionId;
sessionData.accountId = this.accountId;
sessionData.parties = sessionData.parties.map(function (p) { return (0, formatParty_1.formatParty)(p); });
session = new Session_1.Session(sessionData, this._sdk, this._accountLevel);
this._sessionsMap.set(sessionData.id, session);
session.on('status', function () {
_this.onSessionStatusUpdated(session);
});
return [2 /*return*/, session];
}
});
});
};
// Fucntion to create conference session
// The session's parties are empty
// Join as HOST with voice by using webphone sdk to call session.voiceCallToken
// Then bring in other telephony session into this conference
RingCentralCallControl.prototype.createConference = function () {
return __awaiter(this, void 0, void 0, function () {
var response, sessionData, session;
var _this = this;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this._sdk.platform().post('/restapi/v1.0/account/~/telephony/conference', {}, undefined, this.requestOptions)];
case 1:
response = _a.sent();
return [4 /*yield*/, response.json()];
case 2:
sessionData = (_a.sent()).session;
sessionData.extensionId = this.extensionId;
sessionData.accountId = this.accountId;
sessionData.parties = (sessionData.parties || []).map(function (p) { return (0, formatParty_1.formatParty)(p); });
session = new Session_1.Session(sessionData, this._sdk, this._accountLevel);
this._sessionsMap.set(sessionData.id, session);
session.on('status', function () {
_this.onSessionStatusUpdated(session);
});
return [2 /*return*/, session];
}
});
});
};
Object.defineProperty(RingCentralCallControl.prototype, "accountId", {
get: function () {
return this._currentExtension && String(this._currentExtension.account.id);
},
enumerable: false,
configurable: true
});
Object.defineProperty(RingCentralCallControl.prototype, "extensionId", {
get: function () {
return this._currentExtension && String(this._currentExtension.id);
},
enumerable: false,
configurable: true
});
Object.defineProperty(RingCentralCallControl.prototype, "devices", {
get: function () {
return this._devices;
},
enumerable: false,
configurable: true
});
Object.defineProperty(RingCentralCallControl.prototype, "ready", {
get: function () {
return this._ready;
},
enumerable: false,
configurable: true
});
Object.defineProperty(RingCentralCallControl.prototype, "requestOptions", {
get: function () {
return {
userAgent: this._userAgent ? "".concat(this._userAgent, " ").concat(userAgent_1.USER_AGENT) : userAgent_1.USER_AGENT,
};
},
enumerable: false,
configurable: true
});
Object.defineProperty(RingCentralCallControl.prototype, "eventSequenceMap", {
get: function () {
return this._eventSequenceMap;
},
enumerable: false,
configurable: true
});
return RingCentralCallControl;
}(events_1.EventEmitter));
exports.RingCentralCallControl = RingCentralCallControl;
//# sourceMappingURL=index.js.map