86 lines
2.6 KiB
TypeScript
86 lines
2.6 KiB
TypeScript
import { Injectable, inject } from '@angular/core';
|
|
import { SERVER_HEALTH_CHECK_TIMEOUT_MS } from '../constants/server-directory.infrastructure.constants';
|
|
import type {
|
|
ServerEndpoint,
|
|
ServerEndpointHealthResult,
|
|
ServerHealthCheckPayload
|
|
} from '../../domain/models/server-directory.model';
|
|
import { ServerEndpointCompatibilityService } from './server-endpoint-compatibility.service';
|
|
|
|
@Injectable({ providedIn: 'root' })
|
|
export class ServerEndpointHealthService {
|
|
private readonly endpointCompatibility = inject(ServerEndpointCompatibilityService);
|
|
|
|
async probeEndpoint(
|
|
endpoint: Pick<ServerEndpoint, 'url'>,
|
|
clientVersion: string | null
|
|
): Promise<ServerEndpointHealthResult> {
|
|
const startTime = Date.now();
|
|
|
|
try {
|
|
const response = await fetch(`${endpoint.url}/api/health`, {
|
|
method: 'GET',
|
|
signal: AbortSignal.timeout(SERVER_HEALTH_CHECK_TIMEOUT_MS)
|
|
});
|
|
const latency = Date.now() - startTime;
|
|
|
|
if (response.ok) {
|
|
const payload = await response.json() as ServerHealthCheckPayload;
|
|
const versionCompatibility = this.endpointCompatibility.evaluateServerVersion(
|
|
payload.serverVersion,
|
|
clientVersion
|
|
);
|
|
const serverInstanceId = typeof payload.serverInstanceId === 'string' && payload.serverInstanceId.trim().length > 0
|
|
? payload.serverInstanceId.trim()
|
|
: undefined;
|
|
const serverTag = typeof payload.serverTag === 'string' && payload.serverTag.trim().length > 0
|
|
? payload.serverTag.trim()
|
|
: undefined;
|
|
|
|
if (!versionCompatibility.isCompatible) {
|
|
return {
|
|
status: 'incompatible',
|
|
latency,
|
|
serverTag,
|
|
versions: {
|
|
serverInstanceId,
|
|
serverVersion: versionCompatibility.serverVersion,
|
|
clientVersion
|
|
}
|
|
};
|
|
}
|
|
|
|
return {
|
|
status: 'online',
|
|
latency,
|
|
serverTag,
|
|
versions: {
|
|
serverInstanceId,
|
|
serverVersion: versionCompatibility.serverVersion,
|
|
clientVersion
|
|
}
|
|
};
|
|
}
|
|
|
|
return { status: 'offline' };
|
|
} catch {
|
|
try {
|
|
const response = await fetch(`${endpoint.url}/api/servers`, {
|
|
method: 'GET',
|
|
signal: AbortSignal.timeout(SERVER_HEALTH_CHECK_TIMEOUT_MS)
|
|
});
|
|
const latency = Date.now() - startTime;
|
|
|
|
if (response.ok) {
|
|
return {
|
|
status: 'online',
|
|
latency
|
|
};
|
|
}
|
|
} catch { /* both checks failed */ }
|
|
|
|
return { status: 'offline' };
|
|
}
|
|
}
|
|
}
|