116 lines
3.7 KiB
TypeScript
116 lines
3.7 KiB
TypeScript
import {Action, Selector, State, StateContext} from '@ngxs/store';
|
|
import {Injectable} from '@angular/core';
|
|
import {ConfigService} from '../services/config.service';
|
|
import {catchError, map, tap} from 'rxjs/operators';
|
|
import {forkJoin, Observable, of} from 'rxjs';
|
|
import {Service, Status} from '../interfaces/services.interface';
|
|
import {CheckAllServicesStatus, CheckSpecifiedServiceStatus, LoadConfig} from './service-status.action';
|
|
import {CheckServiceStatusService} from '../check-service-status.service';
|
|
|
|
export interface ServiceStatusModel {
|
|
config: any | null;
|
|
loading: boolean;
|
|
error: any | null;
|
|
services: Service[];
|
|
}
|
|
|
|
@State<ServiceStatusModel>({
|
|
name: 'serviceStatus',
|
|
defaults: {
|
|
config: null,
|
|
loading: false,
|
|
error: null,
|
|
services: []
|
|
}
|
|
})
|
|
@Injectable({providedIn: 'root'})
|
|
export class ServiceStatusState {
|
|
constructor(private configService: ConfigService, private checkServiceStatus: CheckServiceStatusService) {
|
|
}
|
|
|
|
@Selector()
|
|
static config(state: ServiceStatusModel) {
|
|
return state.config;
|
|
}
|
|
|
|
@Selector()
|
|
static loading(state: ServiceStatusModel) {
|
|
return state.loading;
|
|
}
|
|
|
|
@Selector()
|
|
static error(state: ServiceStatusModel) {
|
|
return state.error;
|
|
}
|
|
|
|
@Selector()
|
|
static services(state: ServiceStatusModel): Service[] {
|
|
return state.services;
|
|
}
|
|
|
|
@Action(LoadConfig)
|
|
loadConfig(ctx: StateContext<ServiceStatusModel>): Observable<any> {
|
|
ctx.patchState({loading: true, error: null});
|
|
return this.configService.getConfig().pipe(
|
|
tap((data) => {
|
|
ctx.patchState({config: data, loading: false});
|
|
}),
|
|
catchError((err) => {
|
|
ctx.patchState({error: err, loading: false});
|
|
return of(null);
|
|
})
|
|
);
|
|
}
|
|
|
|
@Action(CheckAllServicesStatus)
|
|
checkServicesStatus(ctx: StateContext<ServiceStatusModel>) {
|
|
const config = ctx.getState().config;
|
|
|
|
if (!config || !Array.isArray(config)) {
|
|
ctx.patchState({ services: [], loading: false });
|
|
return;
|
|
}
|
|
|
|
const currentServices = ctx.getState().services;
|
|
const initialServices = config.map((service: Service) => {
|
|
const existing = currentServices.find(s => s.name === service.name);
|
|
return existing
|
|
? { ...existing, status: 'loading' }
|
|
: { ...service, status: 'loading' };
|
|
});
|
|
|
|
ctx.patchState({ services: initialServices, loading: true });
|
|
|
|
const statusObservables = config.map((service: Service) =>
|
|
this.checkServiceStatus.checkStatus(service.name, service.url, service.headers).pipe(
|
|
map((status: Status) => ({ ...service, status, lastChecked: Date.now() }))
|
|
)
|
|
);
|
|
return forkJoin(statusObservables).pipe(
|
|
tap((services: Service[]) => {
|
|
ctx.patchState({ services, loading: false });
|
|
})
|
|
);
|
|
}
|
|
|
|
@Action(CheckSpecifiedServiceStatus)
|
|
checkSpecifiedServiceStatus(ctx: StateContext<ServiceStatusModel>, action: CheckSpecifiedServiceStatus) {
|
|
const config = ctx.getState().config;
|
|
if (!config || !Array.isArray(config)) return;
|
|
const service = config.find((s: Service) => s.name === action.serviceName);
|
|
if (!service) return;
|
|
const services = ctx.getState().services.slice();
|
|
const index = services.findIndex(s => s.name === action.serviceName);
|
|
if (index !== -1) {
|
|
services[index] = { ...services[index], status: 'loading' };
|
|
ctx.patchState({ services });
|
|
}
|
|
this.checkServiceStatus.checkStatus(service.name, service.url, service.headers).subscribe((status: Status) => {
|
|
const updatedServices = ctx.getState().services.map(s =>
|
|
s.name === action.serviceName ? { ...s, status, lastChecked: Date.now() } : s
|
|
);
|
|
ctx.patchState({ services: updatedServices });
|
|
});
|
|
}
|
|
}
|