Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(#48): Added support for negative indexing when using rsq #49

Merged
merged 4 commits into from
Feb 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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}]`
zapfire88 marked this conversation as resolved.
Show resolved Hide resolved
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
Loading