Files
Andrei 58f8093689 Rebrand from 'Redirect Intelligence v2' to 'URL Tracker Tool V2' throughout UI
- Updated all component headers and documentation
- Changed navbar and footer branding
- Updated homepage hero badge
- Modified page title in index.html
- Simplified footer text to 'Built with ❤️'
- Consistent V2 capitalization across all references
2025-08-19 19:12:23 +00:00

216 lines
6.9 KiB
JavaScript

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Child = void 0;
const child_process_1 = require("child_process");
const worker_threads_1 = require("worker_threads");
const net_1 = require("net");
const enums_1 = require("../enums");
const events_1 = require("events");
/**
* @see https://nodejs.org/api/process.html#process_exit_codes
*/
const exitCodesErrors = {
1: 'Uncaught Fatal Exception',
2: 'Unused',
3: 'Internal JavaScript Parse Error',
4: 'Internal JavaScript Evaluation Failure',
5: 'Fatal Error',
6: 'Non-function Internal Exception Handler',
7: 'Internal Exception Handler Run-Time Failure',
8: 'Unused',
9: 'Invalid Argument',
10: 'Internal JavaScript Run-Time Failure',
12: 'Invalid Debug Argument',
13: 'Unfinished Top-Level Await',
};
/**
* Child class
*
* This class is used to create a child process or worker thread, and allows using
* isolated processes or threads for processing jobs.
*
*/
class Child extends events_1.EventEmitter {
constructor(mainFile, processFile, opts = {
useWorkerThreads: false,
}) {
super();
this.mainFile = mainFile;
this.processFile = processFile;
this.opts = opts;
this._exitCode = null;
this._signalCode = null;
this._killed = false;
}
get pid() {
if (this.childProcess) {
return this.childProcess.pid;
}
else if (this.worker) {
return this.worker.threadId;
}
else {
throw new Error('No child process or worker thread');
}
}
get exitCode() {
return this._exitCode;
}
get signalCode() {
return this._signalCode;
}
get killed() {
if (this.childProcess) {
return this.childProcess.killed;
}
return this._killed;
}
async init() {
const execArgv = await convertExecArgv(process.execArgv);
let parent;
if (this.opts.useWorkerThreads) {
this.worker = parent = new worker_threads_1.Worker(this.mainFile, {
execArgv,
stdin: true,
stdout: true,
stderr: true,
});
}
else {
this.childProcess = parent = (0, child_process_1.fork)(this.mainFile, [], {
execArgv,
stdio: 'pipe',
});
}
parent.on('exit', (exitCode, signalCode) => {
this._exitCode = exitCode;
// Coerce to null if undefined for backwards compatibility
signalCode = typeof signalCode === 'undefined' ? null : signalCode;
this._signalCode = signalCode;
this._killed = true;
this.emit('exit', exitCode, signalCode);
// Clean all listeners, we do not expect any more events after "exit"
parent.removeAllListeners();
this.removeAllListeners();
});
parent.on('error', (...args) => this.emit('error', ...args));
parent.on('message', (...args) => this.emit('message', ...args));
parent.on('close', (...args) => this.emit('close', ...args));
parent.stdout.pipe(process.stdout);
parent.stderr.pipe(process.stderr);
await this.initChild();
}
async send(msg) {
return new Promise((resolve, reject) => {
if (this.childProcess) {
this.childProcess.send(msg, (err) => {
if (err) {
reject(err);
}
else {
resolve();
}
});
}
else if (this.worker) {
resolve(this.worker.postMessage(msg));
}
else {
resolve();
}
});
}
killProcess(signal = 'SIGKILL') {
if (this.childProcess) {
this.childProcess.kill(signal);
}
else if (this.worker) {
this.worker.terminate();
}
}
async kill(signal = 'SIGKILL', timeoutMs) {
if (this.hasProcessExited()) {
return;
}
const onExit = onExitOnce(this.childProcess || this.worker);
this.killProcess(signal);
if (timeoutMs !== undefined && (timeoutMs === 0 || isFinite(timeoutMs))) {
const timeoutHandle = setTimeout(() => {
if (!this.hasProcessExited()) {
this.killProcess('SIGKILL');
}
}, timeoutMs);
await onExit;
clearTimeout(timeoutHandle);
}
await onExit;
}
async initChild() {
const onComplete = new Promise((resolve, reject) => {
const onMessageHandler = (msg) => {
if (msg.cmd === enums_1.ParentCommand.InitCompleted) {
resolve();
}
else if (msg.cmd === enums_1.ParentCommand.InitFailed) {
const err = new Error();
err.stack = msg.err.stack;
err.message = msg.err.message;
reject(err);
}
this.off('message', onMessageHandler);
this.off('close', onCloseHandler);
};
const onCloseHandler = (code, signal) => {
if (code > 128) {
code -= 128;
}
const msg = exitCodesErrors[code] || `Unknown exit code ${code}`;
reject(new Error(`Error initializing child: ${msg} and signal ${signal}`));
this.off('message', onMessageHandler);
this.off('close', onCloseHandler);
};
this.on('message', onMessageHandler);
this.on('close', onCloseHandler);
});
await this.send({
cmd: enums_1.ChildCommand.Init,
value: this.processFile,
});
await onComplete;
}
hasProcessExited() {
return !!(this.exitCode !== null || this.signalCode);
}
}
exports.Child = Child;
function onExitOnce(child) {
return new Promise(resolve => {
child.once('exit', () => resolve());
});
}
const getFreePort = async () => {
return new Promise(resolve => {
const server = (0, net_1.createServer)();
server.listen(0, () => {
const { port } = server.address();
server.close(() => resolve(port));
});
});
};
const convertExecArgv = async (execArgv) => {
const standard = [];
const convertedArgs = [];
for (let i = 0; i < execArgv.length; i++) {
const arg = execArgv[i];
if (arg.indexOf('--inspect') === -1) {
standard.push(arg);
}
else {
const argName = arg.split('=')[0];
const port = await getFreePort();
convertedArgs.push(`${argName}=${port}`);
}
}
return standard.concat(convertedArgs);
};
//# sourceMappingURL=child.js.map