mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-15 21:56:18 -08:00
test(performance): add end-to-end Xtream benchmark harness (#1300)
* docs(performance): plan Xtream benchmark * feat(xtream-mock-server): add deterministic 100k fixture * style(xtream-mock-server): apply repository formatting * fix(xtream-mock-server): harden performance fixture data * feat(xtream-mock-server): add performance control plane * docs(performance): correct Xtream capture plan * fix(xtream-mock-server): harden performance controls * fix(xtream-mock-server): harden control lifecycle * feat(performance): add Xtream preload markers * feat(performance): trace Xtream main phases * feat(performance): mark Xtream store publications * feat(performance): trace Xtream database phases * feat(performance): trace Xtream delete cancellation * feat(performance): capture Xtream phase attribution * feat(performance): mark Sources Xtream refresh * test(performance): define Xtream benchmark evidence contracts * test(performance): add Xtream benchmark runner * test(performance): surface failure evidence writes * test(performance): align database read clock * test(performance): preserve capture failure contracts
This commit is contained in:
1 parent
5e725a06f3
commit
a2fafcfc08
256 files changed
+43760
-883
No files matched your search
@@ -0,0 +1,109 @@
|
||||
import { XtreamCodeActions } from '@iptvnator/shared/interfaces';
|
||||
|
||||
import {
|
||||
XTREAM_PHASE_SEMANTIC_TYPE as SEMANTIC,
|
||||
type XtreamPhaseSemanticType,
|
||||
} from './xtream-phase-inventory';
|
||||
|
||||
export type XtreamPhaseCategoryType = 'live' | 'movies' | 'series';
|
||||
export type XtreamPhaseContentType = 'live' | 'movie' | 'series';
|
||||
export type XtreamPhaseProviderAction =
|
||||
| XtreamCodeActions.GetAccountInfo
|
||||
| XtreamCodeActions.GetLiveCategories
|
||||
| XtreamCodeActions.GetLiveStreams
|
||||
| XtreamCodeActions.GetSeries
|
||||
| XtreamCodeActions.GetSeriesCategories
|
||||
| XtreamCodeActions.GetVodCategories
|
||||
| XtreamCodeActions.GetVodStreams;
|
||||
|
||||
export interface XtreamPhaseSemanticSource {
|
||||
readonly categoryType: XtreamPhaseCategoryType | null;
|
||||
readonly contentType: XtreamPhaseContentType | null;
|
||||
readonly providerAction: XtreamPhaseProviderAction | null;
|
||||
}
|
||||
|
||||
const ACTION_SEMANTICS = new Map<string, XtreamPhaseSemanticType>([
|
||||
[XtreamCodeActions.GetAccountInfo, SEMANTIC.ACCOUNT],
|
||||
[XtreamCodeActions.GetLiveCategories, SEMANTIC.LIVE_CATEGORIES],
|
||||
[XtreamCodeActions.GetVodCategories, SEMANTIC.VOD_CATEGORIES],
|
||||
[XtreamCodeActions.GetSeriesCategories, SEMANTIC.SERIES_CATEGORIES],
|
||||
[XtreamCodeActions.GetLiveStreams, SEMANTIC.LIVE_CONTENT],
|
||||
[XtreamCodeActions.GetVodStreams, SEMANTIC.VOD_CONTENT],
|
||||
[XtreamCodeActions.GetSeries, SEMANTIC.SERIES_CONTENT],
|
||||
]);
|
||||
const CATEGORY_SEMANTICS = new Map<string, XtreamPhaseSemanticType>([
|
||||
['live', SEMANTIC.LIVE_CATEGORIES],
|
||||
['movies', SEMANTIC.VOD_CATEGORIES],
|
||||
['series', SEMANTIC.SERIES_CATEGORIES],
|
||||
]);
|
||||
const CONTENT_SEMANTICS = new Map<string, XtreamPhaseSemanticType>([
|
||||
['live', SEMANTIC.LIVE_CONTENT],
|
||||
['movie', SEMANTIC.VOD_CONTENT],
|
||||
['series', SEMANTIC.SERIES_CONTENT],
|
||||
]);
|
||||
|
||||
export function semanticTypeFromXtreamPhaseSource(
|
||||
source: Readonly<Record<keyof XtreamPhaseSemanticSource, unknown>>
|
||||
): XtreamPhaseSemanticType | null | undefined {
|
||||
const populated = [
|
||||
source.providerAction,
|
||||
source.categoryType,
|
||||
source.contentType,
|
||||
].filter((value) => value !== null);
|
||||
if (populated.length === 0) return null;
|
||||
if (populated.length !== 1) return undefined;
|
||||
if (source.providerAction !== null) {
|
||||
return typeof source.providerAction === 'string'
|
||||
? ACTION_SEMANTICS.get(source.providerAction)
|
||||
: undefined;
|
||||
}
|
||||
if (source.categoryType !== null) {
|
||||
return typeof source.categoryType === 'string'
|
||||
? CATEGORY_SEMANTICS.get(source.categoryType)
|
||||
: undefined;
|
||||
}
|
||||
return typeof source.contentType === 'string'
|
||||
? CONTENT_SEMANTICS.get(source.contentType)
|
||||
: undefined;
|
||||
}
|
||||
|
||||
export function xtreamDataSemanticSource(
|
||||
semanticType: XtreamPhaseSemanticType | null
|
||||
): XtreamPhaseSemanticSource {
|
||||
switch (semanticType) {
|
||||
case SEMANTIC.LIVE_CATEGORIES:
|
||||
return source(null, 'live', null);
|
||||
case SEMANTIC.VOD_CATEGORIES:
|
||||
return source(null, 'movies', null);
|
||||
case SEMANTIC.SERIES_CATEGORIES:
|
||||
return source(null, 'series', null);
|
||||
case SEMANTIC.LIVE_CONTENT:
|
||||
return source(null, null, 'live');
|
||||
case SEMANTIC.VOD_CONTENT:
|
||||
return source(null, null, 'movie');
|
||||
case SEMANTIC.SERIES_CONTENT:
|
||||
return source(null, null, 'series');
|
||||
case SEMANTIC.ACCOUNT:
|
||||
throw new Error('account has no database semantic source');
|
||||
case null:
|
||||
return source(null, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
export function xtreamProviderSemanticSource(
|
||||
semanticType: XtreamPhaseSemanticType
|
||||
): XtreamPhaseSemanticSource {
|
||||
const action = [...ACTION_SEMANTICS].find(
|
||||
([, mapped]) => mapped === semanticType
|
||||
)?.[0];
|
||||
if (!action) throw new Error('invalid provider semantic type');
|
||||
return source(action as XtreamPhaseProviderAction, null, null);
|
||||
}
|
||||
|
||||
function source(
|
||||
providerAction: XtreamPhaseProviderAction | null,
|
||||
categoryType: XtreamPhaseCategoryType | null,
|
||||
contentType: XtreamPhaseContentType | null
|
||||
): XtreamPhaseSemanticSource {
|
||||
return Object.freeze({ categoryType, contentType, providerAction });
|
||||
}
|
||||
Reference in new issue
Block a user