From 16fd44a441c3c7b3cd2010b70b67a54005ae6079 Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Fri, 4 Oct 2024 14:00:06 +0200 Subject: [PATCH] refactor: allow aux change direction while playing --- .../api-integration/integration.controller.ts | 5 +- apps/server/src/app.ts | 7 +- .../src/classes/simple-timer/SimpleTimer.ts | 21 ++++-- .../__tests__/SimpleTimer.test.ts | 72 ++++++++++++++++--- apps/server/src/config/config.ts | 3 + .../aux-timer-service/AuxTimerService.ts | 5 +- 6 files changed, 92 insertions(+), 21 deletions(-) diff --git a/apps/server/src/api-integration/integration.controller.ts b/apps/server/src/api-integration/integration.controller.ts index d88c2fe6f..09a33d56b 100644 --- a/apps/server/src/api-integration/integration.controller.ts +++ b/apps/server/src/api-integration/integration.controller.ts @@ -230,8 +230,9 @@ const actionHandlers: Record = { } else if (command && typeof command === 'object') { const reply = { payload: {} }; if ('duration' in command) { - const time = numberOrError(command.duration); - reply.payload = auxTimerService.setTime(time * 1000); //frontend is seconds based + // convert duration in seconds to ms + const timeInMs = numberOrError(command.duration) * 1000; + reply.payload = auxTimerService.setTime(timeInMs); } if ('direction' in command) { if (command.direction === SimpleDirection.CountUp || command.direction === SimpleDirection.CountDown) { diff --git a/apps/server/src/app.ts b/apps/server/src/app.ts index 2ffdf7998..278176efe 100644 --- a/apps/server/src/app.ts +++ b/apps/server/src/app.ts @@ -48,6 +48,7 @@ import { initialiseProject } from './services/project-service/ProjectService.js' import { clearUploadfolder } from './utils/upload.js'; import { generateCrashReport } from './utils/generateCrashReport.js'; import { getNetworkInterfaces } from './utils/networkInterfaces.js'; +import { timerConfig } from './config/config.js'; console.log('\n'); consoleHighlight(`Starting Ontime version ${ONTIME_VERSION}`); @@ -187,8 +188,8 @@ export const startServer = async ( eventNext: state.eventNext, publicEventNext: state.publicEventNext, auxtimer1: { - duration: 0, - current: 0, + duration: timerConfig.auxTimerDefault, + current: timerConfig.auxTimerDefault, playback: SimplePlayback.Stop, direction: SimpleDirection.CountDown, }, @@ -198,7 +199,7 @@ export const startServer = async ( // initialise logging service, escalateErrorFn is only exists in electron logger.init(escalateErrorFn); - // initialise rundown service + // initialise rundown service const persistedRundown = getDataProvider().getRundown(); const persistedCustomFields = getDataProvider().getCustomFields(); initRundown(persistedRundown, persistedCustomFields); diff --git a/apps/server/src/classes/simple-timer/SimpleTimer.ts b/apps/server/src/classes/simple-timer/SimpleTimer.ts index 7465be16d..cc3e03fde 100644 --- a/apps/server/src/classes/simple-timer/SimpleTimer.ts +++ b/apps/server/src/classes/simple-timer/SimpleTimer.ts @@ -9,6 +9,13 @@ export class SimpleTimer { }; private startedAt: number | null = null; private pausedAt: number | null = null; + private initialDuration = 0; + + constructor(initialTime: number = 0) { + this.state.duration = initialTime; + this.initialDuration = initialTime; + this.state.current = initialTime; + } public reset() { this.state = { @@ -25,14 +32,19 @@ export class SimpleTimer { */ public setTime(time: number): SimpleTimerState { this.state.duration = time; + this.initialDuration = time; this.state.current = time; return this.state; } - public setDirection(direction: SimpleDirection): SimpleTimerState { - this.state.playback = SimplePlayback.Stop; - this.state.current = this.state.duration; + public setDirection(direction: SimpleDirection, timeNow: number): SimpleTimerState { + // if we are playing, we need to reset the targets + if (this.state.playback === SimplePlayback.Start) { + this.startedAt = timeNow; + this.state.duration = this.state.current; + } this.state.direction = direction; + this.update(timeNow); return this.state; } @@ -57,7 +69,8 @@ export class SimpleTimer { public stop(): SimpleTimerState { this.state.playback = SimplePlayback.Stop; - this.state.current = this.state.duration; + this.state.duration = this.initialDuration; + this.state.current = this.initialDuration; this.startedAt = null; return this.state; } diff --git a/apps/server/src/classes/simple-timer/__tests__/SimpleTimer.test.ts b/apps/server/src/classes/simple-timer/__tests__/SimpleTimer.test.ts index 7409ff6f9..c516eb6fa 100644 --- a/apps/server/src/classes/simple-timer/__tests__/SimpleTimer.test.ts +++ b/apps/server/src/classes/simple-timer/__tests__/SimpleTimer.test.ts @@ -88,7 +88,7 @@ describe('SimpleTimer count-down', () => { }); test('count-up mode', () => { - const initialState = timer.setDirection(SimpleDirection.CountUp); + const initialState = timer.setDirection(SimpleDirection.CountUp, 0); expect(initialState.current).toBe(initialTime); let newState = timer.start(0); @@ -114,16 +114,68 @@ describe('SimpleTimer count-down', () => { expect(newState).toStrictEqual(expected); }); - test('changing direction stops the timer', () => { - const newState = timer.setDirection(SimpleDirection.CountDown); - const expected: SimpleTimerState = { - duration: initialTime, - current: initialTime, - direction: SimpleDirection.CountDown, - playback: SimplePlayback.Stop, - }; + test('changing direction keeps the current time', () => { + timer.reset(); + timer.setTime(1000); - expect(newState).toStrictEqual(expected); + const initialState = timer.setDirection(SimpleDirection.CountUp, 0); + expect(initialState.current).toBe(1000); + + let newState = timer.start(0); + expect(newState).toStrictEqual({ + duration: 1000, + current: 1000, + direction: SimpleDirection.CountUp, + playback: SimplePlayback.Start, + }); + + newState = timer.update(100); + expect(newState).toStrictEqual({ + duration: 1000, + current: initialTime + 100, + direction: SimpleDirection.CountUp, + playback: SimplePlayback.Start, + }); + + newState = timer.update(500); + expect(newState).toStrictEqual({ + duration: 1000, + current: 1500, + direction: SimpleDirection.CountUp, + playback: SimplePlayback.Start, + }); + + newState = timer.setDirection(SimpleDirection.CountDown, 600); + expect(newState).toStrictEqual({ + duration: 1500, + current: 1500, + direction: SimpleDirection.CountDown, + playback: SimplePlayback.Start, + }); + + newState = timer.update(700); + expect(newState).toStrictEqual({ + duration: 1500, + current: 1400, + direction: SimpleDirection.CountDown, + playback: SimplePlayback.Start, + }); + + newState = timer.setDirection(SimpleDirection.CountUp, 700); + expect(newState).toStrictEqual({ + duration: 1400, + current: 1400, + direction: SimpleDirection.CountUp, + playback: SimplePlayback.Start, + }); + + newState = timer.update(800); + expect(newState).toStrictEqual({ + duration: 1400, + current: 1500, + direction: SimpleDirection.CountUp, + playback: SimplePlayback.Start, + }); }); }); }); diff --git a/apps/server/src/config/config.ts b/apps/server/src/config/config.ts index e2d0b540c..67af650e8 100644 --- a/apps/server/src/config/config.ts +++ b/apps/server/src/config/config.ts @@ -1,6 +1,9 @@ +import { MILLIS_PER_MINUTE } from 'ontime-utils'; + export const timerConfig = { skipLimit: 1000, // threshold of skip for recalculating updateRate: 32, // how often do we update the timer notificationRate: 1000, // how often do we notify clients and integrations triggerAhead: 10, // how far ahead do we trigger the end event + auxTimerDefault: 5 * MILLIS_PER_MINUTE, // default aux timer duration }; diff --git a/apps/server/src/services/aux-timer-service/AuxTimerService.ts b/apps/server/src/services/aux-timer-service/AuxTimerService.ts index 601e8186d..48d9157f2 100644 --- a/apps/server/src/services/aux-timer-service/AuxTimerService.ts +++ b/apps/server/src/services/aux-timer-service/AuxTimerService.ts @@ -2,6 +2,7 @@ import { SimpleDirection, SimpleTimerState } from 'ontime-types'; import { SimpleTimer } from '../../classes/simple-timer/SimpleTimer.js'; import { eventStore } from '../../stores/EventStore.js'; +import { timerConfig } from '../../config/config.js'; export type EmitFn = (state: SimpleTimerState) => void; export type GetTimeFn = () => number; @@ -13,7 +14,7 @@ export class AuxTimerService { private getTime: GetTimeFn; constructor(emit: EmitFn, getTime: GetTimeFn) { - this.timer = new SimpleTimer(); + this.timer = new SimpleTimer(timerConfig.auxTimerDefault); this.emit = emit; this.getTime = getTime; } @@ -30,7 +31,7 @@ export class AuxTimerService { @broadcastReturn setDirection(direction: SimpleDirection) { - return this.timer.setDirection(direction); + return this.timer.setDirection(direction, this.getTime()); } @broadcastReturn