refactor: roll mode

* chore: escalate stack trace to console

* refactor: event finding in roll

* docs: initial roll specification

* refactor: call to roll

* refactor: normalise index

* refactor: roll into next event

* refactor: hot reload on waiting to roll

* refactor: wait to roll next
This commit is contained in:
Carlos Valente
2024-08-04 21:34:01 +02:00
committed by GitHub
parent 3012d73285
commit da11ef64c2
21 changed files with 1093 additions and 982 deletions
+93
View File
@@ -0,0 +1,93 @@
import { dayInMs, getFirstEvent, getLastEvent } from 'ontime-utils';
import { OntimeEvent, MaybeNumber, PlayableEvent, isPlayableEvent } from 'ontime-types';
import { normaliseEndTime } from './timerUtils.js';
/**
* Finds current event in a rolling rundown
*/
export function loadRoll(
timedEvents: OntimeEvent[],
timeNow: number,
): {
event: PlayableEvent | null;
index: MaybeNumber;
isPending?: boolean;
} {
const { firstEvent } = getFirstEvent(timedEvents);
const { lastEvent } = getLastEvent(timedEvents);
if (!firstEvent || !lastEvent) {
return { event: null, index: null };
}
// check that the rundown wraps around midnight
const wrapsAroundMidnight = firstEvent.timeStart > lastEvent.timeEnd;
if (!wrapsAroundMidnight) {
// check whether we are before or after the rundown
const lastNormalEnd = normaliseEndTime(lastEvent.timeStart, lastEvent.timeEnd);
const isAfterRundown = timeNow > lastNormalEnd;
const isBeforeRundown = timeNow < firstEvent.timeStart && !isAfterRundown;
if (isAfterRundown || isBeforeRundown) {
return { event: firstEvent, index: 0, isPending: true };
}
}
// we know we are in the middle of the rundown and we need to find the current event
// account for number of times we went over midnight
let daySpan = 0;
for (let i = 0; i < timedEvents.length; i++) {
const event = timedEvents[i];
if (!isPlayableEvent(event)) {
continue;
}
// we check if event crosses midnight
if (event.timeStart > event.timeEnd) {
daySpan++;
}
const correctedDays = dayInMs * daySpan;
const correctedStart = event.timeStart + correctedDays;
const correctedEnd = event.timeEnd + correctedDays;
/**
* there are 3 possible states for an event
* 1. event is already finished
* 2. event is running
* 3. event is in the future
*/
// 1. event is already finished
// when does the event end (handle midnight)
const normalEnd = normaliseEndTime(correctedStart, correctedEnd);
if (normalEnd <= timeNow) {
continue;
}
// 2. event is running and is the first event in our time slot
const isFromDayBefore = normalEnd > dayInMs && timeNow < event.timeEnd;
const hasStarted = isFromDayBefore || timeNow >= event.timeStart;
if (hasStarted) {
return { event, index: i };
}
// 3. event will run in the future
// we set the isPending flag to indicate that the event is currently playing
return { event, index: i, isPending: true };
}
// in case we were unable to find anything, we load the first event
return { event: firstEvent, index: 0, isPending: true };
}
/**
* Utility function, checks whether the event start is the day after
*/
export function normaliseRollStart(start: number, clock: number) {
return start < clock ? start + dayInMs : start;
}