forked from defunkt/toes
84 lines
1.9 KiB
TypeScript
84 lines
1.9 KiB
TypeScript
import type { Subprocess } from 'bun'
|
|
import { toSubdomain } from '@urls'
|
|
import { LOCAL_HOST } from '%config'
|
|
import { networkInterfaces } from 'os'
|
|
import { hostLog } from './tui'
|
|
|
|
const _publishers = new Map<string, Subprocess>()
|
|
|
|
const isEnabled = process.env.NODE_ENV === 'production' && process.platform === 'linux'
|
|
|
|
function getLocalIp(): string | null {
|
|
const interfaces = networkInterfaces()
|
|
for (const iface of Object.values(interfaces)) {
|
|
if (!iface) continue
|
|
for (const addr of iface) {
|
|
if (addr.family === 'IPv4' && !addr.internal) {
|
|
return addr.address
|
|
}
|
|
}
|
|
}
|
|
return null
|
|
}
|
|
|
|
export function cleanupStalePublishers() {
|
|
if (!isEnabled) return
|
|
|
|
try {
|
|
const result = Bun.spawnSync(['pkill', '-f', `avahi-publish.*${LOCAL_HOST}`])
|
|
if (result.exitCode === 0) {
|
|
hostLog('mDNS: cleaned up stale avahi-publish processes')
|
|
}
|
|
} catch {}
|
|
}
|
|
|
|
export function publishApp(name: string) {
|
|
if (!isEnabled) return
|
|
if (_publishers.has(name)) return
|
|
|
|
const ip = getLocalIp()
|
|
if (!ip) {
|
|
hostLog(`mDNS: no local IP found, skipping ${name}`)
|
|
return
|
|
}
|
|
|
|
const host = `${toSubdomain(name)}.${LOCAL_HOST}`
|
|
|
|
try {
|
|
const proc = Bun.spawn(['avahi-publish', '-a', host, '-R', ip], {
|
|
stdout: 'ignore',
|
|
stderr: 'ignore',
|
|
})
|
|
|
|
_publishers.set(name, proc)
|
|
hostLog(`mDNS: published ${host} -> ${ip}`)
|
|
|
|
proc.exited.then(() => {
|
|
_publishers.delete(name)
|
|
})
|
|
} catch {
|
|
hostLog(`mDNS: failed to publish ${host}`)
|
|
}
|
|
}
|
|
|
|
export function unpublishApp(name: string) {
|
|
if (!isEnabled) return
|
|
|
|
const proc = _publishers.get(name)
|
|
if (!proc) return
|
|
|
|
proc.kill()
|
|
_publishers.delete(name)
|
|
hostLog(`mDNS: unpublished ${toSubdomain(name)}.${LOCAL_HOST}`)
|
|
}
|
|
|
|
export function unpublishAll() {
|
|
if (!isEnabled) return
|
|
|
|
for (const [name, proc] of _publishers) {
|
|
proc.kill()
|
|
hostLog(`mDNS: unpublished ${toSubdomain(name)}.${LOCAL_HOST}`)
|
|
}
|
|
_publishers.clear()
|
|
}
|