@switchbot/homebridge-switchbot
Version:
The SwitchBot plugin allows you to access your SwitchBot device(s) from HomeKit.
106 lines (87 loc) • 2.7 kB
JavaScript
import { execSync } from 'node:child_process'
import { readFileSync } from 'node:fs'
import { homedir } from 'node:os'
import { resolve } from 'node:path'
function resolvePorts() {
let bridgePort = 51829
let uiPort = 8581
try {
const configPath = resolve(homedir(), '.homebridge-dev', 'config.json')
const config = JSON.parse(readFileSync(configPath, 'utf8'))
if (typeof config?.bridge?.port === 'number') {
bridgePort = config.bridge.port
}
const configUiPlatform = Array.isArray(config?.platforms)
? config.platforms.find(platform => platform?.platform === 'config')
: undefined
if (typeof configUiPlatform?.port === 'number') {
uiPort = configUiPlatform.port
}
} catch {}
return [...new Set([bridgePort, uiPort])]
}
function pidsForPort(port) {
try {
const output = execSync(`lsof -ti tcp:${port}`, { stdio: ['ignore', 'pipe', 'ignore'] }).toString().trim()
return output ? output.split('\n').filter(Boolean) : []
} catch {
return []
}
}
function freePort(port) {
const initialPids = pidsForPort(port)
if (initialPids.length === 0) {
return
}
try {
execSync(`lsof -ti tcp:${port} | xargs -r kill -TERM`, { stdio: ['ignore', 'ignore', 'ignore'] })
} catch {}
const remainingPids = pidsForPort(port)
if (remainingPids.length > 0) {
try {
execSync(`lsof -ti tcp:${port} | xargs -r kill -KILL`, { stdio: ['ignore', 'ignore', 'ignore'] })
} catch {}
}
}
function cleanupDevProcesses() {
let output = ''
try {
output = execSync('ps -axo pid=,command=', { stdio: ['ignore', 'pipe', 'ignore'] }).toString()
} catch {
return
}
const targetPids = output
.split('\n')
.map(line => line.trim())
.filter(Boolean)
.map((line) => {
const firstSpace = line.indexOf(' ')
if (firstSpace === -1) {
return null
}
const pid = Number(line.slice(0, firstSpace).trim())
const command = line.slice(firstSpace + 1)
return Number.isFinite(pid) ? { pid, command } : null
})
.filter((entry) => {
if (!entry) {
return false
}
if (entry.pid === process.pid || entry.pid === process.ppid) {
return false
}
const isNodemonProcess = entry.command.includes('homebridge-switchbot/node_modules/.bin/nodemon')
const isConfigUiProcess = entry.command.trim().startsWith('homebridge-config-ui-x')
return isNodemonProcess || isConfigUiProcess
})
.map(entry => entry.pid)
for (const pid of targetPids) {
try {
process.kill(pid, 'SIGTERM')
} catch {}
}
}
cleanupDevProcesses()
for (const port of resolvePorts()) {
freePort(port)
}