@@ -61,6 +61,7 @@ import {DEHYDRATION_ALGORITHM} from "./crypto/dehydration";
6161const SCROLLBACK_DELAY_MS = 3000 ;
6262export const CRYPTO_ENABLED = isCryptoAvailable ( ) ;
6363const CAPABILITIES_CACHE_MS = 21600000 ; // 6 hours - an arbitrary value
64+ const TURN_CHECK_INTERVAL = 10 * 60 * 1000 ; // poll for turn credentials every 10 minutes
6465
6566function keysFromRecoverySession ( sessions , decryptionKey , roomId ) {
6667 const keys = [ ] ;
@@ -394,7 +395,8 @@ export function MatrixClient(opts) {
394395 this . _clientWellKnownPromise = undefined ;
395396
396397 this . _turnServers = [ ] ;
397- this . _turnServersExpiry = null ;
398+ this . _turnServersExpiry = 0 ;
399+ this . _checkTurnServersIntervalID = null ;
398400
399401 // The SDK doesn't really provide a clean way for events to recalculate the push
400402 // actions for themselves, so we have to kinda help them out when they are encrypted.
@@ -4954,6 +4956,48 @@ MatrixClient.prototype.getTurnServersExpiry = function() {
49544956 return this . _turnServersExpiry ;
49554957} ;
49564958
4959+ MatrixClient . prototype . _checkTurnServers = async function ( ) {
4960+ if ( ! this . _supportsVoip ) {
4961+ return ;
4962+ }
4963+
4964+ let credentialsGood = false ;
4965+ const remainingTime = this . _turnServersExpiry - Date . now ( ) ;
4966+ if ( remainingTime > TURN_CHECK_INTERVAL ) {
4967+ logger . debug ( "TURN creds are valid for another " + remainingTime + " ms: not fetching new ones." ) ;
4968+ credentialsGood = true ;
4969+ } else {
4970+ logger . debug ( "Fetching new TURN credentials" ) ;
4971+ try {
4972+ const res = await this . turnServer ( ) ;
4973+ if ( res . uris ) {
4974+ logger . log ( "Got TURN URIs: " + res . uris + " refresh in " + res . ttl + " secs" ) ;
4975+ // map the response to a format that can be fed to RTCPeerConnection
4976+ const servers = {
4977+ urls : res . uris ,
4978+ username : res . username ,
4979+ credential : res . password ,
4980+ } ;
4981+ this . _turnServers = [ servers ] ;
4982+ // The TTL is in seconds but we work in ms
4983+ this . _turnServersExpiry = Date . now ( ) + ( res . ttl * 1000 ) ;
4984+ credentialsGood = true ;
4985+ }
4986+ } catch ( err ) {
4987+ logger . error ( "Failed to get TURN URIs" , err ) ;
4988+ // If we get a 403, there's no point in looping forever.
4989+ if ( err . httpStatus === 403 ) {
4990+ logger . info ( "TURN access unavailable for this account: stopping credentials checks" ) ;
4991+ if ( this . _checkTurnServersIntervalID !== null ) global . clearInterval ( this . _checkTurnServersIntervalID ) ;
4992+ this . _checkTurnServersIntervalID = null ;
4993+ }
4994+ }
4995+ // otherwise, if we failed for whatever reason, try again the next time we're called.
4996+ }
4997+
4998+ return credentialsGood ;
4999+ } ;
5000+
49575001/**
49585002 * Set whether to allow a fallback ICE server should be used for negotiating a
49595003 * WebRTC connection if the homeserver doesn't provide any servers. Defaults to
@@ -5106,7 +5150,10 @@ MatrixClient.prototype.startClient = async function(opts) {
51065150 }
51075151
51085152 // periodically poll for turn servers if we support voip
5109- checkTurnServers ( this ) ;
5153+ this . _checkTurnServersIntervalID = setInterval ( ( ) => {
5154+ this . _checkTurnServers ( ) ;
5155+ } , TURN_CHECK_INTERVAL ) ;
5156+ this . _checkTurnServers ( ) ;
51105157
51115158 if ( this . _syncApi ) {
51125159 // This shouldn't happen since we thought the client was not running
@@ -5218,7 +5265,7 @@ MatrixClient.prototype.stopClient = function() {
52185265 this . _callEventHandler = null ;
52195266 }
52205267
5221- global . clearTimeout ( this . _checkTurnServersTimeoutID ) ;
5268+ global . clearInterval ( this . _checkTurnServersIntervalID ) ;
52225269 if ( this . _clientWellKnownIntervalID !== undefined ) {
52235270 global . clearInterval ( this . _clientWellKnownIntervalID ) ;
52245271 }
@@ -5435,42 +5482,6 @@ async function(roomId, eventId, relationType, eventType, opts = {}) {
54355482 } ;
54365483} ;
54375484
5438- function checkTurnServers ( client ) {
5439- if ( ! client . _supportsVoip ) {
5440- return ;
5441- }
5442-
5443- client . turnServer ( ) . then ( function ( res ) {
5444- if ( res . uris ) {
5445- logger . log ( "Got TURN URIs: " + res . uris + " refresh in " +
5446- res . ttl + " secs" ) ;
5447- // map the response to a format that can be fed to
5448- // RTCPeerConnection
5449- const servers = {
5450- urls : res . uris ,
5451- username : res . username ,
5452- credential : res . password ,
5453- } ;
5454- client . _turnServers = [ servers ] ;
5455- client . _turnServersExpiry = Date . now ( ) + res . ttl ;
5456- // re-fetch when we're about to reach the TTL
5457- client . _checkTurnServersTimeoutID = setTimeout ( ( ) => {
5458- checkTurnServers ( client ) ;
5459- } , ( res . ttl || ( 60 * 60 ) ) * 1000 * 0.9 ) ;
5460- }
5461- } , function ( err ) {
5462- logger . error ( "Failed to get TURN URIs" ) ;
5463- // If we get a 403, there's no point in looping forever.
5464- if ( err . httpStatus === 403 ) {
5465- logger . info ( "TURN access unavailable for this account" ) ;
5466- return ;
5467- }
5468- client . _checkTurnServersTimeoutID = setTimeout ( function ( ) {
5469- checkTurnServers ( client ) ;
5470- } , 60000 ) ;
5471- } ) ;
5472- }
5473-
54745485function _reject ( callback , reject , err ) {
54755486 if ( callback ) {
54765487 callback ( err ) ;
0 commit comments