mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-09 01:13:55 +00:00
refactor: rundown service fetches data from data provider (#752)
This commit is contained in:
@@ -4,6 +4,7 @@ import {
|
||||
DatabaseModel,
|
||||
GetInfo,
|
||||
HttpSettings,
|
||||
MessageResponse,
|
||||
OntimeRundown,
|
||||
OSCSettings,
|
||||
OscSubscription,
|
||||
@@ -13,7 +14,6 @@ import {
|
||||
UserFields,
|
||||
ViewSettings,
|
||||
} from 'ontime-types';
|
||||
import { MessageResponse } from 'ontime-types';
|
||||
import { ExcelImportMap } from 'ontime-utils';
|
||||
|
||||
import { apiRepoLatest } from '../../externals';
|
||||
|
||||
@@ -31,7 +31,6 @@ import { DataProvider } from './classes/data-provider/DataProvider.js';
|
||||
import { dbLoadingProcess } from './modules/loadDb.js';
|
||||
|
||||
// Services
|
||||
import { EventLoader } from './classes/event-loader/EventLoader.js';
|
||||
import { integrationService } from './services/integration-service/IntegrationService.js';
|
||||
import { logger } from './classes/Logger.js';
|
||||
import { oscIntegration } from './services/integration-service/OscIntegration.js';
|
||||
@@ -43,6 +42,7 @@ import { restoreService } from './services/RestoreService.js';
|
||||
import { messageService } from './services/message-service/MessageService.js';
|
||||
import { populateDemo } from './modules/loadDemo.js';
|
||||
import { getState, updateNumEvents } from './stores/runtimeState.js';
|
||||
import { getNumEvents } from './services/rundown-service/RundownService.js';
|
||||
|
||||
console.log(`Starting Ontime version ${ONTIME_VERSION}`);
|
||||
|
||||
@@ -184,7 +184,7 @@ export const startServer = async () => {
|
||||
runtimeService.init(maybeRestorePoint);
|
||||
|
||||
// TODO: do this on the init of the runtime service
|
||||
const numEvents = EventLoader.getNumEvents();
|
||||
const numEvents = getNumEvents();
|
||||
updateNumEvents(numEvents);
|
||||
|
||||
// eventStore set is a dependency of the services that publish to it
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
import { OntimeEvent, isOntimeEvent } from 'ontime-types';
|
||||
|
||||
import { DataProvider } from '../data-provider/DataProvider.js';
|
||||
|
||||
/**
|
||||
* Manages business logic around loading and finding events
|
||||
*/
|
||||
export class EventLoader {
|
||||
// TODO: migrate logic to RundownService
|
||||
|
||||
/**
|
||||
* returns all events that contain time data
|
||||
* @return {array}
|
||||
*/
|
||||
static getTimedEvents(): OntimeEvent[] {
|
||||
return DataProvider.getRundown().filter((event) => isOntimeEvent(event)) as OntimeEvent[];
|
||||
}
|
||||
|
||||
/**
|
||||
* returns all events that can be loaded
|
||||
* @return {array}
|
||||
*/
|
||||
static getPlayableEvents(): OntimeEvent[] {
|
||||
return DataProvider.getRundown().filter((event) => isOntimeEvent(event) && !event.skip) as OntimeEvent[];
|
||||
}
|
||||
|
||||
/**
|
||||
* returns number of events
|
||||
* @return {number}
|
||||
*/
|
||||
static getNumEvents(): number {
|
||||
return EventLoader.getPlayableEvents().length;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns an event given its index after filtering for OntimeEvents
|
||||
* @param {number} eventIndex
|
||||
* @return {OntimeEvent | undefined}
|
||||
*/
|
||||
static getEventAtIndex(eventIndex: number): OntimeEvent | undefined {
|
||||
const timedEvents = EventLoader.getTimedEvents();
|
||||
return timedEvents.at(eventIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns an event given its id
|
||||
* @param {string} eventId
|
||||
* @return {object | undefined}
|
||||
*/
|
||||
static getEventWithId(eventId: string): OntimeEvent | undefined {
|
||||
const timedEvents = EventLoader.getTimedEvents();
|
||||
return timedEvents.find((event) => event.id === eventId);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns first event given its cue
|
||||
* @param {string} cue
|
||||
* @return {object | undefined}
|
||||
*/
|
||||
static getEventWithCue(cue: string): OntimeEvent | undefined {
|
||||
const timedEvents = EventLoader.getTimedEvents();
|
||||
return timedEvents.find((event) => event.cue.toLowerCase() === cue.toLowerCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* finds the previous event
|
||||
* @return {object | undefined}
|
||||
*/
|
||||
static findPrevious(currentEventId?: string): OntimeEvent | null {
|
||||
const timedEvents = EventLoader.getPlayableEvents();
|
||||
if (!timedEvents || !timedEvents.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// if there is no event running, go to first
|
||||
if (!currentEventId) {
|
||||
return timedEvents.at(0) ?? null;
|
||||
}
|
||||
|
||||
const currentIndex = timedEvents.findIndex((event) => event.id === currentEventId);
|
||||
const newIndex = Math.max(currentIndex - 1, 0);
|
||||
const previousEvent = timedEvents.at(newIndex) ?? null;
|
||||
return previousEvent;
|
||||
}
|
||||
|
||||
/**
|
||||
* finds the next event
|
||||
* @return {object | undefined}
|
||||
*/
|
||||
static findNext(currentEventId?: string): OntimeEvent | null {
|
||||
const timedEvents = EventLoader.getPlayableEvents();
|
||||
if (!timedEvents || !timedEvents.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// if there is no event running, go to first
|
||||
if (!currentEventId) {
|
||||
return timedEvents.at(0) ?? null;
|
||||
}
|
||||
|
||||
const currentIndex = timedEvents.findIndex((event) => event.id === currentEventId);
|
||||
const newIndex = (currentIndex + 1) % timedEvents.length;
|
||||
const nextEvent = timedEvents.at(newIndex);
|
||||
return nextEvent ?? null;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
import { LogOrigin, OntimeEvent, isKeyOfType, isOntimeEvent } from 'ontime-types';
|
||||
import { EventLoader } from '../classes/event-loader/EventLoader.js';
|
||||
import { editEvent } from '../services/rundown-service/RundownService.js';
|
||||
import { editEvent, getEventWithId } from '../services/rundown-service/RundownService.js';
|
||||
import { coerceString, coerceNumber, coerceBoolean, coerceColour } from '../utils/coerceType.js';
|
||||
import { logger } from '../classes/Logger.js';
|
||||
|
||||
@@ -49,7 +48,7 @@ export function updateEvent(
|
||||
propertyName: keyof OntimeEvent,
|
||||
newValue: OntimeEvent[typeof propertyName],
|
||||
) {
|
||||
const event = EventLoader.getEventWithId(eventId);
|
||||
const event = getEventWithId(eventId);
|
||||
if (event) {
|
||||
if (!isOntimeEvent(event)) {
|
||||
throw new Error('Can only update events');
|
||||
|
||||
@@ -5,7 +5,7 @@ import { integrationService } from './integration-service/IntegrationService.js'
|
||||
import { eventStore } from '../stores/EventStore.js';
|
||||
import { restoreService } from './RestoreService.js';
|
||||
import { runtimeService } from './runtime-service/RuntimeService.js';
|
||||
import { EventLoader } from '../classes/event-loader/EventLoader.js';
|
||||
import { getPlayableEvents } from './rundown-service/RundownService.js';
|
||||
|
||||
/**
|
||||
* Service manages Ontime's main timer
|
||||
@@ -71,7 +71,8 @@ export class TimerService {
|
||||
}
|
||||
|
||||
if (doRoll) {
|
||||
const rundown = EventLoader.getPlayableEvents();
|
||||
// TODO: escalate to parent
|
||||
const rundown = getPlayableEvents();
|
||||
runtimeState.roll(rundown);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ import {
|
||||
import { generateId, getCueCandidate } from 'ontime-utils';
|
||||
import { DataProvider } from '../../classes/data-provider/DataProvider.js';
|
||||
import { block as blockDef, delay as delayDef } from '../../models/eventsDefinition.js';
|
||||
import { EventLoader } from '../../classes/event-loader/EventLoader.js';
|
||||
import { sendRefetch } from '../../adapters/websocketAux.js';
|
||||
import { runtimeCacheStore } from '../../stores/cachingStore.js';
|
||||
import {
|
||||
@@ -168,7 +167,7 @@ export async function swapEvents(from: string, to: string) {
|
||||
* Called when we make changes to the rundown object
|
||||
*/
|
||||
function updateChangeNumEvents() {
|
||||
const numEvents = EventLoader.getPlayableEvents().length;
|
||||
const numEvents = getPlayableEvents().length;
|
||||
updateNumEvents(numEvents);
|
||||
}
|
||||
|
||||
@@ -195,3 +194,99 @@ export function notifyChanges(options: { timer?: boolean | string[]; external?:
|
||||
sendRefetch();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* returns all events of type OntimeEvent
|
||||
* @return {array}
|
||||
*/
|
||||
export function getTimedEvents(): OntimeEvent[] {
|
||||
return DataProvider.getRundown().filter((event) => isOntimeEvent(event)) as OntimeEvent[];
|
||||
}
|
||||
|
||||
/**
|
||||
* returns all events that can be loaded
|
||||
* @return {array}
|
||||
*/
|
||||
export function getPlayableEvents(): OntimeEvent[] {
|
||||
return DataProvider.getRundown().filter((event) => isOntimeEvent(event) && !event.skip) as OntimeEvent[];
|
||||
}
|
||||
|
||||
/**
|
||||
* returns number of events that can be loaded
|
||||
* @return {number}
|
||||
*/
|
||||
export function getNumEvents(): number {
|
||||
return getPlayableEvents().length;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns an event given its index after filtering for OntimeEvents
|
||||
* @param {number} eventIndex
|
||||
* @return {OntimeEvent | undefined}
|
||||
*/
|
||||
export function getEventAtIndex(eventIndex: number): OntimeEvent | undefined {
|
||||
const timedEvents = getTimedEvents();
|
||||
return timedEvents.at(eventIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns first event that matches a given ID
|
||||
* @param {string} eventId
|
||||
* @return {object | undefined}
|
||||
*/
|
||||
export function getEventWithId(eventId: string): OntimeEvent | undefined {
|
||||
const timedEvents = getTimedEvents();
|
||||
return timedEvents.find((event) => event.id === eventId);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns first event that matches a given cue
|
||||
* @param {string} cue
|
||||
* @return {object | undefined}
|
||||
*/
|
||||
export function getEventWithCue(cue: string): OntimeEvent | undefined {
|
||||
const timedEvents = getTimedEvents();
|
||||
return timedEvents.find((event) => event.cue.toLowerCase() === cue.toLowerCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* finds the previous event
|
||||
* @return {object | undefined}
|
||||
*/
|
||||
export function findPrevious(currentEventId?: string): OntimeEvent | null {
|
||||
const timedEvents = getPlayableEvents();
|
||||
if (!timedEvents || !timedEvents.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// if there is no event running, go to first
|
||||
if (!currentEventId) {
|
||||
return timedEvents.at(0) ?? null;
|
||||
}
|
||||
|
||||
const currentIndex = timedEvents.findIndex((event) => event.id === currentEventId);
|
||||
const newIndex = Math.max(currentIndex - 1, 0);
|
||||
const previousEvent = timedEvents.at(newIndex) ?? null;
|
||||
return previousEvent;
|
||||
}
|
||||
|
||||
/**
|
||||
* finds the next event
|
||||
* @return {object | undefined}
|
||||
*/
|
||||
export function findNext(currentEventId?: string): OntimeEvent | null {
|
||||
const timedEvents = getPlayableEvents();
|
||||
if (!timedEvents || !timedEvents.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// if there is no event running, go to first
|
||||
if (!currentEventId) {
|
||||
return timedEvents.at(0) ?? null;
|
||||
}
|
||||
|
||||
const currentIndex = timedEvents.findIndex((event) => event.id === currentEventId);
|
||||
const newIndex = (currentIndex + 1) % timedEvents.length;
|
||||
const nextEvent = timedEvents.at(newIndex);
|
||||
return nextEvent ?? null;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { LogOrigin, OntimeEvent, Playback } from 'ontime-types';
|
||||
import { millisToString, validatePlayback } from 'ontime-utils';
|
||||
|
||||
import { EventLoader } from '../../classes/event-loader/EventLoader.js';
|
||||
import { TimerService } from '../TimerService.js';
|
||||
import { logger } from '../../classes/Logger.js';
|
||||
import { RestorePoint } from '../RestoreService.js';
|
||||
import * as runtimeState from '../../stores/runtimeState.js';
|
||||
import { findNext, findPrevious, getEventAtIndex, getEventWithCue, getEventWithId, getPlayableEvents } from '../rundown-service/RundownService.js';
|
||||
|
||||
/**
|
||||
* Service manages runtime status of app
|
||||
@@ -50,7 +50,7 @@ class RuntimeService {
|
||||
}
|
||||
|
||||
private isNewNext() {
|
||||
const timedEvents = EventLoader.getPlayableEvents();
|
||||
const timedEvents = getPlayableEvents();
|
||||
const state = runtimeState.getState();
|
||||
const now = state.eventNow?.id;
|
||||
const next = state.eventNext?.id;
|
||||
@@ -114,7 +114,7 @@ class RuntimeService {
|
||||
this.roll();
|
||||
}
|
||||
// load stuff again, but keep running if our events still exist
|
||||
const eventNow = EventLoader.getEventWithId(state.eventNow.id);
|
||||
const eventNow = getEventWithId(state.eventNow.id);
|
||||
if (eventNow) {
|
||||
runtimeState.reload(eventNow);
|
||||
}
|
||||
@@ -124,7 +124,7 @@ class RuntimeService {
|
||||
isNext = this.isNewNext();
|
||||
if (isNext) {
|
||||
// TODO: do i need to load here?
|
||||
const playableEvents = EventLoader.getPlayableEvents();
|
||||
const playableEvents = getPlayableEvents();
|
||||
runtimeState.loadNext(playableEvents);
|
||||
}
|
||||
}
|
||||
@@ -140,7 +140,7 @@ class RuntimeService {
|
||||
return false;
|
||||
}
|
||||
|
||||
const timedEvents = EventLoader.getPlayableEvents();
|
||||
const timedEvents = getPlayableEvents();
|
||||
const state = runtimeState.getState();
|
||||
// TODO: return success boolean from runtimeState
|
||||
runtimeState.load(event, timedEvents);
|
||||
@@ -158,7 +158,7 @@ class RuntimeService {
|
||||
* @return {boolean} success - whether an event was loaded
|
||||
*/
|
||||
startById(eventId: string): boolean {
|
||||
const event = EventLoader.getEventWithId(eventId);
|
||||
const event = getEventWithId(eventId);
|
||||
const success = this.loadEvent(event);
|
||||
if (success) {
|
||||
this.start();
|
||||
@@ -172,7 +172,7 @@ class RuntimeService {
|
||||
* @return {boolean} success - whether an event was loaded
|
||||
*/
|
||||
startByIndex(eventIndex: number): boolean {
|
||||
const event = EventLoader.getEventAtIndex(eventIndex);
|
||||
const event = getEventAtIndex(eventIndex);
|
||||
const success = this.loadEvent(event);
|
||||
if (success) {
|
||||
this.start();
|
||||
@@ -186,7 +186,7 @@ class RuntimeService {
|
||||
* @return {boolean} success - whether an event was loaded
|
||||
*/
|
||||
startByCue(cue: string): boolean {
|
||||
const event = EventLoader.getEventWithCue(cue);
|
||||
const event = getEventWithCue(cue);
|
||||
const success = this.loadEvent(event);
|
||||
if (success) {
|
||||
this.start();
|
||||
@@ -200,7 +200,7 @@ class RuntimeService {
|
||||
* @return {boolean} success - whether an event was loaded
|
||||
*/
|
||||
loadById(eventId: string): boolean {
|
||||
const event = EventLoader.getEventWithId(eventId);
|
||||
const event = getEventWithId(eventId);
|
||||
const success = this.loadEvent(event);
|
||||
return success;
|
||||
}
|
||||
@@ -211,7 +211,7 @@ class RuntimeService {
|
||||
* @return {boolean} success - whether an event was loaded
|
||||
*/
|
||||
loadByIndex(eventIndex: number): boolean {
|
||||
const event = EventLoader.getEventAtIndex(eventIndex);
|
||||
const event = getEventAtIndex(eventIndex);
|
||||
const success = this.loadEvent(event);
|
||||
return success;
|
||||
}
|
||||
@@ -222,7 +222,7 @@ class RuntimeService {
|
||||
* @return {boolean} success - whether an event was loaded
|
||||
*/
|
||||
loadByCue(cue: string): boolean {
|
||||
const event = EventLoader.getEventWithCue(cue);
|
||||
const event = getEventWithCue(cue);
|
||||
const success = this.loadEvent(event);
|
||||
return success;
|
||||
}
|
||||
@@ -233,7 +233,7 @@ class RuntimeService {
|
||||
*/
|
||||
loadPrevious(): boolean {
|
||||
const state = runtimeState.getState();
|
||||
const previousEvent = EventLoader.findPrevious(state.eventNow?.id);
|
||||
const previousEvent = findPrevious(state.eventNow?.id);
|
||||
if (previousEvent) {
|
||||
const success = this.loadEvent(previousEvent);
|
||||
return success;
|
||||
@@ -247,7 +247,7 @@ class RuntimeService {
|
||||
*/
|
||||
loadNext(): boolean {
|
||||
const state = runtimeState.getState();
|
||||
const nextEvent = EventLoader.findNext(state.eventNow?.id);
|
||||
const nextEvent = findNext(state.eventNow?.id);
|
||||
if (nextEvent) {
|
||||
const success = this.loadEvent(nextEvent);
|
||||
return success;
|
||||
@@ -317,7 +317,7 @@ class RuntimeService {
|
||||
* Sets playback to roll
|
||||
*/
|
||||
roll() {
|
||||
const playableEvents = EventLoader.getPlayableEvents();
|
||||
const playableEvents = getPlayableEvents();
|
||||
try {
|
||||
this.eventTimer.roll(playableEvents);
|
||||
} catch (error) {
|
||||
@@ -346,12 +346,12 @@ class RuntimeService {
|
||||
|
||||
// the db would have to change for the event not to exist
|
||||
// we do not kow the reason for the crash, so we check anyway
|
||||
const event = EventLoader.getEventWithId(selectedEventId);
|
||||
const event = getEventWithId(selectedEventId);
|
||||
if (!event) {
|
||||
return;
|
||||
}
|
||||
|
||||
const timedEvents = EventLoader.getPlayableEvents();
|
||||
const timedEvents = getPlayableEvents();
|
||||
runtimeState.resume(restorePoint, event, timedEvents);
|
||||
logger.info(LogOrigin.Playback, 'Resuming playback');
|
||||
}
|
||||
|
||||
@@ -48,18 +48,16 @@ describe('mutation on runtimeState', () => {
|
||||
beforeEach(() => {
|
||||
clear();
|
||||
|
||||
vi.mock('../../classes/event-loader/EventLoader.js', () => ({
|
||||
EventLoader: {
|
||||
getPlayableEvents: vi.fn().mockReturnValue([
|
||||
{
|
||||
id: 'mock',
|
||||
cue: 'mock',
|
||||
timeStart: 0,
|
||||
timeEnd: 1000,
|
||||
duration: 1000,
|
||||
},
|
||||
]),
|
||||
},
|
||||
vi.mock('../../services/rundown-service/RundownService.js', () => ({
|
||||
getPlayableEvents: vi.fn().mockReturnValue([
|
||||
{
|
||||
id: 'mock',
|
||||
cue: 'mock',
|
||||
timeStart: 0,
|
||||
timeEnd: 1000,
|
||||
duration: 1000,
|
||||
},
|
||||
]),
|
||||
}));
|
||||
});
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@ import { calculateDuration, dayInMs } from 'ontime-utils';
|
||||
|
||||
import { clock } from '../services/Clock.js';
|
||||
import { RestorePoint } from '../services/RestoreService.js';
|
||||
import { getPlayableEvents } from '../services/rundown-service/RundownService.js';
|
||||
import { getCurrent, getExpectedFinish, getRollTimers, skippedOutOfEvent, updateRoll } from '../services/timerUtils.js';
|
||||
import { EventLoader } from '../classes/event-loader/EventLoader.js';
|
||||
import { timerConfig } from '../config/config.js';
|
||||
|
||||
const initialRuntime: Runtime = {
|
||||
@@ -102,7 +102,7 @@ function patchTimer(newState: Partial<TimerState>) {
|
||||
*/
|
||||
function fetchNumEvents(): number {
|
||||
// TODO: could we avoid having this dependency?
|
||||
return EventLoader.getPlayableEvents().length;
|
||||
return getPlayableEvents().length;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user