refactor: rundown service fetches data from data provider (#752)

This commit is contained in:
Carlos Valente
2024-01-31 19:30:44 +01:00
committed by GitHub
parent cf08bfc796
commit 91fd275564
9 changed files with 133 additions and 146 deletions
+1 -1
View File
@@ -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';
+2 -2
View File
@@ -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');
+3 -2
View File
@@ -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,
},
]),
}));
});
+2 -2
View File
@@ -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;
}
/**