1
0
mirror of https://github.com/MontFerret/ferret.git synced 2024-12-16 11:37:36 +02:00
ferret/pkg/drivers/cdp/driver.go

200 lines
3.7 KiB
Go
Raw Normal View History

package cdp
2018-09-18 22:42:38 +02:00
import (
"context"
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"
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"
"github.com/MontFerret/ferret/pkg/drivers"
"github.com/MontFerret/ferret/pkg/runtime/logging"
2018-09-18 22:42:38 +02:00
)
const DriverName = "cdp"
const BlankPageURL = "about:blank"
var defaultViewport = &drivers.Viewport{
Width: 1600,
Height: 900,
}
type Driver struct {
mu sync.Mutex
dev *devtool.DevTools
conn *rpcc.Conn
client *cdp.Client
session *session.Manager
contextID target.BrowserContextID
options *Options
}
func NewDriver(opts ...Option) *Driver {
drv := new(Driver)
drv.options = newOptions(opts)
drv.dev = devtool.New(drv.options.Address)
2018-09-24 03:11:13 +02:00
return drv
2018-09-18 22:42:38 +02:00
}
func (drv *Driver) Name() string {
return drv.options.Name
}
func (drv *Driver) Open(ctx context.Context, params drivers.Params) (drivers.HTMLPage, error) {
logger := logging.FromContext(ctx)
2018-09-24 03:11:13 +02:00
err := drv.init(ctx)
if err != nil {
logger.
Error().
Timestamp().
Err(err).
Str("driver", drv.options.Name).
Msg("failed to initialize the driver")
2018-09-24 03:11:13 +02:00
return nil, err
}
// Args for a new target belonging to the browser context
createTargetArgs := target.NewCreateTargetArgs(BlankPageURL)
if !drv.options.KeepCookies && !params.KeepCookies {
// Set it to an incognito mode
createTargetArgs.SetBrowserContextID(drv.contextID)
}
// New target
2018-09-24 03:11:13 +02:00
createTarget, err := drv.client.Target.CreateTarget(ctx, createTargetArgs)
2018-09-18 22:42:38 +02:00
if err != nil {
logger.
Error().
Timestamp().
Err(err).
Str("driver", drv.options.Name).
Msg("failed to create a browser target")
2018-09-18 22:42:38 +02:00
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 {
logger.
Error().
Timestamp().
Err(err).
Str("driver", drv.options.Name).
Msg("failed to establish a connection")
2018-09-18 22:42:38 +02:00
return nil, err
}
if params.UserAgent == "" {
params.UserAgent = drv.options.UserAgent
2018-11-22 18:44:05 +02:00
}
if params.Viewport == nil {
params.Viewport = defaultViewport
}
if drv.options.Headers != nil && params.Headers == nil {
params.Headers = make(drivers.HTTPHeaders)
}
// set default headers
for k, v := range drv.options.Headers {
_, exists := params.Headers[k]
// do not override user's set values
if !exists {
params.Headers[k] = v
}
}
if drv.options.Cookies != nil && params.Cookies == nil {
params.Cookies = make(drivers.HTTPCookies)
}
// set default cookies
for k, v := range drv.options.Cookies {
_, exists := params.Cookies[k]
// do not override user's set values
if !exists {
params.Cookies[k] = v
}
}
return LoadHTMLPage(ctx, conn, params)
2018-09-18 22:42:38 +02:00
}
2018-09-27 04:03:06 +02:00
func (drv *Driver) Close() error {
drv.mu.Lock()
defer drv.mu.Unlock()
2018-09-24 03:11:13 +02:00
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 {
drv.mu.Lock()
defer drv.mu.Unlock()
2018-09-24 03:11:13 +02:00
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")
}
drv.conn = bconn
drv.client = bc
drv.session = sess
if drv.options.KeepCookies {
return nil
}
2018-09-24 03:11:13 +02:00
createCtx, err := bc.Target.CreateBrowserContext(ctx)
if err != nil {
bconn.Close()
sess.Close()
return err
}
drv.contextID = createCtx.BrowserContextID
}
2018-09-18 22:42:38 +02:00
return nil
}