UNPKG

homebridge-config-ui-x

Version:

A web based management, configuration and control platform for Homebridge.

169 lines 6.41 kB
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