multiple
This commit is contained in:
parent
1216210150
commit
dda9dbe915
|
@ -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
|
||||
}
|
||||
|
|
111
daemon/daemon.go
111
daemon/daemon.go
|
@ -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 {
|
||||
|
|
BIN
mcp/cremote-mcp
BIN
mcp/cremote-mcp
Binary file not shown.
Loading…
Reference in New Issue