/* * (C) Copyright 2017-2020 OpenVidu (https://openvidu.io) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ import { Publisher } from './Publisher'; import { ConnectionProperties } from './ConnectionProperties'; import { OpenViduRole } from './OpenViduRole'; import { IceServerProperties } from './IceServerProperties'; /** * See [[Session.connections]] */ export class Connection { /** * Identifier of the Connection. You can call methods [[Session.forceDisconnect]] * or [[Session.updateConnection]] passing this property as parameter */ connectionId: string; /** * Returns the status of the Connection. Can be: * - `pending`: if the Connection is waiting for any user to use * its internal token to connect to the session, calling method * [Session.connect](https://docs.openvidu.io/en/stable/api/openvidu-browser/classes/Session.html#connect) * in OpenVidu Browser. * - `active`: if the internal token of the Connection has already * been used by some user to connect to the session, and it cannot be used * again. */ status: string; /** * Timestamp when the Connection was created, in UTC milliseconds (ms since Jan 1, 1970, 00:00:00 UTC) */ createdAt: number; /** * Timestamp when the Connection was taken by a user (passing from status "pending" to "active") * in UTC milliseconds (ms since Jan 1, 1970, 00:00:00 UTC) */ activeAt: number; /** * PRO * Geo location of the Connection, with the following format: `"CITY, COUNTRY"` (`"unknown"` if it wasn't possible to locate it) */ location: string; /** * IP of the Connection, as seen by OpenVidu Server */ ip: string; /** * A complete description of the platform used by the participant to connect to the session */ platform: string; /** * Data associated to the Connection on the client-side. This value is set with second parameter of method * [Session.connect](/en/stable/api/openvidu-browser/classes/Session.html#connect) in OpenVidu Browser */ clientData: string; /** * The [[ConnectionProperties]] assigned to the Connection */ connectionProperties: ConnectionProperties; /** * Token associated to the Connection. This is the value that must be sent to the client-side to be consumed in OpenVidu Browser * method [Session.connect](https://docs.openvidu.io/en/stable/api/openvidu-browser/classes/Session.html#connect). */ token: string; /** * Array of Publisher objects this particular Connection is publishing to the Session (each Publisher object has one Stream, uniquely * identified by its `streamId`). You can call [[Session.forceUnpublish]] passing any of this values as parameter */ publishers: Publisher[] = []; /** * Array of streams (their `streamId` properties) this particular Connection is subscribed to. Each one always corresponds to one * Publisher of some other Connection: each string of this array must be equal to one [[Publisher.streamId]] of other Connection */ subscribers: string[] = []; /** * @hidden deprecated. Inside ConnectionProperties */ role?: OpenViduRole; /** * @hidden deprecated. Inside ConnectionProperties */ serverData?: string; /** * @hidden */ constructor(json) { this.resetWithJson(json); } /** * @hidden */ resetWithJson(json): Connection { this.connectionId = json.connectionId; this.status = json.status; this.createdAt = json.createdAt; this.activeAt = json.activeAt; this.location = json.location; this.ip = json.ip; this.platform = json.platform; this.clientData = json.clientData; this.token = json.token; if (this.connectionProperties != null) { this.connectionProperties.type = json.type; this.connectionProperties.data = json.serverData; this.connectionProperties.record = json.record; this.connectionProperties.role = json.role; this.connectionProperties.kurentoOptions = json.kurentoOptions; this.connectionProperties.rtspUri = json.rtspUri; this.connectionProperties.adaptativeBitrate = json.adaptativeBitrate; this.connectionProperties.onlyPlayWithSubscribers = json.onlyPlayWithSubscribers; this.connectionProperties.networkCache = json.networkCache; this.connectionProperties.customIceServers = json.customIceServers ?? [] } else { this.connectionProperties = { type: json.type, data: json.serverData, record: json.record, role: json.role, kurentoOptions: json.kurentoOptions, rtspUri: json.rtspUri, adaptativeBitrate: json.adaptativeBitrate, onlyPlayWithSubscribers: json.onlyPlayWithSubscribers, networkCache: json.networkCache, customIceServers: json.customIceServers ?? [] } } this.role = json.role; this.serverData = json.serverData; // publishers may be null if (json.publishers != null) { // 1. Array to store fetched Publishers and later remove closed ones const fetchedPublisherIds: string[] = []; json.publishers.forEach(jsonPublisher => { const publisherObj: Publisher = new Publisher(jsonPublisher); fetchedPublisherIds.push(publisherObj.streamId); let storedPublisher = this.publishers.find(c => c.streamId === publisherObj.streamId); if (!!storedPublisher) { // 2. Update existing Publisher storedPublisher.resetWithJson(jsonPublisher); } else { // 3. Add new Publisher this.publishers.push(publisherObj); } }); // 4. Remove closed Publishers from local collection for (var i = this.publishers.length - 1; i >= 0; --i) { if (!fetchedPublisherIds.includes(this.publishers[i].streamId)) { this.publishers.splice(i, 1); } } } // subscribers may be null if (json.subscribers != null) { // 1. Array to store fetched Subscribers and later remove closed ones const fetchedSubscriberIds: string[] = []; json.subscribers.forEach(jsonSubscriber => { fetchedSubscriberIds.push(jsonSubscriber.streamId) if (this.subscribers.indexOf(jsonSubscriber.streamId) === -1) { // 2. Add new Subscriber this.subscribers.push(jsonSubscriber.streamId); } }); // 3. Remove closed Subscribers from local collection for (var i = this.subscribers.length - 1; i >= 0; --i) { if (!fetchedSubscriberIds.includes(this.subscribers[i])) { this.subscribers.splice(i, 1); } } } return this; } /** * @hidden */ equalTo(other: Connection): boolean { let equals: boolean = ( this.connectionId === other.connectionId && this.status === other.status && this.createdAt === other.createdAt && this.activeAt === other.activeAt && this.connectionProperties.type === other.connectionProperties.type && this.connectionProperties.data === other.connectionProperties.data && this.connectionProperties.record === other.connectionProperties.record && this.connectionProperties.role === other.connectionProperties.role && this.connectionProperties.rtspUri === other.connectionProperties.rtspUri && this.connectionProperties.adaptativeBitrate === other.connectionProperties.adaptativeBitrate && this.connectionProperties.onlyPlayWithSubscribers === other.connectionProperties.onlyPlayWithSubscribers && this.connectionProperties.networkCache === other.connectionProperties.networkCache && this.connectionProperties.customIceServers.length === other.connectionProperties.customIceServers.length && this.token === other.token && this.location === other.location && this.ip === other.ip && this.platform === other.platform && this.clientData === other.clientData && this.subscribers.length === other.subscribers.length && this.publishers.length === other.publishers.length); if (equals) { if (this.connectionProperties.kurentoOptions != null) { equals = JSON.stringify(this.connectionProperties.kurentoOptions) === JSON.stringify(other.connectionProperties.kurentoOptions); } else { equals = (this.connectionProperties.kurentoOptions === other.connectionProperties.kurentoOptions); } } if (equals) { if (this.connectionProperties.customIceServers != null) { const simpleIceComparator = (a: IceServerProperties, b: IceServerProperties) => (a.url > b.url) ? 1 : -1 const sortedIceServers = this.connectionProperties.customIceServers.sort(simpleIceComparator); const sortedOtherIceServers = other.connectionProperties.customIceServers.sort(simpleIceComparator); equals = JSON.stringify(sortedIceServers) === JSON.stringify(sortedOtherIceServers); } } if (equals) { equals = JSON.stringify(this.subscribers.sort()) === JSON.stringify(other.subscribers.sort()); if (equals) { let i = 0; while (equals && i < this.publishers.length) { equals = this.publishers[i].equalTo(other.publishers[i]); i++; } return equals; } else { return false; } } else { return false; } } /** * @hidden */ overrideConnectionProperties(newConnectionProperties: ConnectionProperties): void { // For now only properties record and role if (newConnectionProperties.record != null) { this.connectionProperties.record = newConnectionProperties.record; } if (newConnectionProperties.role != null) { this.connectionProperties.role = newConnectionProperties.role; } } }