Skip to content

Commit

Permalink
feat(#48): Added support for negative indexing when using rsq (#49)
Browse files Browse the repository at this point in the history
* feat(#48): Added support for negative indexing when using rsq

* fix: removed console.log and fixed wrong example url in readme

* chore: added info about the use of negative rsq values to README

* fix: removed console.log left over from testing
  • Loading branch information
zapfire88 authored Feb 1, 2024
1 parent 8715493 commit 1aa47bc
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 17 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,13 +95,13 @@ Currently, the Chaos Stream Proxy supports 4 types of corruptions for HLS and MP

To specify the configurations for a particular corruption, you will need to add a stringified JSON object as a query parameter to the proxied URL.
Each corruption has a unique configuration JSON object template. Each object can be used to target one specific segment for corruption.
e.i. `https://<chaos-proxy>/api/v2/manifests/hls/proxy-master.m3u8?url=<some_url>?some_corruption=[{i:0},{i:1},{i:2}, ... ,{i:N}]`
e.i. `https://<chaos-proxy>/api/v2/manifests/hls/proxy-master.m3u8?url=<some_url>&some_corruption=[{i:0},{i:1},{i:2}, ... ,{i:N}]`

Across all corruptions, there are 3 ways to target a segment in a playlist for corruption.

1. `i`: The segment's list index in any Media Playlist, with HLS segments starting at 0 and MPEG-DASH segments starting at 1. For a Media Playlist with 12 segments, `i`=11, would target the last segment for HLS and `i`=12, would target the last segment for MPEG-DASH.
2. `sq`: The segment's Media Sequence Number for HLS, or the "$Number$" or "$Time$" part of a segment URL for DASH. For an HLS Media Playlist with 12 segments, and where `#EXT-X-MEDIA-SEQUENCE` is 100, `sq`=111 would target the last segment. When corrupting a live HLS stream it is recommended to target with `rsq`.
3. `rsq`: A relative sequence number, counted from where the live stream is currently at when requesting manifest. (**HLS SUPPORTED ONLY IN STATEFUL MODE**)
3. `rsq`: A relative sequence number, counted from where the live stream is currently at when requesting manifest. Can also use a negative integer, which enables counting backwards from the end of the manifest instead. (**HLS SUPPORTED ONLY IN STATEFUL MODE**)

Below are configuration JSON object templates for the currently supported corruptions. A query should have its value be an array consisting of any one of these 3 types of items:

Expand Down
4 changes: 2 additions & 2 deletions src/manifests/handlers/hls/media.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,12 @@ export default async function hlsMediaHandler(
}
}
}

const [error, allMutations, levelMutations] =
configUtils.getAllManifestConfigs(
mediaSequence,
false,
mediaSequenceOffset
mediaSequenceOffset,
mediaM3U.items.PlaylistItem.length
);
if (error) {
return generateErrorResponse(error);
Expand Down
37 changes: 37 additions & 0 deletions src/manifests/utils/configs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,44 @@ describe('configs', () => {
// Act

const [err, actual] = configs.getAllManifestConfigs(0, false, 100);
// Assert
expect(err).toBeNull();
expect(actual.get(115)).toEqual(
new Map([
[
'statusCode',
{
fields: { code: 400 },
sq: 115
}
]
])
);
expect(actual.get(15)).toEqual(
new Map([
[
'throttle',
{
fields: { rate: 1000 },
sq: 15
}
]
])
);
});
it('should handle media sequence offsets with negative rsq value', () => {
// Arrange
const configs = statefulConfig.corruptorConfigUtils(
new URLSearchParams(
'statusCode=[{rsq:-1,code:400}]&throttle=[{sq:15,rate:1000}]'
)
);

configs.register(statusCodeConfig).register(throttleConfig);

// Act

const [err, actual] = configs.getAllManifestConfigs(0, false, 100, 15);
// Assert
expect(err).toBeNull();
expect(actual.get(115)).toEqual(
Expand Down
17 changes: 14 additions & 3 deletions src/manifests/utils/configs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ export interface CorruptorConfigUtils {
getAllManifestConfigs: (
mseq?: number,
isDash?: boolean,
mseqOffset?: number
mseqOffset?: number,
playlistSize?: number
) => [
ServiceError | null,
IndexedCorruptorConfigMap | null,
Expand Down Expand Up @@ -131,7 +132,12 @@ export const corruptorConfigUtils = function (
}
return this;
},
getAllManifestConfigs(mseq = 0, isDash = false, mseqOffset = 0) {
getAllManifestConfigs(
mseq = 0,
isDash = false,
mseqOffset = 0,
playlistSize = 0
) {
const outputMap = new CorruptorIndexMap();
const levelMap = new CorruptorLevelMap();
const configs = (
Expand Down Expand Up @@ -171,7 +177,11 @@ export const corruptorConfigUtils = function (
// Replace relative sequence numbers with absolute ones
params = params.map((param) => {
if (param.rsq) {
param.sq = Number(param.rsq) + mseqOffset;
const rsq = Number(param.rsq);
param['sq'] =
rsq < 0 && playlistSize > 0
? mseqOffset + playlistSize + rsq + 1
: Number(param.rsq) + mseqOffset;
delete param.rsq;
}
return param;
Expand All @@ -182,6 +192,7 @@ export const corruptorConfigUtils = function (
if (error) {
return [error, null];
}

configList.forEach((item) => {
if (item.i != undefined) {
outputMap.deepSet(item.i, config.name, item, false);
Expand Down
14 changes: 4 additions & 10 deletions src/manifests/utils/hlsManifestUtils.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import { M3U, Manifest } from '../../shared/types';
import {
newState,
proxyPathBuilder,
segmentUrlParamString
} from '../../shared/utils';
import { proxyPathBuilder, segmentUrlParamString } from '../../shared/utils';
import { CorruptorConfigMap, IndexedCorruptorConfigMap } from './configs';
import clone from 'clone';

Expand Down Expand Up @@ -143,15 +139,13 @@ export default function (): HLSManifestTools {
configsMap: IndexedCorruptorConfigMap
) {
const m3u: M3U = clone(originalM3U);
const playlistSize = m3u.items.PlaylistItem.length;

// configs for each index
const corruptions = this.utils.mergeMap(
m3u.items.PlaylistItem.length,
configsMap
);
const corruptions = this.utils.mergeMap(playlistSize, configsMap);

// Attach corruptions to manifest
for (let i = 0; i < m3u.items.PlaylistItem.length; i++) {
for (let i = 0; i < playlistSize; i++) {
const item = m3u.items.PlaylistItem[i];
const corruption = corruptions[i];
let sourceSegURL: string = item.get('uri');
Expand Down

0 comments on commit 1aa47bc

Please sign in to comment.