common-ui/src/lib/error/error.service.ts
2021-12-17 16:23:16 +02:00

60 lines
2.1 KiB
TypeScript

import { Injectable } from '@angular/core';
import { fromEvent, merge, Observable, Subject } from 'rxjs';
import { HttpErrorResponse, HttpStatusCode } from '@angular/common/http';
import { LoadingService } from '../loading';
import { delay, filter, map, mapTo } from 'rxjs/operators';
import { NavigationStart, Router } from '@angular/router';
import { shareLast } from '../utils';
const BANDWIDTH_LIMIT_EXCEEDED = 509 as const;
const OFFLINE_STATUSES = [
HttpStatusCode.BadGateway,
HttpStatusCode.ServiceUnavailable,
HttpStatusCode.GatewayTimeout,
BANDWIDTH_LIMIT_EXCEEDED,
] as const;
const isOffline = (error?: HttpErrorResponse) => !!error && OFFLINE_STATUSES.includes(error.status);
@Injectable({ providedIn: 'root' })
export class ErrorService {
readonly error$ = new Subject<HttpErrorResponse | undefined>();
readonly offline$: Observable<Event>;
readonly online$: Observable<Event>;
readonly serverError$ = this.error$.pipe(filter(error => !error || !isOffline(error)));
readonly connectionStatus$: Observable<string | undefined>;
private readonly _online$ = new Subject();
constructor(private readonly _loadingService: LoadingService, private readonly _router: Router) {
_router.events.pipe(filter(event => event instanceof NavigationStart)).subscribe(() => {
this.clear();
});
this.offline$ = this._offline();
this.online$ = this._online();
const removeIndicator$ = this.online$.pipe(delay(3000), mapTo(undefined));
this.connectionStatus$ = merge(this.online$, this.offline$, removeIndicator$).pipe(map(event => event?.type));
}
set(error: HttpErrorResponse): void {
this._loadingService.stop();
this.error$.next(error);
}
setOnline(): void {
this._online$.next();
}
clear(): void {
this.error$.next();
}
private _offline() {
return merge(fromEvent(window, 'offline'), this.error$.pipe(filter(isOffline), mapTo(new Event('offline')), shareLast()));
}
private _online() {
return merge(fromEvent(window, 'online'), this._online$.pipe(mapTo(new Event('online')))).pipe(shareLast());
}
}