"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ServerService = void 0;
const node_buffer_1 = require("node:buffer");
const node_child_process_1 = require("node:child_process");
const node_path_1 = require("node:path");
const node_process_1 = __importDefault(require("node:process"));
const node_stream_1 = require("node:stream");
const node_util_1 = require("node:util");
const hap_types_1 = require("@homebridge/hap-client/dist/hap-types");
const common_1 = require("@nestjs/common");
const fs_extra_1 = require("fs-extra");
const node_cache_1 = __importDefault(require("node-cache"));
const systeminformation_1 = require("systeminformation");
const tcp_port_used_1 = require("tcp-port-used");
const config_service_1 = require("../../core/config/config.service");
const homebridge_ipc_service_1 = require("../../core/homebridge-ipc/homebridge-ipc.service");
const logger_service_1 = require("../../core/logger/logger.service");
const accessories_service_1 = require("../accessories/accessories.service");
const config_editor_service_1 = require("../config-editor/config-editor.service");
const pump = (0, node_util_1.promisify)(node_stream_1.pipeline);
let ServerService = class ServerService {
    constructor(configService, configEditorService, accessoriesService, homebridgeIpcService, logger) {
        this.configService = configService;
        this.configEditorService = configEditorService;
        this.accessoriesService = accessoriesService;
        this.homebridgeIpcService = homebridgeIpcService;
        this.logger = logger;
        this.serverServiceCache = new node_cache_1.default({ stdTTL: 300 });
        this.setupCode = null;
        this.paired = false;
        this.accessoryId = this.configService.homebridgeConfig.bridge.username.split(':').join('');
        this.accessoryInfoPath = (0, node_path_1.join)(this.configService.storagePath, 'persist', `AccessoryInfo.${this.accessoryId}.json`);
    }
    async deleteSingleDeviceAccessories(id, cachedAccessoriesDir) {
        const cachedAccessories = (0, node_path_1.join)(cachedAccessoriesDir, `cachedAccessories.${id}`);
        const cachedAccessoriesBackup = (0, node_path_1.join)(cachedAccessoriesDir, `.cachedAccessories.${id}.bak`);
        if (await (0, fs_extra_1.pathExists)(cachedAccessories)) {
            await (0, fs_extra_1.unlink)(cachedAccessories);
            this.logger.warn(`Bridge ${id} accessory removal: removed ${cachedAccessories}.`);
        }
        if (await (0, fs_extra_1.pathExists)(cachedAccessoriesBackup)) {
            await (0, fs_extra_1.unlink)(cachedAccessoriesBackup);
            this.logger.warn(`Bridge ${id} accessory removal: removed ${cachedAccessoriesBackup}.`);
        }
    }
    async deleteSingleDevicePairing(id, resetPairingInfo) {
        const persistPath = (0, node_path_1.join)(this.configService.storagePath, 'persist');
        const accessoryInfo = (0, node_path_1.join)(persistPath, `AccessoryInfo.${id}.json`);
        const identifierCache = (0, node_path_1.join)(persistPath, `IdentifierCache.${id}.json`);
        try {
            const configFile = await this.configEditorService.getConfigFile();
            const username = id.match(/.{1,2}/g).join(':').toUpperCase();
            const uiConfig = configFile.platforms.find(x => x.platform === 'config');
            let blacklistChanged = false;
            if (uiConfig.accessoryControl?.instanceBlacklist?.includes(username)) {
                blacklistChanged = true;
                uiConfig.accessoryControl.instanceBlacklist = uiConfig.accessoryControl.instanceBlacklist
                    .filter((x) => x.toUpperCase() !== username);
            }
            if (resetPairingInfo) {
                const pluginBlocks = [
                    ...(configFile.accessories || []),
                    ...(configFile.platforms || []),
                    { _bridge: configFile.bridge },
                ]
                    .filter((block) => block._bridge?.username?.toUpperCase() === username.toUpperCase());
                const pluginBlock = pluginBlocks.find((block) => block._bridge?.port);
                const otherBlocks = pluginBlocks.filter((block) => !block._bridge?.port);
                if (pluginBlock) {
                    pluginBlock._bridge.username = this.configEditorService.generateUsername();
                    pluginBlock._bridge.pin = this.configEditorService.generatePin();
                    otherBlocks.forEach((block) => {
                        block._bridge.username = pluginBlock._bridge.username;
                    });
                    if (blacklistChanged) {
                        uiConfig.accessoryControl.instanceBlacklist = uiConfig.accessoryControl.instanceBlacklist
                            .concat(pluginBlock._bridge.username.toUpperCase());
                    }
                    this.logger.warn(`Bridge ${id} reset: new username: ${pluginBlock._bridge.username} and new pin: ${pluginBlock._bridge.pin}.`);
                }
                else {
                    this.logger.error(`Failed to reset username and pin for child bridge ${id} as the plugin block could not be found.`);
                }
            }
            if (blacklistChanged) {
                uiConfig.accessoryControl.instanceBlacklist = uiConfig.accessoryControl.instanceBlacklist
                    .sort((a, b) => a.localeCompare(b));
            }
            await this.configEditorService.updateConfigFile(configFile);
        }
        catch (e) {
            this.logger.error(`Failed to reset username and pin for child bridge ${id} as ${e.message}.`);
        }
        if (await (0, fs_extra_1.pathExists)(accessoryInfo)) {
            await (0, fs_extra_1.unlink)(accessoryInfo);
            this.logger.warn(`Bridge ${id} reset: removed ${accessoryInfo}.`);
        }
        if (await (0, fs_extra_1.pathExists)(identifierCache)) {
            await (0, fs_extra_1.unlink)(identifierCache);
            this.logger.warn(`Bridge ${id} reset: removed ${identifierCache}.`);
        }
        await this.deleteDeviceAccessories(id);
    }
    async restartServer() {
        this.logger.log('Homebridge restart request received.');
        if (!await this.configService.uiRestartRequired() && !await this.nodeVersionChanged()) {
            this.logger.log('UI/Bridge settings have not changed - only restarting Homebridge process.');
            this.homebridgeIpcService.restartHomebridge();
            this.accessoriesService.resetInstancePool();
            return { ok: true, command: 'SIGTERM', restartingUI: false };
        }
        setTimeout(() => {
            if (this.configService.ui.restart) {
                this.logger.log(`Executing restart command ${this.configService.ui.restart}.`);
                (0, node_child_process_1.exec)(this.configService.ui.restart, (err) => {
                    if (err) {
                        this.logger.log('Restart command exited with an error, failed to restart Homebridge.');
                    }
                });
            }
            else {
                this.logger.log('Sending SIGTERM to process...');
                node_process_1.default.kill(node_process_1.default.pid, 'SIGTERM');
            }
        }, 500);
        return { ok: true, command: this.configService.ui.restart, restartingUI: true };
    }
    async resetHomebridgeAccessory() {
        this.configService.hbServiceUiRestartRequired = true;
        const configFile = await this.configEditorService.getConfigFile();
        const oldUsername = configFile.bridge.username;
        configFile.bridge.pin = this.configEditorService.generatePin();
        configFile.bridge.username = this.configEditorService.generateUsername();
        const uiConfig = configFile.platforms.find(x => x.platform === 'config');
        if (uiConfig.accessoryControl?.instanceBlacklist?.includes(oldUsername.toUpperCase())) {
            uiConfig.accessoryControl.instanceBlacklist = uiConfig.accessoryControl.instanceBlacklist
                .filter((x) => x.toUpperCase() !== oldUsername.toUpperCase())
                .concat(configFile.bridge.pin)
                .sort((a, b) => a.localeCompare(b));
        }
        this.logger.warn(`Homebridge bridge reset: new username ${configFile.bridge.username} and new pin ${configFile.bridge.pin}.`);
        await this.configEditorService.updateConfigFile(configFile);
        await (0, fs_extra_1.remove)((0, node_path_1.resolve)(this.configService.storagePath, 'accessories'));
        await (0, fs_extra_1.remove)((0, node_path_1.resolve)(this.configService.storagePath, 'persist'));
        this.logger.log('Homebridge bridge reset: accessories and persist directories were removed.');
    }
    async getDevicePairings() {
        const persistPath = (0, node_path_1.join)(this.configService.storagePath, 'persist');
        const devices = (await (0, fs_extra_1.readdir)(persistPath))
            .filter(x => x.match(/AccessoryInfo\.([A-Fa-f0-9]+)\.json$/));
        const configFile = await this.configEditorService.getConfigFile();
        return Promise.all(devices.map(async (x) => {
            return await this.getDevicePairingById(x.split('.')[1], configFile);
        }));
    }
    async getDevicePairingById(deviceId, configFile = null) {
        const persistPath = (0, node_path_1.join)(this.configService.storagePath, 'persist');
        let device;
        try {
            device = await (0, fs_extra_1.readJson)((0, node_path_1.join)(persistPath, `AccessoryInfo.${deviceId}.json`));
        }
        catch (e) {
            throw new common_1.NotFoundException();
        }
        if (!configFile) {
            configFile = await this.configEditorService.getConfigFile();
        }
        const username = deviceId.match(/.{1,2}/g).join(':');
        const isMain = this.configService.homebridgeConfig.bridge.username.toUpperCase() === username.toUpperCase();
        const pluginBlock = configFile.accessories
            .concat(configFile.platforms)
            .concat([{ _bridge: configFile.bridge }])
            .find((block) => block._bridge?.username?.toUpperCase() === username.toUpperCase());
        try {
            device._category = Object.entries(hap_types_1.Categories).find(([, value]) => value === device.category)[0].toLowerCase();
        }
        catch (e) {
            device._category = 'Other';
        }
        device.name = pluginBlock?._bridge.name || pluginBlock?.name || device.displayName;
        device._id = deviceId;
        device._username = username;
        device._main = isMain;
        device._isPaired = device.pairedClients && Object.keys(device.pairedClients).length > 0;
        device._setupCode = this.generateSetupCode(device);
        device._couldBeStale = !device._main && device._category === 'bridge' && !pluginBlock;
        delete device.signSk;
        delete device.signPk;
        delete device.configHash;
        delete device.pairedClients;
        delete device.pairedClientsPermission;
        return device;
    }
    async deleteDevicePairing(id, resetPairingInfo) {
        this.logger.warn(`Shutting down Homebridge before resetting paired bridge ${id}...`);
        await this.homebridgeIpcService.restartAndWaitForClose();
        await this.deleteSingleDevicePairing(id, resetPairingInfo);
        return { ok: true };
    }
    async deleteDevicesPairing(bridges) {
        this.logger.warn(`Shutting down Homebridge before resetting paired bridges ${bridges.map(x => x.id).join(', ')}...`);
        await this.homebridgeIpcService.restartAndWaitForClose();
        for (const { id, resetPairingInfo } of bridges) {
            try {
                await this.deleteSingleDevicePairing(id, resetPairingInfo);
            }
            catch (e) {
                this.logger.error(`Failed to reset paired bridge ${id} as ${e.message}.`);
            }
        }
        return { ok: true };
    }
    async deleteDeviceAccessories(id) {
        this.logger.warn(`Shutting down Homebridge before removing accessories for paired bridge ${id}...`);
        await this.homebridgeIpcService.restartAndWaitForClose();
        const cachedAccessoriesDir = (0, node_path_1.join)(this.configService.storagePath, 'accessories');
        await this.deleteSingleDeviceAccessories(id, cachedAccessoriesDir);
    }
    async deleteDevicesAccessories(bridges) {
        this.logger.warn(`Shutting down Homebridge before removing accessories for paired bridges ${bridges.map(x => x.id).join(', ')}...`);
        await this.homebridgeIpcService.restartAndWaitForClose();
        const cachedAccessoriesDir = (0, node_path_1.join)(this.configService.storagePath, 'accessories');
        for (const { id } of bridges) {
            try {
                await this.deleteSingleDeviceAccessories(id, cachedAccessoriesDir);
            }
            catch (e) {
                this.logger.error(`Failed to remove accessories for bridge ${id} as ${e.message}.`);
            }
        }
    }
    async getCachedAccessories() {
        const cachedAccessoriesDir = (0, node_path_1.join)(this.configService.storagePath, 'accessories');
        const cachedAccessoryFiles = (await (0, fs_extra_1.readdir)(cachedAccessoriesDir))
            .filter(x => x.match(/^cachedAccessories\.([A-F,0-9]+)$/) || x === 'cachedAccessories');
        const cachedAccessories = [];
        await Promise.all(cachedAccessoryFiles.map(async (x) => {
            const accessories = await (0, fs_extra_1.readJson)((0, node_path_1.join)(cachedAccessoriesDir, x));
            for (const accessory of accessories) {
                accessory.$cacheFile = x;
                cachedAccessories.push(accessory);
            }
        }));
        return cachedAccessories;
    }
    async deleteCachedAccessory(uuid, cacheFile) {
        cacheFile = cacheFile || 'cachedAccessories';
        const cachedAccessoriesPath = (0, node_path_1.resolve)(this.configService.storagePath, 'accessories', cacheFile);
        this.logger.warn(`Shutting down Homebridge before removing cached accessory ${uuid}...`);
        await this.homebridgeIpcService.restartAndWaitForClose();
        const cachedAccessories = await (0, fs_extra_1.readJson)(cachedAccessoriesPath);
        const accessoryIndex = cachedAccessories.findIndex(x => x.UUID === uuid);
        if (accessoryIndex > -1) {
            cachedAccessories.splice(accessoryIndex, 1);
            await (0, fs_extra_1.writeJson)(cachedAccessoriesPath, cachedAccessories);
            this.logger.warn(`Removed cached accessory with UUID ${uuid} from file ${cacheFile}.`);
        }
        else {
            this.logger.error(`Cannot find cached accessory with UUID ${uuid} from file ${cacheFile}.`);
            throw new common_1.NotFoundException();
        }
        return { ok: true };
    }
    async deleteCachedAccessories(accessories) {
        this.logger.warn(`Shutting down Homebridge before removing cached accessories ${accessories.map(x => x.uuid).join(', ')}.`);
        await this.homebridgeIpcService.restartAndWaitForClose();
        const accessoriesByCacheFile = new Map();
        for (const { cacheFile, uuid } of accessories) {
            const accessoryCacheFile = cacheFile || 'cachedAccessories';
            if (!accessoriesByCacheFile.has(accessoryCacheFile)) {
                accessoriesByCacheFile.set(accessoryCacheFile, []);
            }
            accessoriesByCacheFile.get(accessoryCacheFile).push({ uuid });
        }
        for (const [cacheFile, accessories] of accessoriesByCacheFile.entries()) {
            const cachedAccessoriesPath = (0, node_path_1.resolve)(this.configService.storagePath, 'accessories', cacheFile);
            const cachedAccessories = await (0, fs_extra_1.readJson)(cachedAccessoriesPath);
            for (const { uuid } of accessories) {
                try {
                    const accessoryIndex = cachedAccessories.findIndex(x => x.UUID === uuid);
                    if (accessoryIndex > -1) {
                        cachedAccessories.splice(accessoryIndex, 1);
                        this.logger.warn(`Removed cached accessory with UUID ${uuid} from file ${cacheFile}.`);
                    }
                    else {
                        this.logger.error(`Cannot find cached accessory with UUID ${uuid} from file ${cacheFile}.`);
                    }
                }
                catch (e) {
                    this.logger.error(`Failed to remove cached accessory with UUID ${uuid} from file ${cacheFile} as ${e.message}.`);
                }
            }
            await (0, fs_extra_1.writeJson)(cachedAccessoriesPath, cachedAccessories);
        }
        return { ok: true };
    }
    async deleteAllCachedAccessories() {
        const cachedAccessoriesDir = (0, node_path_1.join)(this.configService.storagePath, 'accessories');
        const cachedAccessoryPaths = (await (0, fs_extra_1.readdir)(cachedAccessoriesDir))
            .filter(x => x.match(/cachedAccessories\.([A-F,0-9]+)/) || x === 'cachedAccessories' || x === '.cachedAccessories.bak')
            .map(x => (0, node_path_1.resolve)(cachedAccessoriesDir, x));
        const cachedAccessoriesPath = (0, node_path_1.resolve)(this.configService.storagePath, 'accessories', 'cachedAccessories');
        await this.homebridgeIpcService.restartAndWaitForClose();
        this.logger.warn('Shutting down Homebridge before removing cached accessories');
        try {
            this.logger.log('Clearing all cached accessories...');
            for (const thisCachedAccessoriesPath of cachedAccessoryPaths) {
                if (await (0, fs_extra_1.pathExists)(thisCachedAccessoriesPath)) {
                    await (0, fs_extra_1.unlink)(thisCachedAccessoriesPath);
                    this.logger.warn(`Removed ${thisCachedAccessoriesPath}.`);
                }
            }
        }
        catch (e) {
            this.logger.error(`Failed to clear all cached accessories at ${cachedAccessoriesPath} as ${e.message}.`);
            console.error(e);
            throw new common_1.InternalServerErrorException('Failed to clear Homebridge accessory cache - see logs.');
        }
        return { ok: true };
    }
    async getSetupCode() {
        if (this.setupCode) {
            return this.setupCode;
        }
        else {
            if (!await (0, fs_extra_1.pathExists)(this.accessoryInfoPath)) {
                return null;
            }
            const accessoryInfo = await (0, fs_extra_1.readJson)(this.accessoryInfoPath);
            this.setupCode = this.generateSetupCode(accessoryInfo);
            return this.setupCode;
        }
    }
    generateSetupCode(accessoryInfo) {
        const buffer = node_buffer_1.Buffer.allocUnsafe(8);
        let valueLow = Number.parseInt(accessoryInfo.pincode.replace(/-/g, ''), 10);
        const valueHigh = accessoryInfo.category >> 1;
        valueLow |= 1 << 28;
        buffer.writeUInt32BE(valueLow, 4);
        if (accessoryInfo.category & 1) {
            buffer[4] = buffer[4] | 1 << 7;
        }
        buffer.writeUInt32BE(valueHigh, 0);
        let encodedPayload = (buffer.readUInt32BE(4) + (buffer.readUInt32BE(0) * 2 ** 32)).toString(36).toUpperCase();
        if (encodedPayload.length !== 9) {
            for (let i = 0; i <= 9 - encodedPayload.length; i += 1) {
                encodedPayload = `0${encodedPayload}`;
            }
        }
        return `X-HM://${encodedPayload}${accessoryInfo.setupID}`;
    }
    async getBridgePairingInformation() {
        if (!await (0, fs_extra_1.pathExists)(this.accessoryInfoPath)) {
            return new common_1.ServiceUnavailableException('Pairing Information Not Available Yet');
        }
        const accessoryInfo = await (0, fs_extra_1.readJson)(this.accessoryInfoPath);
        return {
            displayName: accessoryInfo.displayName,
            pincode: accessoryInfo.pincode,
            setupCode: await this.getSetupCode(),
            isPaired: accessoryInfo.pairedClients && Object.keys(accessoryInfo.pairedClients).length > 0,
        };
    }
    async getSystemNetworkInterfaces() {
        const fromCache = this.serverServiceCache.get('network-interfaces');
        const interfaces = fromCache || (await (0, systeminformation_1.networkInterfaces)()).filter((adapter) => {
            return !adapter.internal
                && (adapter.ip4 || (adapter.ip6));
        });
        if (!fromCache) {
            this.serverServiceCache.set('network-interfaces', interfaces);
        }
        return interfaces;
    }
    async getHomebridgeNetworkInterfaces() {
        const config = await this.configEditorService.getConfigFile();
        if (!config.bridge?.bind) {
            return [];
        }
        if (Array.isArray(config.bridge?.bind)) {
            return config.bridge.bind;
        }
        if (typeof config.bridge?.bind === 'string') {
            return [config.bridge.bind];
        }
        return [];
    }
    async getHomebridgeMdnsSetting() {
        const config = await this.configEditorService.getConfigFile();
        if (!config.bridge.advertiser) {
            config.bridge.advertiser = 'bonjour-hap';
        }
        return {
            advertiser: config.bridge.advertiser,
        };
    }
    async setHomebridgeMdnsSetting(setting) {
        const config = await this.configEditorService.getConfigFile();
        config.bridge.advertiser = setting.advertiser;
        await this.configEditorService.updateConfigFile(config);
    }
    async setHomebridgeNetworkInterfaces(adapters) {
        const config = await this.configEditorService.getConfigFile();
        if (!config.bridge) {
            config.bridge = {};
        }
        if (!adapters.length) {
            delete config.bridge.bind;
        }
        else {
            config.bridge.bind = adapters;
        }
        await this.configEditorService.updateConfigFile(config);
    }
    async lookupUnusedPort() {
        const randomPort = () => Math.floor(Math.random() * (60000 - 30000 + 1) + 30000);
        let port = randomPort();
        while (await (0, tcp_port_used_1.check)(port)) {
            port = randomPort();
        }
        return { port };
    }
    async getHomebridgePort() {
        const config = await this.configEditorService.getConfigFile();
        return { port: config.bridge.port };
    }
    async getUsablePorts() {
        const config = await this.configEditorService.getConfigFile();
        let start;
        let end;
        if (config.ports && typeof config.ports === 'object') {
            if (config.ports.start) {
                start = config.ports.start;
            }
            if (config.ports.end) {
                end = config.ports.end;
            }
        }
        return { start, end };
    }
    async setHomebridgeName(name) {
        if (!name || !(/^[\p{L}\p{N}][\p{L}\p{N} ']*[\p{L}\p{N}]$/u).test(name)) {
            throw new common_1.BadRequestException('Invalid name');
        }
        const config = await this.configEditorService.getConfigFile();
        config.bridge.name = name;
        await this.configEditorService.updateConfigFile(config);
    }
    async setHomebridgePort(port) {
        if (!port || typeof port !== 'number' || !Number.isInteger(port) || port < 1025 || port > 65533) {
            throw new common_1.BadRequestException('Invalid port number');
        }
        const config = await this.configEditorService.getConfigFile();
        config.bridge.port = port;
        await this.configEditorService.updateConfigFile(config);
    }
    async setUsablePorts(value) {
        let config = await this.configEditorService.getConfigFile();
        if (value.start === null) {
            delete value.start;
        }
        if (value.end === null) {
            delete value.end;
        }
        if ('start' in value && (typeof value.start !== 'number' || value.start < 1025 || value.start > 65533)) {
            throw new common_1.BadRequestException('Port start must be a number between 1025 and 65533.');
        }
        if ('end' in value && (typeof value.end !== 'number' || value.end < 1025 || value.end > 65533)) {
            throw new common_1.BadRequestException('Port end must be a number between 1025 and 65533.');
        }
        if ('start' in value && 'end' in value && value.start >= value.end) {
            throw new common_1.BadRequestException('Ports start must be less than end.');
        }
        if ('start' in value && !('end' in value) && config.ports?.end && value.start >= config.ports.end) {
            throw new common_1.BadRequestException('Ports start must be less than end.');
        }
        if ('end' in value && !('start' in value) && config.ports?.start && config.ports.start >= value.end) {
            throw new common_1.BadRequestException('Ports start must be less than end.');
        }
        if (!value.start && !value.end) {
            delete config.ports;
        }
        else {
            config.ports = {};
            if (value.start) {
                config.ports.start = value.start;
            }
            if (value.end) {
                config.ports.end = value.end;
            }
        }
        const { bridge, ports, ...rest } = config;
        config = ports ? { bridge, ports, ...rest } : { bridge, ...rest };
        await this.configEditorService.updateConfigFile(config);
    }
    async uploadWallpaper(data) {
        const configFile = await this.configEditorService.getConfigFile();
        const uiConfigBlock = configFile.platforms.find(x => x.platform === 'config');
        if (uiConfigBlock) {
            if (uiConfigBlock.wallpaper) {
                const oldPath = (0, node_path_1.join)(this.configService.storagePath, uiConfigBlock.wallpaper);
                if (await (0, fs_extra_1.pathExists)(oldPath)) {
                    try {
                        await (0, fs_extra_1.unlink)(oldPath);
                        this.logger.log(`Old wallpaper file ${oldPath} deleted successfully.`);
                    }
                    catch (e) {
                        this.logger.error(`Failed to delete old wallpaper ${oldPath} as ${e.message}.`);
                    }
                }
            }
            const fileExtension = (0, node_path_1.extname)(data.filename);
            const newPath = (0, node_path_1.join)(this.configService.storagePath, `ui-wallpaper${fileExtension}`);
            await pump(data.file, (0, fs_extra_1.createWriteStream)(newPath));
            uiConfigBlock.wallpaper = `ui-wallpaper${fileExtension}`;
            await this.configEditorService.updateConfigFile(configFile);
            this.logger.log('Wallpaper uploaded and set in the config file.');
        }
    }
    async deleteWallpaper() {
        const configFile = await this.configEditorService.getConfigFile();
        const uiConfigBlock = configFile.platforms.find(x => x.platform === 'config');
        const fullPath = (0, node_path_1.join)(this.configService.storagePath, uiConfigBlock.wallpaper);
        if (uiConfigBlock && uiConfigBlock.wallpaper) {
            if (await (0, fs_extra_1.pathExists)(fullPath)) {
                try {
                    await (0, fs_extra_1.unlink)(fullPath);
                    this.logger.log(`Wallpaper file ${uiConfigBlock.wallpaper} deleted successfully.`);
                }
                catch (e) {
                    this.logger.error(`Failed to delete wallpaper file (${uiConfigBlock.wallpaper}) as ${e.message}.`);
                }
            }
            delete uiConfigBlock.wallpaper;
            await this.configEditorService.updateConfigFile(configFile);
            this.configService.removeWallpaperCache();
            this.logger.log('Wallpaper reference removed from the config file.');
        }
    }
    async nodeVersionChanged() {
        return new Promise((res) => {
            let result = false;
            const child = (0, node_child_process_1.spawn)(node_process_1.default.execPath, ['-v'], { shell: true });
            child.stdout.once('data', (data) => {
                result = data.toString().trim() !== node_process_1.default.version;
            });
            child.on('error', () => {
                result = true;
            });
            child.on('close', () => {
                return res(result);
            });
        });
    }
};
exports.ServerService = ServerService;
exports.ServerService = ServerService = __decorate([
    (0, common_1.Injectable)(),
    __metadata("design:paramtypes", [config_service_1.ConfigService,
        config_editor_service_1.ConfigEditorService,
        accessories_service_1.AccessoriesService,
        homebridge_ipc_service_1.HomebridgeIpcService,
        logger_service_1.Logger])
], ServerService);
//# sourceMappingURL=server.service.js.map