Files
smartproxy/ts/proxies/smart-proxy/rust-binary-locator.ts

113 lines
3.6 KiB
TypeScript

import * as plugins from '../../plugins.js';
import { logger } from '../../core/utils/logger.js';
/**
* Locates the RustProxy binary using a priority-ordered search strategy:
* 1. SMARTPROXY_RUST_BINARY environment variable
* 2. Platform-specific optional npm package
* 3. Local development build at ./rust/target/release/rustproxy
* 4. System PATH
*/
export class RustBinaryLocator {
private cachedPath: string | null = null;
/**
* Find the RustProxy binary path.
* Returns null if no binary is available.
*/
public async findBinary(): Promise<string | null> {
if (this.cachedPath !== null) {
return this.cachedPath;
}
const path = await this.searchBinary();
this.cachedPath = path;
return path;
}
/**
* Clear the cached binary path (e.g., after a failed launch).
*/
public clearCache(): void {
this.cachedPath = null;
}
private async searchBinary(): Promise<string | null> {
// 1. Environment variable override
const envPath = process.env.SMARTPROXY_RUST_BINARY;
if (envPath) {
if (await this.isExecutable(envPath)) {
logger.log('info', `RustProxy binary found via SMARTPROXY_RUST_BINARY: ${envPath}`, { component: 'rust-locator' });
return envPath;
}
logger.log('warn', `SMARTPROXY_RUST_BINARY set but not executable: ${envPath}`, { component: 'rust-locator' });
}
// 2. Platform-specific optional npm package
const platformBinary = await this.findPlatformPackageBinary();
if (platformBinary) {
logger.log('info', `RustProxy binary found in platform package: ${platformBinary}`, { component: 'rust-locator' });
return platformBinary;
}
// 3. Local development build
const localPaths = [
plugins.path.resolve(process.cwd(), 'rust/target/release/rustproxy'),
plugins.path.resolve(process.cwd(), 'rust/target/debug/rustproxy'),
];
for (const localPath of localPaths) {
if (await this.isExecutable(localPath)) {
logger.log('info', `RustProxy binary found at local path: ${localPath}`, { component: 'rust-locator' });
return localPath;
}
}
// 4. System PATH
const systemPath = await this.findInPath('rustproxy');
if (systemPath) {
logger.log('info', `RustProxy binary found in system PATH: ${systemPath}`, { component: 'rust-locator' });
return systemPath;
}
logger.log('error', 'No RustProxy binary found. Set SMARTPROXY_RUST_BINARY, install the platform package, or build with: cd rust && cargo build --release', { component: 'rust-locator' });
return null;
}
private async findPlatformPackageBinary(): Promise<string | null> {
const platform = process.platform;
const arch = process.arch;
const packageName = `@push.rocks/smartproxy-${platform}-${arch}`;
try {
// Try to resolve the platform-specific package
const packagePath = require.resolve(`${packageName}/rustproxy`);
if (await this.isExecutable(packagePath)) {
return packagePath;
}
} catch {
// Package not installed - expected for development
}
return null;
}
private async isExecutable(filePath: string): Promise<boolean> {
try {
await plugins.fs.promises.access(filePath, plugins.fs.constants.X_OK);
return true;
} catch {
return false;
}
}
private async findInPath(binaryName: string): Promise<string | null> {
const pathDirs = (process.env.PATH || '').split(plugins.path.delimiter);
for (const dir of pathDirs) {
const fullPath = plugins.path.join(dir, binaryName);
if (await this.isExecutable(fullPath)) {
return fullPath;
}
}
return null;
}
}