mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-22 07:29:08 +00:00
add http integration
This commit is contained in:
+19
-9
@@ -1,4 +1,4 @@
|
|||||||
import { LogOrigin, OSCSettings } from 'ontime-types';
|
import { HTTPSettings, LogOrigin, OSCSettings } from 'ontime-types';
|
||||||
|
|
||||||
import 'dotenv/config';
|
import 'dotenv/config';
|
||||||
import express from 'express';
|
import express from 'express';
|
||||||
@@ -29,6 +29,7 @@ import { eventLoader } from './classes/event-loader/EventLoader.js';
|
|||||||
import { integrationService } from './services/integration-service/IntegrationService.js';
|
import { integrationService } from './services/integration-service/IntegrationService.js';
|
||||||
import { logger } from './classes/Logger.js';
|
import { logger } from './classes/Logger.js';
|
||||||
import { oscIntegration } from './services/integration-service/OscIntegration.js';
|
import { oscIntegration } from './services/integration-service/OscIntegration.js';
|
||||||
|
import { httpIntegration } from './services/integration-service/HttpIntegration.js';
|
||||||
import { populateStyles } from './modules/loadStyles.js';
|
import { populateStyles } from './modules/loadStyles.js';
|
||||||
import { eventStore, getInitialPayload } from './stores/EventStore.js';
|
import { eventStore, getInitialPayload } from './stores/EventStore.js';
|
||||||
import { PlaybackService } from './services/PlaybackService.js';
|
import { PlaybackService } from './services/PlaybackService.js';
|
||||||
@@ -161,7 +162,6 @@ export const startServer = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description starts OSC server
|
|
||||||
* @description starts OSC server
|
* @description starts OSC server
|
||||||
* @param overrideConfig
|
* @param overrideConfig
|
||||||
* @return {Promise<void>}
|
* @return {Promise<void>}
|
||||||
@@ -190,20 +190,30 @@ export const startOSCServer = async (overrideConfig = null) => {
|
|||||||
/**
|
/**
|
||||||
* starts integrations
|
* starts integrations
|
||||||
*/
|
*/
|
||||||
export const startIntegrations = async (config?: { osc: OSCSettings }) => {
|
export const startIntegrations = async (config?: { osc: OSCSettings; http: HTTPSettings }) => {
|
||||||
checkStart(OntimeStartOrder.InitIO);
|
checkStart(OntimeStartOrder.InitIO);
|
||||||
|
|
||||||
const { osc } = config ?? DataProvider.getData();
|
const { osc, http } = config ?? DataProvider.getData();
|
||||||
|
|
||||||
if (!osc) {
|
if (!osc) {
|
||||||
return 'OSC Invalid configuration';
|
return 'OSC Invalid configuration';
|
||||||
|
} else {
|
||||||
|
const { success, message } = oscIntegration.init(osc);
|
||||||
|
logger.info(LogOrigin.Tx, message);
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
integrationService.register(oscIntegration);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if (!http) {
|
||||||
|
return 'HTTP Invalid configuration';
|
||||||
|
} else {
|
||||||
|
const { success, message } = httpIntegration.init(http);
|
||||||
|
logger.info(LogOrigin.Tx, message);
|
||||||
|
|
||||||
const { success, message } = oscIntegration.init(osc);
|
if (success) {
|
||||||
logger.info(LogOrigin.Tx, message);
|
integrationService.register(httpIntegration);
|
||||||
|
}
|
||||||
if (success) {
|
|
||||||
integrationService.register(oscIntegration);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -56,4 +56,15 @@ export const dbModel: DatabaseModel = {
|
|||||||
onFinish: [],
|
onFinish: [],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
http: {
|
||||||
|
enabledOut: false,
|
||||||
|
subscriptions: {
|
||||||
|
onLoad: [],
|
||||||
|
onStart: [],
|
||||||
|
onPause: [],
|
||||||
|
onStop: [],
|
||||||
|
onUpdate: [],
|
||||||
|
onFinish: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,106 @@
|
|||||||
|
//TODO: cleanup stuff left over from OSC copy
|
||||||
|
import http from 'node:http';
|
||||||
|
import { HTTPSettings, Subscription } from 'ontime-types';
|
||||||
|
|
||||||
|
import IIntegration, { TimerLifeCycleKey } from './IIntegration.js';
|
||||||
|
import { parseTemplateNested } from './integrationUtils.js';
|
||||||
|
import { isObject } from '../../utils/varUtils.js';
|
||||||
|
import { dbModel } from '../../models/dataModel.js';
|
||||||
|
import { validateHttpObject } from '../../utils/parserFunctions.js';
|
||||||
|
|
||||||
|
type Action = TimerLifeCycleKey | string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Class contains logic towards outgoing HTTP communications
|
||||||
|
* @class
|
||||||
|
*/
|
||||||
|
export class HttpIntegration implements IIntegration {
|
||||||
|
subscriptions: Subscription;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
// this.httpClient = null;
|
||||||
|
this.subscriptions = dbModel.http.subscriptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes httpClient
|
||||||
|
*/
|
||||||
|
init(config: HTTPSettings) {
|
||||||
|
const { subscriptions } = config;
|
||||||
|
|
||||||
|
this.initSubscriptions(subscriptions);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// this allows re-calling the init function during runtime
|
||||||
|
// this.httpClient?.close();
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
message: `HTTP integration client}`,
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: `Failed initialising HTTP: ${error}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
initSubscriptions(subscriptionOptions: Subscription) {
|
||||||
|
if (validateHttpObject(subscriptionOptions)) {
|
||||||
|
this.subscriptions = { ...subscriptionOptions };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(action: Action, state?: object) {
|
||||||
|
if (false) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: 'Client not initialised',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!action) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: 'HTTP called with no action',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// check subscriptions for action
|
||||||
|
const eventSubscriptions = this.subscriptions?.[action] || [];
|
||||||
|
|
||||||
|
eventSubscriptions.forEach((sub) => {
|
||||||
|
const { enabled, message } = sub;
|
||||||
|
if (enabled && message) {
|
||||||
|
const parsedMessage = parseTemplateNested(message, state || {});
|
||||||
|
this.emit(parsedMessage);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
emit(path: string) {
|
||||||
|
http.get(path, (res) => {
|
||||||
|
if (res.statusCode < 300) {
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
message: 'HTTP Message sent',
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: `Error sending message responds: ${res.statusCode}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
shutdown() {
|
||||||
|
console.log('Shutting down HTTP integration');
|
||||||
|
// if (this.httpClient) {
|
||||||
|
// // this.httpClient?.close();
|
||||||
|
// this.httpClient = null;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const httpIntegration = new HttpIntegration();
|
||||||
@@ -20,6 +20,7 @@ import {
|
|||||||
parseAliases,
|
parseAliases,
|
||||||
parseProject,
|
parseProject,
|
||||||
parseOsc,
|
parseOsc,
|
||||||
|
parseHttp,
|
||||||
parseRundown,
|
parseRundown,
|
||||||
parseSettings,
|
parseSettings,
|
||||||
parseUserFields,
|
parseUserFields,
|
||||||
@@ -319,7 +320,7 @@ export const parseJson = async (jsonData, enforce = false): Promise<DatabaseMode
|
|||||||
// Import OSC settings if any
|
// Import OSC settings if any
|
||||||
returnData.osc = parseOsc(jsonData, enforce);
|
returnData.osc = parseOsc(jsonData, enforce);
|
||||||
// Import HTTP settings if any
|
// Import HTTP settings if any
|
||||||
// returnData.http = parseHttp(jsonData, enforce);
|
returnData.http = parseHttp(jsonData, enforce);
|
||||||
|
|
||||||
return returnData as DatabaseModel;
|
return returnData as DatabaseModel;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import {
|
|||||||
Alias,
|
Alias,
|
||||||
EndAction,
|
EndAction,
|
||||||
OntimeRundown,
|
OntimeRundown,
|
||||||
|
HTTPSettings,
|
||||||
OSCSettings,
|
OSCSettings,
|
||||||
Subscription,
|
Subscription,
|
||||||
SubscriptionOptions,
|
SubscriptionOptions,
|
||||||
@@ -190,7 +191,7 @@ export const parseViewSettings = (data, enforce): ViewSettings => {
|
|||||||
* Parses and validates subscription entry
|
* Parses and validates subscription entry
|
||||||
* @param data
|
* @param data
|
||||||
*/
|
*/
|
||||||
export const validateOscSubscriptionEntry = (data: OscSubscriptionOptions): boolean => {
|
export const validateOscSubscriptionEntry = (data: SubscriptionOptions): boolean => {
|
||||||
for (const subscription in data) {
|
for (const subscription in data) {
|
||||||
if (typeof data[subscription].message !== 'string' || typeof data[subscription].enabled !== 'boolean') {
|
if (typeof data[subscription].message !== 'string' || typeof data[subscription].enabled !== 'boolean') {
|
||||||
return false;
|
return false;
|
||||||
@@ -203,7 +204,7 @@ export const validateOscSubscriptionEntry = (data: OscSubscriptionOptions): bool
|
|||||||
* Parses and validates subscription object
|
* Parses and validates subscription object
|
||||||
* @param data
|
* @param data
|
||||||
*/
|
*/
|
||||||
export const validateOscObject = (data: OscSubscription): boolean => {
|
export const validateOscObject = (data: Subscription): boolean => {
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -252,22 +253,78 @@ export const parseOsc = (
|
|||||||
} else return {};
|
} else return {};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses and validates subscription entry
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export const validateHttpSubscriptionEntry = (data: SubscriptionOptions): boolean => {
|
||||||
|
for (const subscription in data) {
|
||||||
|
if (typeof data[subscription].message !== 'string' || typeof data[subscription].enabled !== 'boolean') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses and validates subscription object
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export const validateHttpObject = (data: Subscription): boolean => {
|
||||||
|
if (!data) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const timerKeys = Object.keys(TimerLifeCycle);
|
||||||
|
for (const key of timerKeys) {
|
||||||
|
if (!(key in data) || !Array.isArray(data[key])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (const subscription of data[key]) {
|
||||||
|
if (typeof subscription.message !== 'string' || typeof subscription.enabled !== 'boolean') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse Http portion of an entry
|
* Parse Http portion of an entry
|
||||||
* @param {object} data - data object
|
* @param {object} data - data object
|
||||||
* @param {boolean} enforce - whether to create a definition if one is missing
|
* @param {boolean} enforce - whether to create a definition if one is missing
|
||||||
* @returns {object} - event object data
|
* @returns {object} - event object data
|
||||||
*/
|
*/
|
||||||
export const parseHttp = (data, enforce) => {
|
export const parseHttp = (
|
||||||
const newHttp = {};
|
data: {
|
||||||
|
http?: Partial<HTTPSettings>;
|
||||||
|
},
|
||||||
|
enforce: boolean,
|
||||||
|
): HTTPSettings | Record<string, never> => {
|
||||||
if ('http' in data) {
|
if ('http' in data) {
|
||||||
console.log('Found HTTP definition, importing...');
|
console.log('Found HTTP definition, importing...');
|
||||||
|
|
||||||
|
const loadedConfig = data?.http || {};
|
||||||
|
const validatedSubscriptions = validateHttpObject(loadedConfig.subscriptions)
|
||||||
|
? loadedConfig.subscriptions
|
||||||
|
: dbModel.http.subscriptions;
|
||||||
|
|
||||||
|
return {
|
||||||
|
portIn: loadedConfig.portIn ?? dbModel.http.portIn,
|
||||||
|
portOut: loadedConfig.portOut ?? dbModel.http.portOut,
|
||||||
|
targetIP: loadedConfig.targetIP ?? dbModel.http.targetIP,
|
||||||
|
enabledIn: loadedConfig.enabledIn ?? dbModel.http.enabledIn,
|
||||||
|
enabledOut: loadedConfig.enabledOut ?? dbModel.http.enabledOut,
|
||||||
|
subscriptions: validatedSubscriptions,
|
||||||
|
};
|
||||||
} else if (enforce) {
|
} else if (enforce) {
|
||||||
/* Not yet */
|
console.log('Created HTTP object in db');
|
||||||
}
|
return { ...dbModel.http };
|
||||||
return newHttp;
|
} else return {};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse aliases portion of an entry
|
* Parse aliases portion of an entry
|
||||||
* @param {object} data - data object
|
* @param {object} data - data object
|
||||||
|
|||||||
@@ -259,6 +259,17 @@
|
|||||||
"targetIP": "127.0.0.1",
|
"targetIP": "127.0.0.1",
|
||||||
"enabled": true
|
"enabled": true
|
||||||
},
|
},
|
||||||
|
"http": {
|
||||||
|
"enabledOut": false,
|
||||||
|
"subscriptions": {
|
||||||
|
"onLoad": [],
|
||||||
|
"onStart": [],
|
||||||
|
"onPause": [],
|
||||||
|
"onStop": [],
|
||||||
|
"onUpdate": [],
|
||||||
|
"onFinish": []
|
||||||
|
}
|
||||||
|
},
|
||||||
"aliases": [
|
"aliases": [
|
||||||
{
|
{
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
|
|||||||
@@ -148,5 +148,16 @@
|
|||||||
"onUpdate": [],
|
"onUpdate": [],
|
||||||
"onFinish": []
|
"onFinish": []
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"http": {
|
||||||
|
"enabledOut": true,
|
||||||
|
"subscriptions": {
|
||||||
|
"onLoad": [],
|
||||||
|
"onStart": [],
|
||||||
|
"onPause": [],
|
||||||
|
"onStop": [],
|
||||||
|
"onUpdate": [],
|
||||||
|
"onFinish": []
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -468,5 +468,16 @@
|
|||||||
],
|
],
|
||||||
"onFinish": []
|
"onFinish": []
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"http": {
|
||||||
|
"enabledOut": true,
|
||||||
|
"subscriptions": {
|
||||||
|
"onLoad": [],
|
||||||
|
"onStart": [],
|
||||||
|
"onPause": [],
|
||||||
|
"onStop": [],
|
||||||
|
"onUpdate": [],
|
||||||
|
"onFinish": []
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,6 +5,7 @@ import { OSCSettings } from './core/OscSettings.type.js';
|
|||||||
import { Settings } from './core/Settings.type.js';
|
import { Settings } from './core/Settings.type.js';
|
||||||
import { UserFields } from './core/UserFields.type.js';
|
import { UserFields } from './core/UserFields.type.js';
|
||||||
import { ViewSettings } from './core/Views.type.js';
|
import { ViewSettings } from './core/Views.type.js';
|
||||||
|
import { HTTPSettings } from '../index.js';
|
||||||
|
|
||||||
export type DatabaseModel = {
|
export type DatabaseModel = {
|
||||||
rundown: OntimeRundown;
|
rundown: OntimeRundown;
|
||||||
@@ -14,4 +15,5 @@ export type DatabaseModel = {
|
|||||||
aliases: Alias[];
|
aliases: Alias[];
|
||||||
userFields: UserFields;
|
userFields: UserFields;
|
||||||
osc: OSCSettings;
|
osc: OSCSettings;
|
||||||
|
http: HTTPSettings;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import { Subscription } from './Subscription.type.js';
|
||||||
|
|
||||||
|
|
||||||
|
export interface HTTPSettings {
|
||||||
|
enabledOut: boolean;
|
||||||
|
subscriptions: Subscription;
|
||||||
|
}
|
||||||
@@ -33,6 +33,7 @@ export type { Subscription, SubscriptionOptions } from './definitions/core/Subsc
|
|||||||
// ---> OSC
|
// ---> OSC
|
||||||
export type { OSCSettings } from './definitions/core/OscSettings.type.js';
|
export type { OSCSettings } from './definitions/core/OscSettings.type.js';
|
||||||
// ---> HTTP
|
// ---> HTTP
|
||||||
|
export type { HTTPSettings } from './definitions/core/HttpSettings.type.js';
|
||||||
|
|
||||||
// SERVER RUNTIME
|
// SERVER RUNTIME
|
||||||
export { type Log, LogLevel, type LogMessage, LogOrigin } from './definitions/runtime/Logger.type.js';
|
export { type Log, LogLevel, type LogMessage, LogOrigin } from './definitions/runtime/Logger.type.js';
|
||||||
|
|||||||
Reference in New Issue
Block a user