From 1a0f65a2c979374a48b3c35aeee5e45cffe6267b Mon Sep 17 00:00:00 2001 From: DimaDemchenko Date: Fri, 6 Sep 2024 16:07:33 +0300 Subject: [PATCH] refactor: Update SegmentsStorage interface --- .eslintrc.common.cjs | 2 + packages/p2p-media-loader-core/src/core.ts | 10 +++-- .../src/hybrid-loader.ts | 45 +++++++++++++------ .../p2p-media-loader-core/src/p2p/loader.ts | 14 +++--- .../src/p2p/loaders-container.ts | 8 +++- .../src/segments-storage/index.ts | 24 +++++++--- .../segments-memory-storage.ts | 11 +++-- packages/p2p-media-loader-core/src/types.ts | 4 +- 8 files changed, 81 insertions(+), 37 deletions(-) diff --git a/.eslintrc.common.cjs b/.eslintrc.common.cjs index bbfa562d..a575bd50 100644 --- a/.eslintrc.common.cjs +++ b/.eslintrc.common.cjs @@ -26,5 +26,7 @@ module.exports = { tsx: "never", }, ], + + "@typescript-eslint/no-unused-vars": ["warn", { argsIgnorePattern: "^_" }], }, }; diff --git a/packages/p2p-media-loader-core/src/core.ts b/packages/p2p-media-loader-core/src/core.ts index 409a741c..c2415d0e 100644 --- a/packages/p2p-media-loader-core/src/core.ts +++ b/packages/p2p-media-loader-core/src/core.ts @@ -397,11 +397,13 @@ export class Core { } if (!this.segmentStorage) { - const storageClass = isLive - ? (this.commonCoreConfig.liveSegmentsStorage ?? SegmentsMemoryStorage) - : (this.commonCoreConfig.vodSegmentsStorage ?? SegmentsMemoryStorage); + const createCustomStorage = isLive + ? this.commonCoreConfig.liveSegmentsStorage + : this.commonCoreConfig.vodSegmentsStorage; - const segmentStorage = new storageClass(); + const segmentStorage = createCustomStorage + ? createCustomStorage(isLive) + : new SegmentsMemoryStorage(); await segmentStorage.initialize( this.commonCoreConfig, diff --git a/packages/p2p-media-loader-core/src/hybrid-loader.ts b/packages/p2p-media-loader-core/src/hybrid-loader.ts index 9212ba64..10f5d835 100644 --- a/packages/p2p-media-loader-core/src/hybrid-loader.ts +++ b/packages/p2p-media-loader-core/src/hybrid-loader.ts @@ -106,25 +106,33 @@ export class HybridLoader { segment.externalId, segment.startTime, segment.endTime, + this.config.swarmId ?? this.streamManifestUrl, + stream.type, + this.streamDetails.isLive, ); const engineRequest = new EngineRequest(segment, callbacks); - const streamSwarmId = StreamUtils.getStreamSwarmId( - this.config.swarmId ?? this.streamManifestUrl, - stream, - ); + const swarmId = this.config.swarmId ?? this.streamManifestUrl; + const streamSwarmId = StreamUtils.getStreamSwarmId(swarmId, stream); try { - if (this.segmentStorage.hasSegment(streamSwarmId, segment.externalId)) { + if ( + this.segmentStorage.hasSegment( + streamSwarmId, + segment.externalId, + swarmId, + ) + ) { const data = await this.segmentStorage.getSegmentData( streamSwarmId, segment.externalId, + swarmId, ); if (data) { const { queueDownloadRatio } = this.generateQueue(); engineRequest.resolve(data, this.getBandwidth(queueDownloadRatio)); } - } else { + this.engineRequest = engineRequest; } } catch { @@ -197,10 +205,8 @@ export class HybridLoader { } this.requests.remove(request); - const streamSwarmId = StreamUtils.getStreamSwarmId( - this.config.swarmId ?? this.streamManifestUrl, - stream, - ); + const swarmId = this.config.swarmId ?? this.streamManifestUrl; + const streamSwarmId = StreamUtils.getStreamSwarmId(swarmId, stream); void this.segmentStorage.storeSegment( streamSwarmId, @@ -208,6 +214,7 @@ export class HybridLoader { request.data, segment.startTime, segment.endTime, + swarmId, segment.stream.type, this.streamDetails.isLive, ); @@ -388,15 +395,20 @@ export class HybridLoader { this.config, this.p2pLoaders.currentLoader, )) { + const swarmId = this.config.swarmId ?? this.streamManifestUrl; const streamSwarmId = StreamUtils.getStreamSwarmId( - this.config.swarmId ?? this.streamManifestUrl, + swarmId, segment.stream, ); if ( !statuses.isHttpDownloadable || statuses.isP2PDownloadable || - this.segmentStorage.hasSegment(streamSwarmId, segment.externalId) + this.segmentStorage.hasSegment( + streamSwarmId, + segment.externalId, + swarmId, + ) ) { continue; } @@ -490,13 +502,18 @@ export class HybridLoader { maxPossibleLength++; const { segment } = item; + const swarmId = this.config.swarmId ?? this.streamManifestUrl; const streamSwarmId = StreamUtils.getStreamSwarmId( - this.config.swarmId ?? this.streamManifestUrl, + swarmId, segment.stream, ); if ( - this.segmentStorage.hasSegment(streamSwarmId, segment.externalId) || + this.segmentStorage.hasSegment( + streamSwarmId, + segment.externalId, + swarmId, + ) || this.requests.get(segment)?.status === "succeed" ) { alreadyLoadedCount++; diff --git a/packages/p2p-media-loader-core/src/p2p/loader.ts b/packages/p2p-media-loader-core/src/p2p/loader.ts index 4d786e8d..cc619d9b 100644 --- a/packages/p2p-media-loader-core/src/p2p/loader.ts +++ b/packages/p2p-media-loader-core/src/p2p/loader.ts @@ -89,13 +89,16 @@ export class P2PLoader { } private getSegmentsAnnouncement() { + const swarmId = this.config.swarmId ?? this.streamManifestUrl; const streamSwarmId = StreamUtils.getStreamSwarmId( this.config.swarmId ?? this.streamManifestUrl, this.stream, ); - const loaded: number[] = - this.segmentStorage.getStoredSegmentIds(streamSwarmId); + const loaded: number[] = this.segmentStorage.getStoredSegmentIds( + swarmId, + streamSwarmId, + ); const httpLoading: number[] = []; for (const request of this.requests.httpRequests()) { @@ -137,14 +140,13 @@ export class P2PLoader { ); if (!segment) return; - const streamSwarmId = StreamUtils.getStreamSwarmId( - this.config.swarmId ?? this.streamManifestUrl, - this.stream, - ); + const swarmId = this.config.swarmId ?? this.streamManifestUrl; + const streamSwarmId = StreamUtils.getStreamSwarmId(swarmId, this.stream); const segmentData = await this.segmentStorage.getSegmentData( streamSwarmId, segmentExternalId, + swarmId, ); if (!segmentData) { peer.sendSegmentAbsentCommand(segmentExternalId, requestId); diff --git a/packages/p2p-media-loader-core/src/p2p/loaders-container.ts b/packages/p2p-media-loader-core/src/p2p/loaders-container.ts index 6ff7da0c..ac4dd351 100644 --- a/packages/p2p-media-loader-core/src/p2p/loaders-container.ts +++ b/packages/p2p-media-loader-core/src/p2p/loaders-container.ts @@ -65,11 +65,15 @@ export class P2PLoadersContainer { changeCurrentLoader(stream: StreamWithSegments) { const loaderItem = this.loaders.get(stream.runtimeId); if (this._currentLoaderItem) { + const swarmId = this.config.swarmId ?? this.streamManifestUrl; const streamSwarmId = StreamUtils.getStreamSwarmId( - this.config.swarmId ?? this.streamManifestUrl, + swarmId, this._currentLoaderItem.stream, ); - const ids = this.segmentStorage.getStoredSegmentIds(streamSwarmId); + const ids = this.segmentStorage.getStoredSegmentIds( + swarmId, + streamSwarmId, + ); if (!ids.length) this.destroyAndRemoveLoader(this._currentLoaderItem); else this.setLoaderDestroyTimeout(this._currentLoaderItem); } diff --git a/packages/p2p-media-loader-core/src/segments-storage/index.ts b/packages/p2p-media-loader-core/src/segments-storage/index.ts index 7f245de9..09c5fd49 100644 --- a/packages/p2p-media-loader-core/src/segments-storage/index.ts +++ b/packages/p2p-media-loader-core/src/segments-storage/index.ts @@ -3,7 +3,7 @@ import { CommonCoreConfig, StreamConfig, StreamType } from "../types.js"; export interface SegmentsStorage { /** * Initializes storage - * @param coreConfig - Storage configuration + * @param coreConfig - Core configuration with storage options * @param mainStreamConfig - Main stream configuration * @param secondaryStreamConfig - Secondary stream configuration */ @@ -14,33 +14,40 @@ export interface SegmentsStorage { ): Promise; /** - * Updates playback position + * Provides playback position from player * @param position - Playback position * @param rate - Playback rate */ onPlaybackUpdated(position: number, rate: number): void; /** - * Updates segment request information + * Provides segment request information from player * @param streamId - Stream identifier * @param segmentId - Segment identifier * @param startTime - Segment start time * @param endTime - Segment end time + * @param swarmId - Swarm identifier + * @param streamType - Stream type + * @param isLiveStream - Is live stream */ onSegmentRequested( streamId: string, segmentId: number, startTime: number, endTime: number, + swarmId: string, + streamType: StreamType, + isLiveStream: boolean, ): void; /** - * Stores segment data + * Stores segment data * @param streamId - Stream identifier * @param segmentId - Segment identifier * @param data - Segment data * @param startTime - Segment start time * @param endTime - Segment end time + * @param swarmId - Swarm identifier * @param streamType - Stream type * @param isLiveStream - Is live stream */ @@ -50,6 +57,7 @@ export interface SegmentsStorage { data: ArrayBuffer, startTime: number, endTime: number, + swarmId: string, streamType: StreamType, isLiveStream: boolean, ): Promise; @@ -58,24 +66,28 @@ export interface SegmentsStorage { * Returns segment data * @param streamId - Stream identifier * @param segmentId - Segment identifier + * @param swarmId - Swarm identifier */ getSegmentData( streamId: string, segmentId: number, + swarmId: string, ): Promise; /** * Returns true if segment is in storage * @param streamId - Stream identifier * @param segmentId - Segment identifier + * @param swarmId - Swarm identifier */ - hasSegment(streamId: string, segmentId: number): boolean; + hasSegment(streamId: string, segmentId: number, swarmId: string): boolean; /** * Returns segment IDs of a stream that are stored in the storage * @param streamId - Stream identifier + * @param swarmId - Swarm identifier */ - getStoredSegmentIds(streamId: string): number[]; + getStoredSegmentIds(streamId: string, swarmId: string): number[]; /** * Function to subscribe on stream updates diff --git a/packages/p2p-media-loader-core/src/segments-storage/segments-memory-storage.ts b/packages/p2p-media-loader-core/src/segments-storage/segments-memory-storage.ts index 871de26b..edbc3d52 100644 --- a/packages/p2p-media-loader-core/src/segments-storage/segments-memory-storage.ts +++ b/packages/p2p-media-loader-core/src/segments-storage/segments-memory-storage.ts @@ -1,4 +1,4 @@ -import { CommonCoreConfig, StreamConfig } from "../types.js"; +import { CommonCoreConfig, StreamConfig, StreamType } from "../types.js"; import debug from "debug"; import { EventTarget } from "../utils/event-target.js"; import { SegmentsStorage } from "./index.js"; @@ -69,6 +69,9 @@ export class SegmentsMemoryStorage implements SegmentsStorage { segmentId: number, startTime: number, endTime: number, + _swarmId: string, + _streamType: StreamType, + _isLiveStream: boolean, ): void { this.lastRequestedSegment = { streamId, @@ -85,7 +88,8 @@ export class SegmentsMemoryStorage implements SegmentsStorage { data: ArrayBuffer, startTime: number, endTime: number, - streamType: string, + _swarmId: string, + streamType: StreamType, isLiveStream: boolean, ) { const storageId = getStorageItemId(streamId, segmentId); @@ -107,6 +111,7 @@ export class SegmentsMemoryStorage implements SegmentsStorage { async getSegmentData( streamId: string, segmentId: number, + _swarmId: string, ): Promise { const segmentStorageId = getStorageItemId(streamId, segmentId); const dataItem = this.cache.get(segmentStorageId); @@ -116,7 +121,7 @@ export class SegmentsMemoryStorage implements SegmentsStorage { return dataItem.data; } - hasSegment(streamId: string, externalId: number): boolean { + hasSegment(streamId: string, externalId: number, _swarmId: string): boolean { const segmentStorageId = getStorageItemId(streamId, externalId); const segment = this.cache.get(segmentStorageId); diff --git a/packages/p2p-media-loader-core/src/types.ts b/packages/p2p-media-loader-core/src/types.ts index b6c3674c..740e1948 100644 --- a/packages/p2p-media-loader-core/src/types.ts +++ b/packages/p2p-media-loader-core/src/types.ts @@ -134,7 +134,7 @@ export type CommonCoreConfig = { * vodSegmentsStorage: undefined * ``` */ - vodSegmentsStorage?: new () => SegmentsStorage; + vodSegmentsStorage?: (isLive: boolean) => SegmentsStorage; /** * Custom storage class for live segments. @@ -144,7 +144,7 @@ export type CommonCoreConfig = { * liveSegmentsStorage: undefined * ``` */ - liveSegmentsStorage?: new () => SegmentsStorage; + liveSegmentsStorage?: (isLive: boolean) => SegmentsStorage; }; /**