1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
//! `BrowserType` — a browser engine entry point (Playwright-shaped).
//!
//! Unlike upstream Playwright, this crate drives Chromium directly over CDP
//! and does **not** spawn a Node.js driver. `BrowserType` is therefore a thin
//! handle whose only real engine is Chromium; `firefox()`/`webkit()` exist for
//! API shape parity and resolve to Chromium (with a warning).
use crate::browser::Browser;
use crate::browser_context::BrowserContext;
use crate::browser_process;
use crate::error::Result;
use crate::options::{ConnectOverCdpOptions, LaunchOptions};
use std::path::PathBuf;
/// Which browser engine a [`BrowserType`] represents.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Engine {
Chromium,
Firefox,
Webkit,
}
/// A browser engine. Created from a [`Playwright`](crate::Playwright) handle.
#[derive(Debug, Clone, Copy)]
pub struct BrowserType {
engine: Engine,
}
impl BrowserType {
pub(crate) fn new(engine: Engine) -> Self {
Self { engine }
}
/// Chromium engine (the only fully-supported engine here).
pub fn chromium() -> Self {
Self::new(Engine::Chromium)
}
/// Engine name: `"chromium"`, `"firefox"`, or `"webkit"`.
pub fn name(&self) -> &'static str {
match self.engine {
Engine::Chromium => "chromium",
Engine::Firefox => "firefox",
Engine::Webkit => "webkit",
}
}
/// Best-effort discovery of the executable path for this engine.
pub fn executable_path(&self) -> Option<PathBuf> {
browser_process::discover_executable(&LaunchOptions::default()).ok()
}
/// Launch a browser with default options.
pub async fn launch(&self) -> Result<Browser> {
self.launch_with_options(LaunchOptions::default()).await
}
/// Launch a browser with the given options.
///
/// Only Chromium is driven here; `firefox`/`webkit` log a warning and fall
/// back to launching Chromium (kept for porting compatibility).
pub async fn launch_with_options(&self, opts: LaunchOptions) -> Result<Browser> {
if !matches!(self.engine, Engine::Chromium) {
tracing::warn!(
engine = self.name(),
"playwright-cdp only drives Chromium via CDP; launching Chromium instead"
);
}
Browser::launch(opts).await
}
/// Launch a browser with a persistent user-data-dir and return its default
/// [`BrowserContext`]. Cookies / localStorage persist to `user_data_dir`
/// across runs. Mirrors Playwright's `browserType.launchPersistentContext`.
///
/// `user_data_dir` accepts any path-like value (`impl AsRef<Path>`), so you
/// can pass a `&str`, `&Path`, `&PathBuf`, or an owned `PathBuf` directly.
pub async fn launch_persistent_context(
&self,
user_data_dir: impl AsRef<std::path::Path>,
) -> Result<BrowserContext> {
self.launch_persistent_context_with_options(user_data_dir, LaunchOptions::default())
.await
}
/// Like [`launch_persistent_context`](Self::launch_persistent_context) but with
/// custom launch options. The `user_data_dir` passed here overrides any
/// `user_data_dir` set on `opts`.
///
/// `user_data_dir` accepts any path-like value (`impl AsRef<Path>`), so you
/// can pass a `&str`, `&Path`, `&PathBuf`, or an owned `PathBuf` directly.
pub async fn launch_persistent_context_with_options(
&self,
user_data_dir: impl AsRef<std::path::Path>,
mut opts: LaunchOptions,
) -> Result<BrowserContext> {
if !matches!(self.engine, Engine::Chromium) {
tracing::warn!(
engine = self.name(),
"playwright-cdp only drives Chromium via CDP; launching Chromium instead"
);
}
opts.user_data_dir = Some(PathBuf::from(user_data_dir.as_ref()));
let browser = Browser::launch(opts).await?;
// The persistent context is the browser's default (non-isolated) context:
// browser_context_id == None, backed by the on-disk user-data-dir.
let ctx = BrowserContext::default_for(browser);
// Owning context: close() must tear the whole browser down, matching
// Playwright's persistent-context semantics.
ctx.mark_persistent();
Ok(ctx)
}
/// Attach to an already-running browser over CDP.
pub async fn connect_over_cdp(
&self,
endpoint: &str,
opts: Option<ConnectOverCdpOptions>,
) -> Result<Browser> {
Browser::connect_over_cdp(endpoint, opts).await
}
}