browserhost

package
v2.22.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 25, 2026 License: GPL-3.0 Imports: 21 Imported by: 0

Documentation

Overview

Package browserhost manages Chrome processes that browser steps keep alive between step executions: their durable records, reachability probes, and cleanup.

Index

Constants

View Source
const (
	// AgentProvider identifies browser steps in agent sessions.
	AgentProvider = "browser"
	// DataDirName is the directory under the Dagu data directory that holds
	// browser state.
	DataDirName = "browser"
)
View Source
const BotCheckCloudflare = "cloudflare"

BotCheckCloudflare names Cloudflare's check of whether a browser is run by a person, which a site behind Cloudflare answers with in place of the page.

View Source
const (

	// ReapInterval is how often a long-lived process sweeps browser sessions.
	ReapInterval = time.Minute
)
View Source
const SessionRetention = 24 * time.Hour

SessionRetention is how long a browser session's history is kept after its browser closed on its own.

View Source
const StagehandExtensionName = "Stagehand Runtime"

StagehandExtensionName is the name the Stagehand runtime extension reports to Chrome.

Variables

View Source
var ErrExtensionNotFound = errors.New("stagehand runtime extension is not loaded")

ErrExtensionNotFound reports that the connected browser has no enabled Stagehand runtime extension.

View Source
var ErrNoFileChooser = errors.New("no file picker opened")

ErrNoFileChooser reports that no file picker opened.

View Source
var ErrSingleFileChooser = errors.New("the file picker takes one file")

ErrSingleFileChooser reports a file picker that takes one file when it was to be given several.

View Source
var ErrUnreachable = errors.New("browser is not running")

ErrUnreachable reports that nothing accepts connections at a browser's DevTools address, so the browser is no longer running.

Functions

func BrowserID

func BrowserID(ctx context.Context, cdpURL string) (string, error)

BrowserID identifies the browser answering at cdpURL. A browser started later on the same address has another identity. The error wraps ErrUnreachable when nothing accepts connections there.

func BrowserProcessID

func BrowserProcessID(ctx context.Context, cdpURL string) (int, error)

BrowserProcessID returns the process ID of the browser at cdpURL.

func ChooseFiles

func ChooseFiles(ctx context.Context, cdpURL string, paths []string, wait time.Duration, open func(context.Context) error) error

ChooseFiles gives the files at paths, which must be absolute, to the first file picker a page or frame of the browser at cdpURL opens while open runs or within wait after it returns. Pickers are intercepted, so none is shown. It returns ErrNoFileChooser when no picker opens, and ErrSingleFileChooser, giving nothing, when the picker takes one file and paths holds several.

func CloseBrowser

func CloseBrowser(ctx context.Context, cdpURL string) error

CloseBrowser asks the browser at cdpURL to exit. A browser that no longer answers is treated as already closed.

func DenyDownloads

func DenyDownloads(ctx context.Context, cdpURL string) error

DenyDownloads makes the browser at cdpURL refuse every download.

func Probe

func Probe(ctx context.Context, cdpURL string) error

Probe reports whether a browser answers on its DevTools endpoint.

func RecordID

func RecordID(dagRunID, stepName string) string

RecordID returns the record identifier for a step of a DAG run.

func Release

func Release(ctx context.Context, store *Store, record Record) error

Release closes the browser described by record, deletes the files it owns, and removes the record.

func RetireAbandoned

func RetireAbandoned(ctx context.Context, store *Store, id string, now time.Time) (bool, error)

RetireAbandoned retires the browser session id when nothing will use its browser again, unless one of its commands holds it. It reports whether the session was retired.

func RunReaper

func RunReaper(ctx context.Context, browserDataDir string, resumable ResumableFunc)

RunReaper sweeps the browsers steps keep and the browser sessions under the browser data directory until ctx is cancelled.

func Sweep

func Sweep(ctx context.Context, store *Store, now time.Time, resumable ResumableFunc) error

Sweep closes browsers that no step can resume and removes their records: running sessions whose owner process is gone, detached sessions past their deadline, and detached sessions whose step can no longer resume.

func SweepAll

func SweepAll(ctx context.Context, browserDataDir string, now time.Time, resumable ResumableFunc) error

SweepAll sweeps the browsers steps keep and the browser sessions under the browser data directory.

func UsesProfile added in v2.18.2

func UsesProfile(ctx context.Context, cdpURL, dir string) (bool, error)

UsesProfile reports whether the browser at cdpURL was started with dir as its user data directory. Each launch uses its own directory, so a match identifies the browser that launch started.

Types

type BlockedRequestWatcher added in v2.17.2

type BlockedRequestWatcher struct {
	// contains filtered or unexported fields
}

BlockedRequestWatcher counts the requests of a browser's pages and frames that a DevTools client blocked, by host.

func WatchBlockedRequests added in v2.17.2

func WatchBlockedRequests(ctx context.Context, cdpURL string) (*BlockedRequestWatcher, error)

WatchBlockedRequests counts blocked requests in the pages of the browser at cdpURL, including pages and frames opened later, until the watcher is closed.

func (*BlockedRequestWatcher) Close added in v2.17.2

func (w *BlockedRequestWatcher) Close() error

Close stops watching.

func (*BlockedRequestWatcher) Take added in v2.17.2

func (w *BlockedRequestWatcher) Take() (map[string]int, error)

Take returns the number of requests blocked per host since the previous call, or nil when none were. Its error reports that the watcher lost its connection and counts no further requests.

type Dialog

type Dialog struct {
	// Type is alert, confirm, prompt, or beforeunload.
	Type    string
	Message string
}

Dialog is a JavaScript dialog a page opened and the watcher accepted.

type DialogWatcher

type DialogWatcher struct {
	// contains filtered or unexported fields
}

DialogWatcher accepts the JavaScript dialogs a browser's pages open. An open dialog blocks its page until it is answered.

func WatchDialogs

func WatchDialogs(ctx context.Context, cdpURL string) (*DialogWatcher, error)

WatchDialogs accepts every dialog in the pages of the browser at cdpURL, including pages opened later, until the watcher is closed. A prompt is answered with its default text.

func (*DialogWatcher) Close

func (w *DialogWatcher) Close() error

Close stops watching. Dialogs opened afterwards stay open.

func (*DialogWatcher) Take

func (w *DialogWatcher) Take() []Dialog

Take returns the dialogs accepted since the previous call.

type Download

type Download struct {
	Name string
	Path string
}

Download is a file the browser finished saving.

type DownloadWatcher

type DownloadWatcher struct {
	// contains filtered or unexported fields
}

DownloadWatcher saves the browser's downloads into a directory and tracks which are still in progress.

func WatchDownloads

func WatchDownloads(ctx context.Context, cdpURL, dir string) (*DownloadWatcher, error)

WatchDownloads saves downloads from the browser at cdpURL into dir until the watcher is closed.

func (*DownloadWatcher) Close

func (w *DownloadWatcher) Close() error

Close stops watching. Downloads still in progress are left to the browser.

func (*DownloadWatcher) Wait

func (w *DownloadWatcher) Wait(ctx context.Context, grace, timeout time.Duration) ([]Download, error)

Wait returns the downloads completed since the previous call. It first allows grace for a download to begin, then waits until none is in progress. It fails when a download was canceled or is still running when timeout passes.

type Extension

type Extension struct {
	ID      string `json:"id"`
	Name    string `json:"name"`
	Path    string `json:"path"`
	Enabled bool   `json:"enabled"`
}

Extension describes an unpacked extension loaded into a browser.

func StagehandExtension

func StagehandExtension(ctx context.Context, cdpURL string) (Extension, error)

StagehandExtension returns the enabled Stagehand runtime extension loaded into the browser at cdpURL.

type PageResponse

type PageResponse struct {
	Status int
	// BotCheck names the check the site answered with in place of the page,
	// such as BotCheckCloudflare, or is empty.
	BotCheck string
}

PageResponse is how a site answered the document a page loaded.

type PageResponseWatcher

type PageResponseWatcher struct {
	// contains filtered or unexported fields
}

PageResponseWatcher keeps how sites answered the documents a browser's pages loaded, by host.

func WatchPageResponses

func WatchPageResponses(ctx context.Context, cdpURL string) (*PageResponseWatcher, error)

WatchPageResponses keeps how sites answer the documents the pages of the browser at cdpURL load, including pages opened later, until the watcher is closed. A document a frame loads is not a page's.

func (*PageResponseWatcher) Close

func (w *PageResponseWatcher) Close() error

Close stops watching.

func (*PageResponseWatcher) Response

func (w *PageResponseWatcher) Response(host string) (PageResponse, bool)

Response returns how host last answered a document a page loaded.

type Record

type Record struct {
	ID       string `json:"id"`
	DAGName  string `json:"dagName"`
	DAGRunID string `json:"dagRunId"`
	StepName string `json:"stepName"`
	// Generation is the agent-session generation that owns the browser.
	Generation int   `json:"generation"`
	State      State `json:"state"`
	// Deadline bounds how long a detached browser waits to be resumed.
	Deadline time.Time `json:"deadline,omitzero"`

	CDPURL          string `json:"cdpUrl"`
	ExtensionID     string `json:"extensionId,omitempty"`
	ExtensionDir    string `json:"extensionDir,omitempty"`
	UserDataDir     string `json:"userDataDir,omitempty"`
	OwnsUserDataDir bool   `json:"ownsUserDataDir,omitempty"`
	Profile         string `json:"profile,omitempty"`
	DownloadsDir    string `json:"downloadsDir,omitempty"`

	// BrowserPID and BrowserStartedAt identify the browser process, so it can
	// be ended when it no longer answers on its DevTools address.
	BrowserPID       int   `json:"browserPid,omitempty"`
	BrowserStartedAt int64 `json:"browserStartedAt,omitempty"`

	// CertProxyURL locates the proxy presenting the browser's client
	// certificates, which runs while the browser does; CertProxyPID and
	// CertProxyStartedAt identify its process, so it can be ended with the
	// browser.
	CertProxyURL       string `json:"certProxyUrl,omitempty"`
	CertProxyPID       int    `json:"certProxyPid,omitempty"`
	CertProxyStartedAt int64  `json:"certProxyStartedAt,omitempty"`

	// OwnerPID and OwnerStartedAt identify the process driving a running
	// browser, so a crashed owner can be detected even after PID reuse.
	OwnerPID       int   `json:"ownerPid,omitempty"`
	OwnerStartedAt int64 `json:"ownerStartedAt,omitempty"`

	// Cursor is the index of the next operation a resumed step runs.
	Cursor int `json:"cursor"`
	// Outputs holds values extracted before the step detached.
	Outputs map[string]any `json:"outputs,omitempty"`
	// ReplayPending and ReplayUsed carry the step's replay cache changes
	// across the wait: the act operations it recorded or dropped, applied
	// only if the step succeeds, and the recordings it replayed, as they
	// were read.
	ReplayPending map[string]json.RawMessage `json:"replayPending,omitempty"`
	ReplayUsed    map[string]json.RawMessage `json:"replayUsed,omitempty"`

	// WorkDir holds the files a browser session owns, such as its
	// screenshots and downloads. It is removed with the browser.
	WorkDir string `json:"workDir,omitempty"`
	// Interactive is a browser session's own state, which the browser
	// runtime defines.
	Interactive json.RawMessage `json:"interactive,omitempty"`
}

Record is the durable description of one browser session kept by a step.

func Retire

func Retire(ctx context.Context, store *Store, record Record, keepUntil time.Time) (Record, error)

Retire closes the browser of a browser session and deletes the files it owns, but keeps the record, as ended, until keepUntil, so the session's history can still be read. It returns the ended record.

type ResumableFunc

type ResumableFunc func(context.Context, Record) bool

ResumableFunc reports whether a detached session still belongs to a step that can resume it. A nil ResumableFunc treats every unexpired session as resumable.

type State

type State string

State describes who currently holds a browser session.

const (
	// StateRunning means a step execution, or a browser session command, is
	// driving the browser.
	StateRunning State = "running"
	// StateDetached means the browser waits for a step to resume it.
	StateDetached State = "detached"
	// StateInteractive means a browser session's browser waits for the
	// session's next command.
	StateInteractive State = "interactive"
	// StateEnded means a browser session's browser is closed. Its record
	// keeps the session's history until its deadline.
	StateEnded State = "ended"
)

type Store

type Store struct {
	// contains filtered or unexported fields
}

Store persists browser session records as private files.

func NewInteractiveStore

func NewInteractiveStore(browserDataDir string) *Store

NewInteractiveStore returns the store of browser sessions, rooted under the browser data directory. It is kept apart from the steps' store, whose sweeps release records in states they do not know.

func NewStore

func NewStore(browserDataDir string) *Store

NewStore returns the store of the browsers steps keep, rooted under the browser data directory.

func (*Store) Delete

func (s *Store) Delete(id string) error

Delete removes the record with id. A missing record is not an error.

func (*Store) List

func (s *Store) List() ([]Record, error)

List returns every readable record.

func (*Store) Load

func (s *Store) Load(id string) (Record, error)

Load returns the record with id. A missing record reports os.ErrNotExist.

func (*Store) Purge

func (s *Store) Purge(id string) error

Purge removes the record of id with its work and lock directories.

func (*Store) Save

func (s *Store) Save(record Record) error

Save writes the record, replacing any previous version.

func (*Store) SessionLock

func (s *Store) SessionLock(id string) dirlock.DirLock

SessionLock returns the lock held by whatever uses the browser of the session id: one of its commands, or a sweep closing it.

func (*Store) WorkDir

func (s *Store) WorkDir(id string) string

WorkDir returns the directory for the files the session id owns.

type Version

type Version struct {
	// Product names the browser and its version, such as
	// Chrome/155.0.8059.80, whatever user agent the browser was given.
	Product string
	// UserAgent is the user agent the browser's pages send.
	UserAgent string
}

Version is what a browser reports about itself.

func BrowserVersion

func BrowserVersion(ctx context.Context, cdpURL string) (Version, error)

BrowserVersion reports what the browser at cdpURL says about itself. The error wraps ErrUnreachable when nothing accepts connections there.

Directories

Path Synopsis
Package certproxy presents TLS client certificates on behalf of a browser.
Package certproxy presents TLS client certificates on behalf of a browser.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL