toes/src/server/wifi.ts

85 lines
2.1 KiB
TypeScript

import * as nmcli from './wifi-nmcli'
import { hostLog } from './tui'
import type { ConnectResult, WifiNetwork, WifiStatus } from '@types'
export type { ConnectResult, WifiNetwork, WifiStatus } from '@types'
let _setupMode = false
const _listeners = new Set<(setupMode: boolean) => void>()
export const isSetupMode = () => _setupMode
export const onSetupModeChange = (cb: (setupMode: boolean) => void) => {
_listeners.add(cb)
return () => _listeners.delete(cb)
}
function setSetupMode(mode: boolean) {
if (_setupMode === mode) return
_setupMode = mode
hostLog(mode ? 'Entering WiFi setup mode' : 'Exiting WiFi setup mode')
for (const cb of _listeners) cb(mode)
}
export async function getWifiStatus(): Promise<WifiStatus> {
try {
return await nmcli.status()
} catch {
return { connected: false, ssid: '', ip: '' }
}
}
export async function scanNetworks(): Promise<WifiNetwork[]> {
try {
return await nmcli.scanNetworks()
} catch {
return []
}
}
export async function connectToWifi(ssid: string, password?: string): Promise<ConnectResult> {
try {
const result = await nmcli.connectToNetwork(ssid, password)
if (result.ok) {
setSetupMode(false)
hostLog(`Connected to WiFi: ${ssid} (${result.ip})`)
}
return result
} catch (e) {
return { ok: false, error: e instanceof Error ? e.message : String(e) }
}
}
export async function initWifi(): Promise<void> {
// Skip on non-Linux or when no WiFi hardware
if (process.platform !== 'linux') {
hostLog('WiFi setup: skipped (not Linux)')
return
}
if (!nmcli.hasHardware()) {
hostLog('WiFi setup: skipped (no WiFi hardware)')
return
}
const status = await getWifiStatus()
if (status.connected) {
hostLog(`WiFi: connected to ${status.ssid} (${status.ip})`)
return
}
// No WiFi connection - enter setup mode
hostLog('WiFi: not connected, starting setup hotspot...')
setSetupMode(true)
try {
await nmcli.startHotspot()
hostLog('WiFi hotspot started: "Toes Setup" (password: toessetup)')
} catch (e) {
hostLog(`Failed to start hotspot: ${e instanceof Error ? e.message : String(e)}`)
}
}