console
This commit is contained in:
155
daemon/daemon.go
155
daemon/daemon.go
@@ -22,13 +22,22 @@ import (
|
||||
type Daemon struct {
|
||||
browser *rod.Browser
|
||||
tabs map[string]*rod.Page
|
||||
iframePages map[string]*rod.Page // Maps tab ID to iframe page context
|
||||
currentTab string // ID of the current/last used tab
|
||||
tabHistory []string // Stack of tab IDs in order of activation (LIFO)
|
||||
iframePages map[string]*rod.Page // Maps tab ID to iframe page context
|
||||
currentTab string // ID of the current/last used tab
|
||||
tabHistory []string // Stack of tab IDs in order of activation (LIFO)
|
||||
consoleLogs map[string][]ConsoleLog // Maps tab ID to console logs
|
||||
mu sync.Mutex
|
||||
server *http.Server
|
||||
}
|
||||
|
||||
// ConsoleLog represents a console log entry
|
||||
type ConsoleLog struct {
|
||||
Level string `json:"level"` // log, warn, error, info, debug
|
||||
Message string `json:"message"` // The log message
|
||||
Timestamp time.Time `json:"timestamp"` // When the log occurred
|
||||
Source string `json:"source"` // Source location if available
|
||||
}
|
||||
|
||||
// Command represents a command sent from the client to the daemon
|
||||
type Command struct {
|
||||
Action string `json:"action"`
|
||||
@@ -90,6 +99,7 @@ func NewDaemon(host string, port int) (*Daemon, error) {
|
||||
tabs: make(map[string]*rod.Page),
|
||||
iframePages: make(map[string]*rod.Page),
|
||||
tabHistory: make([]string, 0),
|
||||
consoleLogs: make(map[string][]ConsoleLog),
|
||||
}
|
||||
|
||||
// Create HTTP server
|
||||
@@ -462,6 +472,43 @@ func (d *Daemon) handleCommand(w http.ResponseWriter, r *http.Request) {
|
||||
response = Response{Success: true}
|
||||
}
|
||||
|
||||
case "console-logs":
|
||||
tabID := cmd.Params["tab"]
|
||||
clearStr := cmd.Params["clear"]
|
||||
|
||||
// Parse clear flag
|
||||
clear := false
|
||||
if clearStr == "true" {
|
||||
clear = true
|
||||
}
|
||||
|
||||
logs, err := d.getConsoleLogs(tabID, clear)
|
||||
if err != nil {
|
||||
response = Response{Success: false, Error: err.Error()}
|
||||
} else {
|
||||
response = Response{Success: true, Data: logs}
|
||||
}
|
||||
|
||||
case "console-command":
|
||||
tabID := cmd.Params["tab"]
|
||||
command := cmd.Params["command"]
|
||||
timeoutStr := cmd.Params["timeout"]
|
||||
|
||||
// Parse timeout (default to 5 seconds if not specified)
|
||||
timeout := 5
|
||||
if timeoutStr != "" {
|
||||
if parsedTimeout, err := strconv.Atoi(timeoutStr); err == nil && parsedTimeout > 0 {
|
||||
timeout = parsedTimeout
|
||||
}
|
||||
}
|
||||
|
||||
result, err := d.executeConsoleCommand(tabID, command, timeout)
|
||||
if err != nil {
|
||||
response = Response{Success: false, Error: err.Error()}
|
||||
} else {
|
||||
response = Response{Success: true, Data: result}
|
||||
}
|
||||
|
||||
default:
|
||||
response = Response{Success: false, Error: "Unknown action"}
|
||||
}
|
||||
@@ -513,6 +560,9 @@ func (d *Daemon) openTab(timeout int) (string, error) {
|
||||
d.tabHistory = append(d.tabHistory, res.tabID)
|
||||
d.currentTab = res.tabID
|
||||
|
||||
// Set up console logging for this tab
|
||||
d.setupConsoleLogging(res.tabID, res.page)
|
||||
|
||||
return res.tabID, nil
|
||||
case <-ctx.Done():
|
||||
return "", fmt.Errorf("opening tab timed out after %d seconds", timeout)
|
||||
@@ -532,6 +582,9 @@ func (d *Daemon) openTab(timeout int) (string, error) {
|
||||
d.tabHistory = append(d.tabHistory, tabID)
|
||||
d.currentTab = tabID
|
||||
|
||||
// Set up console logging for this tab
|
||||
d.setupConsoleLogging(tabID, page)
|
||||
|
||||
return tabID, nil
|
||||
}
|
||||
}
|
||||
@@ -1742,3 +1795,99 @@ func (d *Daemon) handleFileDownload(w http.ResponseWriter, r *http.Request) {
|
||||
log.Printf("Error streaming file to client: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// setupConsoleLogging sets up console log capture for a tab
|
||||
func (d *Daemon) setupConsoleLogging(tabID string, page *rod.Page) {
|
||||
// Initialize console logs for this tab
|
||||
d.consoleLogs[tabID] = make([]ConsoleLog, 0)
|
||||
|
||||
// Listen for console events
|
||||
go page.EachEvent(func(e *proto.RuntimeConsoleAPICalled) {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
|
||||
// Convert console level
|
||||
level := string(e.Type)
|
||||
|
||||
// Build message from arguments
|
||||
var message string
|
||||
for i, arg := range e.Args {
|
||||
if i > 0 {
|
||||
message += " "
|
||||
}
|
||||
// Handle different argument types
|
||||
if !arg.Value.Nil() {
|
||||
message += arg.Value.String()
|
||||
} else if arg.Description != "" {
|
||||
message += arg.Description
|
||||
} else {
|
||||
message += "[object]"
|
||||
}
|
||||
}
|
||||
|
||||
// Create console log entry
|
||||
logEntry := ConsoleLog{
|
||||
Level: level,
|
||||
Message: message,
|
||||
Timestamp: time.Now(),
|
||||
Source: "", // Could be enhanced with stack trace info
|
||||
}
|
||||
|
||||
// Add to console logs (keep last 1000 entries per tab)
|
||||
logs := d.consoleLogs[tabID]
|
||||
logs = append(logs, logEntry)
|
||||
if len(logs) > 1000 {
|
||||
logs = logs[1:] // Remove oldest entry
|
||||
}
|
||||
d.consoleLogs[tabID] = logs
|
||||
})()
|
||||
}
|
||||
|
||||
// getConsoleLogs retrieves console logs for a tab
|
||||
func (d *Daemon) getConsoleLogs(tabID string, clear bool) ([]ConsoleLog, error) {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
|
||||
// Use current tab if not specified
|
||||
if tabID == "" {
|
||||
tabID = d.currentTab
|
||||
}
|
||||
|
||||
if tabID == "" {
|
||||
return nil, fmt.Errorf("no tab specified and no current tab available")
|
||||
}
|
||||
|
||||
// Check if tab exists
|
||||
if _, exists := d.tabs[tabID]; !exists {
|
||||
return nil, fmt.Errorf("tab not found: %s", tabID)
|
||||
}
|
||||
|
||||
// Get logs for this tab
|
||||
logs, exists := d.consoleLogs[tabID]
|
||||
if !exists {
|
||||
logs = make([]ConsoleLog, 0)
|
||||
}
|
||||
|
||||
// Clear logs if requested
|
||||
if clear {
|
||||
d.consoleLogs[tabID] = make([]ConsoleLog, 0)
|
||||
}
|
||||
|
||||
return logs, nil
|
||||
}
|
||||
|
||||
// executeConsoleCommand executes a command in the browser console
|
||||
func (d *Daemon) executeConsoleCommand(tabID, command string, timeout int) (string, error) {
|
||||
// Use current tab if not specified
|
||||
if tabID == "" {
|
||||
tabID = d.currentTab
|
||||
}
|
||||
|
||||
if tabID == "" {
|
||||
return "", fmt.Errorf("no tab specified and no current tab available")
|
||||
}
|
||||
|
||||
// Execute the command as JavaScript and return the result
|
||||
// This is similar to evalJS but specifically for console commands
|
||||
return d.evalJS(tabID, command, timeout)
|
||||
}
|
||||
|
Reference in New Issue
Block a user