jobs-monorepo/internal/browser/launch-chrome.go
2026-01-26 17:33:48 +05:00

103 lines
2.4 KiB
Go

package browser
import (
"encoding/json"
"fmt"
"net/http"
"os/exec"
"runtime"
"time"
)
func launchChrome() (string, *exec.Cmd, error) {
var chromePath string
switch runtime.GOOS {
case "darwin":
chromePath = "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
case "linux":
chromePath = "google-chrome"
case "windows":
chromePath = "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe"
default:
return "", nil, fmt.Errorf("unsupported OS: %s", runtime.GOOS)
}
// Kill any existing Chrome debug instances first
exec.Command("pkill", "-f", "remote-debugging-port=9222").Run()
time.Sleep(500 * time.Millisecond)
cmd := exec.Command(chromePath,
"--remote-debugging-port=9222",
"--no-first-run",
"--no-default-browser-check",
"--user-data-dir=/tmp/chrome-debug-profile",
// Anti-detection flags
"--disable-blink-features=AutomationControlled",
"--disable-infobars",
"--disable-dev-shm-usage",
"--disable-browser-side-navigation",
"--disable-gpu",
"--no-sandbox",
"--disable-setuid-sandbox",
// Hide automation indicators
"--disable-extensions",
"--disable-plugins-discovery",
"--disable-bundled-ppapi-flash",
// Reduce fingerprinting
"--disable-background-networking",
"--disable-sync",
"--disable-translate",
"--metrics-recording-only",
"--safebrowsing-disable-auto-update",
"--disable-client-side-phishing-detection",
"--disable-default-apps",
"--disable-hang-monitor",
"--disable-popup-blocking",
"--disable-prompt-on-repost",
// Window size to look like a real browser
"--window-size=1920,1080",
"--start-maximized",
)
if err := cmd.Start(); err != nil {
return "", nil, fmt.Errorf("failed to start Chrome: %w", err)
}
// Poll the debug endpoint to get the WebSocket URL
var wsURL string
for range 50 {
time.Sleep(200 * time.Millisecond)
resp, err := http.Get("http://127.0.0.1:9222/json/version")
if err != nil {
continue
}
var result struct {
WebSocketDebuggerURL string `json:"webSocketDebuggerUrl"`
}
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
resp.Body.Close()
continue
}
resp.Body.Close()
if result.WebSocketDebuggerURL != "" {
wsURL = result.WebSocketDebuggerURL
break
}
}
if wsURL == "" {
cmd.Process.Kill()
return "", nil, fmt.Errorf("timeout waiting for Chrome WebSocket URL")
}
// Wait for Chrome to be fully ready to accept connections
time.Sleep(1 * time.Second)
return wsURL, cmd, nil
}