Files
donutbrowser/nodecar/src/proxy-runner.ts
T
2025-05-29 11:20:13 +04:00

113 lines
2.7 KiB
TypeScript

import { spawn } from "child_process";
import path from "path";
import getPort from "get-port";
import {
type ProxyConfig,
saveProxyConfig,
getProxyConfig,
deleteProxyConfig,
isProcessRunning,
generateProxyId,
listProxyConfigs,
} from "./proxy-storage";
/**
* Start a proxy in a separate process
* @param upstreamUrl The upstream proxy URL
* @param options Optional configuration
* @returns Promise resolving to the proxy configuration
*/
export async function startProxyProcess(
upstreamUrl: string,
options: { port?: number; ignoreProxyCertificate?: boolean } = {}
): Promise<ProxyConfig> {
// Generate a unique ID for this proxy
const id = generateProxyId();
// Get a random available port if not specified
const port = options.port || (await getPort());
// Create the proxy configuration
const config: ProxyConfig = {
id,
upstreamUrl,
localPort: port,
ignoreProxyCertificate: options.ignoreProxyCertificate || false,
};
// Save the configuration before starting the process
saveProxyConfig(config);
// Build the command arguments
const args = ["proxy-worker", "start", "--id", id];
// Spawn the process
const child = spawn(
process.execPath,
[path.join(__dirname, "index.js"), ...args],
{
detached: true,
stdio: "ignore",
}
);
// Unref the child to allow the parent to exit independently
child.unref();
// Store the process ID
config.pid = child.pid;
config.localUrl = `http://localhost:${port}`;
// Update the configuration with the process ID
saveProxyConfig(config);
// Wait a bit to ensure the proxy has started
await new Promise((resolve) => setTimeout(resolve, 500));
return config;
}
/**
* Stop a proxy process
* @param id The proxy ID to stop
* @returns Promise resolving to true if stopped, false if not found
*/
export async function stopProxyProcess(id: string): Promise<boolean> {
const config = getProxyConfig(id);
if (!config || !config.pid) {
return false;
}
try {
// Check if the process is running
if (isProcessRunning(config.pid)) {
// Send SIGTERM to the process
process.kill(config.pid);
// Wait a bit to ensure the process has terminated
await new Promise((resolve) => setTimeout(resolve, 300));
}
// Delete the configuration
deleteProxyConfig(id);
return true;
} catch (error) {
console.error(`Error stopping proxy ${id}:`, error);
return false;
}
}
/**
* Stop all proxy processes
* @returns Promise resolving when all proxies are stopped
*/
export async function stopAllProxyProcesses(): Promise<void> {
const configs = listProxyConfigs();
for (const config of configs) {
await stopProxyProcess(config.id);
}
}