chore: auto-commit (97 archivos)

- .claude/CLAUDE.md
- .claude/agents/fn-recopilador/SKILL.md
- .claude/rules/INDEX.md
- .claude/rules/cpp_apps.md
- bash/functions/infra/build_cpp_windows.sh
- cpp/CMakeLists.txt
- cpp/PATTERNS.md
- cpp/framework/app_base.cpp
- cpp/framework/app_base.h
- dev/issues/README.md
- ...

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-09 18:11:24 +02:00
parent 852322a708
commit 750b7abcd5
99 changed files with 7879 additions and 73 deletions
+62 -12
View File
@@ -16,18 +16,25 @@ import (
"sync/atomic"
)
// EventHandler es invocado cuando llega un evento CDP del metodo subscrito.
// El handler corre en la goroutine del readLoop — debe ser rapido o despachar
// a un canal/goroutine propio. params puede ser nil si Chrome no envia.
type EventHandler func(method string, params map[string]any)
// CDPConn es una conexion activa al Chrome DevTools Protocol.
// Gestiona el WebSocket raw y el protocolo JSON-RPC de CDP.
type CDPConn struct {
conn net.Conn
reader *bufio.Reader
mu sync.Mutex
nextID atomic.Int64
port int
pid int
pending map[int64]chan cdpResponse
pendMu sync.Mutex
closed bool
conn net.Conn
reader *bufio.Reader
mu sync.Mutex
nextID atomic.Int64
port int
pid int
pending map[int64]chan cdpResponse
pendMu sync.Mutex
closed bool
handlers map[string][]EventHandler
hMu sync.Mutex
}
type cdpRequest struct {
@@ -245,7 +252,8 @@ func (c *CDPConn) sendCDP(method string, params map[string]any) (map[string]any,
return resp.Result, nil
}
// readLoop lee mensajes del WebSocket y los enruta a los canales pendientes.
// readLoop lee mensajes del WebSocket y los enruta a los canales pendientes
// (respuestas a comandos) o a los handlers registrados (eventos CDP).
// Debe ejecutarse en una goroutine.
func (c *CDPConn) readLoop() {
for {
@@ -277,9 +285,51 @@ func (c *CDPConn) readLoop() {
if ok {
ch <- resp
}
continue
}
// Sin ID = evento CDP. Llamar handlers registrados para ese metodo.
if resp.Method != "" {
c.hMu.Lock()
hs := append([]EventHandler(nil), c.handlers[resp.Method]...)
c.hMu.Unlock()
for _, h := range hs {
// Aislamos panics de handlers ajenos para que un handler
// roto no mate la conexion entera.
func(h EventHandler) {
defer func() { _ = recover() }()
h(resp.Method, resp.Params)
}(h)
}
}
}
}
// OnEvent registra un handler para un metodo CDP (ej "Network.requestWillBeSent").
// Devuelve una funcion `cancel` que des-registra el handler. Multiples handlers
// para el mismo metodo se invocan en orden de registro.
//
// El handler corre en la goroutine de lectura — mantenlo rapido. Para trabajo
// pesado, despacha a un canal/goroutine propios.
func (c *CDPConn) OnEvent(method string, h EventHandler) (cancel func()) {
if c == nil || h == nil || method == "" {
return func() {}
}
c.hMu.Lock()
if c.handlers == nil {
c.handlers = make(map[string][]EventHandler)
}
c.handlers[method] = append(c.handlers[method], h)
idx := len(c.handlers[method]) - 1
c.hMu.Unlock()
return func() {
c.hMu.Lock()
defer c.hMu.Unlock()
hs := c.handlers[method]
if idx < len(hs) {
c.handlers[method] = append(hs[:idx], hs[idx+1:]...)
}
// Si no tiene ID, es un evento CDP — por ahora los ignoramos
// Las funciones que necesiten eventos usan polling o envian el comando y esperan
}
}