mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-21 15:09:10 +00:00
Batch client updates (#1448)
This commit is contained in:
committed by
GitHub
parent
f1f628a48e
commit
d175c788c5
@@ -48,6 +48,7 @@ class RuntimeService {
|
|||||||
|
|
||||||
/** last time we updated the socket */
|
/** last time we updated the socket */
|
||||||
static previousTimerUpdate: number;
|
static previousTimerUpdate: number;
|
||||||
|
static previousRuntimeUpdate: number;
|
||||||
static previousTimerValue: MaybeNumber; // previous timer value, could be null
|
static previousTimerValue: MaybeNumber; // previous timer value, could be null
|
||||||
static previousClockUpdate: number;
|
static previousClockUpdate: number;
|
||||||
|
|
||||||
@@ -58,6 +59,7 @@ class RuntimeService {
|
|||||||
this.eventTimer = eventTimer;
|
this.eventTimer = eventTimer;
|
||||||
|
|
||||||
RuntimeService.previousTimerUpdate = -1;
|
RuntimeService.previousTimerUpdate = -1;
|
||||||
|
RuntimeService.previousRuntimeUpdate = -1;
|
||||||
RuntimeService.previousTimerValue = -1;
|
RuntimeService.previousTimerValue = -1;
|
||||||
RuntimeService.previousClockUpdate = -1;
|
RuntimeService.previousClockUpdate = -1;
|
||||||
RuntimeService.previousState = {} as RuntimeState;
|
RuntimeService.previousState = {} as RuntimeState;
|
||||||
@@ -678,10 +680,17 @@ function broadcastResult(_target: any, _propertyKey: string, descriptor: Propert
|
|||||||
// we do the comparison by explicitly for each property
|
// we do the comparison by explicitly for each property
|
||||||
// to apply custom logic for different datasets
|
// to apply custom logic for different datasets
|
||||||
|
|
||||||
const shouldForceTimerUpdate = getForceUpdate(RuntimeService.previousTimerUpdate, state.clock);
|
const shouldForceTimerUpdate = getForceUpdate(
|
||||||
|
RuntimeService.previousTimerUpdate,
|
||||||
|
state.clock,
|
||||||
|
state.timer.playback,
|
||||||
|
);
|
||||||
|
|
||||||
const shouldUpdateTimer =
|
const shouldUpdateTimer =
|
||||||
shouldForceTimerUpdate || getShouldTimerUpdate(RuntimeService.previousTimerValue, state.timer.current);
|
shouldForceTimerUpdate || getShouldTimerUpdate(RuntimeService.previousTimerValue, state.timer.current);
|
||||||
|
|
||||||
|
const shouldRuntimeUpdate = shouldUpdateTimer || getForceUpdate(RuntimeService.previousRuntimeUpdate, state.clock);
|
||||||
|
|
||||||
// some changes need an immediate update
|
// some changes need an immediate update
|
||||||
const hasNewLoaded = state.eventNow?.id !== RuntimeService.previousState?.eventNow?.id;
|
const hasNewLoaded = state.eventNow?.id !== RuntimeService.previousState?.eventNow?.id;
|
||||||
|
|
||||||
@@ -696,12 +705,20 @@ function broadcastResult(_target: any, _propertyKey: string, descriptor: Propert
|
|||||||
if (hasImmediateChanges || (shouldUpdateTimer && !deepEqual(RuntimeService.previousState?.timer, state.timer))) {
|
if (hasImmediateChanges || (shouldUpdateTimer && !deepEqual(RuntimeService.previousState?.timer, state.timer))) {
|
||||||
RuntimeService.previousTimerUpdate = state.clock;
|
RuntimeService.previousTimerUpdate = state.clock;
|
||||||
RuntimeService.previousTimerValue = state.timer.current;
|
RuntimeService.previousTimerValue = state.timer.current;
|
||||||
|
RuntimeService.previousClockUpdate = state.clock;
|
||||||
|
eventStore.set('clock', state.clock);
|
||||||
eventStore.set('timer', state.timer);
|
eventStore.set('timer', state.timer);
|
||||||
RuntimeService.previousState.timer = { ...state.timer };
|
RuntimeService.previousState.timer = { ...state.timer };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasChangedPlayback || (shouldUpdateTimer && !deepEqual(RuntimeService.previousState?.runtime, state.runtime))) {
|
if (
|
||||||
|
hasChangedPlayback ||
|
||||||
|
(shouldRuntimeUpdate && !deepEqual(RuntimeService.previousState?.runtime, state.runtime))
|
||||||
|
) {
|
||||||
eventStore.set('runtime', state.runtime);
|
eventStore.set('runtime', state.runtime);
|
||||||
|
RuntimeService.previousClockUpdate = state.clock;
|
||||||
|
RuntimeService.previousRuntimeUpdate = state.clock;
|
||||||
|
eventStore.set('clock', state.clock);
|
||||||
RuntimeService.previousState.runtime = { ...state.runtime };
|
RuntimeService.previousState.runtime = { ...state.runtime };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -711,15 +728,14 @@ function broadcastResult(_target: any, _propertyKey: string, descriptor: Propert
|
|||||||
updateEventIfChanged('eventNext', state);
|
updateEventIfChanged('eventNext', state);
|
||||||
updateEventIfChanged('publicEventNext', state);
|
updateEventIfChanged('publicEventNext', state);
|
||||||
|
|
||||||
let syncBlockStartAt = false;
|
|
||||||
|
|
||||||
if (!deepEqual(RuntimeService?.previousState.currentBlock, state.currentBlock)) {
|
if (!deepEqual(RuntimeService?.previousState.currentBlock, state.currentBlock)) {
|
||||||
eventStore.set('currentBlock', state.currentBlock);
|
eventStore.set('currentBlock', state.currentBlock);
|
||||||
RuntimeService.previousState.currentBlock = { ...state.currentBlock };
|
RuntimeService.previousState.currentBlock = { ...state.currentBlock };
|
||||||
syncBlockStartAt = true;
|
RuntimeService.previousClockUpdate = state.clock;
|
||||||
|
eventStore.set('clock', state.clock);
|
||||||
}
|
}
|
||||||
|
|
||||||
const shouldUpdateClock = syncBlockStartAt || getShouldClockUpdate(RuntimeService.previousClockUpdate, state.clock);
|
const shouldUpdateClock = getShouldClockUpdate(RuntimeService.previousClockUpdate, state.clock);
|
||||||
|
|
||||||
if (shouldUpdateClock) {
|
if (shouldUpdateClock) {
|
||||||
RuntimeService.previousClockUpdate = state.clock;
|
RuntimeService.previousClockUpdate = state.clock;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { millisToSeconds } from 'ontime-utils';
|
import { millisToSeconds } from 'ontime-utils';
|
||||||
|
|
||||||
import { timerConfig } from '../../config/config.js';
|
import { timerConfig } from '../../config/config.js';
|
||||||
import { MaybeNumber } from 'ontime-types';
|
import { MaybeNumber, Playback } from 'ontime-types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether we should update the clock value
|
* Checks whether we should update the clock value
|
||||||
@@ -34,8 +34,10 @@ export function getShouldTimerUpdate(previousValue: number, currentValue: MaybeN
|
|||||||
* In some cases we want to force an update to the timer
|
* In some cases we want to force an update to the timer
|
||||||
* - if the clock has slid back
|
* - if the clock has slid back
|
||||||
* - if we have escaped the update rate (clock slid forward)
|
* - if we have escaped the update rate (clock slid forward)
|
||||||
|
* - if we are not playing then there is no need to update the timer
|
||||||
*/
|
*/
|
||||||
export function getForceUpdate(previousUpdate: number, now: number): boolean {
|
export function getForceUpdate(previousUpdate: number, now: number, playbackState: Playback = Playback.Play): boolean {
|
||||||
|
if (playbackState !== Playback.Play) return false;
|
||||||
const isClockBehind = now < previousUpdate;
|
const isClockBehind = now < previousUpdate;
|
||||||
const hasExceededRate = now - previousUpdate >= timerConfig.notificationRate;
|
const hasExceededRate = now - previousUpdate >= timerConfig.notificationRate;
|
||||||
return isClockBehind || hasExceededRate;
|
return isClockBehind || hasExceededRate;
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ export type StoreGetter = <T extends keyof RuntimeStore>(key: T) => Partial<Runt
|
|||||||
|
|
||||||
let store: Partial<RuntimeStore> = {};
|
let store: Partial<RuntimeStore> = {};
|
||||||
|
|
||||||
|
const changedKeys = new Set<keyof RuntimeStore>();
|
||||||
|
let isUpdatePending: NodeJS.Immediate | null = null;
|
||||||
/**
|
/**
|
||||||
* A runtime store that broadcasts its payload
|
* A runtime store that broadcasts its payload
|
||||||
* - init: allows for adding an initial payload to the store
|
* - init: allows for adding an initial payload to the store
|
||||||
@@ -23,16 +25,20 @@ export const eventStore = {
|
|||||||
},
|
},
|
||||||
set<T extends keyof RuntimeStore>(key: T, value: RuntimeStore[T]) {
|
set<T extends keyof RuntimeStore>(key: T, value: RuntimeStore[T]) {
|
||||||
store[key] = value;
|
store[key] = value;
|
||||||
socket.sendAsJson({
|
|
||||||
type: `ontime-${key}`,
|
// check if the key is already marked for and update otherwise push it onto the update array
|
||||||
payload: value,
|
changedKeys.add(key);
|
||||||
});
|
|
||||||
},
|
//if there is already and update pending we don't need to schedule another one
|
||||||
batchSet(values: Partial<RuntimeStore>) {
|
if (!isUpdatePending) {
|
||||||
Object.entries(values).forEach(([key, value]) => {
|
isUpdatePending = setImmediate(() => {
|
||||||
store[key] = value;
|
for (const dataKey of changedKeys) {
|
||||||
});
|
socket.sendAsJson({ type: `ontime-${dataKey}`, payload: store[dataKey] });
|
||||||
this.broadcast();
|
}
|
||||||
|
isUpdatePending = null;
|
||||||
|
changedKeys.clear();
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
poll() {
|
poll() {
|
||||||
return store;
|
return store;
|
||||||
|
|||||||
Reference in New Issue
Block a user