Small bugfix

This commit is contained in:
2025-10-24 16:21:04 +02:00
parent 02391f813b
commit 7ce9003621
21 changed files with 601 additions and 10 deletions

View File

@@ -8,6 +8,9 @@ export class CameraRunner {
socket: Socket;
errorTriggerStartupDelay = 10000;
bootTime = Date.now();
state: ServiceState = 'DISCONNECTED';
message?: string;
error?: string;
@@ -76,6 +79,12 @@ export class CameraRunner {
this.state = state;
this.broadcastState();
if (
error != null &&
Date.now() - this.bootTime > this.errorTriggerStartupDelay
)
this._Main.Twilio.sendError('CameraRunner', error);
if (state == 'FAILED' || state == 'DISCONNECTED')
console.warn(PREFIX, message ?? error);
else console.log(PREFIX, message ?? error);
@@ -147,6 +156,7 @@ export class CameraRunner {
});
this.socket.on('connect', () => {
this._Main.Twilio.resetError('CameraRunner');
this.setInfo('Connected', null, 'CONNECTED');
this.startPollClock();
});

View File

@@ -102,6 +102,7 @@ export interface Config {
webServer: ConfigWebServer;
unity: ConfigUnity;
cameraRunner: ConfigCameraRunner;
twilio: ConfigTwilio;
support: ConfigSupport;
}
@@ -134,6 +135,14 @@ export interface ConfigCameraRunner {
pollInterval: number;
}
export interface ConfigTwilio {
accountSid: string;
authToken: string;
fromNumber: string;
toNumbers: string[];
aggregateTimeout: number;
}
export interface ConfigSupport {
telephone: string;
}

View File

@@ -27,6 +27,13 @@ export const DefaultConfiguration: Config = {
pollInterval: 5000,
},
twilio: {
accountSid: '',
authToken: '',
fromNumber: '',
toNumbers: [],
aggregateTimeout: 15000,
},
support: {
telephone: '+31613392837',
},

View File

@@ -8,12 +8,14 @@ import {
import { CameraRunner } from './CameraRunner';
import { UnityRunner } from './Unity/UnityRunner';
import { UnityWebSocket } from './Unity/UnityWebSocket';
import { TwilioHandler } from './Twilio';
export class Main {
dataPath = join(homedir(), 'MorphixProductions', 'NTSHControl');
ConfigurationManager = new ConfigurationManager(this);
WebServer = new WebServer(this);
Twilio = new TwilioHandler(this);
CameraRunner = new CameraRunner(this);
UnityRunner = new UnityRunner(this);
@@ -24,6 +26,7 @@ export class Main {
async start() {
await this.ConfigurationManager.load();
await this.WebServer.listen();
await this.Twilio.load();
await this.CameraRunner.connect();
@@ -47,9 +50,14 @@ export class Main {
'Failed to reboot CameraRunner:',
response.message
);
this.Twilio.sendError(
'CameraRunner',
`Failed to reboot CameraRunner: ${response.message}`
);
resolve(false);
} else {
console.log('CameraRunner rebooted successfully.');
this.Twilio.sendError('CameraRunner', null);
resolve(true);
}
}

71
src/Twilio.ts Normal file
View File

@@ -0,0 +1,71 @@
import { Main } from './Main';
const PREFIX = '[Twilio]';
export class TwilioHandler {
private _Main: Main;
client;
constructor(Main: Main) {
this._Main = Main;
}
load() {
this.client = require('twilio')(
this._Main.Config.twilio.accountSid,
this._Main.Config.twilio.authToken
);
}
async resetError(category: TwilioCategories) {
if (!this.lastErrors.has(category)) return;
this.lastErrors.delete(category);
}
private lastErrors: Map<TwilioCategories, string> = new Map();
private errorLog: string[] = [];
private errorTimeout: NodeJS.Timeout;
async sendError(category: TwilioCategories, error: string) {
if (this.lastErrors.get(category) === error) return;
this.lastErrors.set(category, error);
if (error == null) return;
this.errorLog.push(`${category}: ${error}`);
clearTimeout(this.errorTimeout);
this.errorTimeout = setTimeout(async () => {
const errorMessage = this.errorLog
.map((error) => `- ${error}`)
.join('\n');
this.errorLog = [];
console.log(PREFIX, `Sending to Twilio:\n`, errorMessage);
const promises = this._Main.Config.twilio.toNumbers.map(
(toNumber) => this.sendMessage(toNumber, errorMessage)
);
await Promise.all(promises);
}, 15000);
}
sendMessage(to: string, message: string) {
return new Promise<boolean>((resolve) => {
this.client.messages
.create({
body: message,
from: `${this._Main.Config.twilio.fromNumber}`,
to: to,
})
.then((message: any) => {
console.log(`Twilio message sent with SID: ${message.sid}`);
resolve(true);
})
.catch((error: any) => {
console.error('Error sending Twilio message:', error);
resolve(false);
});
});
}
}
type TwilioCategories = 'CameraRunner' | 'UnityRunner' | 'UnityWebSocket';

View File

@@ -14,6 +14,8 @@ export class UnityRunner {
message?: string = 'Awaiting startup delay...';
error?: string;
bootTime = Date.now();
startTime: number = null;
output: { current: string[]; last: string[] } = { current: [], last: [] };
@@ -71,6 +73,8 @@ export class UnityRunner {
this.state = state;
this.broadcastState();
if (error != null) this._Main.Twilio.sendError('UnityRunner', error);
this.output.current.push(
`[${new Date().toLocaleTimeString('nl-NL')}] [System] [${state}] ${
message ?? error
@@ -280,6 +284,7 @@ export class UnityRunner {
)
return;
this._Main.Twilio.resetError('UnityRunner');
this.setInfo('Running', '', 'RUNNING');
this._Main.UnityWebSocket.connect();
}, 5000);

View File

@@ -10,6 +10,8 @@ export class UnityWebSocket {
message?: string = 'Waiting for process...';
error?: string;
errorTriggerStartupDelay = 1000;
parameters: UnityParameters = {
timelineWatching: false,
timelineStanding: false,
@@ -113,6 +115,8 @@ export class UnityWebSocket {
this.state = state;
this.broadcastState();
if (error != null) this._Main.Twilio.sendError('UnityWebSocket', error);
if (state == 'FAILED' || state == 'DISCONNECTED')
console.warn(PREFIX, message ?? error);
else console.log(PREFIX, message ?? error);
@@ -146,7 +150,15 @@ export class UnityWebSocket {
this.parameters.outOfService =
message.heartbeat.showOutOfService ?? false;
this.parameters.sensors = message.heartbeat.dataSensors;
this.parameters.sliders = message.heartbeat.dataSliders;
this.parameters.sliders = message.heartbeat.dataSliders.map(
(slider) => {
return {
...slider,
decimalPlaces:
slider.min == 0 && slider.max == 1 ? 2 : null,
};
}
);
this.broadcastState();
break;
@@ -226,6 +238,8 @@ export class UnityWebSocket {
this.socket.on('open', () => {
this.startFetchClocks();
this._Main.Twilio.resetError('UnityWebSocket');
this.setInfo('Connected', null, 'CONNECTED');
});