1- import { DeleteSession , GetAccessToken , GetQueue , ReplaceQueue } from "../database/db"
1+ import { setMaxIdleHTTPParsers } from "http" ;
2+ import { DeleteSession , GetAccessToken , GetExpiration , GetQueue , IsValidSid , ReplaceQueue } from "../database/db"
3+ import { updateTokens } from "./refreshTokens" ;
4+ import { sleep } from "../../src/utils"
25
36// Goals for this class:
47// - Create an instance of WebSocketController at top level of server.ts
@@ -27,7 +30,7 @@ export class WebSocketController {
2730
2831
2932 // Adds new {sid, intervalID} to checkQueueUpdatesIntervals
30- public addSessionInterval ( sid : string ) : void {
33+ public async addSessionInterval ( sid : string ) : Promise < void > {
3134 // Check if session already exists, if it does, simply increment user cound
3235 if ( this . checkQueueUpdatesIntervals . has ( sid ) ) {
3336 this . incrementUserCount ( sid ) ;
@@ -36,6 +39,9 @@ export class WebSocketController {
3639
3740 this . currentSongProgress . set ( sid , { progress : 0 , lastUpdated : 0 , isPlaying : false , duration : 0 } ) ;
3841
42+ // Set an interval to trigger before the expiration to create a new access token
43+ this . createRefreshTokenTimeout ( sid ) ;
44+
3945 // Calls checkQueueUpdates every 5 seconds
4046 let intervalID = setInterval ( async ( ) => {
4147 const existing = this . currentSongProgress . get ( sid ) ;
@@ -87,7 +93,7 @@ export class WebSocketController {
8793 console . log ( "Terminating session interval and database information" ) ;
8894 this . destroySession ( sid ) ;
8995 }
90- } , 60000 )
96+ } , 600000 ) // 10 minutes
9197 }
9298 }
9399
@@ -214,5 +220,42 @@ export class WebSocketController {
214220 } catch ( error ) {
215221 console . error ( `Failed to sync song progress for session ${ sid } :` , error ) ;
216222 }
217- }
223+ }
224+
225+ // To be called every expires_in seconds, which is returned from original
226+ // access_token request
227+ private async updateAccessToken ( sid : string ) : Promise < void > {
228+ let failCount = 0 ;
229+ // Attempt to update token up to 3 times
230+ while ( failCount < 3 && ! ( await updateTokens ( sid ) ) ) {
231+ failCount ++ ;
232+ sleep ( 1 )
233+ }
234+ if ( failCount == 3 ) // If updateTokens fails 3 times, assume new token cannot be acquired
235+ return ;
236+
237+ await this . createRefreshTokenTimeout ( sid ) ; // Repeat cycle
238+ }
239+
240+
241+ private async createRefreshTokenTimeout ( sid : string ) : Promise < void > {
242+ const now : any = new Date ( ) ;
243+ let expiration_str : string ;
244+
245+ if ( await IsValidSid ( sid ) ) {
246+ expiration_str = await GetExpiration ( sid ) ;
247+ }
248+ else {
249+ console . error ( "@@@ Failed to validate session: " , sid ) ;
250+ return ; // Session has ended
251+ }
252+
253+ const expiration : any = new Date ( expiration_str )
254+ const expires_in : number = ( expiration - now ) - 10000 ; // Difference in milliseconds (minus 10 seconds)
255+ if ( expires_in >= 0 ) {
256+ setTimeout ( async ( ) => {
257+ this . updateAccessToken ( sid ) ;
258+ } , expires_in )
259+ }
260+ }
218261} ;
0 commit comments