mirror of
https://github.com/garrytan/gstack.git
synced 2026-05-18 18:32:28 +08:00
feat: multi-workspace support via CONDUCTOR_PORT
Each Conductor workspace gets its own isolated browser instance. Port derived as CONDUCTOR_PORT - 45600 (e.g., 55040 → 9440). State files and logs namespaced per port (/tmp/browse-server-9440.json). Falls back to port range scan (9400-9410) when no CONDUCTOR_PORT set. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -12,7 +12,12 @@
|
|||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
const STATE_FILE = process.env.BROWSE_STATE_FILE || '/tmp/browse-server.json';
|
const PORT_OFFSET = 45600;
|
||||||
|
const BROWSE_PORT = process.env.CONDUCTOR_PORT
|
||||||
|
? parseInt(process.env.CONDUCTOR_PORT, 10) - PORT_OFFSET
|
||||||
|
: parseInt(process.env.BROWSE_PORT || '0', 10);
|
||||||
|
const INSTANCE_SUFFIX = BROWSE_PORT ? `-${BROWSE_PORT}` : '';
|
||||||
|
const STATE_FILE = process.env.BROWSE_STATE_FILE || `/tmp/browse-server${INSTANCE_SUFFIX}.json`;
|
||||||
// When compiled, import.meta.dir is virtual. Use env var or well-known path.
|
// When compiled, import.meta.dir is virtual. Use env var or well-known path.
|
||||||
const SERVER_SCRIPT = process.env.BROWSE_SERVER_SCRIPT
|
const SERVER_SCRIPT = process.env.BROWSE_SERVER_SCRIPT
|
||||||
|| (import.meta.dir.startsWith('/') && !import.meta.dir.includes('$bunfs')
|
|| (import.meta.dir.startsWith('/') && !import.meta.dir.includes('$bunfs')
|
||||||
|
|||||||
@@ -18,7 +18,12 @@ import * as crypto from 'crypto';
|
|||||||
|
|
||||||
// ─── Auth (inline) ─────────────────────────────────────────────
|
// ─── Auth (inline) ─────────────────────────────────────────────
|
||||||
const AUTH_TOKEN = crypto.randomUUID();
|
const AUTH_TOKEN = crypto.randomUUID();
|
||||||
const STATE_FILE = process.env.BROWSE_STATE_FILE || '/tmp/browse-server.json';
|
const PORT_OFFSET = 45600;
|
||||||
|
const BROWSE_PORT = process.env.CONDUCTOR_PORT
|
||||||
|
? parseInt(process.env.CONDUCTOR_PORT, 10) - PORT_OFFSET
|
||||||
|
: parseInt(process.env.BROWSE_PORT || '0', 10); // 0 = auto-scan
|
||||||
|
const INSTANCE_SUFFIX = BROWSE_PORT ? `-${BROWSE_PORT}` : '';
|
||||||
|
const STATE_FILE = process.env.BROWSE_STATE_FILE || `/tmp/browse-server${INSTANCE_SUFFIX}.json`;
|
||||||
const IDLE_TIMEOUT_MS = parseInt(process.env.BROWSE_IDLE_TIMEOUT || '1800000', 10); // 30 min
|
const IDLE_TIMEOUT_MS = parseInt(process.env.BROWSE_IDLE_TIMEOUT || '1800000', 10); // 30 min
|
||||||
|
|
||||||
function validateAuth(req: Request): boolean {
|
function validateAuth(req: Request): boolean {
|
||||||
@@ -29,8 +34,8 @@ function validateAuth(req: Request): boolean {
|
|||||||
// ─── Buffer (from buffers.ts) ────────────────────────────────────
|
// ─── Buffer (from buffers.ts) ────────────────────────────────────
|
||||||
import { consoleBuffer, networkBuffer, addConsoleEntry, addNetworkEntry, type LogEntry, type NetworkEntry } from './buffers';
|
import { consoleBuffer, networkBuffer, addConsoleEntry, addNetworkEntry, type LogEntry, type NetworkEntry } from './buffers';
|
||||||
export { consoleBuffer, networkBuffer, addConsoleEntry, addNetworkEntry, type LogEntry, type NetworkEntry };
|
export { consoleBuffer, networkBuffer, addConsoleEntry, addNetworkEntry, type LogEntry, type NetworkEntry };
|
||||||
const CONSOLE_LOG_PATH = '/tmp/browse-console.log';
|
const CONSOLE_LOG_PATH = `/tmp/browse-console${INSTANCE_SUFFIX}.log`;
|
||||||
const NETWORK_LOG_PATH = '/tmp/browse-network.log';
|
const NETWORK_LOG_PATH = `/tmp/browse-network${INSTANCE_SUFFIX}.log`;
|
||||||
let lastConsoleFlushed = 0;
|
let lastConsoleFlushed = 0;
|
||||||
let lastNetworkFlushed = 0;
|
let lastNetworkFlushed = 0;
|
||||||
|
|
||||||
@@ -98,8 +103,20 @@ const META_COMMANDS = new Set([
|
|||||||
'url',
|
'url',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Find available port
|
// Find port: deterministic from CONDUCTOR_PORT, or scan range
|
||||||
async function findPort(): Promise<number> {
|
async function findPort(): Promise<number> {
|
||||||
|
// Deterministic port from CONDUCTOR_PORT (e.g., 55040 - 45600 = 9440)
|
||||||
|
if (BROWSE_PORT) {
|
||||||
|
try {
|
||||||
|
const testServer = Bun.serve({ port: BROWSE_PORT, fetch: () => new Response('ok') });
|
||||||
|
testServer.stop();
|
||||||
|
return BROWSE_PORT;
|
||||||
|
} catch {
|
||||||
|
throw new Error(`[browse] Port ${BROWSE_PORT} (from CONDUCTOR_PORT ${process.env.CONDUCTOR_PORT}) is in use`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback: scan range
|
||||||
const start = parseInt(process.env.BROWSE_PORT_START || '9400', 10);
|
const start = parseInt(process.env.BROWSE_PORT_START || '9400', 10);
|
||||||
for (let port = start; port < start + 10; port++) {
|
for (let port = start; port < start + 10; port++) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
Reference in New Issue
Block a user