Mode-based architecture complete: Created ModeSwitch orchestrator (3006), Mode1Test isolated (3005), Mode2Test placeholder, added active mode label to frontend

This commit is contained in:
2026-01-17 14:37:14 +00:00
parent e4e3e65ea4
commit 319289cfac
63 changed files with 977 additions and 8756 deletions
+171
View File
@@ -0,0 +1,171 @@
import { Hono } from 'hono';
import { serveStatic } from 'hono/bun';
import { spawn } from 'bun';
import fs from 'fs';
// Configuration
const MODES_DIR = '/home/admin/Job-Info-Test';
const MODE_CONFIG_FILE = `${MODES_DIR}/ModeSwitch/activeMode.txt`;
const SHARED_PORT = 3005;
const ORCHESTRATOR_PORT = 3006;
// Mode folder mappings
const MODE_FOLDERS: Record<string, string> = {
'Mode1Test': 'Mode1Test',
'Mode2Test': 'Mode2Test',
};
let currentMode: string = 'Mode1Test';
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();
return content || 'Test1Mode';
}
} catch (err) {
console.error('Failed to read mode config:', err);
}
return 'Mode1Test';
}
// 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<void> {
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<boolean> {
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}...`);
// Start the mode's backend server
currentProcess = Bun.spawn({
cmd: ['bun', 'run', 'backend/server.ts'],
cwd: modePath,
stdout: 'pipe',
stderr: 'pipe',
env: {
...process.env,
PORT: String(SHARED_PORT),
},
});
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();
// Health check
app.get('/health', (c) => {
return c.json({ status: 'ok', orchestratorPort: ORCHESTRATOR_PORT, sharedPort: SHARED_PORT });
});
// Get current mode
app.get('/api/mode', (c) => {
return c.json({ currentMode, availableModes: ['Mode1Test', 'Mode2Test'] });
});
// Switch mode (with graceful restart)
app.post('/api/mode/switch/:mode', async (c) => {
const newMode = c.req.param('mode');
const validModes = ['Mode1Test', 'Mode2Test'];
if (!validModes.includes(newMode)) {
return c.json({ error: 'Invalid mode', availableModes: validModes }, 400);
}
if (newMode === currentMode) {
return c.json({ message: 'Already in this mode', currentMode });
}
const success = await startMode(newMode);
if (success) {
return c.json({ message: 'Mode switched successfully', currentMode: newMode });
} else {
return c.json({ error: 'Failed to switch mode' }, 500);
}
});
// 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,
};