diff --git a/.gitignore b/.gitignore index cade38a..ca9f805 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ node_modules/ dist/ .env dev +.history/ diff --git a/.prettierignore b/.prettierignore index 83ffe87..fb94fc2 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,3 +1,4 @@ dist/ *.yml README.md +.history/ diff --git a/README.md b/README.md index ae2c692..91e1309 100644 --- a/README.md +++ b/README.md @@ -107,8 +107,8 @@ e.i. `https:///api/v2/manifests/hls/proxy-master.m3u8?url=/api/v2/manifests/dash/proxy-master.mpd?url=https://livesim https:///api/v2/manifests/dash/proxy-master.mpd?url=https://f53accc45b7aded64ed8085068f31881.egress.mediapackage-vod.eu-north-1.amazonaws.com/out/v1/1c63bf88e2664639a6c293b4d055e6bb/64651f16da554640930b7ce2cd9f758b/66d211307b7d43d3bd515a3bfb654e1c/manifest.mpd&throttle=[{i:*,rate:10000}] ``` +7. LIVE: Example of MPEG-DASH with a segment delay of 5000ms on segment with relative sequence number equal to 2: + +``` +https:///api/v2/manifests/dash/proxy-master.mpd?url=https://livesim.dashif.org/livesim/testpic_2s/Manifest.mpd&delay=[{rsq:2, ms:5000}] +``` ## Development Environment To deploy and update development environment create and push a tag with the suffix `-dev`, for example `my-feat-test-dev`. If you run `npm run deploy:dev` it will automatically create a tag based on git revision with the `-dev` suffix and push it. diff --git a/package-lock.json b/package-lock.json index 011f5b0..a233a32 100644 --- a/package-lock.json +++ b/package-lock.json @@ -48,7 +48,7 @@ "eslint-plugin-prettier": "^4.2.1", "husky": "^2.7.0", "lint-staged": "^12.3.4", - "prettier": "^2.8.7", + "prettier": "2.8.8", "ts-jest": "^27.1.3", "tsc-watch": "^5.0.3", "typescript": "^3.7.3" @@ -10988,9 +10988,9 @@ } }, "node_modules/prettier": { - "version": "2.8.7", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.7.tgz", - "integrity": "sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw==", + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", "dev": true, "bin": { "prettier": "bin-prettier.js" @@ -21315,9 +21315,9 @@ "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" }, "prettier": { - "version": "2.8.7", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.7.tgz", - "integrity": "sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw==", + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", "dev": true }, "prettier-linter-helpers": { diff --git a/package.json b/package.json index 0fc1b80..c559082 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ "eslint-plugin-prettier": "^4.2.1", "husky": "^2.7.0", "lint-staged": "^12.3.4", - "prettier": "^2.8.7", + "prettier": "2.8.8", "ts-jest": "^27.1.3", "tsc-watch": "^5.0.3", "typescript": "^3.7.3" diff --git a/src/manifests/handlers/dash/segment.ts b/src/manifests/handlers/dash/segment.ts index 59b60d1..7d4b279 100644 --- a/src/manifests/handlers/dash/segment.ts +++ b/src/manifests/handlers/dash/segment.ts @@ -4,7 +4,9 @@ import { composeALBEvent, generateErrorResponse, isValidUrl, - segmentUrlParamString + segmentUrlParamString, + STATEFUL, + newState } from '../../../shared/utils'; import delaySCC from '../../utils/corruptions/delay'; import statusCodeSCC from '../../utils/corruptions/statusCode'; @@ -56,6 +58,10 @@ export default async function dashSegmentHandler( } const reqSegmentIndexInt = parseInt(reqSegmentIndexOrTimeStr); + const stateKey = STATEFUL + ? newState({ initialSequenceNumber: undefined }) + : undefined; + // Replace RepresentationID in url if present if (representationIdStr) { segmentUrl = segmentUrl.replace( @@ -85,7 +91,8 @@ export default async function dashSegmentHandler( const dashUtils = dashManifestUtils(); const mergedMaps = dashUtils.utils.mergeMap( reqSegmentIndexInt, - allMutations + allMutations, + stateKey ); const segUrl = new URL(segmentUrl); const cleanSegUrl = segUrl.origin + segUrl.pathname; diff --git a/src/manifests/utils/configs.test.ts b/src/manifests/utils/configs.test.ts index d145658..9e8b558 100644 --- a/src/manifests/utils/configs.test.ts +++ b/src/manifests/utils/configs.test.ts @@ -257,6 +257,60 @@ describe('configs', () => { ); }); }); + + describe('not in stateful mode', () => { + let nonStatefulConfig; + beforeAll(() => { + delete process.env.STATEFUL; // Ensure STATEFUL is not set + nonStatefulConfig = require('./configs'); + }); + + it('should handle DASH mode without stateful', () => { + // Arrange + const configs = nonStatefulConfig.corruptorConfigUtils( + new URLSearchParams( + 'statusCode=[{rsq:15,code:400}]&throttle=[{sq:15,rate:1000}]' + ) + ); + + configs.register(statusCodeConfig).register(throttleConfig); + + // Act + + const [err, actual] = configs.getAllManifestConfigs(0, true); + + // Assert + expect(err).toEqual({ + status: 400, + message: + 'Relative sequence numbers on DASH are only supported when proxy is running in stateful mode' + }); + expect(actual).toBeNull(); + }); + + it('should handle HLS mode without stateful', () => { + // Arrange + const configs = nonStatefulConfig.corruptorConfigUtils( + new URLSearchParams( + 'statusCode=[{rsq:15,code:400}]&throttle=[{sq:15,rate:1000}]' + ) + ); + + configs.register(statusCodeConfig).register(throttleConfig); + + // Act + + const [err, actual] = configs.getAllManifestConfigs(0, false); + + // Assert + expect(err).toEqual({ + status: 400, + message: + 'Relative sequence numbers on HLS are only supported when proxy is running in stateful mode' + }); + expect(actual).toBeNull(); + }); + }); }); describe('getAllSegmentConfigs', () => { diff --git a/src/manifests/utils/configs.ts b/src/manifests/utils/configs.ts index bf678bb..8c0aa60 100644 --- a/src/manifests/utils/configs.ts +++ b/src/manifests/utils/configs.ts @@ -167,6 +167,16 @@ export const corruptorConfigUtils = function ( null ]; } + if (hasRelativeSequences && !STATEFUL && isDash) { + return [ + { + status: 400, + message: + 'Relative sequence numbers on DASH are only supported when proxy is running in stateful mode' + }, + null + ]; + } // If bitrate is set, filter out segments that doesn't match params = params.filter( diff --git a/src/manifests/utils/dashManifestUtils.test.ts b/src/manifests/utils/dashManifestUtils.test.ts index f136674..59c1496 100644 --- a/src/manifests/utils/dashManifestUtils.test.ts +++ b/src/manifests/utils/dashManifestUtils.test.ts @@ -157,7 +157,8 @@ describe('utils.mergeMap', () => { // Act const actual = dashManifestUtils().utils.mergeMap( mockReqSegIndex, - mockAllCorruptions + mockAllCorruptions, + undefined ); const expected = new Map() .set('a', { fields: { ms: 100 } }) @@ -191,7 +192,11 @@ describe('utils.mergeMap', () => { const actual: CorruptorConfigMap[] = []; for (let segIdx = 0; segIdx < 3; segIdx++) { actual.push( - dashManifestUtils().utils.mergeMap(segIdx, mockAllCorruptions) + dashManifestUtils().utils.mergeMap( + segIdx, + mockAllCorruptions, + undefined + ) ); } @@ -226,7 +231,11 @@ describe('utils.mergeMap', () => { const actual: CorruptorConfigMap[] = []; for (let segIdx = 0; segIdx < 3; segIdx++) { actual.push( - dashManifestUtils().utils.mergeMap(segIdx, mockAllCorruptions) + dashManifestUtils().utils.mergeMap( + segIdx, + mockAllCorruptions, + undefined + ) ); } const expected = [ @@ -252,7 +261,8 @@ describe('utils.mergeMap', () => { // Act const actual = dashManifestUtils().utils.mergeMap( mockReqSegIndex, - mockAllCorruptions + mockAllCorruptions, + undefined ); const expected = new Map().set('a', { fields: {} diff --git a/src/manifests/utils/dashManifestUtils.ts b/src/manifests/utils/dashManifestUtils.ts index 8dee572..99b67b4 100644 --- a/src/manifests/utils/dashManifestUtils.ts +++ b/src/manifests/utils/dashManifestUtils.ts @@ -7,7 +7,8 @@ import { URLSearchParams } from 'url'; interface DASHManifestUtils { mergeMap: ( segmentListSize: number, - configsMap: IndexedCorruptorConfigMap + configsMap: IndexedCorruptorConfigMap, + stateKey: string | undefined ) => CorruptorConfigMap; } diff --git a/src/shared/utils.ts b/src/shared/utils.ts index 923d8ef..6fe93fe 100644 --- a/src/shared/utils.ts +++ b/src/shared/utils.ts @@ -14,7 +14,7 @@ import { FastifyInstance } from 'fastify'; import { addSSMUrlParametersToUrl } from './aws.utils'; - +import { URLSearchParams } from 'url'; import dotenv from 'dotenv'; import { Readable } from 'stream'; import NodeCache from 'node-cache';