import { Hono } from 'hono'; import { cors } from 'hono/cors'; import * as fs from 'node:fs'; // Configuration const MODES_DIR = '/home/admin/Job-Info-Test'; const MODE_CONFIG_FILE = `${MODES_DIR}/ModeSwitch/activeMode.txt`; const SHARED_PORT = 3005; // Mode services run here - NEVER use 3000 or 3001 const ORCHESTRATOR_PORT = 3006; // Orchestrator API runs here // Mode folder mappings - only Mode6Test exists currently const MODE_FOLDERS: Record = { 'Mode1': 'Mode1', 'Mode1Svelte': 'Mode1Svelte', 'Mode2Svelte': 'Mode2Svelte', 'Mode3': 'Mode3', 'Mode6Test': 'Mode6Test', }; let currentMode: string = 'Mode1Svelte'; let currentProcess: any = null; // Helper: Read active mode from config file function readActiveMode(): string { try { if (fs.existsSync(MODE_CONFIG_FILE)) { const content = fs.readFileSync(MODE_CONFIG_FILE, 'utf-8').trim(); if (content && MODE_FOLDERS[content]) { return content; } } } catch (err) { console.error('Failed to read mode config:', err); } return 'Mode6Test'; } // Helper: Write active mode to config file function writeActiveMode(mode: string): void { try { fs.writeFileSync(MODE_CONFIG_FILE, mode, 'utf-8'); } catch (err) { console.error('Failed to write mode config:', err); } } // Helper: Kill process on shared port async function killProcessOnPort(port: number): Promise { try { await Bun.spawn({ cmd: ['pkill', '-f', `bun.*:${port}`], stdout: 'ignore', stderr: 'ignore', }); // Fallback: Try to kill any Bun process we spawned if (currentProcess) { currentProcess.kill(); currentProcess = null; } // Give OS time to release the port await new Promise(resolve => setTimeout(resolve, 500)); } catch (err) { console.error(`Failed to kill process on port ${port}:`, err); } } // Helper: Start a mode async function startMode(mode: string): Promise { try { // Kill any existing process await killProcessOnPort(SHARED_PORT); const folderName = MODE_FOLDERS[mode]; if (!folderName) { console.error(`Unknown mode: ${mode}`); return false; } const modePath = `${MODES_DIR}/${folderName}`; if (!fs.existsSync(modePath)) { console.error(`Mode folder not found: ${modePath}`); return false; } console.log(`[ModeSwitch] Starting ${mode} (${folderName}/) on port ${SHARED_PORT}...`); // Mode1Svelte and Mode2Svelte use Node.js adapter with build/index.js if (mode === 'Mode1Svelte' || mode === 'Mode2Svelte') { const buildPath = `${modePath}/build`; if (!fs.existsSync(buildPath)) { console.error(`Build directory not found for ${mode}. Run: cd ${modePath} && npm run build`); return false; } // Start with Node.js currentProcess = Bun.spawn({ cmd: ['node', 'build/index.js'], cwd: modePath, env: { ...process.env, PORT: String(SHARED_PORT), }, stdout: 'pipe', stderr: 'pipe', }); } else { // Other modes (Mode1, Mode6Test) use Bun with backend/server.ts const serverPath = 'backend/server.ts'; currentProcess = Bun.spawn({ cmd: [process.execPath, 'run', serverPath], cwd: modePath, env: { ...process.env, PORT: String(SHARED_PORT), }, stdout: 'pipe', stderr: 'pipe', }); } currentMode = mode; writeActiveMode(mode); // Read and log output from the spawned process if (currentProcess.stdout) { (async () => { const reader = currentProcess.stdout.getReader(); while (true) { const { done, value } = await reader.read(); if (done) break; console.log(`[${mode}]`, new TextDecoder().decode(value)); } })(); } console.log(`✓ ${mode} started successfully on port ${SHARED_PORT}`); return true; } catch (err) { console.error(`Failed to start ${mode}:`, err); return false; } } // Initialize app const app = new Hono(); // Enable CORS app.use('*', cors()); // API: Get current mode status app.get('/status', (c) => { return c.json({ currentMode, availableModes: Object.keys(MODE_FOLDERS), sharedPort: SHARED_PORT, orchestratorPort: ORCHESTRATOR_PORT, }); }); // API: Switch to a different mode app.post('/switch/:mode', async (c) => { const mode = c.req.param('mode'); if (!MODE_FOLDERS[mode]) { return c.json({ success: false, error: `Unknown mode: ${mode}. Available: ${Object.keys(MODE_FOLDERS).join(', ')}` }, 400); } if (mode === currentMode) { return c.json({ success: true, message: `Already running ${mode}`, currentMode }); } const success = await startMode(mode); if (success) { return c.json({ success: true, message: `Switched to ${mode}`, currentMode: mode }); } else { return c.json({ success: false, error: `Failed to start ${mode}` }, 500); } }); // API: Restart current mode app.post('/restart', async (c) => { console.log(`[ModeSwitch] Restarting ${currentMode}...`); const success = await startMode(currentMode); return c.json({ success, message: success ? `Restarted ${currentMode}` : `Failed to restart ${currentMode}`, currentMode }); }); // API: List available modes app.get('/modes', (c) => { return c.json({ modes: Object.keys(MODE_FOLDERS), currentMode }); }); // Startup message console.log(` ================================================================================ [ModeSwitch Orchestrator] ================================================================================ Listening on port: ${ORCHESTRATOR_PORT} Shared mode port: ${SHARED_PORT} Config file: ${MODE_CONFIG_FILE} ================================================================================ `); // Start initial mode const initialMode = readActiveMode(); await startMode(initialMode); // Export for Bun export default { port: ORCHESTRATOR_PORT, fetch: app.fetch, };