Sync Mode6Test frontend improvements: pinch zoom 500% max, no flicker/flip, deferred rendering
This commit is contained in:
@@ -0,0 +1 @@
|
||||
Mode6Test
|
||||
@@ -0,0 +1,150 @@
|
||||
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-Prod';
|
||||
const MODE_CONFIG_FILE = `${MODES_DIR}/ModeSwitch/activeMode.txt`;
|
||||
const SHARED_PORT = 3000;
|
||||
const ORCHESTRATOR_PORT = 3001;
|
||||
|
||||
// Mode folder mappings
|
||||
const MODE_FOLDERS: Record<string, string> = {
|
||||
'Mode1Test': 'Mode1Test',
|
||||
'Mode2Test': 'Mode2Test',
|
||||
'Mode3Test': 'Mode3Test',
|
||||
'Mode6Test': 'Mode6Test',
|
||||
};
|
||||
|
||||
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}...`);
|
||||
|
||||
// Determine server path based on mode
|
||||
// Mode2Test uses AuthAndToken/backend/server.ts
|
||||
// Mode1Test and Mode3Test use backend/server.ts
|
||||
let serverPath = 'backend/server.ts';
|
||||
if (mode === 'Mode2Test') {
|
||||
serverPath = 'AuthAndToken/backend/server.ts';
|
||||
}
|
||||
|
||||
// Start the mode's backend server
|
||||
currentProcess = Bun.spawn({
|
||||
cmd: [process.execPath, 'run', serverPath],
|
||||
cwd: modePath,
|
||||
env: {
|
||||
// Force mode service to bind to shared port
|
||||
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();
|
||||
|
||||
// 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,
|
||||
};
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"lockfileVersion": 1,
|
||||
"configVersion": 1,
|
||||
"workspaces": {
|
||||
"": {
|
||||
"name": "mode-switch",
|
||||
"dependencies": {
|
||||
"dotenv": "^17.2.3",
|
||||
"hono": "^4.10.8",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bun": "latest",
|
||||
"typescript": "^5",
|
||||
},
|
||||
},
|
||||
},
|
||||
"packages": {
|
||||
"@types/bun": ["@types/bun@1.3.6", "", { "dependencies": { "bun-types": "1.3.6" } }, "sha512-uWCv6FO/8LcpREhenN1d1b6fcspAB+cefwD7uti8C8VffIv0Um08TKMn98FynpTiU38+y2dUO55T11NgDt8VAA=="],
|
||||
|
||||
"@types/node": ["@types/node@25.0.9", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-/rpCXHlCWeqClNBwUhDcusJxXYDjZTyE8v5oTO7WbL8eij2nKhUeU89/6xgjU7N4/Vh3He0BtyhJdQbDyhiXAw=="],
|
||||
|
||||
"bun-types": ["bun-types@1.3.6", "", { "dependencies": { "@types/node": "*" } }, "sha512-OlFwHcnNV99r//9v5IIOgQ9Uk37gZqrNMCcqEaExdkVq3Avwqok1bJFmvGMCkCE0FqzdY8VMOZpfpR3lwI+CsQ=="],
|
||||
|
||||
"dotenv": ["dotenv@17.2.3", "", {}, "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w=="],
|
||||
|
||||
"hono": ["hono@4.11.4", "", {}, "sha512-U7tt8JsyrxSRKspfhtLET79pU8K+tInj5QZXs1jSugO1Vq5dFj3kmZsRldo29mTBfcjDRVRXrEZ6LS63Cog9ZA=="],
|
||||
|
||||
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
||||
|
||||
"undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
[2026-01-17 14:30] Mode-Based Architecture Implementation Complete
|
||||
|
||||
=== ARCHITECTURE ===
|
||||
✓ Created three-folder structure:
|
||||
- Mode1Test/: Original application (standalone project)
|
||||
- Mode2Test/: Placeholder for alternative configuration
|
||||
- ModeSwitch/: Orchestrator hub (controls mode switching)
|
||||
|
||||
✓ ModeSwitch Orchestrator (Bun + Hono):
|
||||
- Listens on port 3006 (control/monitoring)
|
||||
- Manages port 3005 (shared public port)
|
||||
- Reads activeMode.txt to determine startup mode
|
||||
- Kills existing process and starts new mode on demand
|
||||
- Hot-swap: Switch modes via API without manual restart
|
||||
|
||||
✓ Mode Folders:
|
||||
- Each mode is a standalone, complete project
|
||||
- Has own package.json, backend/, frontend/, logs/
|
||||
- Runs on shared port 3005 when active
|
||||
- Can be locked read-only once stable
|
||||
|
||||
=== ENDPOINTS ===
|
||||
Orchestrator (port 3006):
|
||||
GET /health - Health check
|
||||
GET /api/mode - Get current mode and available modes
|
||||
POST /api/mode/switch/:mode - Switch to different mode
|
||||
|
||||
App (port 3005):
|
||||
Available when active mode is running
|
||||
|
||||
=== NAMING CONSISTENCY ===
|
||||
Resolved: oldTest → Mode1Test
|
||||
Updated:
|
||||
- Folder renamed
|
||||
- orchestrator.ts MODE_FOLDERS mapping
|
||||
- activeMode.txt
|
||||
- README.md references
|
||||
- API response lists
|
||||
|
||||
=== CURRENT STATUS ===
|
||||
✓ Mode1Test running on port 3005
|
||||
✓ Orchestrator running on port 3006
|
||||
✓ Ready for Mode2Test implementation
|
||||
✓ Root directory clean (only 3 mode folders + Monica.txt + README.md + .git)
|
||||
|
||||
=== NEXT PHASE ===
|
||||
Ready to begin Mode2Test development
|
||||
@@ -0,0 +1,26 @@
|
||||
|
||||
================================================================================
|
||||
[ModeSwitch Orchestrator]
|
||||
================================================================================
|
||||
Listening on port: 3006
|
||||
Shared mode port: 3005
|
||||
Config file: /home/admin/Job-Info-Test/ModeSwitch/activeMode.txt
|
||||
================================================================================
|
||||
|
||||
[ModeSwitch] Starting Mode5Test (Mode5Test/) on port 3005...
|
||||
✓ Mode5Test started successfully on port 3005
|
||||
7 | if (typeof entryNamespace?.default?.fetch === 'function') {
|
||||
8 | const server = Bun.serve(entryNamespace.default);
|
||||
9 | console.debug(`Started ${server.development ? 'development ' : ''}server: ${server.protocol}://${server.hostname}:${server.port}`);
|
||||
10 | }
|
||||
11 | }, reportError);
|
||||
12 | const server = Bun.serve(entryNamespace.default);
|
||||
^
|
||||
error: Failed to start server. Is port 3006 in use?
|
||||
syscall: "listen",
|
||||
errno: 0,
|
||||
code: "EADDRINUSE"
|
||||
|
||||
at bun:main:12:28
|
||||
|
||||
Bun v1.3.2 (Linux x64 baseline)
|
||||
@@ -0,0 +1 @@
|
||||
47889
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "mode-switch",
|
||||
"version": "1.0.0",
|
||||
"description": "Mode switching orchestrator - controls which mode (Test1Mode, Mode2Test) runs on port 3005",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "bun run backend/orchestrator.ts",
|
||||
"dev": "bun --watch backend/orchestrator.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"hono": "^4.10.8",
|
||||
"dotenv": "^17.2.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bun": "latest",
|
||||
"typescript": "^5"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user