1
0
mirror of https://github.com/MontFerret/ferret.git synced 2024-12-25 01:32:13 +02:00
ferret/pkg/drivers/cdp/input/manager.go

397 lines
8.6 KiB
Go
Raw Normal View History

package input
import (
"context"
"time"
"github.com/mafredri/cdp"
"github.com/mafredri/cdp/protocol/dom"
"github.com/mafredri/cdp/protocol/runtime"
"github.com/MontFerret/ferret/pkg/drivers/cdp/eval"
"github.com/MontFerret/ferret/pkg/drivers/cdp/templates"
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
)
type (
TypeParams struct {
Text core.Value
Clear values.Boolean
Delay values.Int
}
Manager struct {
client *cdp.Client
exec *eval.ExecutionContext
keyboard *Keyboard
mouse *Mouse
}
)
func NewManager(
client *cdp.Client,
exec *eval.ExecutionContext,
keyboard *Keyboard,
mouse *Mouse,
) *Manager {
return &Manager{
client,
exec,
keyboard,
mouse,
}
}
func (m *Manager) Keyboard() *Keyboard {
return m.keyboard
}
func (m *Manager) Mouse() *Mouse {
return m.mouse
}
func (m *Manager) ScrollTop(ctx context.Context) error {
return m.exec.Eval(ctx, templates.ScrollTop())
}
func (m *Manager) ScrollBottom(ctx context.Context) error {
return m.exec.Eval(ctx, templates.ScrollBottom())
}
func (m *Manager) ScrollIntoView(ctx context.Context, objectID runtime.RemoteObjectID) error {
return m.exec.EvalWithArguments(
ctx,
templates.ScrollIntoView(),
runtime.CallArgument{
ObjectID: &objectID,
},
)
}
func (m *Manager) ScrollIntoViewBySelector(ctx context.Context, selector values.String) error {
return m.exec.Eval(ctx, templates.ScrollIntoViewBySelector(selector.String()))
}
func (m *Manager) ScrollByXY(ctx context.Context, x, y values.Float) error {
return m.exec.Eval(
ctx,
templates.Scroll(eval.ParamFloat(float64(x)), eval.ParamFloat(float64(y))),
)
}
func (m *Manager) Focus(ctx context.Context, objectID runtime.RemoteObjectID) error {
err := m.ScrollIntoView(ctx, objectID)
if err != nil {
return err
}
return m.client.DOM.Focus(ctx, dom.NewFocusArgs().SetObjectID(objectID))
}
func (m *Manager) FocusBySelector(ctx context.Context, parentNodeID dom.NodeID, selector values.String) error {
err := m.ScrollIntoViewBySelector(ctx, selector)
if err != nil {
return err
}
found, err := m.client.DOM.QuerySelector(ctx, dom.NewQuerySelectorArgs(parentNodeID, selector.String()))
if err != nil {
return nil
}
return m.client.DOM.Focus(ctx, dom.NewFocusArgs().SetNodeID(found.NodeID))
}
func (m *Manager) MoveMouse(ctx context.Context, objectID runtime.RemoteObjectID) error {
if err := m.ScrollIntoView(ctx, objectID); err != nil {
return err
}
q, err := GetClickablePointByObjectID(ctx, m.client, objectID)
if err != nil {
return err
}
return m.mouse.Move(ctx, q.X, q.Y)
}
func (m *Manager) MoveMouseBySelector(ctx context.Context, parentNodeID dom.NodeID, selector values.String) error {
if err := m.ScrollIntoViewBySelector(ctx, selector); err != nil {
return err
}
found, err := m.client.DOM.QuerySelector(ctx, dom.NewQuerySelectorArgs(parentNodeID, selector.String()))
if err != nil {
return err
}
q, err := GetClickablePointByNodeID(ctx, m.client, found.NodeID)
if err != nil {
return err
}
return m.mouse.Move(ctx, q.X, q.Y)
}
func (m *Manager) MoveMouseByXY(ctx context.Context, x, y values.Float) error {
if err := m.ScrollByXY(ctx, x, y); err != nil {
return err
}
return m.mouse.Move(ctx, float64(x), float64(y))
}
func (m *Manager) Click(ctx context.Context, objectID runtime.RemoteObjectID) error {
if err := m.ScrollIntoView(ctx, objectID); err != nil {
return err
}
points, err := GetClickablePointByObjectID(ctx, m.client, objectID)
if err != nil {
return err
}
if err := m.mouse.Click(ctx, points.X, points.Y, 50); err != nil {
return nil
}
return nil
}
func (m *Manager) ClickBySelector(ctx context.Context, parentNodeID dom.NodeID, selector values.String) error {
if err := m.ScrollIntoViewBySelector(ctx, selector); err != nil {
return err
}
found, err := m.client.DOM.QuerySelector(ctx, dom.NewQuerySelectorArgs(parentNodeID, selector.String()))
if err != nil {
return err
}
points, err := GetClickablePointByNodeID(ctx, m.client, found.NodeID)
if err != nil {
return err
}
if err := m.mouse.Click(ctx, points.X, points.Y, 50); err != nil {
return nil
}
return nil
}
func (m *Manager) ClickBySelectorAll(ctx context.Context, parentNodeID dom.NodeID, selector values.String) error {
if err := m.ScrollIntoViewBySelector(ctx, selector); err != nil {
return err
}
found, err := m.client.DOM.QuerySelectorAll(ctx, dom.NewQuerySelectorAllArgs(parentNodeID, selector.String()))
if err != nil {
return err
}
for _, nodeID := range found.NodeIDs {
_, min := core.NumberBoundaries(100)
beforeTypeDelay := time.Duration(min)
time.Sleep(beforeTypeDelay * time.Millisecond)
points, err := GetClickablePointByNodeID(ctx, m.client, nodeID)
if err != nil {
return err
}
if err := m.mouse.Click(ctx, points.X, points.Y, 50); err != nil {
return nil
}
}
return nil
}
func (m *Manager) Type(ctx context.Context, objectID runtime.RemoteObjectID, params TypeParams) error {
err := m.ScrollIntoView(ctx, objectID)
if err != nil {
return err
}
err = m.client.DOM.Focus(ctx, dom.NewFocusArgs().SetObjectID(objectID))
if err != nil {
return err
}
if params.Clear {
points, err := GetClickablePointByObjectID(ctx, m.client, objectID)
if err != nil {
return err
}
if err := m.ClearByXY(ctx, points); err != nil {
return err
}
}
_, min := core.NumberBoundaries(float64(params.Delay))
beforeTypeDelay := time.Duration(min)
time.Sleep(beforeTypeDelay * time.Millisecond)
return m.keyboard.Type(ctx, params.Text.String(), int(params.Delay))
}
func (m *Manager) TypeBySelector(ctx context.Context, parentNodeID dom.NodeID, selector values.String, params TypeParams) error {
err := m.ScrollIntoViewBySelector(ctx, selector)
if err != nil {
return err
}
found, err := m.client.DOM.QuerySelector(ctx, dom.NewQuerySelectorArgs(parentNodeID, selector.String()))
if err != nil {
return err
}
err = m.client.DOM.Focus(ctx, dom.NewFocusArgs().SetNodeID(found.NodeID))
if err != nil {
return err
}
if params.Clear {
points, err := GetClickablePointByNodeID(ctx, m.client, found.NodeID)
if err != nil {
return err
}
if err := m.ClearByXY(ctx, points); err != nil {
return err
}
}
_, min := core.NumberBoundaries(float64(params.Delay))
beforeTypeDelay := time.Duration(min)
time.Sleep(beforeTypeDelay * time.Millisecond)
return m.keyboard.Type(ctx, params.Text.String(), int(params.Delay))
}
func (m *Manager) Clear(ctx context.Context, objectID runtime.RemoteObjectID) error {
err := m.ScrollIntoView(ctx, objectID)
if err != nil {
return err
}
points, err := GetClickablePointByObjectID(ctx, m.client, objectID)
if err != nil {
return err
}
err = m.client.DOM.Focus(ctx, dom.NewFocusArgs().SetObjectID(objectID))
if err != nil {
return err
}
return m.ClearByXY(ctx, points)
}
func (m *Manager) ClearBySelector(ctx context.Context, parentNodeID dom.NodeID, selector values.String) error {
err := m.ScrollIntoViewBySelector(ctx, selector)
if err != nil {
return err
}
found, err := m.client.DOM.QuerySelector(ctx, dom.NewQuerySelectorArgs(parentNodeID, selector.String()))
if err != nil {
return err
}
points, err := GetClickablePointByNodeID(ctx, m.client, found.NodeID)
if err != nil {
return err
}
err = m.client.DOM.Focus(ctx, dom.NewFocusArgs().SetNodeID(found.NodeID))
if err != nil {
return err
}
return m.ClearByXY(ctx, points)
}
func (m *Manager) ClearByXY(ctx context.Context, points Quad) error {
err := m.mouse.ClickWithCount(ctx, points.X, points.Y, 3, 5)
if err != nil {
return err
}
return m.keyboard.Press(ctx, "Backspace")
}
func (m *Manager) Select(ctx context.Context, objectID runtime.RemoteObjectID, value *values.Array) (*values.Array, error) {
if err := m.Focus(ctx, objectID); err != nil {
return values.NewArray(0), err
}
val, err := m.exec.EvalWithArgumentsAndReturnValue(ctx, templates.Select(value.String()), runtime.CallArgument{
ObjectID: &objectID,
})
if err != nil {
return nil, err
}
arr, ok := val.(*values.Array)
if !ok {
return values.NewArray(0), core.ErrUnexpected
}
return arr, nil
}
func (m *Manager) SelectBySelector(ctx context.Context, parentNodeID dom.NodeID, selector values.String, value *values.Array) (*values.Array, error) {
if err := m.FocusBySelector(ctx, parentNodeID, selector); err != nil {
return values.NewArray(0), err
}
res, err := m.exec.EvalWithReturnValue(ctx, templates.SelectBySelector(selector.String(), value.String()))
if err != nil {
return values.NewArray(0), err
}
arr, ok := res.(*values.Array)
if !ok {
return values.NewArray(0), core.ErrUnexpected
}
return arr, nil
}