homebridge-config-ui-x
Version:
A web based management, configuration and control platform for Homebridge.
169 lines • 6.41 kB
JavaScript
import { execFileSync, execSync } from 'node:child_process';
import { createWriteStream } from 'node:fs';
import { arch } from 'node:os';
import { resolve } from 'node:path';
import process from 'node:process';
import axios from 'axios';
import { pathExists, remove } from 'fs-extra/esm';
import { RE_SERVICE_NAME } from '../../core/regex.constants.js';
import { BasePlatform } from '../base-platform.js';
export class Win32Installer extends BasePlatform {
async install() {
this.checkIsAdmin();
this.assertSafeServiceName();
await this.hbService.portCheck();
await this.hbService.storagePathCheck();
await this.hbService.configCheck();
const nssmPath = await this.downloadNssm();
const installArgs = [
'install',
this.hbService.serviceName,
process.execPath,
this.hbService.selfPath,
'run',
'-I',
'-U',
this.hbService.storagePath,
];
const setUserDirArgs = [
'set',
this.hbService.serviceName,
'AppEnvironmentExtra',
`:UIX_STORAGE_PATH=${this.hbService.storagePath}`,
];
try {
execFileSync(nssmPath, installArgs);
execFileSync(nssmPath, setUserDirArgs);
await this.configureFirewall();
await this.start();
await this.hbService.printPostInstallInstructions();
}
catch (e) {
console.error(e.toString());
this.hbService.logger('ERROR: Failed Operation', 'fail');
}
}
async uninstall() {
this.checkIsAdmin();
this.assertSafeServiceName();
await this.stop();
try {
execFileSync('sc', ['delete', this.hbService.serviceName]);
this.hbService.logger(`Removed ${this.hbService.serviceName} Service`, 'succeed');
}
catch (e) {
console.error(e.toString());
this.hbService.logger('ERROR: Failed Operation', 'fail');
}
}
async start() {
this.checkIsAdmin();
this.assertSafeServiceName();
try {
this.hbService.logger(`Starting ${this.hbService.serviceName} Service...`);
execFileSync('sc', ['start', this.hbService.serviceName]);
this.hbService.logger(`${this.hbService.serviceName} Started`, 'succeed');
}
catch (e) {
this.hbService.logger(`Failed to start ${this.hbService.serviceName}`, 'fail');
}
}
async stop() {
this.checkIsAdmin();
this.assertSafeServiceName();
try {
this.hbService.logger(`Stopping ${this.hbService.serviceName} Service...`);
execFileSync('sc', ['stop', this.hbService.serviceName]);
this.hbService.logger(`${this.hbService.serviceName} Stopped`, 'succeed');
}
catch (e) {
this.hbService.logger(`Failed to stop ${this.hbService.serviceName}`, 'fail');
}
}
async restart() {
this.checkIsAdmin();
await this.stop();
await new Promise(resolve => setTimeout(resolve, 4000));
await this.start();
}
async rebuild(all = false) {
this.checkIsAdmin();
try {
execSync('npm rebuild --unsafe-perm', {
cwd: process.env.UIX_BASE_PATH,
stdio: 'inherit',
});
this.hbService.logger(`Rebuilt modules in ${process.env.UIX_BASE_PATH} for Node.js ${process.version}.`, 'succeed');
}
catch (e) {
console.error(e.toString());
this.hbService.logger('ERROR: Failed Operation', 'fail');
}
}
async updateNodejs(job) {
this.hbService.logger('ERROR: This command is not supported on Windows.', 'fail');
this.hbService.logger(`Please download Node.js v${job.target} from https://nodejs.org/en/download/ and install manually.`, 'fail');
}
assertSafeServiceName() {
if (!RE_SERVICE_NAME.test(this.hbService.serviceName)) {
this.hbService.logger(`ERROR: Refusing to run — invalid service name "${this.hbService.serviceName}".`, 'fail');
process.exit(1);
}
}
checkIsAdmin() {
try {
execSync('fsutil dirty query %systemdrive% >nul');
}
catch (e) {
this.hbService.logger('ERROR: This command must be run as an Administrator', 'fail');
this.hbService.logger('Node.js command prompt shortcut -> Right Click -> Run as administrator', 'fail');
process.exit(1);
}
}
async downloadNssm() {
const downloadUrl = `https://github.com/homebridge/nssm/releases/download/2.24-101-g897c7ad/nssm_${arch()}.exe`;
const nssmPath = resolve(this.hbService.storagePath, 'nssm.exe');
if (await pathExists(nssmPath)) {
return nssmPath;
}
const nssmFile = createWriteStream(nssmPath);
this.hbService.logger(`Downloading NSSM from ${downloadUrl}`);
return new Promise((res, rej) => {
axios({
method: 'GET',
url: downloadUrl,
responseType: 'stream',
})
.then((response) => {
response.data.pipe(nssmFile).on('finish', () => {
return res(nssmPath);
}).on('error', (err) => {
return rej(err);
});
})
.catch(async (e) => {
nssmFile.close();
await remove(nssmPath);
this.hbService.logger(`Failed to download nssm: ${e.message}`, 'fail');
process.exit(0);
});
});
}
async configureFirewall() {
const cleanFirewallCmd = 'netsh advfirewall firewall Delete rule name="Homebridge"';
const openFirewallCmd = `netsh advfirewall firewall add rule name="Homebridge" dir=in action=allow program="${process.execPath}"`;
try {
execSync(cleanFirewallCmd);
}
catch (e) {
}
try {
execSync(openFirewallCmd);
}
catch (e) {
this.hbService.logger('Failed to configure firewall rule for Homebridge.', 'warn');
this.hbService.logger(e);
}
}
}
//# sourceMappingURL=win32.js.map