@@ -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.
@@ -4955,6 +4957,48 @@ MatrixClient.prototype.getTurnServersExpiry = function() {
49554957 return this . _turnServersExpiry ;
49564958} ;
49574959
4960+ MatrixClient . prototype . _checkTurnServers = async function ( ) {
4961+ if ( ! this . _supportsVoip ) {
4962+ return ;
4963+ }
4964+
4965+ let credentialsGood = false ;
4966+ const remainingTime = this . _turnServersExpiry - Date . now ( ) ;
4967+ if ( remainingTime > TURN_CHECK_INTERVAL ) {
4968+ logger . debug ( "TURN creds are valid for another " + remainingTime + " ms: not fetching new ones." ) ;
4969+ credentialsGood = true ;
4970+ } else {
4971+ logger . debug ( "Fetching new TURN credentials" ) ;
4972+ try {
4973+ const res = await this . turnServer ( ) ;
4974+ if ( res . uris ) {
4975+ logger . log ( "Got TURN URIs: " + res . uris + " refresh in " + res . ttl + " secs" ) ;
4976+ // map the response to a format that can be fed to RTCPeerConnection
4977+ const servers = {
4978+ urls : res . uris ,
4979+ username : res . username ,
4980+ credential : res . password ,
4981+ } ;
4982+ this . _turnServers = [ servers ] ;
4983+ // The TTL is in seconds but we work in ms
4984+ this . _turnServersExpiry = Date . now ( ) + ( res . ttl * 1000 ) ;
4985+ credentialsGood = true ;
4986+ }
4987+ } catch ( err ) {
4988+ logger . error ( "Failed to get TURN URIs" , err ) ;
4989+ // If we get a 403, there's no point in looping forever.
4990+ if ( err . httpStatus === 403 ) {
4991+ logger . info ( "TURN access unavailable for this account: stopping credentials checks" ) ;
4992+ if ( this . _checkTurnServersIntervalID !== null ) global . clearInterval ( this . _checkTurnServersIntervalID ) ;
4993+ this . _checkTurnServersIntervalID = null ;
4994+ }
4995+ }
4996+ // otherwise, if we failed for whatever reason, try again the next time we're called.
4997+ }
4998+
4999+ return credentialsGood ;
5000+ } ;
5001+
49585002/**
49595003 * Set whether to allow a fallback ICE server should be used for negotiating a
49605004 * WebRTC connection if the homeserver doesn't provide any servers. Defaults to
@@ -5107,7 +5151,12 @@ MatrixClient.prototype.startClient = async function(opts) {
51075151 }
51085152
51095153 // periodically poll for turn servers if we support voip
5110- checkTurnServers ( this ) ;
5154+ if ( this . _supportsVoip ) {
5155+ this . _checkTurnServersIntervalID = setInterval ( ( ) => {
5156+ this . _checkTurnServers ( ) ;
5157+ } , TURN_CHECK_INTERVAL ) ;
5158+ this . _checkTurnServers ( ) ;
5159+ }
51115160
51125161 if ( this . _syncApi ) {
51135162 // This shouldn't happen since we thought the client was not running
@@ -5219,7 +5268,7 @@ MatrixClient.prototype.stopClient = function() {
52195268 this . _callEventHandler = null ;
52205269 }
52215270
5222- global . clearTimeout ( this . _checkTurnServersTimeoutID ) ;
5271+ global . clearInterval ( this . _checkTurnServersIntervalID ) ;
52235272 if ( this . _clientWellKnownIntervalID !== undefined ) {
52245273 global . clearInterval ( this . _clientWellKnownIntervalID ) ;
52255274 }
@@ -5436,42 +5485,6 @@ async function(roomId, eventId, relationType, eventType, opts = {}) {
54365485 } ;
54375486} ;
54385487
5439- function checkTurnServers ( client ) {
5440- if ( ! client . _supportsVoip ) {
5441- return ;
5442- }
5443-
5444- client . turnServer ( ) . then ( function ( res ) {
5445- if ( res . uris ) {
5446- logger . log ( "Got TURN URIs: " + res . uris + " refresh in " +
5447- res . ttl + " secs" ) ;
5448- // map the response to a format that can be fed to
5449- // RTCPeerConnection
5450- const servers = {
5451- urls : res . uris ,
5452- username : res . username ,
5453- credential : res . password ,
5454- } ;
5455- client . _turnServers = [ servers ] ;
5456- client . _turnServersExpiry = Date . now ( ) + res . ttl ;
5457- // re-fetch when we're about to reach the TTL
5458- client . _checkTurnServersTimeoutID = setTimeout ( ( ) => {
5459- checkTurnServers ( client ) ;
5460- } , ( res . ttl || ( 60 * 60 ) ) * 1000 * 0.9 ) ;
5461- }
5462- } , function ( err ) {
5463- logger . error ( "Failed to get TURN URIs" ) ;
5464- // If we get a 403, there's no point in looping forever.
5465- if ( err . httpStatus === 403 ) {
5466- logger . info ( "TURN access unavailable for this account" ) ;
5467- return ;
5468- }
5469- client . _checkTurnServersTimeoutID = setTimeout ( function ( ) {
5470- checkTurnServers ( client ) ;
5471- } , 60000 ) ;
5472- } ) ;
5473- }
5474-
54755488function _reject ( callback , reject , err ) {
54765489 if ( callback ) {
54775490 callback ( err ) ;
0 commit comments