forked from defunkt/toes
Refactor app reload logic into dedicated function
This commit is contained in:
parent
b303fa1eef
commit
7935469776
|
|
@ -196,12 +196,11 @@ router.post('/:app/start', c => {
|
||||||
return c.json({ ok: true })
|
return c.json({ ok: true })
|
||||||
})
|
})
|
||||||
|
|
||||||
router.post('/:app/restart', c => {
|
router.post('/:app/restart', async c => {
|
||||||
const appName = c.req.param('app')
|
const appName = c.req.param('app')
|
||||||
if (!appName) return c.json({ error: 'App not found' }, 404)
|
if (!appName) return c.json({ error: 'App not found' }, 404)
|
||||||
|
|
||||||
stopApp(appName)
|
await restartApp(appName)
|
||||||
startApp(appName)
|
|
||||||
return c.json({ ok: true })
|
return c.json({ ok: true })
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { APPS_DIR, allApps, emit, registerApp, removeApp, restartApp, startApp } from '$apps'
|
import { APPS_DIR, allApps, emit, registerApp, reloadApp, removeApp, restartApp, startApp } from '$apps'
|
||||||
import { computeHash, generateManifest } from '../sync'
|
import { computeHash, generateManifest } from '../sync'
|
||||||
import { loadGitignore } from '@gitignore'
|
import { loadGitignore } from '@gitignore'
|
||||||
import { existsSync, mkdirSync, readdirSync, readFileSync, realpathSync, rmSync, unlinkSync, watch, writeFileSync } from 'fs'
|
import { existsSync, mkdirSync, readdirSync, readFileSync, realpathSync, rmSync, unlinkSync, watch, writeFileSync } from 'fs'
|
||||||
|
|
@ -115,25 +115,14 @@ router.post('/apps/:app/reload', async c => {
|
||||||
const appName = c.req.param('app')
|
const appName = c.req.param('app')
|
||||||
if (!appName) return c.json({ error: 'App name required' }, 400)
|
if (!appName) return c.json({ error: 'App name required' }, 400)
|
||||||
|
|
||||||
emit({ type: 'app:reload', app: appName })
|
try {
|
||||||
|
await reloadApp(appName)
|
||||||
// Register new app or restart existing
|
} catch (e) {
|
||||||
const app = allApps().find(a => a.name === appName)
|
return c.json({ error: `Failed to reload app: ${e instanceof Error ? e.message : String(e)}` }, 500)
|
||||||
if (!app) {
|
|
||||||
// New app - register it
|
|
||||||
registerApp(appName)
|
|
||||||
} else if (app.state === 'running') {
|
|
||||||
// Existing app - restart it
|
|
||||||
try {
|
|
||||||
await restartApp(appName)
|
|
||||||
} catch (e) {
|
|
||||||
return c.json({ error: `Failed to restart app: ${e instanceof Error ? e.message : String(e)}` }, 500)
|
|
||||||
}
|
|
||||||
} else if (app.state === 'stopped' || app.state === 'invalid') {
|
|
||||||
// App not running - try to start it
|
|
||||||
startApp(appName)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emit({ type: 'app:reload', app: appName })
|
||||||
|
|
||||||
return c.json({ ok: true })
|
return c.json({ ok: true })
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -176,6 +176,69 @@ export function registerApp(dir: string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function reloadApp(dir: string) {
|
||||||
|
const app = _apps.get(dir)
|
||||||
|
if (!app) {
|
||||||
|
// New app — register it
|
||||||
|
registerApp(dir)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Re-read config from disk
|
||||||
|
const { pkg, error } = loadApp(dir)
|
||||||
|
const wasStatic = app.static
|
||||||
|
const nowStatic = !!pkg.toes?.static
|
||||||
|
|
||||||
|
// Update cached metadata
|
||||||
|
app.icon = pkg.toes?.icon ?? DEFAULT_EMOJI
|
||||||
|
app.tool = pkg.toes?.tool
|
||||||
|
app.apps = pkg.toes?.apps
|
||||||
|
app.dashboard = pkg.toes?.dashboard
|
||||||
|
app.share = pkg.toes?.share
|
||||||
|
app.static = pkg.toes?.static
|
||||||
|
app.error = error
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
// App is now invalid
|
||||||
|
if (app.state === 'running' || app.state === 'starting') {
|
||||||
|
stopApp(dir)
|
||||||
|
}
|
||||||
|
app.state = 'invalid'
|
||||||
|
update()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nowStatic) {
|
||||||
|
// Stop process if transitioning from process-based to static
|
||||||
|
if (!wasStatic && (app.state === 'running' || app.state === 'starting')) {
|
||||||
|
stopApp(dir)
|
||||||
|
// Wait for stop
|
||||||
|
const maxWait = 10000
|
||||||
|
const poll = 100
|
||||||
|
let waited = 0
|
||||||
|
while (_apps.get(dir)?.state !== 'stopped' && waited < maxWait) {
|
||||||
|
await new Promise(r => setTimeout(r, poll))
|
||||||
|
waited += poll
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Mark as running (static apps are always "running")
|
||||||
|
app.state = 'running'
|
||||||
|
app.started = Date.now()
|
||||||
|
app.manuallyStopped = false
|
||||||
|
update()
|
||||||
|
publishApp(dir)
|
||||||
|
openTunnelIfEnabled(dir, SERVER_PORT)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process-based app — restart it
|
||||||
|
if (app.state === 'running' || app.state === 'starting') {
|
||||||
|
await restartApp(dir)
|
||||||
|
} else {
|
||||||
|
startApp(dir)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export async function renameApp(oldName: string, newName: string): Promise<{ ok: boolean, error?: string }> {
|
export async function renameApp(oldName: string, newName: string): Promise<{ ok: boolean, error?: string }> {
|
||||||
const app = _apps.get(oldName)
|
const app = _apps.get(oldName)
|
||||||
if (!app) return { ok: false, error: 'App not found' }
|
if (!app) return { ok: false, error: 'App not found' }
|
||||||
|
|
|
||||||
|
|
@ -180,6 +180,9 @@ function openTunnel(appName: string, port: number, subdomain?: string, isReconne
|
||||||
onRequest(req) {
|
onRequest(req) {
|
||||||
const app = getApp(appName)
|
const app = getApp(appName)
|
||||||
if (app?.tunnelUrl) req.headers['x-app-url'] = app.tunnelUrl
|
if (app?.tunnelUrl) req.headers['x-app-url'] = app.tunnelUrl
|
||||||
|
// Static apps are served by the main server via subdomain routing,
|
||||||
|
// so set the Host header so extractSubdomain() can identify the app
|
||||||
|
if (app?.static) req.headers['host'] = `${appName}.localhost`
|
||||||
},
|
},
|
||||||
|
|
||||||
onOpen(assignedSubdomain) {
|
onOpen(assignedSubdomain) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user