feat: add multi-gateway management with auto port detection
- Add GatewayManager for multi-profile gateway lifecycle management - Auto-detect running gateways on startup via PID + health check - Port conflict detection: check managed gateways, allocated ports, and system-level port availability (TCP bind test) - Two-phase startup: sequential port resolution, parallel process launch - Use `gateway start/restart` on normal systems, `gateway run --replace` on WSL/Docker - Wait for health check before returning start/stop responses - Add Gateways page with card-based layout showing profile status - Reorganize sidebar navigation into collapsible groups - Hide API server settings (now auto-managed by GatewayManager) - Profile switch reloads page; Ctrl+C no longer stops gateways - Remove redundant ensureApiServerConfig from index.ts and profiles.ts Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
import Router from '@koa/router'
|
||||
|
||||
export const gatewayRoutes = new Router()
|
||||
|
||||
// Get singleton instance — set during bootstrap
|
||||
let manager: any = null
|
||||
|
||||
export function setGatewayManager(mgr: any) {
|
||||
manager = mgr
|
||||
}
|
||||
|
||||
export function getGatewayManager(): any {
|
||||
return manager
|
||||
}
|
||||
|
||||
// List all gateway statuses
|
||||
gatewayRoutes.get('/api/hermes/gateways', async (ctx) => {
|
||||
if (!manager) {
|
||||
ctx.status = 503
|
||||
ctx.body = { error: 'GatewayManager not initialized' }
|
||||
return
|
||||
}
|
||||
const gateways = await manager.listAll()
|
||||
ctx.body = { gateways }
|
||||
})
|
||||
|
||||
// Start a profile's gateway
|
||||
gatewayRoutes.post('/api/hermes/gateways/:name/start', async (ctx) => {
|
||||
if (!manager) {
|
||||
ctx.status = 503
|
||||
ctx.body = { error: 'GatewayManager not initialized' }
|
||||
return
|
||||
}
|
||||
const { name } = ctx.params
|
||||
try {
|
||||
const status = await manager.start(name)
|
||||
ctx.body = { success: true, gateway: status }
|
||||
} catch (err: any) {
|
||||
ctx.status = 500
|
||||
ctx.body = { error: err.message }
|
||||
}
|
||||
})
|
||||
|
||||
// Stop a profile's gateway
|
||||
gatewayRoutes.post('/api/hermes/gateways/:name/stop', async (ctx) => {
|
||||
if (!manager) {
|
||||
ctx.status = 503
|
||||
ctx.body = { error: 'GatewayManager not initialized' }
|
||||
return
|
||||
}
|
||||
const { name } = ctx.params
|
||||
try {
|
||||
await manager.stop(name)
|
||||
ctx.body = { success: true }
|
||||
} catch (err: any) {
|
||||
ctx.status = 500
|
||||
ctx.body = { error: err.message }
|
||||
}
|
||||
})
|
||||
|
||||
// Check a profile's gateway health
|
||||
gatewayRoutes.get('/api/hermes/gateways/:name/health', async (ctx) => {
|
||||
if (!manager) {
|
||||
ctx.status = 503
|
||||
ctx.body = { error: 'GatewayManager not initialized' }
|
||||
return
|
||||
}
|
||||
const { name } = ctx.params
|
||||
const status = await manager.detectStatus(name)
|
||||
ctx.body = { gateway: status }
|
||||
})
|
||||
Reference in New Issue
Block a user