// 统一启动入口:本地运行 Next CLI,Docker 保留 standalone,两者共管 WebDAV 生命周期。 import { execFile, spawn } from "node:child_process"; import { createRequire } from "node:module"; import { getWebdavConfig } from "../src/server/webdav/config.mjs"; const mode = process.argv[2] || "standalone"; if (!["dev", "start", "standalone"].includes(mode)) throw new Error("启动模式必须为 dev、start 或 standalone"); const local = mode !== "standalone"; const load = createRequire(import.meta.url); if (local) { process.env.NODE_ENV = mode === "dev" ? "development" : "production"; // 复用当前 Next 安装中的 env loader,与 Next 的 .env* 优先级和变量展开保持一致。 const loadNext = createRequire(load.resolve("next/package.json")); loadNext("@next/env").loadEnvConfig(process.cwd(), mode === "dev"); process.env.PORT = process.env.PORT?.trim() || "3200"; process.env.WEBDAV_PORT = process.env.WEBDAV_PORT?.trim() || "3201"; } const config = getWebdavConfig(); if (config.enabled && config.port === Number(process.env.PORT)) throw new Error("WebDAV 与管理页不能使用相同端口"); const children = []; let stopping = false; const stop = (code = 0) => { if (stopping) return; stopping = true; process.exitCode = code; for (const child of children) { if (child.exitCode !== null || child.signalCode !== null) continue; // next dev 还会创建服务进程;Windows 必须结束整个子进程树,避免残留监听端口。 if (process.platform === "win32") execFile("taskkill", ["/PID", String(child.pid), "/T", "/F"], () => {}); else child.kill("SIGTERM"); } setTimeout(() => { for (const child of children) child.kill("SIGKILL"); }, 6000).unref(); }; const start = (file, args = [], env = process.env) => { const child = spawn(process.execPath, [file, ...args], { stdio: "inherit", env }); children.push(child); child.on("error", () => stop(1)); child.on("exit", (code, signal) => { if (!stopping) stop(code || (signal ? 1 : 0)); }); }; if (local) start(load.resolve("next/dist/bin/next"), [mode, "-p", process.env.PORT]); else start("server.js"); if (config.enabled) { const env = { ...process.env }; // 本地无密钥的演示模式沿用网页的 mock 密钥,不改变 Next 进程的演示提示。 if (local && !env.TORBOX_API_KEY?.trim() && !env.ACCESS_TOKEN?.trim()) env.ACCESS_TOKEN = "mock"; start("scripts/webdav.mjs", [], env); } process.once("SIGINT", () => stop()); process.once("SIGTERM", () => stop());