Compare commits

..

No commits in common. "2937fb237208c93d4b82e9f910bef1fdaa48e041" and "00c37bd9e8d39441ba76f7bf0d4a44c715b90ba0" have entirely different histories.

4 changed files with 5 additions and 54 deletions

View File

@ -4,7 +4,7 @@ export const getLogDates = (name: string): Promise<string[]> =>
export const getLogsForDate = (name: string, date: string): Promise<string[]> =>
fetch(`/api/apps/${name}/logs?date=${date}`).then(r => r.json())
export const getSystemInfo = (): Promise<{ version: string, sha: string, uptime: number }> =>
export const getSystemInfo = (): Promise<{ version: string, sha: string }> =>
fetch('/api/system/info').then(r => r.json())
export const shareApp = (name: string) =>

View File

@ -19,20 +19,6 @@ import {
type UpdateInfo = { available: boolean, current: string, latest: string, commits: string[] }
function formatUptime(ms: number): string {
const seconds = Math.floor(ms / 1000)
const days = Math.floor(seconds / 86400)
const hours = Math.floor((seconds % 86400) / 3600)
const minutes = Math.floor((seconds % 3600) / 60)
const secs = seconds % 60
const parts: string[] = []
if (days > 0) parts.push(`${days}d`)
if (hours > 0) parts.push(`${hours}h`)
if (minutes > 0) parts.push(`${minutes}m`)
parts.push(`${secs}s`)
return parts.join(' ')
}
function pollUntilBack(onBack: () => void, onTimeout?: () => void) {
let elapsed = 0
const poll = setInterval(async () => {
@ -55,7 +41,6 @@ function pollUntilBack(onBack: () => void, onTimeout?: () => void) {
export function SettingsPage({ render }: { render: () => void }) {
const [version, setVersion] = useState('')
const [sha, setSha] = useState('')
const [uptime, setUptime] = useState(0)
const [themeChoice, setThemeChoice] = useState(localStorage.getItem('theme') || 'system')
const [restarting, setRestarting] = useState(false)
const [updateInfo, setUpdateInfo] = useState<UpdateInfo | null>(null)
@ -66,16 +51,9 @@ export function SettingsPage({ render }: { render: () => void }) {
getSystemInfo().then(info => {
setVersion(info.version)
setSha(info.sha)
setUptime(info.uptime)
})
}, [])
// Tick uptime every second
useEffect(() => {
const interval = setInterval(() => setUptime(u => u + 1000), 1000)
return () => clearInterval(interval)
}, [])
const goBack = () => {
navigate('/')
}
@ -95,7 +73,6 @@ export function SettingsPage({ render }: { render: () => void }) {
getSystemInfo().then(info => {
setVersion(info.version)
setSha(info.sha)
setUptime(info.uptime)
})
}
@ -198,14 +175,9 @@ export function SettingsPage({ render }: { render: () => void }) {
</Section>
<Section>
<SectionTitle>Server</SectionTitle>
<div style={{ display: 'flex', flexDirection: 'column', gap: 8, fontSize: 14 }}>
<span>Uptime: {formatUptime(uptime)}</span>
</div>
<div style={{ marginTop: 12 }}>
<Button variant="danger" onClick={handleRestart} disabled={restarting}>
{restarting ? 'Restarting...' : 'Restart Server'}
</Button>
</div>
<Button variant="danger" onClick={handleRestart} disabled={restarting}>
{restarting ? 'Restarting...' : 'Restart Server'}
</Button>
</Section>
</MainContent>
</Main>

View File

@ -203,13 +203,12 @@ router.sse('/metrics/stream', (send) => {
// System info
const projectRoot = join(import.meta.dir, '../../..')
const startedAt = Date.now()
const pkg = JSON.parse(readFileSync(join(projectRoot, 'package.json'), 'utf-8'))
const sha = Bun.spawnSync(['git', 'rev-parse', '--short', 'HEAD'], { cwd: projectRoot }).stdout.toString().trim() || 'unknown'
let isUpdating = false
router.get('/info', c => {
return c.json({ version: pkg.version, sha, uptime: Date.now() - startedAt })
return c.json({ version: pkg.version, sha })
})
// Get recent unified logs

View File

@ -4,12 +4,7 @@ import { LOCAL_HOST } from '%config'
import { networkInterfaces } from 'os'
import { hostLog } from './tui'
const MAX_REPUBLISH_DELAY = 30_000
const REPUBLISH_BASE_DELAY = 1_000
const _killed = new Set<string>()
const _publishers = new Map<string, Subprocess>()
const _republishAttempts = new Map<string, number>()
const isEnabled = process.env.NODE_ENV === 'production' && process.platform === 'linux'
@ -56,12 +51,10 @@ export function publishApp(name: string) {
})
_publishers.set(name, proc)
_republishAttempts.delete(name)
hostLog(`mDNS: published ${host} -> ${ip}`)
proc.exited.then(() => {
_publishers.delete(name)
if (!_killed.delete(name)) republish(name)
})
} catch {
hostLog(`mDNS: failed to publish ${host}`)
@ -71,11 +64,9 @@ export function publishApp(name: string) {
export function unpublishApp(name: string) {
if (!isEnabled) return
_republishAttempts.delete(name)
const proc = _publishers.get(name)
if (!proc) return
_killed.add(name)
proc.kill()
_publishers.delete(name)
hostLog(`mDNS: unpublished ${toSubdomain(name)}.${LOCAL_HOST}`)
@ -84,20 +75,9 @@ export function unpublishApp(name: string) {
export function unpublishAll() {
if (!isEnabled) return
_republishAttempts.clear()
for (const [name, proc] of _publishers) {
_killed.add(name)
proc.kill()
hostLog(`mDNS: unpublished ${toSubdomain(name)}.${LOCAL_HOST}`)
}
_publishers.clear()
}
function republish(name: string) {
const attempts = _republishAttempts.get(name) ?? 0
const delay = Math.min(REPUBLISH_BASE_DELAY * 2 ** attempts, MAX_REPUBLISH_DELAY)
_republishAttempts.set(name, attempts + 1)
hostLog(`mDNS: ${toSubdomain(name)}.${LOCAL_HOST} exited unexpectedly, retrying in ${delay}ms`)
setTimeout(() => publishApp(name), delay)
}