mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-10 18:03:47 +00:00
V2 ws store (#310)
* Update TimerService.ts * refactor: message service publishes to store * refactor: several type improvements * V2 ws store wss (#309) * refactor: shared logging types * refactor: simplify message service consumption * refactor: create discrete logging system * refactor: move socket.io > websocket
This commit is contained in:
@@ -1,159 +0,0 @@
|
||||
import { Server } from 'node-osc';
|
||||
import { OSCSettings } from 'ontime-types';
|
||||
|
||||
import { PlaybackService } from '../services/PlaybackService.js';
|
||||
import { messageManager } from '../classes/message-manager/MessageManager.js';
|
||||
import { socketProvider } from '../classes/socket/SocketController.js';
|
||||
|
||||
let oscServer = null;
|
||||
|
||||
/**
|
||||
* @description utility function to shut down osc server
|
||||
*/
|
||||
export const shutdownOSCServer = () => {
|
||||
if (oscServer != null) oscServer.close();
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialises OSC server
|
||||
*/
|
||||
export const initiateOSC = (config: OSCSettings) => {
|
||||
oscServer = new Server(config.portIn, '0.0.0.0');
|
||||
|
||||
oscServer.on('error', console.error);
|
||||
|
||||
oscServer.on('message', function (msg) {
|
||||
// message should look like /ontime/{path} {args} where
|
||||
// ontime: fixed message for app
|
||||
// path: command to be called
|
||||
// args: extra data, only used on some API entries (delay, goto)
|
||||
|
||||
// split message
|
||||
const [, address, path] = msg[0].split('/');
|
||||
const args = msg[1];
|
||||
|
||||
// get first part before (ontime)
|
||||
if (address !== 'ontime') {
|
||||
console.error('RX', `OSC IN: Message address ${address} not recognised`, msg);
|
||||
return;
|
||||
}
|
||||
|
||||
// get second part (command)
|
||||
if (!path) {
|
||||
console.error('RX', 'OSC IN: No path found');
|
||||
return;
|
||||
}
|
||||
|
||||
switch (path.toLowerCase()) {
|
||||
case 'onair': {
|
||||
messageManager.setOnAir(true);
|
||||
break;
|
||||
}
|
||||
case 'offair': {
|
||||
messageManager.setOnAir(false);
|
||||
break;
|
||||
}
|
||||
case 'play': {
|
||||
PlaybackService.start();
|
||||
break;
|
||||
}
|
||||
case 'start': {
|
||||
try {
|
||||
const eventIndex = Number(args);
|
||||
if (isNaN(eventIndex)) {
|
||||
socketProvider.error('RX', `OSC IN: event index not recognised ${args}`);
|
||||
return;
|
||||
}
|
||||
PlaybackService.startByIndex(eventIndex);
|
||||
} catch (error) {
|
||||
console.log('Error loading event: ', error);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'startid': {
|
||||
if (!args) {
|
||||
socketProvider.error('RX', `OSC IN: No ID in request`);
|
||||
return;
|
||||
}
|
||||
PlaybackService.loadById(args);
|
||||
break;
|
||||
}
|
||||
case 'pause': {
|
||||
PlaybackService.pause();
|
||||
break;
|
||||
}
|
||||
case 'prev': {
|
||||
PlaybackService.loadPrevious();
|
||||
break;
|
||||
}
|
||||
case 'next': {
|
||||
PlaybackService.loadNext();
|
||||
break;
|
||||
}
|
||||
case 'unload':
|
||||
case 'stop': {
|
||||
PlaybackService.stop();
|
||||
break;
|
||||
}
|
||||
case 'reload': {
|
||||
PlaybackService.reload();
|
||||
break;
|
||||
}
|
||||
case 'roll': {
|
||||
PlaybackService.roll();
|
||||
break;
|
||||
}
|
||||
case 'delay': {
|
||||
try {
|
||||
const delayTime = Number(args);
|
||||
if (isNaN(delayTime)) {
|
||||
socketProvider.error('RX', `OSC IN: delay time not recognised ${args}`);
|
||||
return;
|
||||
}
|
||||
PlaybackService.setDelay(delayTime);
|
||||
} catch (error) {
|
||||
console.log('Error adding delay: ', error);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'goto':
|
||||
case 'load': {
|
||||
try {
|
||||
const eventIndex = Number(args);
|
||||
if (isNaN(eventIndex) || eventIndex <= 0) {
|
||||
socketProvider.error('RX', `OSC IN: event index not recognised or out of range ${eventIndex}`);
|
||||
} else {
|
||||
PlaybackService.loadByIndex(eventIndex - 1);
|
||||
}
|
||||
} catch (error) {
|
||||
socketProvider.error('RX', `OSC IN: error calling goto ${error}`);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'gotoid':
|
||||
case 'loadid': {
|
||||
if (!args) {
|
||||
socketProvider.error('RX', `OSC IN: event ID not recognised: ${args}}`);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
PlaybackService.loadById(args.toString().toLowerCase());
|
||||
} catch (error) {
|
||||
socketProvider.error('RX', `OSC IN: error calling goto ${error}`);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'get-playback': {
|
||||
const playback = global.timer.state;
|
||||
global.timer.sendOsc('playback', playback);
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
socketProvider.warning('RX', `OSC IN: unhandled message ${path}`);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,188 @@
|
||||
import { messageService } from '../services/message-service/MessageService.js';
|
||||
import { PlaybackService } from '../services/PlaybackService.js';
|
||||
import { eventStore } from '../stores/EventStore.js';
|
||||
|
||||
export function dispatchFromAdapter(type: string, payload: unknown, source?: 'osc' | 'ws') {
|
||||
switch (type.toLowerCase()) {
|
||||
case 'test-ontime': {
|
||||
return { topic: 'hello' };
|
||||
}
|
||||
|
||||
case 'ontime-poll': {
|
||||
return {
|
||||
topic: 'poll',
|
||||
payload: eventStore.poll(),
|
||||
};
|
||||
}
|
||||
|
||||
case 'set-onair': {
|
||||
if (typeof payload !== 'undefined') {
|
||||
messageService.setOnAir(Boolean(payload));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'onair': {
|
||||
messageService.setOnAir(true);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'offair': {
|
||||
messageService.setOnAir(false);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'set-timer-message-text': {
|
||||
if (typeof payload !== 'string') {
|
||||
throw new Error(`Unable to parse payload: ${payload}`);
|
||||
}
|
||||
messageService.setTimerText(payload);
|
||||
break;
|
||||
}
|
||||
case 'set-timer-message-visible': {
|
||||
if (typeof payload === 'undefined') {
|
||||
throw new Error(`Unable to parse payload: ${payload}`);
|
||||
}
|
||||
messageService.setTimerVisibility(Boolean(payload));
|
||||
break;
|
||||
}
|
||||
|
||||
case 'set-public-message-text': {
|
||||
if (typeof payload !== 'string') {
|
||||
throw new Error(`Unable to parse payload: ${payload}`);
|
||||
}
|
||||
messageService.setPublicText(payload);
|
||||
break;
|
||||
}
|
||||
case 'set-public-message-visible': {
|
||||
if (typeof payload === 'undefined') {
|
||||
throw new Error(`Unable to parse payload: ${payload}`);
|
||||
}
|
||||
messageService.setPublicVisibility(Boolean(payload));
|
||||
break;
|
||||
}
|
||||
|
||||
case 'set-lower-message-text': {
|
||||
if (typeof payload !== 'string') {
|
||||
throw new Error(`Unable to parse payload: ${payload}`);
|
||||
}
|
||||
messageService.setLowerText(payload);
|
||||
break;
|
||||
}
|
||||
case 'set-lower-message-visible': {
|
||||
if (typeof payload === 'undefined') {
|
||||
throw new Error(`Unable to parse payload: ${payload}`);
|
||||
}
|
||||
messageService.setLowerVisibility(Boolean(payload));
|
||||
break;
|
||||
}
|
||||
|
||||
case 'start': {
|
||||
PlaybackService.start();
|
||||
break;
|
||||
}
|
||||
|
||||
case 'startindex': {
|
||||
const eventIndex = Number(payload);
|
||||
if (isNaN(eventIndex) || eventIndex <= 0) {
|
||||
throw new Error(`Event index not recognised or out of range ${eventIndex}`);
|
||||
}
|
||||
|
||||
try {
|
||||
// Indexes in frontend are 1 based
|
||||
PlaybackService.startByIndex(eventIndex - 1);
|
||||
} catch (error) {
|
||||
throw new Error(`Error loading event:: ${error}`);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'startid': {
|
||||
if (!payload) {
|
||||
throw new Error(`Event ID not recognised: ${payload}`);
|
||||
}
|
||||
PlaybackService.startById(payload);
|
||||
break;
|
||||
}
|
||||
case 'pause': {
|
||||
PlaybackService.pause();
|
||||
break;
|
||||
}
|
||||
case 'previous': {
|
||||
PlaybackService.loadPrevious();
|
||||
break;
|
||||
}
|
||||
case 'next': {
|
||||
PlaybackService.loadNext();
|
||||
break;
|
||||
}
|
||||
case 'unload':
|
||||
case 'stop': {
|
||||
PlaybackService.stop();
|
||||
break;
|
||||
}
|
||||
case 'reload': {
|
||||
PlaybackService.reload();
|
||||
break;
|
||||
}
|
||||
case 'roll': {
|
||||
PlaybackService.roll();
|
||||
break;
|
||||
}
|
||||
case 'delay': {
|
||||
const delayTime = Number(payload);
|
||||
if (isNaN(delayTime)) {
|
||||
throw new Error(`Delay time not recognised ${payload}`);
|
||||
}
|
||||
|
||||
try {
|
||||
PlaybackService.setDelay(delayTime);
|
||||
} catch (error) {
|
||||
throw new Error(`Could not add delay: ${error}`);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'gotoindex':
|
||||
case 'loadindex': {
|
||||
const eventIndex = Number(payload);
|
||||
if (isNaN(eventIndex) || eventIndex <= 0) {
|
||||
throw new Error(`Event index not recognised or out of range ${eventIndex}`);
|
||||
}
|
||||
|
||||
try {
|
||||
// Indexes in frontend are 1 based
|
||||
PlaybackService.loadByIndex(eventIndex - 1);
|
||||
} catch (error) {
|
||||
throw new Error(`Event index not recognised or out of range ${error}`);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'gotoid':
|
||||
case 'loadid': {
|
||||
if (!payload) {
|
||||
throw new Error(`Event ID not recognised: ${payload}`);
|
||||
}
|
||||
|
||||
try {
|
||||
PlaybackService.loadById(payload.toString().toLowerCase());
|
||||
} catch (error) {
|
||||
throw new Error(`OSC IN: error calling goto ${error}`);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'get-playback': {
|
||||
const playback = eventStore.get('playback');
|
||||
return { topic: 'playback', payload: playback };
|
||||
}
|
||||
|
||||
case 'get-timer': {
|
||||
const timer = eventStore.get('timer');
|
||||
return { topic: 'timer', payload: timer };
|
||||
}
|
||||
|
||||
default: {
|
||||
throw new Error(`Unhandled message ${type}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,10 @@
|
||||
// Create controller for GET request to '/playback'
|
||||
// Returns ACK message
|
||||
import { PlaybackService } from '../services/PlaybackService.js';
|
||||
import { eventStore } from '../stores/EventStore.js';
|
||||
|
||||
// Create controller for POST request to '/playback'
|
||||
// Returns playback state
|
||||
export const pbGet = async (req, res) => {
|
||||
res.send({ playback: global.timer.state });
|
||||
res.send({ playback: eventStore.get('playback') });
|
||||
};
|
||||
|
||||
// Create controller for POST request to '/playback/start'
|
||||
|
||||
Reference in New Issue
Block a user