UNPKG

shell-mirror

Version:

Access your Mac shell from any device securely. Perfect for mobile coding with Claude Code CLI, Gemini CLI, and any shell tool.

145 lines (129 loc) 4.38 kB
const os = require('os'); /** * Network utilities for local WebSocket server setup */ class NetworkUtils { /** * Get the local IP address for WebSocket server binding * Prioritizes Wi-Fi and Ethernet interfaces over others */ static getLocalIP() { const interfaces = os.networkInterfaces(); // Priority order for interface selection const priorityOrder = [ 'Wi-Fi', // macOS Wi-Fi 'en0', // macOS primary interface 'en1', // macOS secondary interface 'eth0', // Linux Ethernet 'wlan0', // Linux Wi-Fi 'Ethernet', // Windows Ethernet 'Wi-Fi' // Windows Wi-Fi (might be different name) ]; // First, try priority interfaces for (const interfaceName of priorityOrder) { const addresses = interfaces[interfaceName]; if (addresses) { for (const addr of addresses) { if (addr.family === 'IPv4' && !addr.internal) { console.log(`🌐 Selected network interface: ${interfaceName} (${addr.address})`); return addr.address; } } } } // Fallback: find any non-internal IPv4 address for (const interfaceName in interfaces) { const addresses = interfaces[interfaceName]; for (const addr of addresses) { if (addr.family === 'IPv4' && !addr.internal) { console.log(`🌐 Fallback network interface: ${interfaceName} (${addr.address})`); return addr.address; } } } // Last resort: localhost (won't work for remote clients) console.warn('⚠️ No external network interface found, using localhost'); return '127.0.0.1'; } /** * Find an available port for the WebSocket server * @param {number} startPort - Starting port to check * @param {number} maxAttempts - Maximum number of ports to try */ static async findAvailablePort(startPort = 8080, maxAttempts = 10) { const net = require('net'); for (let i = 0; i < maxAttempts; i++) { const port = startPort + i; const isAvailable = await this.checkPortAvailable(port); if (isAvailable) { console.log(`🔌 Found available port: ${port}`); return port; } } throw new Error(`No available ports found in range ${startPort}-${startPort + maxAttempts - 1}`); } /** * Check if a specific port is available * @param {number} port - Port to check */ static checkPortAvailable(port) { return new Promise((resolve) => { const net = require('net'); const server = net.createServer(); server.listen(port, (err) => { if (err) { resolve(false); } else { server.once('close', () => resolve(true)); server.close(); } }); server.on('error', () => resolve(false)); }); } /** * Generate WebSocket server configuration * @param {number} port - Port for WebSocket server */ static generateWebSocketConfig(port) { const localIP = this.getLocalIP(); return { host: '0.0.0.0', // Bind to all interfaces port: port, localIP: localIP, wsUrl: `ws://${localIP}:${port}`, httpsWsUrl: `wss://${localIP}:${port}` // For future HTTPS support }; } /** * Display network connectivity information * @param {object} config - WebSocket configuration */ static displayNetworkInfo(config) { console.log(''); console.log('🌐 Network Configuration:'); console.log(` Local IP: ${config.localIP}`); console.log(` WebSocket URL: ${config.wsUrl}`); console.log(` Binding: ${config.host}:${config.port}`); console.log(''); console.log('📱 Access from other devices:'); console.log(` Use this URL in browser: https://shellmirror.app`); console.log(` Mac agent WebSocket: ${config.wsUrl}`); console.log(''); } /** * Validate WebSocket URL format * @param {string} wsUrl - WebSocket URL to validate */ static validateWebSocketURL(wsUrl) { try { const url = new URL(wsUrl); return (url.protocol === 'ws:' || url.protocol === 'wss:') && url.hostname && url.port; } catch (error) { return false; } } } module.exports = NetworkUtils;