Refactor app reload to handle state transitions
This commit is contained in:
parent
c634d488b6
commit
b303fa1eef
|
|
@ -1,4 +1,4 @@
|
|||
import { APPS_DIR, allApps, emit, registerApp, reloadApp, removeApp, restartApp, startApp } from '$apps'
|
||||
import { APPS_DIR, allApps, emit, registerApp, removeApp, restartApp, startApp } from '$apps'
|
||||
import { computeHash, generateManifest } from '../sync'
|
||||
import { loadGitignore } from '@gitignore'
|
||||
import { existsSync, mkdirSync, readdirSync, readFileSync, realpathSync, rmSync, unlinkSync, watch, writeFileSync } from 'fs'
|
||||
|
|
@ -115,14 +115,25 @@ router.post('/apps/:app/reload', async c => {
|
|||
const appName = c.req.param('app')
|
||||
if (!appName) return c.json({ error: 'App name required' }, 400)
|
||||
|
||||
try {
|
||||
await reloadApp(appName)
|
||||
} catch (e) {
|
||||
return c.json({ error: `Failed to reload app: ${e instanceof Error ? e.message : String(e)}` }, 500)
|
||||
}
|
||||
|
||||
emit({ type: 'app:reload', app: appName })
|
||||
|
||||
// Register new app or restart existing
|
||||
const app = allApps().find(a => a.name === appName)
|
||||
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)
|
||||
}
|
||||
|
||||
return c.json({ ok: true })
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -176,69 +176,6 @@ 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 }> {
|
||||
const app = _apps.get(oldName)
|
||||
if (!app) return { ok: false, error: 'App not found' }
|
||||
|
|
|
|||
|
|
@ -180,9 +180,6 @@ function openTunnel(appName: string, port: number, subdomain?: string, isReconne
|
|||
onRequest(req) {
|
||||
const app = getApp(appName)
|
||||
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) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user