import {BehaviorSubject, catchError, of, Subject} from "rxjs"; import {Injectable} from "@angular/core"; import {AuthService} from "@service/auth.service"; import {environment} from "@environment"; import ApiService from "@api/api.service"; @Injectable({ providedIn: 'root', }) export class TokenRefreshService { private tokenRefreshing$ = new BehaviorSubject(false); private refreshTokenTimeout: any; private refreshTokenExpireMs: number = environment.retryDelay; constructor(private authService: AuthService) { this.setRefreshTokenExpireMs(AuthService.tokenExpiresIn); } private startTokenRefresh(): void { this.refreshTokenTimeout = setTimeout(() => { this.refreshToken(); }, this.refreshTokenExpireMs); } private refreshToken(): void { if (this.tokenRefreshing$.value) return; this.tokenRefreshing$.next(true); this.authService.refreshToken() .pipe( catchError(error => { if (error.status === 403 || error.status === 401 || !localStorage.getItem(ApiService.tokenKey)) { localStorage.removeItem(ApiService.tokenKey); return of(undefined); } let retryTime = this.refreshTokenExpireMs; if (retryTime < environment.retryDelay) retryTime = environment.retryDelay; // 15 minutes if (retryTime * 2 <= 900_000) retryTime *= 2; else retryTime = 900_000; return of(retryTime); })) .subscribe(data => { if (data) this.setRefreshTokenExpireMs(data); this.tokenRefreshing$.next(false); }); } public getTokenRefreshing$(): Subject { return this.tokenRefreshing$; } public setRefreshTokenExpireMs(expireMs: number | string | Date | null = null): void { let expireMsNumber: number; if (expireMs === null) expireMsNumber = -1; else if (expireMs instanceof Date || typeof expireMs === 'string') expireMsNumber = new Date(expireMs).getTime() - 1000 - Date.now(); else expireMsNumber = expireMs; if (expireMsNumber < environment.retryDelay) expireMsNumber = environment.retryDelay; this.refreshTokenExpireMs = expireMsNumber; console.log('New refresh token interval:', this.refreshTokenExpireMs); clearTimeout(this.refreshTokenTimeout); this.startTokenRefresh(); } }