From 750c76cdba16f6c4a3cf14fc7c3416ec0050bd3c Mon Sep 17 00:00:00 2001 From: DimaDemchenko Date: Mon, 19 Aug 2024 11:03:20 +0300 Subject: [PATCH] refactor: Implemented segments-storage interface --- .../src/hybrid-loader.ts | 21 +++++-- .../p2p-media-loader-core/src/p2p/loader.ts | 6 +- .../src/segments-storage.ts | 56 +++++-------------- .../segments-storage.interface.ts | 29 ++++++++++ .../src/segments-storage/segments-types.ts | 14 +++++ .../src/segments-storage/utils.ts | 24 ++++++++ 6 files changed, 97 insertions(+), 53 deletions(-) create mode 100644 packages/p2p-media-loader-core/src/segments-storage/segments-storage.interface.ts create mode 100644 packages/p2p-media-loader-core/src/segments-storage/segments-types.ts create mode 100644 packages/p2p-media-loader-core/src/segments-storage/utils.ts diff --git a/packages/p2p-media-loader-core/src/hybrid-loader.ts b/packages/p2p-media-loader-core/src/hybrid-loader.ts index 83744337..f78dda44 100644 --- a/packages/p2p-media-loader-core/src/hybrid-loader.ts +++ b/packages/p2p-media-loader-core/src/hybrid-loader.ts @@ -1,9 +1,5 @@ import { HttpRequestExecutor } from "./http-loader.js"; -import { - createSegmentInfoItem, - getStorageItemId, - SegmentsMemoryStorage, -} from "./segments-storage.js"; +import { SegmentsMemoryStorage } from "./segments-storage.js"; import { CoreEventMap, EngineCallbacks, @@ -26,6 +22,11 @@ import * as Utils from "./utils/utils.js"; import debug from "debug"; import { QueueItem } from "./utils/queue.js"; import { EventTarget } from "./utils/event-target.js"; +import { + createSegmentDataItem, + createSegmentInfoItem, + getStorageItemId, +} from "./segments-storage/utils.js"; const FAILED_ATTEMPTS_CLEAR_INTERVAL = 60000; const PEER_UPDATE_LATENCY = 1000; @@ -223,10 +224,18 @@ export class HybridLoader { streamId, segment.externalId, ); + const segmentDataItem = createSegmentDataItem( + getStorageItemId(streamSwarmId, segment.externalId), + request.data, + now, + streamId, + segment.externalId, + streamSwarmId, + ); void this.segmentStorage.storeSegment( segmentInfoItem, - request.data, + segmentDataItem, this.streamDetails.isLive, ); break; diff --git a/packages/p2p-media-loader-core/src/p2p/loader.ts b/packages/p2p-media-loader-core/src/p2p/loader.ts index bc7c9637..ecff1870 100644 --- a/packages/p2p-media-loader-core/src/p2p/loader.ts +++ b/packages/p2p-media-loader-core/src/p2p/loader.ts @@ -5,15 +5,13 @@ import { StreamConfig, StreamWithSegments, } from "../types.js"; -import { - getStorageItemId, - SegmentsMemoryStorage, -} from "../segments-storage.js"; +import { SegmentsMemoryStorage } from "../segments-storage.js"; import { RequestsContainer } from "../requests/request-container.js"; import { P2PTrackerClient } from "./tracker-client.js"; import * as StreamUtils from "../utils/stream.js"; import * as Utils from "../utils/utils.js"; import { EventTarget } from "../utils/event-target.js"; +import { getStorageItemId } from "../segments-storage/utils.js"; export class P2PLoader { private readonly trackerClient: P2PTrackerClient; diff --git a/packages/p2p-media-loader-core/src/segments-storage.ts b/packages/p2p-media-loader-core/src/segments-storage.ts index bc4db35c..0addfe23 100644 --- a/packages/p2p-media-loader-core/src/segments-storage.ts +++ b/packages/p2p-media-loader-core/src/segments-storage.ts @@ -1,43 +1,21 @@ import { CommonCoreConfig } from "./types.js"; import debug from "debug"; import { EventTarget } from "./utils/event-target.js"; +import { ISegmentsStorage } from "./segments-storage/segments-storage.interface.js"; +import { + SegmentDataItem, + SegmentInfoItem, +} from "./segments-storage/segments-types.js"; type StorageConfig = CommonCoreConfig; -export function getStorageItemId(streamSwarmId: string, externalId: number) { - return `${streamSwarmId}|${externalId}`; -} - -export function createSegmentInfoItem( - streamSwarmId: string, - streamId: string, - externalId: number, -): SegmentInfoItem { - return { streamSwarmId, streamId, externalId }; -} - -type SegmentInfoItem = { - streamSwarmId: string; - streamId: string; - externalId: number; -}; - -type SegmentDataItem = { - storageId: string; - data: ArrayBuffer; - lastAccessed: number; - streamId: string; - externalId: number; - streamSwarmId: string; -}; - type StorageEventHandlers = { [key in `onStorageUpdated-${string}`]: () => void; }; const DEFAULT_LIVE_CACHED_SEGMENT_EXPIRATION = 1200; -export class SegmentsMemoryStorage { +export class SegmentsMemoryStorage implements ISegmentsStorage { private cache = new Map(); private cacheMap = new Map>(); private _isInitialized = false; @@ -74,11 +52,11 @@ export class SegmentsMemoryStorage { // eslint-disable-next-line @typescript-eslint/require-await async storeSegment( - segment: SegmentInfoItem, - data: ArrayBuffer, + segmentInfoItem: SegmentInfoItem, + segmentDataItem: SegmentDataItem, isLiveStream: boolean, ) { - const { streamId, externalId, streamSwarmId } = segment; + const { streamId, externalId, streamSwarmId } = segmentInfoItem; if (!this.cacheMap.has(streamSwarmId)) { this.cacheMap.set(streamSwarmId, new Map()); @@ -88,18 +66,10 @@ export class SegmentsMemoryStorage { if (streamCache === undefined) return; - streamCache.set(externalId, segment); - - const storageId = getStorageItemId(streamSwarmId, externalId); - this.cache.set(storageId, { - storageId, - data, - lastAccessed: performance.now(), - streamId, - externalId, - streamSwarmId, - }); - this.logger(`add segment: ${storageId}`); + streamCache.set(externalId, segmentInfoItem); + + this.cache.set(segmentDataItem.storageId, segmentDataItem); + this.logger(`add segment: ${segmentDataItem.storageId}`); this.dispatchStorageUpdatedEvent(streamId); void this.clear(isLiveStream); } diff --git a/packages/p2p-media-loader-core/src/segments-storage/segments-storage.interface.ts b/packages/p2p-media-loader-core/src/segments-storage/segments-storage.interface.ts new file mode 100644 index 00000000..3db9580a --- /dev/null +++ b/packages/p2p-media-loader-core/src/segments-storage/segments-storage.interface.ts @@ -0,0 +1,29 @@ +import { SegmentDataItem, SegmentInfoItem } from "./segments-types.js"; + +export interface ISegmentsStorage { + readonly isInitialized: boolean; + + initialize(): Promise; + + addIsSegmentLockedPredicate( + predicate: (segment: SegmentInfoItem) => boolean, + ): void; + + storeSegment( + segmentInfoItem: SegmentInfoItem, + segmentDataItem: SegmentDataItem, + isLiveStream: boolean, + ): Promise; + + getSegmentData(segmentStorageId: string): Promise; + + hasSegment(segmentStorageId: string): boolean; + + getStoredSegmentExternalIdsOfStream(streamSwarmId: string): number[]; + + subscribeOnUpdate(streamId: string, listener: () => void): void; + + unsubscribeFromUpdate(streamId: string, listener: () => void): void; + + destroy(): Promise; +} diff --git a/packages/p2p-media-loader-core/src/segments-storage/segments-types.ts b/packages/p2p-media-loader-core/src/segments-storage/segments-types.ts new file mode 100644 index 00000000..bcf7d66d --- /dev/null +++ b/packages/p2p-media-loader-core/src/segments-storage/segments-types.ts @@ -0,0 +1,14 @@ +export type SegmentInfoItem = { + streamSwarmId: string; + streamId: string; + externalId: number; +}; + +export type SegmentDataItem = { + storageId: string; + data: ArrayBuffer; + lastAccessed: number; + streamId: string; + externalId: number; + streamSwarmId: string; +}; diff --git a/packages/p2p-media-loader-core/src/segments-storage/utils.ts b/packages/p2p-media-loader-core/src/segments-storage/utils.ts new file mode 100644 index 00000000..b51bb249 --- /dev/null +++ b/packages/p2p-media-loader-core/src/segments-storage/utils.ts @@ -0,0 +1,24 @@ +import { SegmentDataItem, SegmentInfoItem } from "./segments-types.js"; + +export function getStorageItemId(streamSwarmId: string, externalId: number) { + return `${streamSwarmId}|${externalId}`; +} + +export function createSegmentInfoItem( + streamSwarmId: string, + streamId: string, + externalId: number, +): SegmentInfoItem { + return { streamSwarmId, streamId, externalId }; +} + +export function createSegmentDataItem( + storageId: string, + data: ArrayBuffer, + lastAccessed: number, + streamId: string, + externalId: number, + streamSwarmId: string, +): SegmentDataItem { + return { storageId, data, lastAccessed, streamId, externalId, streamSwarmId }; +}