chromedp/context.go
Daniel Martí 32d4bae280 clean up various pieces of the API
First, collapse Browser.Start with NewBrowser. There's no reason to
split them up.

Second, unexport Browser.userDataDir, since it's only needed for a test.
It's also a bad precedent, as only the ExecAllocator will control the
user data directory.

Third, export Context.Browser, since we were already exporting
Context.Allocator.

Finally, remove the Executor interface, a duplicate of cdp.Executor.
2019-04-01 12:18:16 +01:00

115 lines
2.5 KiB
Go

package chromedp
import (
"context"
"fmt"
"github.com/chromedp/cdproto/css"
"github.com/chromedp/cdproto/dom"
"github.com/chromedp/cdproto/inspector"
"github.com/chromedp/cdproto/log"
"github.com/chromedp/cdproto/page"
"github.com/chromedp/cdproto/runtime"
"github.com/chromedp/cdproto/target"
)
// Context is attached to any context.Context which is valid for use with Run.
type Context struct {
Allocator Allocator
Browser *Browser
sessionID target.SessionID
}
// NewContext creates a browser context using the parent context.
func NewContext(parent context.Context, opts ...ContextOption) (context.Context, context.CancelFunc) {
ctx, cancel := context.WithCancel(parent)
c := &Context{}
if pc := FromContext(parent); pc != nil {
c.Allocator = pc.Allocator
}
for _, o := range opts {
o(c)
}
if c.Allocator == nil {
WithExecAllocator(
NoFirstRun,
NoDefaultBrowserCheck,
Headless,
)(&c.Allocator)
}
ctx = context.WithValue(ctx, contextKey{}, c)
return ctx, cancel
}
type contextKey struct{}
// FromContext extracts the Context data stored inside a context.Context.
func FromContext(ctx context.Context) *Context {
c, _ := ctx.Value(contextKey{}).(*Context)
return c
}
// Run runs an action against the provided context. The provided context must
// contain a valid Allocator; typically, that will be created via NewContext or
// NewAllocator.
func Run(ctx context.Context, action Action) error {
c := FromContext(ctx)
if c == nil || c.Allocator == nil {
return ErrInvalidContext
}
if c.Browser == nil {
browser, err := c.Allocator.Allocate(ctx)
if err != nil {
return err
}
c.Browser = browser
}
if c.sessionID == "" {
if err := c.newSession(ctx); err != nil {
return err
}
}
return action.Do(ctx, c.Browser.executorForTarget(ctx, c.sessionID))
}
func (c *Context) newSession(ctx context.Context) error {
create := target.CreateTarget("about:blank")
targetID, err := create.Do(ctx, c.Browser)
if err != nil {
return err
}
attach := target.AttachToTarget(targetID)
sessionID, err := attach.Do(ctx, c.Browser)
if err != nil {
return err
}
target := c.Browser.executorForTarget(ctx, sessionID)
// enable domains
for _, enable := range []Action{
log.Enable(),
runtime.Enable(),
//network.Enable(),
inspector.Enable(),
page.Enable(),
dom.Enable(),
css.Enable(),
} {
if err := enable.Do(ctx, target); err != nil {
return fmt.Errorf("unable to execute %T: %v", enable, err)
}
}
c.sessionID = sessionID
return nil
}
type ContextOption func(*Context)