UNPKG

homebridge-kasa-python

Version:

Plugin that uses Python-Kasa API to communicate with Kasa Devices.

133 lines 4.85 kB
import { spawn } from 'node:child_process'; import { writeFile } from 'node:fs/promises'; export function deferAndCombine(fn, timeout, runNowFn) { let requests = []; let timer = null; const processRequests = () => { const currentRequests = requests; requests = []; fn(currentRequests.length) .then(value => currentRequests.forEach(req => req.resolve(value))) .catch(error => currentRequests.forEach(req => req.reject(error))) .finally(() => timer = null); }; return (arg) => { if (runNowFn && arg !== undefined) { runNowFn(arg); } return new Promise((resolve, reject) => { requests.push({ resolve, reject }); if (!timer) { timer = setTimeout(processRequests, timeout); } }); }; } export function delay(ms) { return new Promise((resolve) => { setTimeout(resolve, ms); }); } export function isObjectLike(candidate) { return typeof candidate === 'object' && candidate !== null || typeof candidate === 'function'; } export function lookup(object, compareFn, value) { const compare = compareFn ?? ((objectProp, search) => objectProp === search); if (isObjectLike(object)) { return Object.keys(object).find(key => compare(object[key], value)); } return undefined; } export function lookupCharacteristicNameByUUID(characteristic, uuid) { return Object.keys(characteristic).find(key => (characteristic[key].UUID === uuid)); } export function prefixLogger(logger, prefix) { const methods = ['info', 'warn', 'error', 'debug', 'log']; const clonedLogger = methods.reduce((acc, method) => { acc[method] = (...args) => { const prefixString = typeof prefix === 'function' ? prefix() : prefix; if (method === 'log') { const [level, message, ...parameters] = args; logger[method](level, `${prefixString} ${message}`, ...parameters); } else { const [message, ...parameters] = args; logger[method](`${prefixString} ${message}`, ...parameters); } }; return acc; }, {}); clonedLogger.prefix = typeof logger.prefix === 'string' ? `${prefix} ${logger.prefix}` : prefix; return clonedLogger; } export async function runCommand(logger, command, args = [], options, hideStdout = false, hideStderr = false, returnProcess = false, suppressErrors = []) { const MAX_BUFFER_SIZE = 1024 * 1024; let stdout = ''; let stderr = ''; let outputFile = null; const filteredArgs = args.filter(arg => { if (arg.startsWith('>')) { outputFile = arg.substring(1).trim(); return false; } return true; }); logger.debug(`Running command: ${command} ${filteredArgs.join(' ')}`); const p = spawn(command, filteredArgs, { ...options, env: process.env, }); logger.debug(`Command PID: ${p.pid}`); p.stdout.setEncoding('utf8').on('data', data => { stdout += data; if (stdout.length > MAX_BUFFER_SIZE) { stdout = stdout.slice(-MAX_BUFFER_SIZE); } if (!hideStdout) { logger.debug(`STDOUT: ${data.trim()}`); } }); p.stderr.setEncoding('utf8').on('data', data => { stderr += data; if (stderr.length > MAX_BUFFER_SIZE) { stderr = stderr.slice(-MAX_BUFFER_SIZE); } if (!hideStderr) { logger.error(`STDERR: ${data.trim()}`); } }); if (returnProcess) { logger.debug('Command started and returning process.'); const stderrReady = new Promise((resolve) => { p.stderr.once('data', () => { logger.debug('Process data received.'); resolve(); }); }); await stderrReady; return [stdout, stderr, null, p]; } const exitCode = await new Promise((resolve, reject) => { p.on('close', (code) => { logger.debug(`Command closed with exit code: ${code}`); resolve(code); }).on('error', (error) => { const errorMessage = error.message.toLowerCase(); const shouldSuppress = suppressErrors.some(err => errorMessage.includes(err)); if (!shouldSuppress) { logger.error('Command encountered an error:', error); } reject(error); }); }); p.stdout.destroy(); p.stderr.destroy(); p.kill(); if (outputFile) { logger.debug(`Writing command output to file: ${outputFile}`); await writeFile(outputFile, stdout); } logger.debug('Command finished.'); return [stdout, stderr, exitCode]; } //# sourceMappingURL=utils.js.map