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) }