3253828fef
Add complete navegator system for stealthy browser automation: - CDP client with WebSocket communication - Browser API with navigation, storage, network, runtime - Stealth flags and anti-detection scripts - Persistent profile support - Examples and comprehensive documentation Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
118 lines
2.6 KiB
Go
118 lines
2.6 KiB
Go
package browser
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// Action representa una acción realizada en el navegador.
|
|
type Action struct {
|
|
Timestamp time.Time `json:"timestamp"`
|
|
Type string `json:"type"`
|
|
Params map[string]interface{} `json:"params"`
|
|
Result interface{} `json:"result,omitempty"`
|
|
Error string `json:"error,omitempty"`
|
|
}
|
|
|
|
// Recorder registra todas las acciones del navegador.
|
|
type Recorder struct {
|
|
file *os.File
|
|
encoder *json.Encoder
|
|
mu sync.Mutex
|
|
enabled bool
|
|
}
|
|
|
|
// NewRecorder crea un nuevo recorder que escribe en un archivo.
|
|
func NewRecorder(filepath string) (*Recorder, error) {
|
|
file, err := os.Create(filepath)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to create recorder file: %w", err)
|
|
}
|
|
|
|
r := &Recorder{
|
|
file: file,
|
|
encoder: json.NewEncoder(file),
|
|
enabled: true,
|
|
}
|
|
|
|
// Escribir header
|
|
fmt.Fprintf(file, "# Navegator Recording - %s\n", time.Now().Format(time.RFC3339))
|
|
fmt.Fprintf(file, "# Este archivo puede ser usado para reproducir las acciones\n\n")
|
|
|
|
return r, nil
|
|
}
|
|
|
|
// Record registra una acción.
|
|
func (r *Recorder) Record(actionType string, params map[string]interface{}, result interface{}, err error) {
|
|
if !r.enabled {
|
|
return
|
|
}
|
|
|
|
r.mu.Lock()
|
|
defer r.mu.Unlock()
|
|
|
|
action := Action{
|
|
Timestamp: time.Now(),
|
|
Type: actionType,
|
|
Params: params,
|
|
Result: result,
|
|
}
|
|
|
|
if err != nil {
|
|
action.Error = err.Error()
|
|
}
|
|
|
|
// Escribir JSON
|
|
r.encoder.Encode(action)
|
|
|
|
// También escribir comentario legible
|
|
if params["url"] != nil {
|
|
fmt.Fprintf(r.file, "# %s - %s: %v\n", action.Timestamp.Format("15:04:05"), actionType, params["url"])
|
|
} else if params["selector"] != nil {
|
|
fmt.Fprintf(r.file, "# %s - %s: %v\n", action.Timestamp.Format("15:04:05"), actionType, params["selector"])
|
|
} else {
|
|
fmt.Fprintf(r.file, "# %s - %s\n", action.Timestamp.Format("15:04:05"), actionType)
|
|
}
|
|
}
|
|
|
|
// Close cierra el recorder.
|
|
func (r *Recorder) Close() error {
|
|
r.mu.Lock()
|
|
defer r.mu.Unlock()
|
|
|
|
if r.file != nil {
|
|
fmt.Fprintf(r.file, "\n# Recording ended at %s\n", time.Now().Format(time.RFC3339))
|
|
return r.file.Close()
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Enable activa el recording.
|
|
func (r *Recorder) Enable() {
|
|
r.mu.Lock()
|
|
defer r.mu.Unlock()
|
|
r.enabled = true
|
|
}
|
|
|
|
// Disable desactiva el recording.
|
|
func (r *Recorder) Disable() {
|
|
r.mu.Lock()
|
|
defer r.mu.Unlock()
|
|
r.enabled = false
|
|
}
|
|
|
|
// AddComment agrega un comentario al log.
|
|
func (r *Recorder) AddComment(comment string) {
|
|
if !r.enabled {
|
|
return
|
|
}
|
|
|
|
r.mu.Lock()
|
|
defer r.mu.Unlock()
|
|
|
|
fmt.Fprintf(r.file, "\n# %s\n", comment)
|
|
}
|