feat(stalker): bootstrap main session runtime

This commit is contained in:
4gray committed 2026-07-27 11:36:52 +02:00
1 parent 68d1555975
commit dfdce824d9
3 files changed
+127 -1

No files matched your search

@@ -0,0 +1,68 @@
import {
STALKER_SESSION_FAILURE_REASONS,
type StalkerSessionConnectionDescriptor,
} from '@iptvnator/shared/interfaces';
import type { DatabaseWorkerClient } from '../database-worker-client';
import {
createStalkerPlaylistReader,
createStalkerSessionManager,
} from './stalker-session-runtime';
const descriptor: StalkerSessionConnectionDescriptor = {
connectionMode: 'persisted-open',
macAddress: '00:1A:79:AA:BB:CC',
playlistRef: 'playlist-7',
profilePreset: {
id: 'mag250-public-5_1-minimal-v1',
version: 1,
},
sourceUrl: 'https://portal.test/c/',
};
describe('Stalker session runtime', () => {
it('loads a playlist through the non-EPG database worker contract', async () => {
const request = jest.fn().mockResolvedValue({ _id: 'playlist-7' });
const readPlaylist = createStalkerPlaylistReader({
request,
} as unknown as Pick<DatabaseWorkerClient, 'request'>);
await expect(readPlaylist('playlist-7')).resolves.toEqual({
_id: 'playlist-7',
});
expect(request).toHaveBeenCalledWith('DB_GET_APP_PLAYLIST', {
playlistId: 'playlist-7',
});
});
it('consults worker-backed saved credentials before resolving a persisted connection', async () => {
const request = jest.fn().mockResolvedValue({
_id: 'playlist-7',
macAddress: descriptor.macAddress,
password: 'saved-password',
portalUrl: descriptor.sourceUrl,
type: 'stalker',
username: 'saved-user',
});
const resolve = jest.fn().mockResolvedValue({
kind: 'failure',
reason: STALKER_SESSION_FAILURE_REASONS.EndpointNotFound,
retryable: false,
stage: 'resolving',
});
const manager = createStalkerSessionManager({
databaseWorker: {
request,
} as unknown as Pick<DatabaseWorkerClient, 'request'>,
resolver: { resolve },
});
await expect(manager.open(1, { descriptor })).resolves.toMatchObject({
kind: 'failure',
reason: STALKER_SESSION_FAILURE_REASONS.EndpointNotFound,
});
expect(request).toHaveBeenCalledWith('DB_GET_APP_PLAYLIST', {
playlistId: 'playlist-7',
});
expect(resolve).toHaveBeenCalledTimes(1);
});
});
@@ -0,0 +1,51 @@
import {
databaseWorkerClient,
type DatabaseWorkerClient,
} from '../database-worker-client';
import { stalkerPlaybackContextService } from '../stalker-playback-context.service';
import { mapRawOperation } from './stalker-operation-adapter';
import { createStalkerSavedCredentialsLoader } from './stalker-saved-credentials';
import {
StalkerSessionManager,
type StalkerSessionManagerDependencies,
type StalkerSessionPlaybackContextPort,
} from './stalker-session-manager';
type StalkerDatabaseWorker = Pick<DatabaseWorkerClient, 'request'>;
export type StalkerSessionRuntimeDependencies = Omit<
StalkerSessionManagerDependencies,
'loadSavedCredentials' | 'mapRawOperation' | 'playbackContexts'
> & {
readonly databaseWorker?: StalkerDatabaseWorker;
readonly playbackContexts?: StalkerSessionPlaybackContextPort;
};
export function createStalkerPlaylistReader(
databaseWorker: StalkerDatabaseWorker = databaseWorkerClient
): (playlistRef: string) => Promise<unknown> {
return (playlistRef) =>
databaseWorker.request('DB_GET_APP_PLAYLIST', {
playlistId: playlistRef,
});
}
export function createStalkerSessionManager(
dependencies: StalkerSessionRuntimeDependencies = {}
): StalkerSessionManager {
const {
databaseWorker = databaseWorkerClient,
playbackContexts = stalkerPlaybackContextService,
...managerDependencies
} = dependencies;
return new StalkerSessionManager({
...managerDependencies,
loadSavedCredentials: createStalkerSavedCredentialsLoader(
createStalkerPlaylistReader(databaseWorker)
),
mapRawOperation,
playbackContexts,
});
}
export const stalkerSessionManager = createStalkerSessionManager();
+8 -1
View File
@@ -24,10 +24,12 @@ import SettingsEvents from './app/events/settings.events';
import SharedEvents from './app/events/shared.events';
import SquirrelEvents from './app/events/squirrel.events';
import StalkerEvents from './app/events/stalker.events';
import StalkerSessionEvents from './app/events/stalker-session.events';
import { isStartupTraceEnabled, trace } from './app/services/debug-trace';
import { registerStaticHeaderShims } from './app/services/request-header-overrides.service';
import { AppUpdateService } from './app/services/app-update.service';
import { databaseWorkerClient } from './app/services/database-worker-client';
import { stalkerSessionManager } from './app/services/stalker-session/stalker-session-runtime';
import WindowEvents from './app/events/window.events';
import XtreamEvents from './app/events/xtream.events';
import { environment } from './environments/environment';
@@ -142,6 +144,9 @@ export default class Main {
SharedEvents.bootstrapSharedEvents();
PlayerEvents.bootstrapPlayerEvents();
SettingsEvents.bootstrapSettingsEvents();
StalkerSessionEvents.bootstrapStalkerSessionEvents(
stalkerSessionManager
);
StalkerEvents.bootstrapStalkerEvents();
XtreamEvents.bootstrapXtreamEvents();
DatabaseEvents.bootstrapDatabaseEvents();
@@ -209,6 +214,8 @@ runEmbeddedMpvRuntimeDiagnosticOrContinue(process.argv, () => {
shutdownEmbeddedMpv();
shutdownMpvSession();
shutdownVlcSession();
void databaseWorkerClient.shutdown();
void stalkerSessionManager
.destroyAll()
.finally(() => databaseWorkerClient.shutdown());
});
});