1
0
mirror of https://github.com/MontFerret/ferret.git synced 2024-12-14 11:23:02 +02:00
ferret/pkg/html/dynamic/driver.go

162 lines
3.0 KiB
Go
Raw Normal View History

2018-09-27 04:03:06 +02:00
package dynamic
2018-09-18 22:42:38 +02:00
import (
"context"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/corpix/uarand"
2018-09-24 03:11:13 +02:00
"github.com/mafredri/cdp"
2018-09-18 22:42:38 +02:00
"github.com/mafredri/cdp/devtool"
"github.com/mafredri/cdp/protocol/emulation"
"github.com/mafredri/cdp/protocol/page"
2018-09-24 03:11:13 +02:00
"github.com/mafredri/cdp/protocol/target"
2018-09-18 22:42:38 +02:00
"github.com/mafredri/cdp/rpcc"
2018-09-24 03:11:13 +02:00
"github.com/mafredri/cdp/session"
"github.com/pkg/errors"
"sync"
2018-09-18 22:42:38 +02:00
)
2018-09-27 04:03:06 +02:00
type Driver struct {
2018-09-24 03:11:13 +02:00
sync.Mutex
dev *devtool.DevTools
conn *rpcc.Conn
client *cdp.Client
session *session.Manager
contextID target.BrowserContextID
opts *Options
2018-09-24 03:11:13 +02:00
}
2018-09-18 22:42:38 +02:00
func NewDriver(address string, opts ...Option) *Driver {
2018-09-27 04:03:06 +02:00
drv := new(Driver)
2018-09-24 03:11:13 +02:00
drv.dev = devtool.New(address)
drv.opts = new(Options)
for _, opt := range opts {
opt(drv.opts)
}
2018-09-18 22:42:38 +02:00
2018-09-24 03:11:13 +02:00
return drv
2018-09-18 22:42:38 +02:00
}
func (drv *Driver) GetDocument(ctx context.Context, targetURL values.String) (values.HTMLNode, error) {
2018-09-24 03:11:13 +02:00
err := drv.init(ctx)
if err != nil {
return nil, err
}
2018-09-18 22:42:38 +02:00
ctx, cancel := context.WithTimeout(ctx, DefaultTimeout)
defer cancel()
url := targetURL.String()
2018-10-05 03:37:28 +02:00
if url == "" {
2018-10-06 02:42:23 +02:00
url = BlankPageURL
2018-10-05 03:37:28 +02:00
}
2018-09-24 03:11:13 +02:00
// Create a new target belonging to the browser context, similar
// to opening a new tab in an incognito window.
createTargetArgs := target.NewCreateTargetArgs(url).SetBrowserContextID(drv.contextID)
createTarget, err := drv.client.Target.CreateTarget(ctx, createTargetArgs)
2018-09-18 22:42:38 +02:00
if err != nil {
return nil, err
}
2018-09-24 03:11:13 +02:00
// Connect to target using the existing websocket connection.
conn, err := drv.session.Dial(ctx, createTarget.TargetID)
2018-09-18 22:42:38 +02:00
if err != nil {
return nil, err
}
client := cdp.NewClient(conn)
err = runBatch(
func() error {
return client.Page.Enable(ctx)
},
func() error {
return client.Page.SetLifecycleEventsEnabled(
ctx,
page.NewSetLifecycleEventsEnabledArgs(true),
)
},
func() error {
return client.DOM.Enable(ctx)
},
func() error {
return client.Runtime.Enable(ctx)
},
func() error {
return client.Emulation.SetUserAgentOverride(
ctx,
emulation.NewSetUserAgentOverrideArgs(uarand.GetRandom()),
)
},
)
return LoadHTMLDocument(ctx, conn, client, url)
2018-09-18 22:42:38 +02:00
}
2018-09-27 04:03:06 +02:00
func (drv *Driver) Close() error {
2018-09-24 03:11:13 +02:00
drv.Lock()
defer drv.Unlock()
if drv.session != nil {
drv.session.Close()
return drv.conn.Close()
}
return nil
}
2018-09-27 04:03:06 +02:00
func (drv *Driver) init(ctx context.Context) error {
2018-09-24 03:11:13 +02:00
drv.Lock()
defer drv.Unlock()
if drv.session == nil {
ver, err := drv.dev.Version(ctx)
if err != nil {
return errors.Wrap(err, "failed to initialize driver")
}
bconn, err := rpcc.DialContext(ctx, ver.WebSocketDebuggerURL)
if err != nil {
return errors.Wrap(err, "failed to initialize driver")
}
bc := cdp.NewClient(bconn)
sess, err := session.NewManager(bc)
if err != nil {
bconn.Close()
return errors.Wrap(err, "failed to initialize driver")
}
createCtx, err := bc.Target.CreateBrowserContext(ctx)
if err != nil {
bconn.Close()
sess.Close()
return err
}
drv.conn = bconn
drv.client = bc
drv.session = sess
drv.contextID = createCtx.BrowserContextID
}
2018-09-18 22:42:38 +02:00
return nil
}