mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-07 00:13:53 +00:00
refactor: migrate to OSC min
This commit is contained in:
@@ -113,31 +113,31 @@ describe('parseNestedTemplate() -> stringToOSCArgs()', () => {
|
||||
const payloads = [
|
||||
{
|
||||
test: '"string with space and {{not.so.easy}}"',
|
||||
expect: [{ type: 'string', value: 'string with space and data with space' }],
|
||||
expect: { type: 'string', value: 'string with space and data with space' },
|
||||
},
|
||||
{
|
||||
test: '',
|
||||
expect: [],
|
||||
expect: undefined,
|
||||
},
|
||||
{
|
||||
test: ' ',
|
||||
expect: [],
|
||||
expect: undefined,
|
||||
},
|
||||
{
|
||||
test: '""',
|
||||
expect: [{ type: 'string', value: '' }],
|
||||
expect: { type: 'string', value: '' },
|
||||
},
|
||||
{
|
||||
test: '"string with space and {{not.so.empty}}"',
|
||||
expect: [{ type: 'string', value: 'string with space and ' }],
|
||||
expect: { type: 'string', value: 'string with space and ' },
|
||||
},
|
||||
{
|
||||
test: '"string with space and {{not.so.number}}"',
|
||||
expect: [{ type: 'string', value: 'string with space and 1234' }],
|
||||
expect: { type: 'string', value: 'string with space and 1234' },
|
||||
},
|
||||
{
|
||||
test: '"string with space and {{not.so.stringNumber}}"',
|
||||
expect: [{ type: 'string', value: 'string with space and 1234' }],
|
||||
expect: { type: 'string', value: 'string with space and 1234' },
|
||||
},
|
||||
{
|
||||
test: '"{{not.so.easy}}" 1',
|
||||
@@ -155,7 +155,7 @@ describe('parseNestedTemplate() -> stringToOSCArgs()', () => {
|
||||
},
|
||||
{
|
||||
test: '',
|
||||
expect: [],
|
||||
expect: undefined,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -174,22 +174,28 @@ describe('test stringToOSCArgs()', () => {
|
||||
{ type: 'string', value: 'test' },
|
||||
{ type: 'integer', value: 1111 },
|
||||
{ type: 'float', value: 0.1111 },
|
||||
{ type: 'T', value: true },
|
||||
{ type: 'F', value: false },
|
||||
{ type: 'true' },
|
||||
{ type: 'false' },
|
||||
];
|
||||
expect(stringToOSCArgs(test)).toStrictEqual(expected);
|
||||
});
|
||||
|
||||
it('empty is nothing', () => {
|
||||
expect(stringToOSCArgs(undefined)).toStrictEqual([]);
|
||||
const test = undefined;
|
||||
const expected = undefined;
|
||||
expect(stringToOSCArgs(test)).toStrictEqual(expected);
|
||||
});
|
||||
|
||||
it('empty is nothing', () => {
|
||||
expect(stringToOSCArgs('')).toStrictEqual([]);
|
||||
const test = '';
|
||||
const expected = undefined;
|
||||
expect(stringToOSCArgs(test)).toStrictEqual(expected);
|
||||
});
|
||||
|
||||
it('1 space is nothing', () => {
|
||||
expect(stringToOSCArgs(' ')).toStrictEqual([]);
|
||||
const test = ' ';
|
||||
const expected = undefined;
|
||||
expect(stringToOSCArgs(test)).toStrictEqual(expected);
|
||||
});
|
||||
|
||||
it('keep other types in strings', () => {
|
||||
@@ -210,8 +216,8 @@ describe('test stringToOSCArgs()', () => {
|
||||
{ type: 'string', value: 'test space' },
|
||||
{ type: 'integer', value: 1111 },
|
||||
{ type: 'float', value: 0.1111 },
|
||||
{ type: 'T', value: true },
|
||||
{ type: 'F', value: false },
|
||||
{ type: 'true' },
|
||||
{ type: 'false' },
|
||||
];
|
||||
expect(stringToOSCArgs(test)).toStrictEqual(expected);
|
||||
});
|
||||
@@ -222,8 +228,8 @@ describe('test stringToOSCArgs()', () => {
|
||||
{ type: 'string', value: 'test " space' },
|
||||
{ type: 'integer', value: 1111 },
|
||||
{ type: 'float', value: 0.1111 },
|
||||
{ type: 'T', value: true },
|
||||
{ type: 'F', value: false },
|
||||
{ type: 'true' },
|
||||
{ type: 'false' },
|
||||
];
|
||||
expect(stringToOSCArgs(test)).toStrictEqual(expected);
|
||||
});
|
||||
@@ -233,8 +239,8 @@ describe('test stringToOSCArgs()', () => {
|
||||
const expected = [
|
||||
{ type: 'integer', value: 1111 },
|
||||
{ type: 'float', value: 0.1111 },
|
||||
{ type: 'T', value: true },
|
||||
{ type: 'F', value: false },
|
||||
{ type: 'true' },
|
||||
{ type: 'false' },
|
||||
];
|
||||
expect(stringToOSCArgs(test)).toStrictEqual(expected);
|
||||
});
|
||||
|
||||
@@ -5,6 +5,7 @@ import type { Request, Response } from 'express';
|
||||
|
||||
import * as automationDao from './automation.dao.js';
|
||||
import * as automationService from './automation.service.js';
|
||||
import { oscServer } from '../../adapters/OscAdapter.js';
|
||||
|
||||
export function getAutomationSettings(_req: Request, res: Response<AutomationSettings>) {
|
||||
res.json(automationDao.getAutomationSettings());
|
||||
@@ -20,6 +21,11 @@ export function postAutomationSettings(req: Request, res: Response<AutomationSet
|
||||
automations: req.body.automations ?? undefined,
|
||||
blueprints: req.body.blueprints ?? undefined,
|
||||
});
|
||||
if (automationSettings.enabledOscIn) {
|
||||
oscServer.init(automationSettings.oscPortIn);
|
||||
} else {
|
||||
oscServer.shutdown();
|
||||
}
|
||||
res.status(200).send(automationSettings);
|
||||
} catch (error) {
|
||||
const message = getErrorMessage(error);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { FilterRule, MaybeNumber } from 'ontime-types';
|
||||
import { millisToString, removeLeadingZero, splitWhitespace, getPropertyFromPath } from 'ontime-utils';
|
||||
|
||||
import { Argument } from 'node-osc';
|
||||
import type { OscArgOrArrayInput, OscArgInput } from 'osc-min';
|
||||
|
||||
type FilterOperator = 'equals' | 'not_equals' | 'greater_than' | 'less_than' | 'contains';
|
||||
|
||||
@@ -13,41 +12,44 @@ export function isFilterRule(value: string): value is FilterRule {
|
||||
return value === 'all' || value === 'any';
|
||||
}
|
||||
|
||||
export function stringToOSCArgs(argsString: string | undefined): Argument[] {
|
||||
if (typeof argsString === 'undefined' || argsString === '') {
|
||||
return new Array<Argument>();
|
||||
function toOscValue(argString: string): OscArgInput {
|
||||
const argAsNum = Number(argString);
|
||||
// NOTE: number like: 1 2.0 33333
|
||||
if (!Number.isNaN(argAsNum)) {
|
||||
return { type: argString.includes('.') ? 'float' : 'integer', value: argAsNum };
|
||||
}
|
||||
|
||||
if (argString.startsWith('"') && argString.endsWith('"')) {
|
||||
// NOTE: "quoted string"
|
||||
return { type: 'string', value: argString.substring(1, argString.length - 1) };
|
||||
}
|
||||
|
||||
if (argString === 'TRUE') {
|
||||
// NOTE: Boolean true
|
||||
return { type: 'true' };
|
||||
}
|
||||
|
||||
if (argString === 'FALSE') {
|
||||
// NOTE: Boolean false
|
||||
return { type: 'false' };
|
||||
}
|
||||
|
||||
// NOTE: string
|
||||
return { type: 'string', value: argString };
|
||||
}
|
||||
|
||||
export function stringToOSCArgs(argsString: string | undefined): OscArgInput | OscArgOrArrayInput[] | undefined {
|
||||
if (typeof argsString === 'undefined' || argsString === '') return;
|
||||
|
||||
const matches = splitWhitespace(argsString);
|
||||
|
||||
if (!matches) {
|
||||
return new Array<Argument>();
|
||||
if (!matches) return;
|
||||
|
||||
if (matches.length === 1) {
|
||||
return toOscValue(matches[0]);
|
||||
}
|
||||
|
||||
const parsedArguments: Argument[] = matches.map((argString: string) => {
|
||||
const argAsNum = Number(argString);
|
||||
// NOTE: number like: 1 2.0 33333
|
||||
if (!Number.isNaN(argAsNum)) {
|
||||
return { type: argString.includes('.') ? 'float' : 'integer', value: argAsNum };
|
||||
}
|
||||
|
||||
if (argString.startsWith('"') && argString.endsWith('"')) {
|
||||
// NOTE: "quoted string"
|
||||
return { type: 'string', value: argString.substring(1, argString.length - 1) };
|
||||
}
|
||||
|
||||
if (argString === 'TRUE') {
|
||||
// NOTE: Boolean true
|
||||
return { type: 'T', value: true };
|
||||
}
|
||||
|
||||
if (argString === 'FALSE') {
|
||||
// NOTE: Boolean false
|
||||
return { type: 'F', value: false };
|
||||
}
|
||||
|
||||
// NOTE: string
|
||||
return { type: 'string', value: argString };
|
||||
});
|
||||
const parsedArguments: OscArgOrArrayInput[] = matches.map(toOscValue);
|
||||
|
||||
return parsedArguments;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
import { LogOrigin, OSCOutput } from 'ontime-types';
|
||||
|
||||
import { Client, Message } from 'node-osc';
|
||||
import { type OscPacketInput, toBuffer as oscPacketToBuffer } from 'osc-min';
|
||||
import * as dgram from 'node:dgram';
|
||||
|
||||
import { logger } from '../../../classes/Logger.js';
|
||||
import { type RuntimeState } from '../../../stores/runtimeState.js';
|
||||
import { parseTemplateNested, stringToOSCArgs } from '../automation.utils.js';
|
||||
|
||||
const udpClient = dgram.createSocket('udp4');
|
||||
|
||||
/**
|
||||
* Expose possibility to send a message using OSC protocol
|
||||
*/
|
||||
@@ -15,25 +18,30 @@ export function emitOSC(output: OSCOutput, state: RuntimeState) {
|
||||
}
|
||||
|
||||
/** Parses the state and prepares payload to be emitted */
|
||||
function preparePayload(output: OSCOutput, state: RuntimeState): Message {
|
||||
function preparePayload(output: OSCOutput, state: RuntimeState): OscPacketInput {
|
||||
// check for templates in the address
|
||||
const parsedAddress = parseTemplateNested(output.address, state);
|
||||
const message = new Message(parsedAddress);
|
||||
|
||||
// check for templates in the arguments
|
||||
const parsedArguments = output.args ? parseTemplateNested(output.args, state) : undefined;
|
||||
// check we have the correct type
|
||||
message.append(stringToOSCArgs(parsedArguments));
|
||||
return message;
|
||||
const oscArguments = stringToOSCArgs(parsedArguments);
|
||||
return { address: parsedAddress, args: oscArguments };
|
||||
}
|
||||
|
||||
/** Emits message over transport */
|
||||
function emit(targetIP: string, targetPort: number, message: Message) {
|
||||
logger.info(LogOrigin.Rx, `Sending OSC: ${targetIP}:${targetPort}`);
|
||||
function emit(targetIP: string, targetPort: number, packet: OscPacketInput) {
|
||||
logger.info(LogOrigin.Tx, `Sending OSC: ${targetIP}:${targetPort}`);
|
||||
|
||||
const oscClient = new Client(targetIP, targetPort);
|
||||
oscClient.send(message, () => {
|
||||
oscClient.close();
|
||||
/**
|
||||
* TODO: remove this type casting when change is merged
|
||||
* https://github.com/DefinitelyTyped/DefinitelyTyped/pull/71659
|
||||
*/
|
||||
const buffer = oscPacketToBuffer(packet) as unknown as Uint8Array;
|
||||
udpClient.send(buffer, 0, buffer.byteLength, targetPort, targetIP, (error) => {
|
||||
if (error) {
|
||||
logger.warning(LogOrigin.Tx, `Failed sending OSC: ${error}`);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user