export interface Segment { start : number ; end : number ; } export interface SegmentPolicy { computeSegments ( contentLength ) : Segment [ ] ; } export function isSegmentPolicy ( segmentOptions ? ) { if ( ! segmentOptions ) { return false ; } return "computeSegments" in segmentOptions && typeof segmentOptions . computeSegments === "function" ; } export function resolveSegmentPolicy ( segmentOptions ? ) { if ( isSegmentPolicy ( segmentOptions ) ) { return segmentOptions ; } return new DefaultSegmentPolicy ( segmentOptions ?. segmentThreshold ?? 2 * 1000000 , 4 ) ; } export interface DefaultSegmentPolicyOptions { default segmentThreshold ? : number ; } export class DefaultSegmentPolicy implements SegmentPolicy { constructor ( readonly segmentThreshold , readonly concurrency ) { } computeSegments ( total ) { const { segmentThreshold : chunkSize , concurrency } = this ; const partSize = Math . max ( chunkSize , Math . floor ( total / concurrency ) ) ; const segments = [ ] ; for ( let cur = 0 , chunkSize = 0 ; cur < total ; cur += chunkSize ) { const remain = total - cur ; if ( remain >= partSize ) { chunkSize = partSize ; segments . push ( { start : cur , end : cur + chunkSize - 1 } ) ; } else { const last = segments [ segments . length - 1 ] ; if ( ! last ) { segments . push ( { start : 0 , end : remain - 1 } ) ; } else { last . end = last . end + remain ; } cur = total ; } } return segments ; } }