3c250a9252
App Go para ejecutar scripts de navegación automatizada usando las funciones CDP del registry. Incluye script de creación de dashboard en Metabase para monitoreo. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
103 lines
2.8 KiB
Go
103 lines
2.8 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"net"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// getWindowsHostIP obtiene la IP del host Windows desde WSL2.
|
|
// Lee /etc/resolv.conf que WSL2 configura con la IP del host.
|
|
func getWindowsHostIP() string {
|
|
data, err := os.ReadFile("/etc/resolv.conf")
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
for _, line := range strings.Split(string(data), "\n") {
|
|
line = strings.TrimSpace(line)
|
|
if strings.HasPrefix(line, "nameserver ") {
|
|
ip := strings.TrimPrefix(line, "nameserver ")
|
|
ip = strings.TrimSpace(ip)
|
|
if ip != "" {
|
|
return ip
|
|
}
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// getWindowsGatewayIP obtiene la IP del gateway (host Windows) desde la tabla de rutas.
|
|
func getWindowsGatewayIP() string {
|
|
data, err := os.ReadFile("/proc/net/route")
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
for _, line := range strings.Split(string(data), "\n") {
|
|
fields := strings.Fields(line)
|
|
if len(fields) >= 3 && fields[1] == "00000000" { // default route
|
|
hexIP := fields[2]
|
|
if len(hexIP) == 8 {
|
|
// /proc/net/route stores IPs as little-endian 32-bit hex
|
|
// "011017AC" -> bytes [01,10,17,AC] -> IP 172.23.16.1 (reversed)
|
|
var a, b, c, d uint8
|
|
fmt.Sscanf(hexIP[0:2], "%02x", &a)
|
|
fmt.Sscanf(hexIP[2:4], "%02x", &b)
|
|
fmt.Sscanf(hexIP[4:6], "%02x", &c)
|
|
fmt.Sscanf(hexIP[6:8], "%02x", &d)
|
|
return fmt.Sprintf("%d.%d.%d.%d", d, c, b, a)
|
|
}
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// waitForCDP espera a que el puerto CDP esté accesible desde WSL.
|
|
func waitForCDP(host string, port int, timeout time.Duration) error {
|
|
deadline := time.Now().Add(timeout)
|
|
addr := fmt.Sprintf("%s:%d", host, port)
|
|
for time.Now().Before(deadline) {
|
|
conn, err := net.DialTimeout("tcp", addr, 300*time.Millisecond)
|
|
if err == nil {
|
|
conn.Close()
|
|
return nil
|
|
}
|
|
time.Sleep(300 * time.Millisecond)
|
|
}
|
|
return fmt.Errorf("CDP %s no disponible despues de %s", addr, timeout)
|
|
}
|
|
|
|
// startCDPProxy levanta un proxy TCP local que reenvía conexiones al host Windows.
|
|
// Chrome CDP solo acepta conexiones desde localhost, así que el proxy en WSL
|
|
// conecta al host Windows vía portproxy/netsh y expone el puerto localmente.
|
|
// Retorna el puerto local del proxy y una función para cerrarlo.
|
|
func startCDPProxy(windowsHost string, remotePort, localPort int) (net.Listener, error) {
|
|
ln, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", localPort))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("proxy listen: %w", err)
|
|
}
|
|
go func() {
|
|
for {
|
|
client, err := ln.Accept()
|
|
if err != nil {
|
|
return // listener cerrado
|
|
}
|
|
go proxyConn(client, windowsHost, remotePort)
|
|
}
|
|
}()
|
|
return ln, nil
|
|
}
|
|
|
|
func proxyConn(client net.Conn, host string, port int) {
|
|
defer client.Close()
|
|
remote, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", host, port), 5*time.Second)
|
|
if err != nil {
|
|
return
|
|
}
|
|
defer remote.Close()
|
|
go io.Copy(remote, client)
|
|
io.Copy(client, remote)
|
|
}
|