2018-04-18 14:29:07 +02:00
/ *
2020-02-04 11:25:54 +01:00
* ( C ) Copyright 2017 - 2020 OpenVidu ( https : //openvidu.io)
2018-04-18 14:29:07 +02:00
*
* 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 .
*
* /
2018-09-19 15:36:26 +02:00
import axios from 'axios' ;
import { Connection } from './Connection' ;
2018-04-23 11:06:16 +02:00
import { Recording } from './Recording' ;
import { RecordingProperties } from './RecordingProperties' ;
2018-09-19 15:36:26 +02:00
import { Session } from './Session' ;
import { SessionProperties } from './SessionProperties' ;
2019-01-22 14:47:45 +01:00
import { RecordingLayout } from './RecordingLayout' ;
2018-03-14 18:48:29 +01:00
2018-10-09 16:29:28 +02:00
/ * *
* @hidden
* /
interface ObjMap < T > { [ s : string ] : T ; }
2017-06-10 01:44:31 +02:00
export class OpenVidu {
2018-06-04 14:14:17 +02:00
private Buffer = require ( 'buffer/' ) . Buffer ;
2018-03-14 18:48:29 +01:00
2018-07-22 22:13:45 +02:00
/ * *
* @hidden
* /
2020-06-11 13:15:30 +02:00
public host : string ;
2018-07-22 22:13:45 +02:00
/ * *
* @hidden
* /
2019-05-22 17:01:30 +02:00
public basicAuth : string ;
2018-07-22 22:13:45 +02:00
/ * *
* @hidden
* /
2020-10-02 16:40:03 +02:00
static readonly API_PATH : string = '/openvidu/api' ;
2018-07-22 22:13:45 +02:00
/ * *
* @hidden
* /
2020-10-02 16:40:03 +02:00
static readonly API_SESSIONS = OpenVidu . API_PATH + '/sessions' ;
2018-07-22 22:13:45 +02:00
/ * *
* @hidden
* /
2020-10-02 16:40:03 +02:00
static readonly API_TOKENS = OpenVidu . API_PATH + '/tokens' ;
2018-07-22 22:13:45 +02:00
/ * *
* @hidden
* /
2020-10-02 16:40:03 +02:00
static readonly API_RECORDINGS : string = OpenVidu . API_PATH + '/recordings' ;
2018-07-22 22:13:45 +02:00
/ * *
* @hidden
* /
2020-10-02 16:40:03 +02:00
static readonly API_RECORDINGS_START : string = OpenVidu . API_RECORDINGS + '/start' ;
/ * *
* @hidden
* /
static readonly API_RECORDINGS_STOP : string = OpenVidu . API_RECORDINGS + '/stop' ;
2018-07-22 22:13:45 +02:00
/ * *
* Array of active sessions . * * This value will remain unchanged since the last time method [ [ OpenVidu . fetch ] ]
* was called * * . Exceptions to this rule are :
*
2020-10-20 22:09:06 +02:00
* - Calling [ [ OpenVidu . createSession ] ] automatically adds the new Session object to the local collection .
2018-07-22 22:13:45 +02:00
* - Calling [ [ Session . fetch ] ] updates that specific Session status
* - Calling [ [ Session . close ] ] automatically removes the Session from the list of active Sessions
* - Calling [ [ Session . forceDisconnect ] ] automatically updates the inner affected connections for that specific Session
* - Calling [ [ Session . forceUnpublish ] ] also automatically updates the inner affected connections for that specific Session
* - Calling [ [ OpenVidu . startRecording ] ] and [ [ OpenVidu . stopRecording ] ] automatically updates the recording status of the
* Session ( [ [ Session . recording ] ] )
*
* To get the array of active sessions with their current actual value , you must call [ [ OpenVidu . fetch ] ] before consulting
* property [ [ activeSessions ] ]
* /
activeSessions : Session [ ] = [ ] ;
2018-04-24 15:42:23 +02:00
/ * *
2020-10-25 16:42:40 +01:00
* @param hostname URL where your instance of OpenVidu Server is up an running .
* It must be the full URL ( e . g . ` https://12.34.56.78:1234/ ` )
*
2018-04-24 15:42:23 +02:00
* @param secret Secret used on OpenVidu Server initialization
* /
2020-10-25 16:42:40 +01:00
constructor ( private hostname : string , secret : string ) {
2018-03-14 18:48:29 +01:00
this . setHostnameAndPort ( ) ;
2019-05-22 17:01:30 +02:00
this . basicAuth = this . getBasicAuth ( secret ) ;
2018-03-14 18:48:29 +01:00
}
2017-06-10 01:44:31 +02:00
2018-04-25 17:50:55 +02:00
/ * *
2020-10-25 16:42:40 +01:00
* Creates an OpenVidu session . The session identifier will be available at property [ [ Session . sessionId ] ]
2018-04-25 17:50:55 +02:00
*
2018-05-03 10:58:26 +02:00
* @returns A Promise that is resolved to the [ [ Session ] ] if success and rejected with an Error object if not .
2018-04-25 17:50:55 +02:00
* /
public createSession ( properties? : SessionProperties ) : Promise < Session > {
return new Promise < Session > ( ( resolve , reject ) = > {
2019-05-22 17:01:30 +02:00
const session = new Session ( this , properties ) ;
2020-11-19 17:06:50 +01:00
session . getSessionHttp ( )
. then ( response = > {
2018-07-22 22:13:45 +02:00
this . activeSessions . push ( session ) ;
2018-04-25 17:50:55 +02:00
resolve ( session ) ;
} )
. catch ( error = > {
reject ( error ) ;
} ) ;
} ) ;
2018-03-14 18:48:29 +01:00
}
2018-04-18 14:23:16 +02:00
public startRecording ( sessionId : string ) : Promise < Recording > ;
public startRecording ( sessionId : string , name : string ) : Promise < Recording > ;
public startRecording ( sessionId : string , properties : RecordingProperties ) : Promise < Recording > ;
2018-04-24 15:42:23 +02:00
/ * *
* Starts the recording of a [ [ Session ] ]
*
* @param sessionId The ` sessionId ` of the [ [ Session ] ] you want to start recording
* @param name The name you want to give to the video file . You can access this same value in your clients on recording events ( ` recordingStarted ` , ` recordingStopped ` )
*
2019-02-01 18:19:06 +01:00
* @returns A Promise that is resolved to the [ [ Recording ] ] if it successfully started ( the recording can be stopped with guarantees ) and rejected with an Error
* object if not . This Error object has as ` message ` property with the following values :
2018-04-24 15:42:23 +02:00
* - ` 404 ` : no session exists for the passed ` sessionId `
2019-02-01 18:19:06 +01:00
* - ` 406 ` : the session has no connected participants
* - ` 422 ` : when passing [ [ RecordingProperties ] ] , ` resolution ` parameter exceeds acceptable values ( for both width and height , min 100 px and max 1999 px ) or trying
* to start a recording with both ` hasAudio ` and ` hasVideo ` to false
2018-04-24 15:42:23 +02:00
* - ` 409 ` : the session is not configured for using [ [ MediaMode . ROUTED ] ] or it is already being recorded
2020-04-17 18:45:46 +02:00
* - ` 501 ` : OpenVidu Server recording module is disabled ( ` OPENVIDU_RECORDING ` property set to ` false ` )
2018-04-24 15:42:23 +02:00
* /
2018-04-18 14:23:16 +02:00
public startRecording ( sessionId : string , param2? : string | RecordingProperties ) : Promise < Recording > {
2018-04-18 10:39:39 +02:00
return new Promise < Recording > ( ( resolve , reject ) = > {
2018-03-14 18:48:29 +01:00
2018-06-04 14:14:17 +02:00
let data ;
2018-04-18 14:23:16 +02:00
if ( ! ! param2 ) {
if ( ! ( typeof param2 === 'string' ) ) {
2018-04-20 12:04:56 +02:00
const properties = < RecordingProperties > param2 ;
2019-01-22 15:19:22 +01:00
data = {
2018-04-18 14:23:16 +02:00
session : sessionId ,
2018-04-23 11:06:16 +02:00
name : ! ! properties . name ? properties . name : '' ,
2020-11-26 16:54:30 +01:00
outputMode : properties.outputMode ,
hasAudio : properties.hasAudio != null ? properties.hasAudio : null ,
hasVideo : properties.hasVideo != null ? properties.hasVideo : null ,
shmSize : properties.shmSize ,
mediaNode : properties.mediaNode
2019-01-22 15:19:22 +01:00
} ;
2020-11-26 16:54:30 +01:00
if ( ( data . hasVideo == null || data . hasVideo ) && ( data . outputMode == null || data . outputMode . toString ( ) === Recording . OutputMode [ Recording . OutputMode . COMPOSED ]
|| data . outputMode . toString ( ) === Recording . OutputMode [ Recording . OutputMode . COMPOSED_QUICK_START ] ) ) {
data . resolution = properties . resolution ;
data . recordingLayout = ! ! properties . recordingLayout ? properties . recordingLayout : '' ;
2019-01-22 14:47:45 +01:00
if ( data . recordingLayout . toString ( ) === RecordingLayout [ RecordingLayout . CUSTOM ] ) {
data . customLayout = ! ! properties . customLayout ? properties . customLayout : '' ;
}
}
2019-01-22 15:19:22 +01:00
data = JSON . stringify ( data ) ;
2018-04-18 14:23:16 +02:00
} else {
2018-06-04 14:14:17 +02:00
data = JSON . stringify ( {
2018-04-18 14:23:16 +02:00
session : sessionId ,
2020-11-26 16:54:30 +01:00
name : param2
2018-04-18 14:23:16 +02:00
} ) ;
}
} else {
2018-06-04 14:14:17 +02:00
data = JSON . stringify ( {
2018-04-18 14:23:16 +02:00
session : sessionId ,
2020-11-26 16:54:30 +01:00
name : ''
2018-04-18 14:23:16 +02:00
} ) ;
}
2018-03-14 18:48:29 +01:00
2018-06-04 14:14:17 +02:00
axios . post (
2020-10-02 16:40:03 +02:00
this . host + OpenVidu . API_RECORDINGS_START ,
2018-06-04 14:14:17 +02:00
data ,
{
headers : {
2019-05-22 17:01:30 +02:00
'Authorization' : this . basicAuth ,
2018-06-04 14:14:17 +02:00
'Content-Type' : 'application/json'
}
2018-03-14 18:48:29 +01:00
}
2018-06-04 14:14:17 +02:00
)
. then ( res = > {
if ( res . status === 200 ) {
2018-04-18 10:39:39 +02:00
// SUCCESS response from openvidu-server (Recording in JSON format). Resolve new Recording
2018-07-22 22:13:45 +02:00
const r : Recording = new Recording ( res . data ) ;
2018-07-23 00:36:45 +02:00
const activeSession = this . activeSessions . find ( s = > s . sessionId === r . sessionId ) ;
if ( ! ! activeSession ) {
activeSession . recording = true ;
} else {
console . warn ( "No active session found for sessionId '" + r . sessionId + "'. This instance of OpenVidu Node Client didn't create this session" ) ;
}
2018-07-22 22:13:45 +02:00
resolve ( r ) ;
2018-03-14 18:48:29 +01:00
} else {
// ERROR response from openvidu-server. Resolve HTTP status
2018-06-04 14:14:17 +02:00
reject ( new Error ( res . status . toString ( ) ) ) ;
}
} ) . catch ( error = > {
if ( error . response ) {
// The request was made and the server responded with a status code (not 2xx)
reject ( new Error ( error . response . status . toString ( ) ) ) ;
} else if ( error . request ) {
// The request was made but no response was received
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
// http.ClientRequest in node.js
console . error ( error . request ) ;
} else {
// Something happened in setting up the request that triggered an Error
console . error ( 'Error' , error . message ) ;
2018-03-14 18:48:29 +01:00
}
} ) ;
} ) ;
}
2018-04-24 15:42:23 +02:00
/ * *
* Stops the recording of a [ [ Session ] ]
*
* @param recordingId The ` id ` property of the [ [ Recording ] ] you want to stop
*
* @returns A Promise that is resolved to the [ [ Recording ] ] if it successfully stopped and rejected with an Error object if not . This Error object has as ` message ` property with the following values :
* - ` 404 ` : no recording exists for the passed ` recordingId `
* - ` 406 ` : recording has ` starting ` status . Wait until ` started ` status before stopping the recording
* /
2018-04-18 10:39:39 +02:00
public stopRecording ( recordingId : string ) : Promise < Recording > {
return new Promise < Recording > ( ( resolve , reject ) = > {
2018-03-14 18:48:29 +01:00
2018-06-04 14:14:17 +02:00
axios . post (
2020-10-02 16:40:03 +02:00
this . host + OpenVidu . API_RECORDINGS_STOP + '/' + recordingId ,
2018-06-04 14:14:17 +02:00
undefined ,
{
headers : {
2019-05-22 17:01:30 +02:00
'Authorization' : this . basicAuth ,
2018-06-04 14:14:17 +02:00
'Content-Type' : 'application/x-www-form-urlencoded'
}
2018-03-14 18:48:29 +01:00
}
2018-06-04 14:14:17 +02:00
)
. then ( res = > {
if ( res . status === 200 ) {
2018-04-18 10:39:39 +02:00
// SUCCESS response from openvidu-server (Recording in JSON format). Resolve new Recording
2018-07-22 22:13:45 +02:00
const r : Recording = new Recording ( res . data ) ;
2018-07-23 00:36:45 +02:00
const activeSession = this . activeSessions . find ( s = > s . sessionId === r . sessionId ) ;
if ( ! ! activeSession ) {
activeSession . recording = false ;
} else {
console . warn ( "No active session found for sessionId '" + r . sessionId + "'. This instance of OpenVidu Node Client didn't create this session" ) ;
}
2018-07-22 22:13:45 +02:00
resolve ( r ) ;
2018-03-14 18:48:29 +01:00
} else {
// ERROR response from openvidu-server. Resolve HTTP status
2018-06-04 14:14:17 +02:00
reject ( new Error ( res . status . toString ( ) ) ) ;
}
} ) . catch ( error = > {
if ( error . response ) {
// The request was made and the server responded with a status code (not 2xx)
reject ( new Error ( error . response . status . toString ( ) ) ) ;
} else if ( error . request ) {
2018-07-22 22:13:45 +02:00
// The request was made but no response was received `error.request` is an instance of XMLHttpRequest
// in the browser and an instance of http.ClientRequest in node.js
2018-06-04 14:14:17 +02:00
console . error ( error . request ) ;
} else {
// Something happened in setting up the request that triggered an Error
console . error ( 'Error' , error . message ) ;
2018-03-14 18:48:29 +01:00
}
} ) ;
} ) ;
}
2018-04-24 15:42:23 +02:00
/ * *
* Gets an existing [ [ Recording ] ]
*
* @param recordingId The ` id ` property of the [ [ Recording ] ] you want to retrieve
*
* @returns A Promise that is resolved to the [ [ Recording ] ] if it successfully stopped and rejected with an Error object if not . This Error object has as ` message ` property with the following values :
* - ` 404 ` : no recording exists for the passed ` recordingId `
* /
2018-04-18 10:39:39 +02:00
public getRecording ( recordingId : string ) : Promise < Recording > {
return new Promise < Recording > ( ( resolve , reject ) = > {
2018-03-14 18:48:29 +01:00
2018-06-04 14:14:17 +02:00
axios . get (
2020-06-11 13:15:30 +02:00
this . host + OpenVidu . API_RECORDINGS + '/' + recordingId ,
2018-06-04 14:14:17 +02:00
{
headers : {
2019-05-22 17:01:30 +02:00
'Authorization' : this . basicAuth ,
2018-06-04 14:14:17 +02:00
'Content-Type' : 'application/x-www-form-urlencoded'
}
2018-03-14 18:48:29 +01:00
}
2018-06-04 14:14:17 +02:00
)
. then ( res = > {
if ( res . status === 200 ) {
2018-04-18 10:39:39 +02:00
// SUCCESS response from openvidu-server (Recording in JSON format). Resolve new Recording
2018-06-04 14:14:17 +02:00
resolve ( new Recording ( res . data ) ) ;
2018-03-14 18:48:29 +01:00
} else {
// ERROR response from openvidu-server. Resolve HTTP status
2018-06-04 14:14:17 +02:00
reject ( new Error ( res . status . toString ( ) ) ) ;
}
} ) . catch ( error = > {
if ( error . response ) {
// The request was made and the server responded with a status code (not 2xx)
reject ( new Error ( error . response . status . toString ( ) ) ) ;
} else if ( error . request ) {
// The request was made but no response was received
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
// http.ClientRequest in node.js
console . error ( error . request ) ;
} else {
// Something happened in setting up the request that triggered an Error
console . error ( 'Error' , error . message ) ;
2018-03-14 18:48:29 +01:00
}
} ) ;
} ) ;
}
2018-04-24 15:42:23 +02:00
/ * *
* Lists all existing recordings
*
* @returns A Promise that is resolved to an array with all existing recordings
* /
2018-04-18 10:39:39 +02:00
public listRecordings ( ) : Promise < Recording [ ] > {
return new Promise < Recording [ ] > ( ( resolve , reject ) = > {
2018-03-14 18:48:29 +01:00
2018-06-04 14:14:17 +02:00
axios . get (
2020-06-11 13:15:30 +02:00
this . host + OpenVidu . API_RECORDINGS ,
2018-06-04 14:14:17 +02:00
{
headers : {
2019-05-22 17:01:30 +02:00
Authorization : this.basicAuth
2018-06-04 14:14:17 +02:00
}
2018-03-14 18:48:29 +01:00
}
2018-06-04 14:14:17 +02:00
)
. then ( res = > {
if ( res . status === 200 ) {
2018-04-18 10:39:39 +02:00
// SUCCESS response from openvidu-server (JSON arrays of recordings in JSON format). Resolve list of new recordings
2018-04-23 11:06:16 +02:00
const recordingArray : Recording [ ] = [ ] ;
2018-06-04 14:14:17 +02:00
const responseItems = res . data . items ;
2018-04-23 11:06:16 +02:00
for ( const item of responseItems ) {
recordingArray . push ( new Recording ( item ) ) ;
2018-03-14 18:48:29 +01:00
}
2018-10-15 11:33:56 +02:00
// Order recordings by time of creation (newest first)
recordingArray . sort ( ( r1 , r2 ) = > ( r1 . createdAt < r2 . createdAt ) ? 1 : ( ( r2 . createdAt < r1 . createdAt ) ? - 1 : 0 ) ) ;
2018-04-18 10:39:39 +02:00
resolve ( recordingArray ) ;
2018-03-14 18:48:29 +01:00
} else {
// ERROR response from openvidu-server. Resolve HTTP status
2018-06-04 14:14:17 +02:00
reject ( new Error ( res . status . toString ( ) ) ) ;
}
} ) . catch ( error = > {
if ( error . response ) {
// The request was made and the server responded with a status code (not 2xx)
reject ( new Error ( error . response . status . toString ( ) ) ) ;
} else if ( error . request ) {
// The request was made but no response was received
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
// http.ClientRequest in node.js
console . error ( error . request ) ;
} else {
// Something happened in setting up the request that triggered an Error
console . error ( 'Error' , error . message ) ;
2018-03-14 18:48:29 +01:00
}
} ) ;
} ) ;
}
2018-04-24 15:42:23 +02:00
/ * *
2019-06-27 14:04:02 +02:00
* Deletes a [ [ Recording ] ] . The recording must have status ` stopped ` , ` ready ` or ` failed `
2018-04-24 15:42:23 +02:00
*
* @param recordingId
*
* @returns A Promise that is resolved if the Recording was successfully deleted and rejected with an Error object if not . This Error object has as ` message ` property with the following values :
* - ` 404 ` : no recording exists for the passed ` recordingId `
* - ` 409 ` : the recording has ` started ` status . Stop it before deletion
* /
2018-03-14 18:48:29 +01:00
public deleteRecording ( recordingId : string ) : Promise < Error > {
return new Promise < Error > ( ( resolve , reject ) = > {
2018-06-04 14:14:17 +02:00
axios . delete (
2020-06-11 13:15:30 +02:00
this . host + OpenVidu . API_RECORDINGS + '/' + recordingId ,
2018-06-04 14:14:17 +02:00
{
headers : {
2019-05-22 17:01:30 +02:00
'Authorization' : this . basicAuth ,
2018-06-04 14:14:17 +02:00
'Content-Type' : 'application/x-www-form-urlencoded'
}
2018-03-14 18:48:29 +01:00
}
2018-06-04 14:14:17 +02:00
)
. then ( res = > {
if ( res . status === 204 ) {
2018-03-14 18:48:29 +01:00
// SUCCESS response from openvidu-server. Resolve undefined
resolve ( undefined ) ;
} else {
// ERROR response from openvidu-server. Resolve HTTP status
2018-06-04 14:14:17 +02:00
reject ( new Error ( res . status . toString ( ) ) ) ;
}
} ) . catch ( error = > {
if ( error . response ) {
// The request was made and the server responded with a status code (not 2xx)
reject ( new Error ( error . response . status . toString ( ) ) ) ;
} else if ( error . request ) {
// The request was made but no response was received
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
// http.ClientRequest in node.js
console . error ( error . request ) ;
} else {
// Something happened in setting up the request that triggered an Error
console . error ( 'Error' , error . message ) ;
2018-03-14 18:48:29 +01:00
}
} ) ;
} ) ;
2018-01-27 19:39:49 +01:00
}
2018-07-22 22:13:45 +02:00
/ * *
* Updates every property of every active Session with the current status they have in OpenVidu Server .
* After calling this method you can access the updated array of active sessions in [ [ activeSessions ] ]
*
* @returns A promise resolved to true if any Session status has changed with respect to the server , or to false if not .
* This applies to any property or sub - property of any of the sessions locally stored in OpenVidu Node Client
* /
public fetch ( ) : Promise < boolean > {
return new Promise < boolean > ( ( resolve , reject ) = > {
axios . get (
2020-10-15 13:16:29 +02:00
this . host + OpenVidu . API_SESSIONS + '?pendingConnections=true' ,
2018-07-22 22:13:45 +02:00
{
headers : {
2019-05-22 17:01:30 +02:00
Authorization : this.basicAuth
2018-07-22 22:13:45 +02:00
}
}
)
. then ( res = > {
if ( res . status === 200 ) {
// Boolean to store if any Session has changed
let hasChanged = false ;
2020-10-16 13:45:15 +02:00
// 1. Array to store fetched sessionIds and later remove closed ones
const fetchedSessionIds : string [ ] = [ ] ;
res . data . content . forEach ( jsonSession = > {
const fetchedSession : Session = new Session ( this , jsonSession ) ;
fetchedSessionIds . push ( fetchedSession . sessionId ) ;
let storedSession = this . activeSessions . find ( s = > s . sessionId === fetchedSession . sessionId ) ;
2018-07-22 22:13:45 +02:00
if ( ! ! storedSession ) {
2020-10-16 13:45:15 +02:00
// 2. Update existing Session
2018-09-19 15:36:26 +02:00
const changed : boolean = ! storedSession . equalTo ( fetchedSession ) ;
2020-10-16 13:45:15 +02:00
storedSession . resetWithJson ( jsonSession ) ;
2018-07-22 22:13:45 +02:00
console . log ( "Available session '" + storedSession . sessionId + "' info fetched. Any change: " + changed ) ;
hasChanged = hasChanged || changed ;
2020-10-16 13:45:15 +02:00
2018-07-22 22:13:45 +02:00
} else {
2020-10-16 13:45:15 +02:00
// 3. Add new Session
this . activeSessions . push ( fetchedSession ) ;
console . log ( "New session '" + fetchedSession . sessionId + "' info fetched" ) ;
2018-07-22 22:13:45 +02:00
hasChanged = true ;
}
} ) ;
2020-10-16 13:45:15 +02:00
// 4. Remove closed sessions from local collection
for ( var i = this . activeSessions . length - 1 ; i >= 0 ; -- i ) {
let sessionId = this . activeSessions [ i ] . sessionId ;
if ( ! fetchedSessionIds . includes ( sessionId ) ) {
console . log ( "Removing closed session '" + sessionId + "'" ) ;
2018-07-23 10:01:49 +02:00
hasChanged = true ;
2020-10-16 13:45:15 +02:00
this . activeSessions . splice ( i , 1 ) ;
2018-07-23 10:01:49 +02:00
}
2020-10-16 13:45:15 +02:00
}
2018-07-22 22:48:09 +02:00
console . log ( 'Active sessions info fetched: ' , fetchedSessionIds ) ;
2018-07-22 22:13:45 +02:00
resolve ( hasChanged ) ;
} else {
// ERROR response from openvidu-server. Resolve HTTP status
reject ( new Error ( res . status . toString ( ) ) ) ;
}
} ) . catch ( error = > {
if ( error . response ) {
// The request was made and the server responded with a status code (not 2xx)
reject ( new Error ( error . response . status . toString ( ) ) ) ;
} else if ( error . request ) {
// The request was made but no response was received
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
// http.ClientRequest in node.js
console . error ( error . request ) ;
2019-09-11 10:33:10 +02:00
reject ( error ) ;
2018-07-22 22:13:45 +02:00
} else {
// Something happened in setting up the request that triggered an Error
console . error ( 'Error' , error . message ) ;
2019-02-19 10:48:39 +01:00
reject ( new Error ( error . message ) ) ;
2018-07-22 22:13:45 +02:00
}
} ) ;
} ) ;
}
2018-09-19 15:36:26 +02:00
/ * *
* @hidden
2018-10-09 16:29:28 +02:00
* @returns A map paring every existing sessionId with true or false depending on whether it has changed or not
2018-09-19 15:36:26 +02:00
* /
2018-10-09 16:29:28 +02:00
fetchWebRtc ( ) : Promise < any > {
2018-09-19 15:36:26 +02:00
// tslint:disable:no-string-literal
const addWebRtcStatsToConnections = ( connection : Connection , connectionsExtendedInfo : any ) = > {
const connectionExtended = connectionsExtendedInfo . find ( c = > c . connectionId === connection . connectionId ) ;
if ( ! ! connectionExtended ) {
connection . publishers . forEach ( pub = > {
const publisherExtended = connectionExtended . publishers . find ( p = > p . streamId === pub . streamId ) ;
2020-10-16 13:45:15 +02:00
pub [ 'webRtc' ] = {
2018-09-19 15:36:26 +02:00
kms : {
events : publisherExtended.events ,
localCandidate : publisherExtended.localCandidate ,
remoteCandidate : publisherExtended.remoteCandidate ,
receivedCandidates : publisherExtended.receivedCandidates ,
2020-05-14 14:37:49 +02:00
gatheredCandidates : publisherExtended.gatheredCandidates ,
2018-11-13 17:03:57 +01:00
webrtcEndpointName : publisherExtended.webrtcEndpointName ,
localSdp : publisherExtended.localSdp ,
remoteSdp : publisherExtended.remoteSdp
2018-09-19 15:36:26 +02:00
}
} ;
2020-10-16 13:45:15 +02:00
pub [ 'localCandidatePair' ] = parseRemoteCandidatePair ( pub [ 'webRtc' ] . kms . remoteCandidate ) ;
2018-09-19 15:36:26 +02:00
if ( ! ! publisherExtended . serverStats ) {
2020-10-16 13:45:15 +02:00
pub [ 'webRtc' ] . kms . serverStats = publisherExtended . serverStats ;
2018-09-19 15:36:26 +02:00
}
} ) ;
2018-09-24 11:04:54 +02:00
const subscriberArray = [ ] ;
2018-09-19 15:36:26 +02:00
connection . subscribers . forEach ( sub = > {
const subscriberExtended = connectionExtended . subscribers . find ( s = > s . streamId === sub ) ;
const subAux = { } ;
// Standard properties
subAux [ 'streamId' ] = sub ;
subAux [ 'publisher' ] = subscriberExtended . publisher ;
// WebRtc properties
subAux [ 'createdAt' ] = subscriberExtended . createdAt ;
subAux [ 'webRtc' ] = {
kms : {
events : subscriberExtended.events ,
localCandidate : subscriberExtended.localCandidate ,
remoteCandidate : subscriberExtended.remoteCandidate ,
receivedCandidates : subscriberExtended.receivedCandidates ,
2020-05-14 14:37:49 +02:00
gatheredCandidates : subscriberExtended.gatheredCandidates ,
2018-11-13 17:03:57 +01:00
webrtcEndpointName : subscriberExtended.webrtcEndpointName ,
localSdp : subscriberExtended.localSdp ,
remoteSdp : subscriberExtended.remoteSdp
2018-09-19 15:36:26 +02:00
}
} ;
2018-09-24 11:04:54 +02:00
subAux [ 'localCandidatePair' ] = parseRemoteCandidatePair ( subAux [ 'webRtc' ] . kms . remoteCandidate ) ;
2018-09-19 15:36:26 +02:00
if ( ! ! subscriberExtended . serverStats ) {
subAux [ 'webRtc' ] . kms . serverStats = subscriberExtended . serverStats ;
}
2018-09-24 11:04:54 +02:00
subscriberArray . push ( subAux ) ;
2018-09-19 15:36:26 +02:00
} ) ;
2018-09-24 11:04:54 +02:00
connection . subscribers = subscriberArray ;
}
} ;
const parseRemoteCandidatePair = ( candidateStr : string ) = > {
if ( ! candidateStr ) {
return 'ERROR: No remote candidate available' ;
2018-09-19 15:36:26 +02:00
}
2018-09-24 11:04:54 +02:00
const array = candidateStr . split ( /\s+/ ) ;
return {
portNumber : array [ 5 ] ,
ipAddress : array [ 4 ] ,
transport : array [ 2 ] . toLowerCase ( ) ,
candidateType : array [ 7 ] ,
priority : array [ 3 ] ,
raw : candidateStr
} ;
2018-09-19 15:36:26 +02:00
} ;
2018-10-09 16:29:28 +02:00
return new Promise < { changes : boolean , sessionChanges : ObjMap < boolean > } > ( ( resolve , reject ) = > {
2018-09-19 15:36:26 +02:00
axios . get (
2020-06-11 13:15:30 +02:00
this . host + OpenVidu . API_SESSIONS + '?webRtcStats=true' ,
2018-09-19 15:36:26 +02:00
{
headers : {
2019-05-22 17:01:30 +02:00
Authorization : this.basicAuth
2018-09-19 15:36:26 +02:00
}
}
)
. then ( res = > {
if ( res . status === 200 ) {
2018-10-09 16:29:28 +02:00
// Global changes
let globalChanges = false ;
// Collection of sessionIds telling whether each one of them has changed or not
const sessionChanges : ObjMap < boolean > = { } ;
2018-09-19 15:36:26 +02:00
2020-10-16 13:45:15 +02:00
// 1. Array to store fetched sessionIds and later remove closed ones
const fetchedSessionIds : string [ ] = [ ] ;
res . data . content . forEach ( jsonSession = > {
const fetchedSession : Session = new Session ( this , jsonSession ) ;
fetchedSession . connections . forEach ( connection = > {
addWebRtcStatsToConnections ( connection , jsonSession . connections . content ) ;
2018-09-19 15:36:26 +02:00
} ) ;
2020-10-16 13:45:15 +02:00
fetchedSessionIds . push ( fetchedSession . sessionId ) ;
let storedSession = this . activeSessions . find ( s = > s . sessionId === fetchedSession . sessionId ) ;
2018-09-19 15:36:26 +02:00
if ( ! ! storedSession ) {
2018-09-24 11:04:54 +02:00
2020-10-16 13:45:15 +02:00
// 2. Update existing Session
2018-09-24 11:04:54 +02:00
let changed = ! storedSession . equalTo ( fetchedSession ) ;
if ( ! changed ) { // Check if server webrtc information has changed in any Publisher object (Session.equalTo does not check Publisher.webRtc auxiliary object)
2020-10-16 13:45:15 +02:00
fetchedSession . connections . forEach ( ( connection , index1 ) = > {
2018-09-24 11:04:54 +02:00
for ( let index2 = 0 ; ( index2 < connection [ 'publishers' ] . length && ! changed ) ; index2 ++ ) {
2020-10-16 13:45:15 +02:00
changed = changed || JSON . stringify ( connection [ 'publishers' ] [ index2 ] [ 'webRtc' ] ) !== JSON . stringify ( storedSession . connections [ index1 ] [ 'publishers' ] [ index2 ] [ 'webRtc' ] ) ;
2018-09-24 11:04:54 +02:00
}
} ) ;
}
2020-10-16 13:45:15 +02:00
storedSession . resetWithJson ( jsonSession ) ;
storedSession . connections . forEach ( connection = > {
addWebRtcStatsToConnections ( connection , jsonSession . connections . content ) ;
} ) ;
2018-09-19 15:36:26 +02:00
console . log ( "Available session '" + storedSession . sessionId + "' info fetched. Any change: " + changed ) ;
2018-10-09 16:29:28 +02:00
sessionChanges [ storedSession . sessionId ] = changed ;
globalChanges = globalChanges || changed ;
2020-10-16 13:45:15 +02:00
2018-09-19 15:36:26 +02:00
} else {
2020-10-16 13:45:15 +02:00
// 3. Add new Session
this . activeSessions . push ( fetchedSession ) ;
console . log ( "New session '" + fetchedSession . sessionId + "' info fetched" ) ;
sessionChanges [ fetchedSession . sessionId ] = true ;
2018-10-09 16:29:28 +02:00
globalChanges = true ;
2020-10-16 13:45:15 +02:00
2018-09-19 15:36:26 +02:00
}
} ) ;
2020-10-16 13:45:15 +02:00
// 4. Remove closed sessions from local collection
for ( var i = this . activeSessions . length - 1 ; i >= 0 ; -- i ) {
let sessionId = this . activeSessions [ i ] . sessionId ;
if ( ! fetchedSessionIds . includes ( sessionId ) ) {
console . log ( "Removing closed session '" + sessionId + "'" ) ;
sessionChanges [ sessionId ] = true ;
2018-10-09 16:29:28 +02:00
globalChanges = true ;
2020-10-16 13:45:15 +02:00
this . activeSessions . splice ( i , 1 ) ;
2018-09-19 15:36:26 +02:00
}
2020-10-16 13:45:15 +02:00
}
2018-09-19 15:36:26 +02:00
console . log ( 'Active sessions info fetched: ' , fetchedSessionIds ) ;
2018-10-09 16:29:28 +02:00
resolve ( { changes : globalChanges , sessionChanges } ) ;
2018-09-19 15:36:26 +02:00
} else {
// ERROR response from openvidu-server. Resolve HTTP status
reject ( new Error ( res . status . toString ( ) ) ) ;
}
} ) . catch ( error = > {
if ( error . response ) {
// The request was made and the server responded with a status code (not 2xx)
reject ( new Error ( error . response . status . toString ( ) ) ) ;
} else if ( error . request ) {
// The request was made but no response was received
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
// http.ClientRequest in node.js
console . error ( error . request ) ;
} else {
// Something happened in setting up the request that triggered an Error
console . error ( 'Error' , error . message ) ;
}
} ) ;
} ) ;
}
// tslint:enable:no-string-literal
2018-03-14 18:48:29 +01:00
private getBasicAuth ( secret : string ) : string {
2018-06-04 14:14:17 +02:00
return 'Basic ' + this . Buffer ( 'OPENVIDUAPP:' + secret ) . toString ( 'base64' ) ;
2018-01-27 19:39:49 +01:00
}
2018-03-14 18:48:29 +01:00
private setHostnameAndPort ( ) : void {
2019-11-06 16:18:32 +01:00
let url : URL ;
try {
2020-10-25 16:42:40 +01:00
url = new URL ( this . hostname ) ;
2019-11-06 16:18:32 +01:00
} catch ( error ) {
2020-06-11 13:15:30 +02:00
console . error ( 'URL format incorrect' , error ) ;
throw new Error ( 'URL format incorrect: ' + error ) ;
2018-03-14 18:48:29 +01:00
}
2020-06-11 13:15:30 +02:00
this . host = url . protocol + '//' + url . host ;
2017-06-10 01:44:31 +02:00
}
2019-02-19 10:48:39 +01:00
}