mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-13 11:23:50 +00:00
104 lines
2.8 KiB
TypeScript
104 lines
2.8 KiB
TypeScript
import {
|
|
isHTTPOutput,
|
|
isOSCOutput,
|
|
type AutomationFilter,
|
|
type AutomationOutput,
|
|
type FilterRule,
|
|
type RuntimeStore,
|
|
type TimerLifeCycle,
|
|
} from 'ontime-types';
|
|
|
|
import { getState, type RuntimeState } from '../../stores/runtimeState.js';
|
|
import { emitOSC } from './clients/osc.client.js';
|
|
import { emitHTTP } from './clients/http.client.js';
|
|
import { getAutomations, getBlueprints } from './automation.dao.js';
|
|
|
|
/**
|
|
* Exposes a method for triggering actions based on a TimerLifeCycle event
|
|
*/
|
|
export function triggerAutomations(event: TimerLifeCycle, state: RuntimeState) {
|
|
const automations = getAutomations();
|
|
const triggerAutomations = automations.filter((automation) => automation.trigger === event);
|
|
if (triggerAutomations.length === 0) {
|
|
return;
|
|
}
|
|
|
|
const blueprints = getBlueprints();
|
|
if (Object.keys(blueprints).length === 0) {
|
|
return;
|
|
}
|
|
|
|
triggerAutomations.forEach((automation) => {
|
|
const blueprint = blueprints[automation.blueprintId];
|
|
if (!blueprint) {
|
|
return;
|
|
}
|
|
const shouldSend = testConditions(blueprint.filters, blueprint.filterRule, state);
|
|
if (shouldSend) {
|
|
send(blueprint.outputs, state);
|
|
}
|
|
});
|
|
}
|
|
|
|
export function testOutput(payload: AutomationOutput) {
|
|
send([payload]);
|
|
}
|
|
|
|
/**
|
|
* Checks whether the automation conditions are met
|
|
*/
|
|
export function testConditions(
|
|
filters: AutomationFilter[],
|
|
filterRule: FilterRule,
|
|
state: Partial<RuntimeStore>,
|
|
): boolean {
|
|
if (filters.length === 0) {
|
|
return true;
|
|
}
|
|
|
|
if (filterRule === 'all') {
|
|
return filters.every((filter) => evaluateCondition(filter));
|
|
}
|
|
|
|
return filters.some((filter) => evaluateCondition(filter));
|
|
|
|
function evaluateCondition(filter: AutomationFilter): boolean {
|
|
const { field, operator, value } = filter;
|
|
const fieldValue = state[field];
|
|
|
|
// TODO: if value is empty string, the user could be meaning to check if the value does not exist
|
|
switch (operator) {
|
|
case 'equals':
|
|
return fieldValue === value;
|
|
case 'not_equals':
|
|
return fieldValue !== value;
|
|
case 'greater_than':
|
|
return fieldValue > value;
|
|
case 'less_than':
|
|
return fieldValue < value;
|
|
case 'contains':
|
|
return typeof fieldValue === 'string' && fieldValue.includes(value);
|
|
case 'not_contains':
|
|
return typeof fieldValue === 'string' && !fieldValue.includes(value);
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handles preparing and sending of the data
|
|
* Returns a boolean indicating whether a message was sent
|
|
*/
|
|
function send(output: AutomationOutput[], state?: RuntimeState) {
|
|
const stateSnapshot = state ?? getState();
|
|
output.forEach((payload) => {
|
|
if (isOSCOutput(payload)) {
|
|
emitOSC();
|
|
}
|
|
if (isHTTPOutput(payload)) {
|
|
emitHTTP(payload, stateSnapshot);
|
|
}
|
|
});
|
|
}
|