phase-4: add provider-abstracted ConfigService with mock bootstrap loader

This commit is contained in:
sdarbinyan
2026-07-03 01:32:43 +04:00
parent 0f1ebbab7e
commit 3b2c1048c9
5 changed files with 81 additions and 0 deletions

View File

@@ -0,0 +1,16 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { BootstrapConfig } from '../../../shared/models/config';
import { ConfigProvider } from '../../config/config-provider.interface';
@Injectable({ providedIn: 'root' })
export class ApiBootstrapProvider implements ConfigProvider {
private readonly bootstrapUrl = '/bootstrap';
constructor(private readonly http: HttpClient) {}
loadBootstrap(): Observable<BootstrapConfig> {
return this.http.get<BootstrapConfig>(this.bootstrapUrl);
}
}

View File

@@ -0,0 +1,16 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { BootstrapConfig } from '../../../shared/models/config';
import { ConfigProvider } from '../../config/config-provider.interface';
@Injectable({ providedIn: 'root' })
export class MockBootstrapProvider implements ConfigProvider {
private readonly bootstrapUrl = '/assets/mock/bootstrap/bootstrap.json';
constructor(private readonly http: HttpClient) {}
loadBootstrap(): Observable<BootstrapConfig> {
return this.http.get<BootstrapConfig>(this.bootstrapUrl);
}
}

View File

@@ -0,0 +1,6 @@
import { Observable } from 'rxjs';
import { BootstrapConfig } from '../../shared/models/config';
export interface ConfigProvider {
loadBootstrap(): Observable<BootstrapConfig>;
}

View File

@@ -0,0 +1,8 @@
import { InjectionToken, inject } from '@angular/core';
import { ConfigProvider } from './config-provider.interface';
import { MockBootstrapProvider } from '../bootstrap/providers/mock-bootstrap.provider';
export const CONFIG_PROVIDER = new InjectionToken<ConfigProvider>('CONFIG_PROVIDER', {
providedIn: 'root',
factory: () => inject(MockBootstrapProvider)
});

View File

@@ -0,0 +1,35 @@
import { Injectable, inject } from '@angular/core';
import { Observable, throwError } from 'rxjs';
import { catchError, shareReplay, tap } from 'rxjs/operators';
import { BootstrapConfig } from '../../shared/models/config';
import { CONFIG_PROVIDER } from './config-provider.token';
@Injectable({ providedIn: 'root' })
export class ConfigService {
private readonly provider = inject(CONFIG_PROVIDER);
private bootstrapSnapshot: BootstrapConfig | null = null;
private bootstrap$?: Observable<BootstrapConfig>;
loadBootstrap(forceRefresh: boolean = false): Observable<BootstrapConfig> {
if (!this.bootstrap$ || forceRefresh) {
this.bootstrap$ = this.provider.loadBootstrap().pipe(
tap(config => {
this.bootstrapSnapshot = config;
}),
shareReplay(1),
catchError(error => {
this.bootstrap$ = undefined;
this.bootstrapSnapshot = null;
return throwError(() => error);
})
);
}
return this.bootstrap$;
}
getBootstrapSnapshot(): BootstrapConfig | null {
return this.bootstrapSnapshot;
}
}