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 { 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 { // 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 { 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 { try { await plugins.fs.promises.access(filePath, plugins.fs.constants.X_OK); return true; } catch { return false; } } private async findInPath(binaryName: string): Promise { 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; } }