@naria2/node
Version:
Cross-platform wrapper of aria2
126 lines (120 loc) • 4.19 kB
JavaScript
;
const path = require('node:path');
const node_url = require('node:url');
const node_fs = require('node:fs');
const getPort = require('get-port');
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
const path__default = /*#__PURE__*/_interopDefaultCompat(path);
const getPort__default = /*#__PURE__*/_interopDefaultCompat(getPort);
async function launchWebUI(options) {
const serveStatic = interopDefaultCompat(await import('serve-static'));
const finalhandler = interopDefaultCompat(await import('finalhandler'));
const http = await import('http');
const host = options.host;
const port = await getPort__default({ host: options.host, port: options.port });
const clientDir = node_url.fileURLToPath(new URL("../client", (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('ui.cjs', document.baseURI).href))));
const serve = serveStatic(clientDir, { index: ["index.html"] });
const handler = await createWebUIHandler(options);
const server = http.createServer(async (req, res) => {
if (await handler(req, res)) {
return;
}
if (req.url?.startsWith("/connect")) {
req.url = req.url.replace("/connect", "/");
}
serve(req, res, finalhandler(req, res));
});
server.listen(port, options.host);
return {
server,
host,
port,
url: `http://${host ?? "0.0.0.0"}:${port}?port=${options.rpc.port}${options.rpc.secret ? `&secret=${options.rpc.secret}` : ""}`
};
}
async function attachWebUI(_socket, options = {}) {
const socket = await _socket;
const { server, host, port, url } = await launchWebUI({
host: options.host,
port: options.port ?? socket.getOptions().listenPort + 1,
rpc: {
port: socket.getOptions().listenPort,
secret: socket.getOptions().secret
}
});
socket.onClose(() => {
server.close();
});
return {
socket,
server,
host,
port,
url
};
}
async function createWebUIHandler(options) {
const { createProxyMiddleware } = await import('http-proxy-middleware');
const proxyMiddleware = createProxyMiddleware({
target: `http://127.0.0.1:${options.rpc.port}`,
changeOrigin: false,
ws: true,
logger: void 0
});
return async (req, res) => {
if (!req.url)
return false;
try {
const url = new URL(req.url, `http://${req.headers.host}`);
if (url.pathname === "/jsonrpc") {
await proxyMiddleware(req, res, () => {
});
return true;
} else if (url.pathname === "/_/open") {
return await handleWebUIOpenRequest(url, req, res, options);
}
return false;
} catch (error) {
return false;
}
};
}
async function handleWebUIOpenRequest(url, req, res, options) {
try {
const auth = req.headers.authorization;
res.setHeader("Content-Type", "application/json");
if (options.rpc.secret && options.rpc.secret !== auth) {
res.statusCode = 400;
res.write(JSON.stringify({ status: "ERROR" }));
} else {
const dir = url.searchParams.get("dir");
if (dir) {
const open = interopDefaultCompat(await import('open'));
const p = decodeURIComponent(dir);
const stat = await node_fs.promises.stat(p);
if (stat.isDirectory()) {
await open(p).catch(() => {
});
res.write(JSON.stringify({ status: "OK", open: p }));
} else {
const d = path__default.dirname(p);
await open(d).catch(() => {
});
res.write(JSON.stringify({ status: "OK", open: d }));
}
}
}
res.end();
return true;
} catch (error) {
return false;
}
}
function interopDefaultCompat(mod) {
return mod.default ?? mod;
}
exports.attachWebUI = attachWebUI;
exports.createWebUIHandler = createWebUIHandler;
exports.handleWebUIOpenRequest = handleWebUIOpenRequest;
exports.launchWebUI = launchWebUI;