112 lines
3.4 KiB
JavaScript
112 lines
3.4 KiB
JavaScript
import "#nitro-internal-pollyfills";
|
|
import { tmpdir } from "node:os";
|
|
import { useNitroApp } from "nitropack/runtime";
|
|
import { runTask } from "nitropack/runtime";
|
|
import { trapUnhandledNodeErrors } from "nitropack/runtime/internal";
|
|
import { startScheduleRunner } from "nitropack/runtime/internal";
|
|
import { scheduledTasks, tasks } from "#nitro-internal-virtual/tasks";
|
|
import { Server } from "node:http";
|
|
import { join } from "node:path";
|
|
import nodeCrypto from "node:crypto";
|
|
import { parentPort, threadId } from "node:worker_threads";
|
|
import wsAdapter from "crossws/adapters/node";
|
|
import {
|
|
defineEventHandler,
|
|
getQuery,
|
|
getRouterParam,
|
|
readBody,
|
|
toNodeListener
|
|
} from "h3";
|
|
if (!globalThis.crypto) {
|
|
globalThis.crypto = nodeCrypto.webcrypto;
|
|
}
|
|
const { NITRO_NO_UNIX_SOCKET, NITRO_DEV_WORKER_ID } = process.env;
|
|
trapUnhandledNodeErrors();
|
|
parentPort?.on("message", (msg) => {
|
|
if (msg && msg.event === "shutdown") {
|
|
shutdown();
|
|
}
|
|
});
|
|
const nitroApp = useNitroApp();
|
|
const server = new Server(toNodeListener(nitroApp.h3App));
|
|
let listener;
|
|
listen().catch(() => listen(
|
|
true
|
|
/* use random port */
|
|
)).catch((error) => {
|
|
console.error("Dev worker failed to listen:", error);
|
|
return shutdown();
|
|
});
|
|
if (import.meta._websocket) {
|
|
const { handleUpgrade } = wsAdapter(nitroApp.h3App.websocket);
|
|
server.on("upgrade", handleUpgrade);
|
|
}
|
|
nitroApp.router.get(
|
|
"/_nitro/tasks",
|
|
defineEventHandler(async (event) => {
|
|
const _tasks = await Promise.all(
|
|
Object.entries(tasks).map(async ([name, task]) => {
|
|
const _task = await task.resolve?.();
|
|
return [name, { description: _task?.meta?.description }];
|
|
})
|
|
);
|
|
return {
|
|
tasks: Object.fromEntries(_tasks),
|
|
scheduledTasks
|
|
};
|
|
})
|
|
);
|
|
nitroApp.router.use(
|
|
"/_nitro/tasks/:name",
|
|
defineEventHandler(async (event) => {
|
|
const name = getRouterParam(event, "name");
|
|
const payload = {
|
|
...getQuery(event),
|
|
...await readBody(event).then((r) => r?.payload).catch(() => ({}))
|
|
};
|
|
return await runTask(name, { payload });
|
|
})
|
|
);
|
|
if (import.meta._tasks) {
|
|
startScheduleRunner();
|
|
}
|
|
function listen(useRandomPort = Boolean(
|
|
NITRO_NO_UNIX_SOCKET || process.versions.webcontainer || "Bun" in globalThis && process.platform === "win32"
|
|
)) {
|
|
return new Promise((resolve, reject) => {
|
|
try {
|
|
listener = server.listen(useRandomPort ? 0 : getSocketAddress(), () => {
|
|
const address = server.address();
|
|
parentPort?.postMessage({
|
|
event: "listen",
|
|
address: typeof address === "string" ? { socketPath: address } : { host: "localhost", port: address?.port }
|
|
});
|
|
resolve();
|
|
});
|
|
} catch (error) {
|
|
reject(error);
|
|
}
|
|
});
|
|
}
|
|
function getSocketAddress() {
|
|
const socketName = `nitro-worker-${process.pid}-${threadId}-${NITRO_DEV_WORKER_ID}-${Math.round(Math.random() * 1e4)}.sock`;
|
|
if (process.platform === "win32") {
|
|
return join(String.raw`\\.\pipe`, socketName);
|
|
}
|
|
if (process.platform === "linux") {
|
|
const nodeMajor = Number.parseInt(process.versions.node.split(".")[0], 10);
|
|
if (nodeMajor >= 20) {
|
|
return `\0${socketName}`;
|
|
}
|
|
}
|
|
return join(tmpdir(), socketName);
|
|
}
|
|
async function shutdown() {
|
|
server.closeAllConnections?.();
|
|
await Promise.all([
|
|
new Promise((resolve) => listener?.close(resolve)),
|
|
nitroApp.hooks.callHook("close").catch(console.error)
|
|
]);
|
|
parentPort?.postMessage({ event: "exit" });
|
|
}
|