sinch-rtc
Version:
RTC JavaScript/Web SDK
262 lines • 11.4 kB
JavaScript
"use strict";
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());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.InstanceController = void 0;
/* eslint-disable @typescript-eslint/no-var-requires */
const DeviceVersion_1 = require("./DeviceVersion");
const Capability_1 = require("../models/Capability");
const auth_1 = require("../ocra/auth");
const utils_1 = require("../utils/");
const ClientRegistration_1 = require("../ClientRegistration");
const jwt_1 = require("./jwt");
const Errors_1 = require("../utils/Errors");
const UserInstance_1 = require("./UserInstance");
const StorageFactory_1 = require("../storage/StorageFactory");
const { version } = require("../../package.json");
class InstanceController {
constructor(applicationKey, userId, clientEvent, api) {
this.applicationKey = applicationKey;
this.userId = userId;
this.clientEvent = clientEvent;
this.api = api;
this.DefaultCapabilities = [
Capability_1.Capability.P2p,
Capability_1.Capability.IceProxy,
Capability_1.Capability.Ocra,
];
this.deviceId = utils_1.StringHelper.UUID();
this.userInstance = null;
this.createNewInstanceAuthentication = () => __awaiter(this, void 0, void 0, function* () {
yield this.createInstance();
if (this.authentication)
return this.authentication;
else
throw Error("Unable to create instance");
});
this.prolongInstance = () => __awaiter(this, void 0, void 0, function* () {
return utils_1.PromiseHelper.setTimeout(new Promise((resolve, reject) => {
this.clientEvent.onEvent({
eventType: "registration",
context: new ClientRegistration_1.ClientRegistration((jwt) => __awaiter(this, void 0, void 0, function* () {
this.updateInstanceExpiresAt(this.userId, jwt)
.then(() => resolve())
.catch((reason) => {
reject(reason);
});
}), () => {
reject("onCredentialsRequired failed.");
}),
});
}), InstanceController.REGISTRATION_TIMEOUT_MS);
});
this.storage = StorageFactory_1.StorageFactory.createInstanceStorage(this.applicationKey, this.userId);
this.deviceVersion = new DeviceVersion_1.DeviceVersion(InstanceController.APPLICATION_VERSION);
this.capabilities = this.DefaultCapabilities;
this.updateInstanceTtlWindowDays =
InstanceController.UPDATE_INSTANCE_TTL_WINDOW_DAYS_DEFAULT;
this.callUpdateInstanceApi = this.callUpdateInstanceApi.bind(this);
this.setUpdatedInstance = this.setUpdatedInstance.bind(this);
this.storeInstance = this.storeInstance.bind(this);
this.updateInstance = (0, utils_1.pipeAsync)(this.callUpdateInstanceApi, this.setUpdatedInstance, this.storeInstance);
}
removeInstance() {
this.storage.remove();
}
setInstance(userInstance) {
if (this.instance)
this.removeInstance();
this.storage.set(userInstance);
this.userInstance = userInstance;
this.authentication = new auth_1.InstanceRequestSignatureV1Authentication({
applicationKey: this.applicationKey,
username: this.userId,
instance: this.userInstance.instance,
}, userInstance, this.prolongInstance);
this.api.setInstanceAuthentication(this.authentication, this.createNewInstanceAuthentication);
}
get instance() {
return this.userInstance;
}
toggleCapability(capability, enabled) {
const lengthBeforeToggling = this.capabilities.length;
if (enabled) {
this.capabilities.push(capability);
}
else {
this.capabilities = this.capabilities.filter((c) => c !== capability);
}
if (lengthBeforeToggling !== this.capabilities.length) {
this.scheduleInstanceUpdate();
}
}
isCapabilityEnabled(capability) {
return this.capabilities.includes(capability);
}
setUpdateInstanceTtlWindow(updateTtlWindowDays) {
if (updateTtlWindowDays) {
this.updateInstanceTtlWindowDays = updateTtlWindowDays;
}
}
start() {
return __awaiter(this, void 0, void 0, function* () {
const userInstance = this.storage.get();
if (userInstance) {
if (userInstance.hasExpired()) {
this.removeInstance();
}
else {
this.setInstance(userInstance);
this.updateInstanceIfNecessary();
return userInstance.instance;
}
}
// no persisted instance found ask for jwt token
if (!this.clientEvent.hasListeners()) {
throw new Errors_1.InvalidOperationError("No listener registered for onCredentialsRequired");
}
else {
return this.createInstance();
}
});
}
prolongInstanceIfNeeded() {
return __awaiter(this, void 0, void 0, function* () {
if (this.instance &&
this.instance.shouldProlong(this.updateInstanceTtlWindowDays)) {
yield this.prolongInstance();
}
});
}
terminate() {
if (this.updateInstanceTimeoutId) {
clearTimeout(this.updateInstanceTimeoutId);
}
}
createInstance() {
return __awaiter(this, void 0, void 0, function* () {
return utils_1.PromiseHelper.setTimeout(new Promise((resolve, reject) => {
this.clientEvent.onEvent({
eventType: "registration",
context: new ClientRegistration_1.ClientRegistration((jwt) => __awaiter(this, void 0, void 0, function* () {
this.register(jwt)
.then((instance) => resolve(instance))
.catch((reason) => {
reject(reason);
});
}), () => {
reject("onCredentialsRequired failed.");
}),
});
}), InstanceController.REGISTRATION_TIMEOUT_MS);
});
}
updateInstanceIfNecessary() {
const currentInstance = this.instance;
if (!currentInstance) {
console.error("Error during updating instance, current instance not set");
return;
}
if (!this.deviceVersion.equals(currentInstance.instance.version)) {
this.scheduleInstanceUpdate();
}
}
/**
* When the SDK is about to issue an UpdateInstance request, the request is delayed for a short time.
* When the timer has expired, only the latest UpdateInstance request is actually sent over to the backend.
* This is to avoid sending multiple UpdateInstance requests in a very
* short time when multiple properties of an instance (e.g. capabilities / device information) are changed.
*/
scheduleInstanceUpdate() {
if (this.updateInstanceTimeoutId) {
return;
}
this.updateInstanceTimeoutId = setTimeout(() => {
this.updateInstanceTimeoutId = undefined;
this.updateInstance();
}, InstanceController.UPDATE_INSTANCE_DELAY_MS);
}
register(token) {
return __awaiter(this, void 0, void 0, function* () {
const jwt = jwt_1.JWT.parse(token);
this.validateExpireAt(jwt);
const response = yield this.api.createInstance(new auth_1.JwtAuthentication(token), {
applicationKey: this.applicationKey,
createInstanceRequest: {
userId: this.userId,
deviceId: this.deviceId, // todo fix device id
capabilities: this.capabilities,
version: this.deviceVersion,
expireAt: jwt.instanceExpireAt,
},
});
this.setInstance(new UserInstance_1.UserInstance(Object.assign({}, response.instance), response.config, new Date(jwt.iat * 1000)));
return response.instance;
});
}
validateExpireAt(jwt) {
if (jwt.instanceTtl < InstanceController.MIN_TTL_MS)
throw new Errors_1.ArgumentError("instance TTL has to be greater than 48h", (0, utils_1.nameof)(jwt));
}
storeInstance() {
if (!this.instance) {
return undefined;
}
this.storage.set(this.instance);
}
setUpdatedInstance(updatedInstance) {
if (!updatedInstance || !this.instance) {
return undefined;
}
this.instance.instance = updatedInstance;
return updatedInstance;
}
callUpdateInstanceApi() {
return __awaiter(this, void 0, void 0, function* () {
if (!this.instance) {
return undefined;
}
const { id: instanceId } = this.instance.instance;
return yield this.api.updateInstance({
userId: this.userId,
instanceId,
updateInstanceRequest: {
capabilities: this.capabilities,
version: this.deviceVersion,
},
});
});
}
updateInstanceExpiresAt(userId, token) {
return __awaiter(this, void 0, void 0, function* () {
if (this.instance) {
const jwt = jwt_1.JWT.parse(token);
this.validateExpireAt(jwt);
const response = yield this.api.updateInstanceTtl(new auth_1.JwtAuthentication(token), {
instanceId: this.instance.instance.id,
userId,
updateInstanceTtlRequest: {
expireAt: jwt.instanceExpireAt,
},
});
this.instance.iat = new Date(jwt.iat * 1000);
this.instance.instance.expireAt = response.expireAt;
this.storeInstance();
}
});
}
}
exports.InstanceController = InstanceController;
InstanceController.MIN_TTL_MS = 48 * 3600 * 1000;
InstanceController.REGISTRATION_TIMEOUT_MS = 4000;
InstanceController.APPLICATION_VERSION = version;
InstanceController.UPDATE_INSTANCE_DELAY_MS = 500;
InstanceController.UPDATE_INSTANCE_TTL_WINDOW_DAYS_DEFAULT = 180;
//# sourceMappingURL=InstanceController.js.map