Refactor: WebSocket from flush queue to one patch (#1595)

* change flush to one patch

* remove unused types

* create batch

* merge patch into eventStore

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Alex Christoffer Rasmussen
2025-05-07 11:40:30 +02:00
committed by Carlos Valente
parent 0a596624d5
commit bdcec7a472
4 changed files with 34 additions and 95 deletions
@@ -696,6 +696,8 @@ function broadcastResult(_target: any, _propertyKey: string, descriptor: Propert
const result = originalMethod.apply(this, args);
const state = runtimeState.getState();
const batch = eventStore.createBatch();
// we do the comparison by explicitly for each property
// to apply custom logic for different datasets
@@ -758,24 +760,24 @@ function broadcastResult(_target: any, _propertyKey: string, descriptor: Propert
//Now we set all the updates on the eventstore and update the previous value
if (hasChangedPlayback) {
eventStore.set('onAir', state.timer.playback !== Playback.Stop);
batch.add('onAir', state.timer.playback !== Playback.Stop);
}
if (shouldUpdateTimer) {
eventStore.set('timer', state.timer);
batch.add('timer', state.timer);
RuntimeService.previousTimerUpdate = state.clock;
RuntimeService.previousTimerValue = state.timer.current;
RuntimeService.previousState.timer = { ...state.timer };
}
if (shouldRuntimeUpdate) {
eventStore.set('runtime', state.runtime);
batch.add('runtime', state.runtime);
RuntimeService.previousRuntimeUpdate = state.clock;
RuntimeService.previousState.runtime = { ...state.runtime };
}
if (shouldBlockUpdate) {
eventStore.set('currentBlock', state.currentBlock);
batch.add('currentBlock', state.currentBlock);
RuntimeService.previousState.currentBlock = { ...state.currentBlock };
}
@@ -785,7 +787,7 @@ function broadcastResult(_target: any, _propertyKey: string, descriptor: Propert
if (shouldUpdateClock) {
RuntimeService.previousClockUpdate = state.clock;
eventStore.set('clock', state.clock);
batch.add('clock', state.clock);
}
// Update the events if they have changed
@@ -817,7 +819,7 @@ function broadcastResult(_target: any, _propertyKey: string, descriptor: Propert
}
function storeKey(eventKey: RuntimeStateEventKeys) {
eventStore.set(eventKey, state[eventKey]);
batch.add(eventKey, state[eventKey]);
// @ts-expect-error -- not sure how to type this in a sane way
RuntimeService.previousState[eventKey] = { ...state[eventKey] };
}
@@ -836,6 +838,7 @@ function broadcastResult(_target: any, _propertyKey: string, descriptor: Propert
});
}
batch.send();
return result;
};
+15 -18
View File
@@ -1,18 +1,16 @@
import { RuntimeStore } from 'ontime-types';
import { socket } from '../adapters/WebsocketAdapter.js';
import { isEmptyObject } from '../utils/parserUtils.js';
export type PublishFn = <T extends keyof RuntimeStore>(key: T, value: RuntimeStore[T]) => void;
export type StoreGetter = <T extends keyof RuntimeStore>(key: T) => Partial<RuntimeStore>[T];
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
* - batchSet: allows setting several keys with a single broadcast
* - poll: utility to return state
* - broadcast: send its payload as json object
*/
@@ -25,21 +23,20 @@ export const eventStore = {
},
set<T extends keyof RuntimeStore>(key: T, value: RuntimeStore[T]) {
store[key] = value;
// 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] });
}
socket.sendAsJson({ type: 'ontime-flush' });
isUpdatePending = null;
changedKeys.clear();
});
}
socket.sendAsJson({ type: 'ontime-patch', payload: { [key]: value } });
},
createBatch() {
const patch: Partial<RuntimeStore> = {};
return {
add<T extends keyof RuntimeStore>(key: T, value: RuntimeStore[T]) {
patch[key] = value;
},
send() {
if (isEmptyObject(patch)) return;
store = { ...store, ...patch };
socket.sendAsJson({ type: 'ontime-patch', payload: patch });
},
};
},
poll() {
return store as RuntimeStore;