diff --git a/shared/ports.ts b/shared/ports.ts new file mode 100644 index 0000000..b34c7ee --- /dev/null +++ b/shared/ports.ts @@ -0,0 +1,7 @@ +/** + * Calculate the port for a given app based on its ID. + * Uses a base port of 32100 and offsets by appId % 10_000. + */ +export function getAppPort(appId: number): number { + return 32100 + (appId % 10_000); +} diff --git a/src/client_logic/template_hook.ts b/src/client_logic/template_hook.ts index 70fa28c..c65a2fc 100644 --- a/src/client_logic/template_hook.ts +++ b/src/client_logic/template_hook.ts @@ -1,4 +1,5 @@ import { IpcClient } from "@/ipc/ipc_client"; +import { getAppPort } from "../../shared/ports"; import { v4 as uuidv4 } from "uuid"; @@ -29,7 +30,7 @@ export async function neonTemplateHook({ }, { key: "NEXT_PUBLIC_SERVER_URL", - value: "http://localhost:32100", + value: `http://localhost:${getAppPort(appId)}`, }, { key: "GMAIL_USER", diff --git a/src/ipc/handlers/app_handlers.ts b/src/ipc/handlers/app_handlers.ts index afc9304..760fa24 100644 --- a/src/ipc/handlers/app_handlers.ts +++ b/src/ipc/handlers/app_handlers.ts @@ -62,8 +62,12 @@ import { getVercelTeamSlug } from "../utils/vercel_utils"; import { storeDbTimestampAtCurrentVersion } from "../utils/neon_timestamp_utils"; import { AppSearchResult } from "@/lib/schemas"; -const DEFAULT_COMMAND = - "(pnpm install && pnpm run dev --port 32100) || (npm install --legacy-peer-deps && npm run dev -- --port 32100)"; +import { getAppPort } from "../../../shared/ports"; + +function getDefaultCommand(appId: number): string { + const port = getAppPort(appId); + return `(pnpm install && pnpm run dev --port ${port}) || (npm install --legacy-peer-deps && npm run dev -- --port ${port})`; +} async function copyDir( source: string, destination: string, @@ -150,7 +154,7 @@ async function executeAppLocalNode({ installCommand?: string | null; startCommand?: string | null; }): Promise { - const command = getCommand({ installCommand, startCommand }); + const command = getCommand({ appId, installCommand, startCommand }); const spawnedProcess = spawn(command, [], { cwd: appPath, shell: true, @@ -418,6 +422,7 @@ RUN npm install -g pnpm }); // Run the Docker container + const port = getAppPort(appId); const process = spawn( "docker", [ @@ -426,7 +431,7 @@ RUN npm install -g pnpm "--name", containerName, "-p", - "32100:32100", + `${port}:${port}`, "-v", `${appPath}:/app`, "-v", @@ -438,7 +443,7 @@ RUN npm install -g pnpm `dyad-app-${appId}`, "sh", "-c", - getCommand({ installCommand, startCommand }), + getCommand({ appId, installCommand, startCommand }), ], { stdio: "pipe", @@ -817,8 +822,8 @@ export function registerAppHandlers() { const appPath = getDyadAppPath(app.path); try { - // There may have been a previous run that left a process on port 32100. - await cleanUpPort(32100); + // There may have been a previous run that left a process on this port. + await cleanUpPort(getAppPort(appId)); await executeApp({ appPath, appId, @@ -918,8 +923,8 @@ export function registerAppHandlers() { logger.log(`App ${appId} not running. Proceeding to start.`); } - // There may have been a previous run that left a process on port 32100. - await cleanUpPort(32100); + // There may have been a previous run that left a process on this port. + await cleanUpPort(getAppPort(appId)); // Now start the app again const app = await db.query.apps.findFirst({ @@ -1573,16 +1578,18 @@ export function registerAppHandlers() { } function getCommand({ + appId, installCommand, startCommand, }: { + appId: number; installCommand?: string | null; startCommand?: string | null; }) { const hasCustomCommands = !!installCommand?.trim() && !!startCommand?.trim(); return hasCustomCommands ? `${installCommand!.trim()} && ${startCommand!.trim()}` - : DEFAULT_COMMAND; + : getDefaultCommand(appId); } async function cleanUpPort(port: number) {