mirror of
https://github.com/cpvalente/ontime.git
synced 2026-07-26 10:38:55 +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 */
|
||||
static previousTimerUpdate: number;
|
||||
static previousRuntimeUpdate: number;
|
||||
static previousTimerValue: MaybeNumber; // previous timer value, could be null
|
||||
static previousClockUpdate: number;
|
||||
|
||||
@@ -58,6 +59,7 @@ class RuntimeService {
|
||||
this.eventTimer = eventTimer;
|
||||
|
||||
RuntimeService.previousTimerUpdate = -1;
|
||||
RuntimeService.previousRuntimeUpdate = -1;
|
||||
RuntimeService.previousTimerValue = -1;
|
||||
RuntimeService.previousClockUpdate = -1;
|
||||
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
|
||||
// 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 =
|
||||
shouldForceTimerUpdate || getShouldTimerUpdate(RuntimeService.previousTimerValue, state.timer.current);
|
||||
|
||||
const shouldRuntimeUpdate = shouldUpdateTimer || getForceUpdate(RuntimeService.previousRuntimeUpdate, state.clock);
|
||||
|
||||
// some changes need an immediate update
|
||||
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))) {
|
||||
RuntimeService.previousTimerUpdate = state.clock;
|
||||
RuntimeService.previousTimerValue = state.timer.current;
|
||||
RuntimeService.previousClockUpdate = state.clock;
|
||||
eventStore.set('clock', state.clock);
|
||||
eventStore.set('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);
|
||||
RuntimeService.previousClockUpdate = state.clock;
|
||||
RuntimeService.previousRuntimeUpdate = state.clock;
|
||||
eventStore.set('clock', state.clock);
|
||||
RuntimeService.previousState.runtime = { ...state.runtime };
|
||||
}
|
||||
|
||||
@@ -711,15 +728,14 @@ function broadcastResult(_target: any, _propertyKey: string, descriptor: Propert
|
||||
updateEventIfChanged('eventNext', state);
|
||||
updateEventIfChanged('publicEventNext', state);
|
||||
|
||||
let syncBlockStartAt = false;
|
||||
|
||||
if (!deepEqual(RuntimeService?.previousState.currentBlock, state.currentBlock)) {
|
||||
eventStore.set('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) {
|
||||
RuntimeService.previousClockUpdate = state.clock;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { millisToSeconds } from 'ontime-utils';
|
||||
|
||||
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
|
||||
@@ -34,8 +34,10 @@ export function getShouldTimerUpdate(previousValue: number, currentValue: MaybeN
|
||||
* In some cases we want to force an update to the timer
|
||||
* - if the clock has slid back
|
||||
* - 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 hasExceededRate = now - previousUpdate >= timerConfig.notificationRate;
|
||||
return isClockBehind || hasExceededRate;
|
||||
|
||||
@@ -7,6 +7,8 @@ export type StoreGetter = <T extends keyof RuntimeStore>(key: T) => Partial<Runt
|
||||
|
||||
let store: Partial<RuntimeStore> = {};
|
||||
|
||||
const changedKeys = new Set<keyof RuntimeStore>();
|
||||
let isUpdatePending: NodeJS.Immediate | null = null;
|
||||
/**
|
||||
* A runtime store that broadcasts its payload
|
||||
* - 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]) {
|
||||
store[key] = value;
|
||||
socket.sendAsJson({
|
||||
type: `ontime-${key}`,
|
||||
payload: value,
|
||||
});
|
||||
},
|
||||
batchSet(values: Partial<RuntimeStore>) {
|
||||
Object.entries(values).forEach(([key, value]) => {
|
||||
store[key] = value;
|
||||
});
|
||||
this.broadcast();
|
||||
|
||||
// check if the key is already marked for and update otherwise push it onto the update array
|
||||
changedKeys.add(key);
|
||||
|
||||
//if there is already and update pending we don't need to schedule another one
|
||||
if (!isUpdatePending) {
|
||||
isUpdatePending = setImmediate(() => {
|
||||
for (const dataKey of changedKeys) {
|
||||
socket.sendAsJson({ type: `ontime-${dataKey}`, payload: store[dataKey] });
|
||||
}
|
||||
isUpdatePending = null;
|
||||
changedKeys.clear();
|
||||
});
|
||||
}
|
||||
},
|
||||
poll() {
|
||||
return store;
|
||||
|
||||
Reference in New Issue
Block a user