diff --git a/src/app/app.component.ts b/src/app/app.component.ts index a35aebd..e5e41f5 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -14,7 +14,8 @@ import {FocusNextDirective} from "@/directives/focus-next.directive"; ` }) export class AppComponent { - constructor() { + constructor(tokenRefreshService: TokenRefreshService) { registerLocaleData(localeRu); + tokenRefreshService.startTokenRefresh(); } } diff --git a/src/services/token-refresh.service.ts b/src/services/token-refresh.service.ts new file mode 100644 index 0000000..b99996d --- /dev/null +++ b/src/services/token-refresh.service.ts @@ -0,0 +1,72 @@ +import {BehaviorSubject, interval, Subscription, switchMap} from "rxjs"; +import {Injectable} from "@angular/core"; +import {AuthService} from "@service/auth.service"; +import {environment} from "@environment"; + +@Injectable({ + providedIn: 'root', +}) +export class TokenRefreshService { + private tokenRefreshSubscription: Subscription | undefined; + private tokenRefreshing$ = new BehaviorSubject(false); + private refreshTokenExpireMs: number = environment.retryDelay; + + constructor(private authService: AuthService) { + this.setRefreshTokenExpireMs(AuthService.tokenExpiresIn.getTime() - 1000 - Date.now()); + + authService.tokenChangeError.subscribe(_ => { + console.log('Token change error event received'); + this.tokenRefreshing$.next(false); + this.stopTokenRefresh(); + }); + authService.expireTokenChange.subscribe(date => { + console.log('Expire token change event received:', date); + this.setRefreshTokenExpireMs(date.getTime() - 1000 - Date.now()); + }); + } + + public startTokenRefresh(date: Date | null = null): void { + if (date) + this.refreshTokenExpireMs = new Date(date).getTime() - 1000 - Date.now(); + + if (!this.tokenRefreshSubscription || this.tokenRefreshSubscription.closed) { + this.tokenRefreshSubscription = interval(this.refreshTokenExpireMs).pipe( + switchMap(() => { + this.tokenRefreshing$.next(true); + return this.authService.refreshToken(); + }) + ).subscribe({ + next: (_) => { + this.tokenRefreshing$.next(false); + }, + error: error => { + console.error('Token refresh error:', error); + this.tokenRefreshing$.next(false); + } + }); + } + } + + public getTokenRefreshing$(): BehaviorSubject { + return this.tokenRefreshing$; + } + + public stopTokenRefresh(): void { + if (this.tokenRefreshSubscription && !this.tokenRefreshSubscription.closed) { + this.tokenRefreshSubscription.unsubscribe(); + this.tokenRefreshSubscription = undefined; + } + } + + public setRefreshTokenExpireMs(expireMs: number): void { + if (expireMs < environment.retryDelay) + expireMs = 3000; + + console.log(expireMs); + this.refreshTokenExpireMs = expireMs; + + this.stopTokenRefresh(); + this.startTokenRefresh(); + } +} +