/** * Antigravity 자동 발견 모듈 * * localhost의 CDP 포트 범위를 스캔하여 실행 중인 Antigravity 인스턴스를 감지. * 발견된 인스턴스는 자동으로 세션 생성하여 웹 UI에 표시. */ const http = require('http'); // 스캔할 포트 범위 const SCAN_PORTS = [9000, 9222, 9229, 9333, 9001, 9002, 9003, 9004, 9005]; const SCAN_INTERVAL_MS = 15000; // 15초마다 스캔 /** * 특정 포트의 CDP 엔드포인트에 요청하여 Antigravity인지 확인 * @returns {Promise<{port, title, url}|null>} */ function probeCDPPort(host, port, timeoutMs = 2000) { return new Promise((resolve) => { const req = http.get(`http://${host}:${port}/json`, { timeout: timeoutMs }, (res) => { let data = ''; res.on('data', chunk => data += chunk); res.on('end', () => { try { const targets = JSON.parse(data); // Antigravity 워크벤치 타겟 찾기 const mainTarget = targets.find(t => t.type === 'page' && t.url.includes('workbench.html') && !t.url.includes('jetski') ); if (mainTarget) { resolve({ port, title: mainTarget.title || 'Antigravity', url: mainTarget.url, }); } else { resolve(null); } } catch { resolve(null); } }); }); req.on('error', () => resolve(null)); req.on('timeout', () => { req.destroy(); resolve(null); }); }); } /** * 모든 포트를 병렬 스캔하여 Antigravity 인스턴스 목록 반환 * @returns {Promise>} */ async function scanForAntigravity(host = 'localhost') { const probes = SCAN_PORTS.map(port => probeCDPPort(host, port)); const results = await Promise.all(probes); return results.filter(Boolean); } class AutoDiscovery { constructor(options = {}) { this.host = options.host || 'localhost'; this.intervalMs = options.intervalMs || SCAN_INTERVAL_MS; this.onDiscovered = options.onDiscovered || null; // callback({port, title, url}) this.onLost = options.onLost || null; // callback(port) this.knownPorts = new Set(); this.timer = null; } /** * 자동 발견 시작 */ async start() { console.log(`[AutoDiscovery] 시작 — ${this.host}에서 Antigravity 포트 스캔`); // 즉시 한 번 스캔 await this._scan(); // 주기적 스캔 this.timer = setInterval(() => this._scan(), this.intervalMs); } /** * 자동 발견 중지 */ stop() { if (this.timer) { clearInterval(this.timer); this.timer = null; } } /** * 내부 스캔 로직 */ async _scan() { try { const found = await scanForAntigravity(this.host); const foundPorts = new Set(found.map(f => f.port)); // 새로 발견된 인스턴스 for (const instance of found) { if (!this.knownPorts.has(instance.port)) { this.knownPorts.add(instance.port); console.log(`[AutoDiscovery] 발견: ${this.host}:${instance.port} — ${instance.title}`); if (this.onDiscovered) { this.onDiscovered(instance); } } } // 사라진 인스턴스 for (const port of this.knownPorts) { if (!foundPorts.has(port)) { this.knownPorts.delete(port); console.log(`[AutoDiscovery] 소실: ${this.host}:${port}`); if (this.onLost) { this.onLost(port); } } } } catch (err) { console.error('[AutoDiscovery] 스캔 오류:', err.message); } } } module.exports = { AutoDiscovery, scanForAntigravity, probeCDPPort };