From 7073cab8b566ad5c421221eaac961a48b2e3fc85 Mon Sep 17 00:00:00 2001 From: Chris Wanstrath Date: Tue, 24 Feb 2026 19:59:25 -0800 Subject: [PATCH] Add url to wifi status and use dynamic hostname for mDNS --- scripts/install.sh | 1 + src/client/api.ts | 2 +- src/client/components/SettingsPage.tsx | 6 ++++-- src/server/api/wifi.ts | 3 ++- src/server/mdns.ts | 12 +++++++----- 5 files changed, 15 insertions(+), 9 deletions(-) diff --git a/scripts/install.sh b/scripts/install.sh index 3c3cebd..b020230 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -19,6 +19,7 @@ echo ">> Updating system libraries" quiet sudo apt-get update quiet sudo apt-get install -y libcap2-bin quiet sudo apt-get install -y avahi-utils +quiet sudo apt-get install -y dnsmasq quiet sudo apt-get install -y fish echo ">> Setting fish as default shell for toes user" diff --git a/src/client/api.ts b/src/client/api.ts index dff249c..36f55a6 100644 --- a/src/client/api.ts +++ b/src/client/api.ts @@ -13,7 +13,7 @@ export const getLogDates = (name: string): Promise => export const getLogsForDate = (name: string, date: string): Promise => fetch(`/api/apps/${name}/logs?date=${date}`).then(r => r.json()) -export const getWifiStatus = (): Promise => +export const getWifiStatus = (): Promise => fetch('/api/wifi/status').then(r => r.json()) export const restartApp = (name: string) => fetch(`/api/apps/${name}/restart`, { method: 'POST' }) diff --git a/src/client/components/SettingsPage.tsx b/src/client/components/SettingsPage.tsx index 1995976..0ac90c6 100644 --- a/src/client/components/SettingsPage.tsx +++ b/src/client/components/SettingsPage.tsx @@ -85,12 +85,14 @@ export function SettingsPage({ render }: { render: () => void }) { const [error, setError] = useState('') const [successSsid, setSuccessSsid] = useState('') const [successIp, setSuccessIp] = useState('') + const [serverUrl, setServerUrl] = useState('') const fetchStatus = () => { getWifiStatus().then(status => { setConnected(status.connected) setCurrentSsid(status.ssid) setCurrentIp(status.ip) + if (status.url) setServerUrl(status.url) }).catch(() => {}) } @@ -278,10 +280,10 @@ export function SettingsPage({ render }: { render: () => void }) { }}>

Reconnect your device to {successSsid} and visit:

- http://toes.local + {serverUrl} ) : ( diff --git a/src/server/api/wifi.ts b/src/server/api/wifi.ts index 91f1a71..2130f70 100644 --- a/src/server/api/wifi.ts +++ b/src/server/api/wifi.ts @@ -1,3 +1,4 @@ +import { TOES_URL } from '$apps' import { Hype } from '@because/hype' import { connectToWifi, getWifiStatus, isSetupMode, onSetupModeChange, scanNetworks } from '../wifi' @@ -6,7 +7,7 @@ const router = Hype.router() // GET /api/wifi/status - current WiFi state + setup mode flag router.get('/status', async c => { const status = await getWifiStatus() - return c.json({ ...status, setupMode: isSetupMode() }) + return c.json({ ...status, setupMode: isSetupMode(), url: TOES_URL }) }) // GET /api/wifi/scan - list available networks diff --git a/src/server/mdns.ts b/src/server/mdns.ts index e8a74a4..07488d1 100644 --- a/src/server/mdns.ts +++ b/src/server/mdns.ts @@ -1,10 +1,11 @@ import type { Subprocess } from 'bun' import { toSubdomain } from '@urls' -import { networkInterfaces } from 'os' +import { hostname, networkInterfaces } from 'os' import { hostLog } from './tui' const _publishers = new Map() +const HOST_DOMAIN = `${hostname()}.local` const isEnabled = process.env.NODE_ENV === 'production' && process.platform === 'linux' function getLocalIp(): string | null { @@ -24,7 +25,8 @@ export function cleanupStalePublishers() { if (!isEnabled) return try { - const result = Bun.spawnSync(['pkill', '-f', 'avahi-publish.*toes\\.local']) + const pattern = HOST_DOMAIN.replace(/\./g, '\\.') + const result = Bun.spawnSync(['pkill', '-f', `avahi-publish.*${pattern}`]) if (result.exitCode === 0) { hostLog('mDNS: cleaned up stale avahi-publish processes') } @@ -41,7 +43,7 @@ export function publishApp(name: string) { return } - const hostname = `${toSubdomain(name)}.toes.local` + const hostname = `${toSubdomain(name)}.${HOST_DOMAIN}` try { const proc = Bun.spawn(['avahi-publish', '-a', hostname, '-R', ip], { @@ -68,7 +70,7 @@ export function unpublishApp(name: string) { proc.kill() _publishers.delete(name) - hostLog(`mDNS: unpublished ${toSubdomain(name)}.toes.local`) + hostLog(`mDNS: unpublished ${toSubdomain(name)}.${HOST_DOMAIN}`) } export function unpublishAll() { @@ -76,7 +78,7 @@ export function unpublishAll() { for (const [name, proc] of _publishers) { proc.kill() - hostLog(`mDNS: unpublished ${toSubdomain(name)}.toes.local`) + hostLog(`mDNS: unpublished ${toSubdomain(name)}.${HOST_DOMAIN}`) } _publishers.clear() }