Add experimental metrics insights, comparisons, and scope filters
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
import { DEFAULT_TIME_ZONE, validTimeZone } from './time-zone.js';
|
||||
|
||||
export type MetricsDays = 1 | 7 | 30;
|
||||
|
||||
export function parseMetricsDays(value: string | null | undefined): MetricsDays {
|
||||
@@ -5,6 +7,28 @@ export function parseMetricsDays(value: string | null | undefined): MetricsDays
|
||||
return days === 1 || days === 7 || days === 30 ? days : 7;
|
||||
}
|
||||
|
||||
export interface MetricsScope {
|
||||
game: string | null;
|
||||
map: string | null;
|
||||
timeZone: string;
|
||||
}
|
||||
|
||||
export interface MetricsQuery extends MetricsScope {
|
||||
days: MetricsDays;
|
||||
}
|
||||
|
||||
/** A map is an exact recorded label within a game, never a cross-game match. */
|
||||
export function parseMetricsQuery(params: URLSearchParams): MetricsQuery {
|
||||
const requestedGame = params.get('game')?.trim() ?? '';
|
||||
const game = /^[a-z0-9_-]{1,32}$/.test(requestedGame) ? requestedGame : null;
|
||||
const requestedMap = params.get('map');
|
||||
const map = game && requestedMap && requestedMap.trim() && requestedMap.length <= 200 && !/[\u0000-\u001f\u007f]/.test(requestedMap)
|
||||
? requestedMap : null;
|
||||
const requestedZone = params.get('timeZone');
|
||||
return { days: parseMetricsDays(params.get('days')), game, map,
|
||||
timeZone: validTimeZone(requestedZone) ? requestedZone : DEFAULT_TIME_ZONE };
|
||||
}
|
||||
|
||||
/** All durations are hours. Observed is known server time, not collection coverage. */
|
||||
export interface Utilization {
|
||||
observed: number;
|
||||
@@ -16,6 +40,8 @@ export interface Utilization {
|
||||
|
||||
export interface ServerMetrics extends Utilization {
|
||||
server: string;
|
||||
/** A current registration with this name exists; historical identity may differ. */
|
||||
currentRegistered: boolean;
|
||||
}
|
||||
|
||||
export interface MapMetrics extends Utilization {
|
||||
@@ -34,6 +60,33 @@ export interface MetricPoint extends Utilization {
|
||||
partial: boolean;
|
||||
}
|
||||
|
||||
export interface PreviousMetrics {
|
||||
since: number;
|
||||
until: number;
|
||||
summary: Utilization;
|
||||
firstSampleAt: number | null;
|
||||
lastSampleAt: number | null;
|
||||
/** Retained scope evidence starts late or is absent, not a completeness guarantee. */
|
||||
partialHistory: boolean;
|
||||
}
|
||||
|
||||
export interface HeatmapCell extends Utilization {
|
||||
/** Monday = 0, Sunday = 6. */
|
||||
weekday: number;
|
||||
hour: number;
|
||||
/** Distinct local dates with any captured time, including unknown status. */
|
||||
distinctDates: number;
|
||||
}
|
||||
|
||||
export interface PooledPressure {
|
||||
/** Share of known map-hours with every tracked lobby full, from 0 to 100. */
|
||||
value: number | null;
|
||||
fullMapHours: number;
|
||||
knownMapHours: number;
|
||||
coveredMaps: number;
|
||||
totalMaps: number;
|
||||
}
|
||||
|
||||
export interface MetricsData {
|
||||
days: MetricsDays;
|
||||
since: number;
|
||||
@@ -42,8 +95,15 @@ export interface MetricsData {
|
||||
firstRetainedSampleAt: number | null;
|
||||
latestSampleAt: number | null;
|
||||
registeredServerCount: number;
|
||||
scope: MetricsScope;
|
||||
scopeOptions: { games: string[]; maps: { game: string; map: string }[] };
|
||||
scopeFirstSampleAt: number | null;
|
||||
scopeLatestSampleAt: number | null;
|
||||
summary: Utilization;
|
||||
servers: ServerMetrics[];
|
||||
maps: MapMetrics[];
|
||||
points: MetricPoint[];
|
||||
previous: PreviousMetrics;
|
||||
heatmap: { timeZone: string; cells: HeatmapCell[] };
|
||||
pooledPressure: PooledPressure;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user