Implemented shutdown through UI and implemented router check

This commit is contained in:
2025-11-28 10:23:57 +01:00
parent 368f60d7b6
commit b2c5d08ff4
29 changed files with 639 additions and 71 deletions

View File

@@ -99,6 +99,7 @@ export class ConfigurationManager {
}
export interface Config {
router: ConfigRouter;
webServer: ConfigWebServer;
unity: ConfigUnity;
cameraRunner: ConfigCameraRunner;
@@ -106,6 +107,11 @@ export interface Config {
support: ConfigSupport;
}
export interface ConfigRouter {
ip: string;
waitForStartup: boolean;
}
export interface ConfigWebServer {
port: number;
}

View File

@@ -4,6 +4,10 @@ export const DefaultConfiguration: Config = {
webServer: {
port: 6300,
},
router: {
ip: '',
waitForStartup: true,
},
unity: {
executable: {
path: '',

View File

@@ -10,7 +10,10 @@ import { UnityRunner } from './Unity/UnityRunner';
import { UnityWebSocket } from './Unity/UnityWebSocket';
import { TwilioHandler } from './Twilio';
import { delay } from './Utils';
import * as ping from 'ping';
import { shutdown } from './Shutdown';
const PREFIX = '[Main]';
export class Main {
dataPath = join(homedir(), 'MorphixProductions', 'NTSHControl');
@@ -26,6 +29,9 @@ export class Main {
async start() {
await this.ConfigurationManager.load();
await this.waitForRouter();
await this.WebServer.listen();
await this.Twilio.load();
@@ -73,4 +79,41 @@ export class Main {
console.log('Restart complete.');
}
async shutdown() {
console.log('Stopping UnityRunner...');
await this.UnityRunner.stop();
const doShutdown = process.argv.includes('--no-shutdown')
? false
: true;
if (doShutdown) {
console.log('Shutting down system...');
shutdown();
} else {
console.log('Shutdown skipped due to --no-shutdown flag.');
}
process.exit(0);
}
waitForRouter() {
if (this.Config.router?.waitForStartup !== true) return;
return new Promise<void>((resolve) => {
const check = () => {
console.log(PREFIX, 'Waiting for router...');
ping.sys.probe(this.Config.router.ip, async ({ alive }) => {
if (alive) {
console.log(PREFIX, 'Router is online');
await delay(3000);
return resolve();
}
await delay(1000);
check();
});
};
check();
});
}
}

33
src/Shutdown.ts Normal file
View File

@@ -0,0 +1,33 @@
import { exec } from 'child_process';
export function shutdown(): Promise<{ succeed: boolean; message?: string }> {
if (process.platform === 'win32') {
return shutdownWindows();
}
return Promise.resolve({
succeed: false,
message: 'Platform not supported',
});
}
function shutdownWindows(): Promise<{ succeed: boolean; message?: string }> {
return new Promise<{ succeed: boolean; message?: string }>(
(resolve, reject) => {
exec('shutdown /s /t 5', (error, stdout, stderr) => {
if (error) {
console.error(
`Error shutting down Windows: ${error.message}`
);
return resolve({ succeed: false, message: error.message });
}
if (stderr) {
console.error(`Error shutting down Windows: ${stderr}`);
return resolve({ succeed: false, message: stderr });
}
console.log(`Windows shutdown command executed: ${stdout}`);
resolve({ succeed: true });
});
}
);
}

View File

@@ -180,7 +180,10 @@ export class UnityWebSocket {
return {
...slider,
decimalPlaces:
slider.min == 0 && slider.max == 1 ? 2 : null,
(slider.min == 0 || slider.min == -1) &&
slider.max == 1
? 2
: null,
};
}
);
@@ -189,7 +192,10 @@ export class UnityWebSocket {
return {
...slider,
decimalPlaces:
slider.min == 0 && slider.max == 1 ? 2 : null,
(slider.min == 0 || slider.min == -1) &&
slider.max == 1
? 2
: null,
};
});

View File

@@ -6,6 +6,7 @@ import { Main } from '../Main';
import { DashboardRouter } from './DashboardRouter';
import { join } from 'path';
import { CalibrationRouter } from './CalibrationRouter';
import { delay } from '../Utils';
const PREFIX = '[WebServer]';
export class WebServer {
@@ -74,6 +75,20 @@ export class WebServer {
callback({ succeed: true });
}
);
socket.on(
'shutdownInstallation',
async (
callback: (response: {
succeed: boolean;
message?: string;
}) => void
) => {
await delay(1000);
callback({ succeed: true });
this._Main.shutdown();
}
);
socket.on('cameraRunner', (command: string, ...args: any[]) =>
this._Main.CameraRunner.handle(command, ...args)
);