Small bugfix
This commit is contained in:
@@ -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();
|
||||
});
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,13 @@ export const DefaultConfiguration: Config = {
|
||||
|
||||
pollInterval: 5000,
|
||||
},
|
||||
twilio: {
|
||||
accountSid: '',
|
||||
authToken: '',
|
||||
fromNumber: '',
|
||||
toNumbers: [],
|
||||
aggregateTimeout: 15000,
|
||||
},
|
||||
support: {
|
||||
telephone: '+31613392837',
|
||||
},
|
||||
|
||||
@@ -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
71
src/Twilio.ts
Normal 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';
|
||||
@@ -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);
|
||||
|
||||
@@ -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');
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user