This commit is contained in:
Josh at WLTechBlog 2025-08-18 13:30:18 -05:00
parent 1216210150
commit dda9dbe915
3 changed files with 94 additions and 27 deletions

View File

@ -14,7 +14,8 @@ import (
// Client is the client for communicating with the daemon
type Client struct {
serverURL string
serverURL string
httpClient *http.Client
}
// Command represents a command sent from the client to the daemon
@ -34,12 +35,15 @@ type Response struct {
func NewClient(host string, port int) *Client {
return &Client{
serverURL: fmt.Sprintf("http://%s:%d", host, port),
httpClient: &http.Client{
Timeout: 60 * time.Second, // 60 second timeout for long operations
},
}
}
// CheckStatus checks if the daemon is running
func (c *Client) CheckStatus() (bool, error) {
resp, err := http.Get(c.serverURL + "/status")
resp, err := c.httpClient.Get(c.serverURL + "/status")
if err != nil {
return false, err
}
@ -174,7 +178,7 @@ func (c *Client) SendCommand(action string, params map[string]string) (*Response
return nil, err
}
resp, err := http.Post(c.serverURL+"/command", "application/json", bytes.NewBuffer(jsonData))
resp, err := c.httpClient.Post(c.serverURL+"/command", "application/json", bytes.NewBuffer(jsonData))
if err != nil {
return nil, err
}

View File

@ -2822,21 +2822,40 @@ func (d *Daemon) extractMultiple(tabID, selectorsJSON string, timeout int) (*Mul
continue
}
// Extract text content from all matching elements
var texts []string
// Extract content from all matching elements
var values []string
for _, element := range elements {
text, err := element.Text()
var value string
var err error
// Check if it's a form input element and get its value
tagName, _ := element.Eval("() => this.tagName.toLowerCase()")
if tagName.Value.Str() == "input" || tagName.Value.Str() == "textarea" || tagName.Value.Str() == "select" {
// For form elements, get the value property
valueProp, err := element.Property("value")
if err == nil && valueProp.Str() != "" {
value = valueProp.Str()
} else {
// Fallback to text content
value, err = element.Text()
}
} else {
// For non-form elements, get text content
value, err = element.Text()
}
if err != nil {
result.Errors[key] = fmt.Sprintf("failed to get text: %v", err)
result.Errors[key] = fmt.Sprintf("failed to get content: %v", err)
break
}
texts = append(texts, text)
values = append(values, value)
}
if len(texts) == 1 {
result.Results[key] = texts[0]
if len(values) == 1 {
result.Results[key] = values[0]
} else {
result.Results[key] = texts
result.Results[key] = values
}
}
@ -3414,15 +3433,9 @@ func (d *Daemon) interactMultiple(tabID, interactionsJSON string, timeout int) (
Success: false,
}
// Find the element
// Find the element without timeout to avoid context cancellation issues
var element *rod.Element
if timeout > 0 {
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second)
element, err = page.Context(ctx).Element(interaction.Selector)
cancel()
} else {
element, err = page.Element(interaction.Selector)
}
element, err = page.Element(interaction.Selector)
if err != nil {
interactionResult.Error = fmt.Sprintf("failed to find element: %v", err)
@ -3435,6 +3448,14 @@ func (d *Daemon) interactMultiple(tabID, interactionsJSON string, timeout int) (
switch interaction.Action {
case "click":
err = element.Click(proto.InputMouseButtonLeft, 1)
// Retry once if context was canceled
if err != nil && strings.Contains(err.Error(), "context canceled") {
// Try to find element again and click
element, err = page.Element(interaction.Selector)
if err == nil {
err = element.Click(proto.InputMouseButtonLeft, 1)
}
}
if err != nil {
interactionResult.Error = fmt.Sprintf("failed to click: %v", err)
} else {
@ -3450,6 +3471,20 @@ func (d *Daemon) interactMultiple(tabID, interactionsJSON string, timeout int) (
if err == nil {
err = element.Input(interaction.Value)
}
// Retry once if context was canceled
if err != nil && strings.Contains(err.Error(), "context canceled") {
// Try to find element again and fill
element, err = page.Element(interaction.Selector)
if err == nil {
err = element.SelectAllText()
if err == nil {
err = element.Input("")
}
if err == nil {
err = element.Input(interaction.Value)
}
}
}
if err != nil {
interactionResult.Error = fmt.Sprintf("failed to fill: %v", err)
} else {
@ -3457,14 +3492,34 @@ func (d *Daemon) interactMultiple(tabID, interactionsJSON string, timeout int) (
}
case "select":
// For select elements, try to select by text first, then by value
err = element.Select([]string{interaction.Value}, true, rod.SelectorTypeText)
if err != nil {
// Try by value if text selection failed
err = element.Select([]string{interaction.Value}, false, rod.SelectorTypeText)
}
if err != nil {
interactionResult.Error = fmt.Sprintf("failed to select: %v", err)
// For select elements, use JavaScript to set the value
script := fmt.Sprintf(`
const element = arguments[0];
if (element.tagName.toLowerCase() === 'select') {
// Try to select by value first
for (let option of element.options) {
if (option.value === '%s') {
element.value = '%s';
element.dispatchEvent(new Event('change', { bubbles: true }));
return true;
}
}
// Try to select by text if value didn't work
for (let option of element.options) {
if (option.text === '%s') {
element.value = option.value;
element.dispatchEvent(new Event('change', { bubbles: true }));
return true;
}
}
return false;
}
return false;
`, interaction.Value, interaction.Value, interaction.Value)
result, err := element.Eval(script)
if err != nil || !result.Value.Bool() {
interactionResult.Error = fmt.Sprintf("failed to select option: %s", interaction.Value)
} else {
interactionResult.Success = true
}
@ -3476,6 +3531,14 @@ func (d *Daemon) interactMultiple(tabID, interactionsJSON string, timeout int) (
interactionResult.Success = true // Already checked
} else {
err = element.Click(proto.InputMouseButtonLeft, 1)
// Retry once if context was canceled
if err != nil && strings.Contains(err.Error(), "context canceled") {
// Try to find element again and click
element, err = page.Element(interaction.Selector)
if err == nil {
err = element.Click(proto.InputMouseButtonLeft, 1)
}
}
if err != nil {
interactionResult.Error = fmt.Sprintf("failed to check: %v", err)
} else {

Binary file not shown.