Files
Ant-Browser/backend/browser_process_discovery.go

112 lines
2.9 KiB
Go

package backend
import (
"errors"
"fmt"
"os"
"regexp"
"strconv"
"strings"
"time"
)
type browserUserDataProcess struct {
PID int `json:"pid"`
DebugPort int `json:"debugPort"`
CommandLine string `json:"commandLine"`
}
type browserRuntimeDetection struct {
PID int
DebugPort int
DebugReady bool
}
var errBrowserStartHandledByRecoveredRuntime = errors.New("browser start handled by recovered runtime")
var findBrowserUserDataProcesses = findBrowserUserDataProcessesOS
var terminateBrowserUserDataProcess = terminateBrowserUserDataProcessOS
var remoteDebuggingPortPattern = regexp.MustCompile(`(?i)--remote-debugging-port=(\d+)`)
func parseRemoteDebuggingPort(commandLine string) int {
matches := remoteDebuggingPortPattern.FindStringSubmatch(commandLine)
if len(matches) < 2 {
return 0
}
port, err := strconv.Atoi(matches[1])
if err != nil || port <= 0 {
return 0
}
return port
}
func detectBrowserRuntimeByUserDataDir(userDataDir string) (browserRuntimeDetection, bool) {
userDataDir = strings.TrimSpace(userDataDir)
if userDataDir == "" {
return browserRuntimeDetection{}, false
}
if detection, ok := detectBrowserRuntimeByActivePort(userDataDir); ok {
return detection, true
}
processes, err := findBrowserUserDataProcesses(userDataDir)
if err != nil || len(processes) == 0 {
return browserRuntimeDetection{}, false
}
for _, process := range processes {
debugPort := process.DebugPort
if debugPort <= 0 {
debugPort = parseRemoteDebuggingPort(process.CommandLine)
}
if debugPort > 0 {
if err := probeBrowserDebugPort(debugPort, browserDebugProbeTimeout); err == nil {
return browserRuntimeDetection{PID: process.PID, DebugPort: debugPort, DebugReady: true}, true
}
}
}
first := processes[0]
return browserRuntimeDetection{PID: first.PID, DebugPort: first.DebugPort}, true
}
func detectBrowserRuntimeByActivePort(userDataDir string) (browserRuntimeDetection, bool) {
userDataDir = strings.TrimSpace(userDataDir)
if userDataDir == "" {
return browserRuntimeDetection{}, false
}
if debugPort, err := readBrowserDebugPortFile(userDataDir); err == nil && debugPort > 0 {
if err := probeBrowserDebugPort(debugPort, browserDebugProbeTimeout); err == nil {
return browserRuntimeDetection{DebugPort: debugPort, DebugReady: true}, true
}
}
return browserRuntimeDetection{}, false
}
func terminateBrowserProcessesByUserDataDir(userDataDir string, timeout time.Duration) (bool, error) {
processes, err := findBrowserUserDataProcesses(userDataDir)
if err != nil {
return false, err
}
if len(processes) == 0 {
return false, nil
}
var errs []error
terminated := false
for _, process := range processes {
if process.PID <= 0 || process.PID == os.Getpid() {
continue
}
terminated = true
if err := terminateBrowserUserDataProcess(process.PID, timeout); err != nil {
errs = append(errs, fmt.Errorf("pid %d: %w", process.PID, err))
}
}
return terminated, errors.Join(errs...)
}