1use crate::imp::{
2 browser::Browser,
3 browser_context::BrowserContext,
4 core::*,
5 prelude::*,
6 utils::{BrowserChannel, ColorScheme, Geolocation, HttpCredentials, ProxySettings, Viewport},
7};
8
9#[derive(Debug)]
10pub(crate) struct BrowserType {
11 channel: ChannelOwner,
12 name: String,
13 executable: PathBuf,
14}
15
16impl BrowserType {
17 pub(crate) fn try_new(channel: ChannelOwner) -> Result<Self, Error> {
18 let Initializer { name, executable } = serde_json::from_value(channel.initializer.clone())?;
19 Ok(Self {
20 channel,
21 name,
22 executable,
23 })
24 }
25
26 pub(crate) fn name(&self) -> &str {
27 &self.name
28 }
29
30 pub(crate) fn executable(&self) -> &Path {
31 &self.executable
32 }
33
34 pub(crate) async fn launch(
35 &self,
36 args: LaunchArgs<'_, '_, '_>,
37 ) -> Result<Weak<Browser>, Arc<Error>> {
38 let res = send_message!(self, "launch", args);
39 let guid = only_guid(&res)?;
40 let b = get_object!(self.context()?.lock().unwrap(), guid, Browser)?;
41 Ok(b)
42 }
43
44 pub(crate) async fn launch_persistent_context(
45 &self,
46 args: LaunchPersistentContextArgs<'_, '_, '_, '_, '_, '_, '_, '_, '_, '_, '_>,
47 ) -> Result<Weak<BrowserContext>, Arc<Error>> {
48 let res = send_message!(self, "launchPersistentContext", args);
49 let guid = only_guid(&res)?;
50 let b = get_object!(self.context()?.lock().unwrap(), guid, BrowserContext)?;
51 Ok(b)
52 }
53
54 pub(crate) async fn connect_over_cdp(
55 &self,
56 args: ConnectOverCdpArgs<'_>,
57 ) -> ArcResult<Weak<Browser>> {
58 let res = send_message!(self, "connectOverCDP", args);
59 #[derive(Deserialize)]
60 #[serde(rename_all = "camelCase")]
61 struct Response {
62 browser: OnlyGuid,
63 default_context: Option<OnlyGuid>,
64 }
65 let Response {
66 browser,
67 default_context,
68 } = serde_json::from_value((*res).clone()).map_err(Error::Serde)?;
69 let browser = get_object!(self.context()?.lock().unwrap(), &browser.guid, Browser)?;
70 let arc_browser = upgrade(&browser)?;
71 arc_browser.set_is_remote_true();
72 if let Some(OnlyGuid { guid }) = default_context {
73 let default_context =
74 get_object!(self.context()?.lock().unwrap(), &guid, BrowserContext)?;
75 let arc_context = upgrade(&default_context)?;
76 arc_browser.push_context(default_context);
77 arc_context.set_browser(browser.clone());
78 }
79 Ok(browser)
80 }
81
82 pub(crate) async fn connect(&self, args: ConnectArgs<'_>) -> ArcResult<Weak<Browser>> {
83 todo!()
84 }
85}
86
87#[skip_serializing_none]
88#[skip_serializing_none]
89#[derive(Debug, Serialize)]
90#[serde(rename_all = "camelCase")]
91pub(crate) struct LaunchArgs<'a, 'b, 'c> {
92 #[serde(rename = "executablePath")]
93 pub(crate) executable: Option<&'a Path>,
94 pub(crate) args: Option<&'b [String]>,
95 pub(crate) ignore_all_default_args: Option<bool>,
96 #[serde(rename = "handleSIGINT")]
97 pub(crate) handle_sigint: Option<bool>,
98 #[serde(rename = "handleSIGTERM")]
99 pub(crate) handle_sigterm: Option<bool>,
100 #[serde(rename = "handleSIGHUP")]
101 pub(crate) handle_sighup: Option<bool>,
102 pub(crate) timeout: Option<f64>,
103 pub(crate) devtools: Option<bool>,
104 pub(crate) proxy: Option<ProxySettings>,
105 #[serde(rename = "downloadsPath")]
106 pub(crate) downloads: Option<&'c Path>,
107 #[serde(rename = "slowMo")]
108 pub(crate) slowmo: Option<f64>,
109 pub(crate) env: Option<Map<String, Value>>,
110 pub(crate) headless: Option<bool>,
111 pub(crate) chromium_sandbox: Option<bool>,
112 pub(crate) firefox_user_prefs: Option<Map<String, Value>>,
113 pub(crate) channel: Option<BrowserChannel>,
114}
115
116impl<'a, 'b, 'c> Default for LaunchArgs<'a, 'b, 'c> {
117 fn default() -> Self {
118 Self {
119 executable: None,
120 args: None,
121 ignore_all_default_args: None,
122 handle_sigint: None,
123 handle_sigterm: None,
124 handle_sighup: None,
125 timeout: Some(30000.0),
126 devtools: None,
127 proxy: None,
128 downloads: None,
129 slowmo: None,
130 env: None,
131 headless: None,
132 chromium_sandbox: None,
133 firefox_user_prefs: None,
134 channel: None,
135 }
136 }
137}
138
139impl RemoteObject for BrowserType {
140 fn channel(&self) -> &ChannelOwner {
141 &self.channel
142 }
143 fn channel_mut(&mut self) -> &mut ChannelOwner {
144 &mut self.channel
145 }
146}
147
148#[derive(Debug, Deserialize)]
149#[serde(rename_all = "camelCase")]
150struct Initializer {
151 name: String,
152 #[serde(rename = "executablePath")]
153 executable: PathBuf,
154}
155
156#[skip_serializing_none]
158#[derive(Debug, Serialize)]
159#[serde(rename_all = "camelCase")]
160pub(crate) struct LaunchPersistentContextArgs<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k> {
161 user_data_dir: &'a Path,
162 sdk_language: &'static str,
163
164 #[serde(rename = "executablePath")]
165 pub(crate) executable: Option<&'b Path>,
166 pub(crate) args: Option<&'c [String]>,
167 pub(crate) ignore_all_default_args: Option<bool>,
168 #[serde(rename = "handleSIGINT")]
169 pub(crate) handle_sigint: Option<bool>,
170 #[serde(rename = "handleSIGTERM")]
171 pub(crate) handle_sigterm: Option<bool>,
172 #[serde(rename = "handleSIGHUP")]
173 pub(crate) handle_sighup: Option<bool>,
174 pub(crate) timeout: Option<f64>,
175 pub(crate) env: Option<Map<String, Value>>,
176 pub(crate) headless: Option<bool>,
177 pub(crate) devtools: Option<bool>,
178 pub(crate) proxy: Option<ProxySettings>,
179 #[serde(rename = "downloadsPath")]
180 pub(crate) downloads: Option<&'d Path>,
181 #[serde(rename = "slowMo")]
182 pub(crate) slowmo: Option<f64>,
183
184 pub(crate) viewport: Option<Option<Viewport>>,
185 pub(crate) screen: Option<Viewport>,
186 pub(crate) no_viewport: Option<bool>,
187 #[serde(rename = "ignoreHTTPSErrors")]
188 pub(crate) ignore_https_errors: Option<bool>,
189 #[serde(rename = "javaScriptEnabled")]
190 pub(crate) js_enabled: Option<bool>,
191 #[serde(rename = "bypassCSP")]
192 pub(crate) bypass_csp: Option<bool>,
193 pub(crate) user_agent: Option<&'e str>,
194 pub(crate) locale: Option<&'f str>,
195 pub(crate) timezone_id: Option<&'g str>,
196 pub(crate) geolocation: Option<Geolocation>,
197 pub(crate) permissions: Option<&'h [String]>,
198 #[serde(rename = "extraHTTPHeaders")]
199 pub(crate) extra_http_headers: Option<HashMap<String, String>>,
200 pub(crate) offline: Option<bool>,
201 pub(crate) http_credentials: Option<&'i HttpCredentials>,
202 pub(crate) device_scale_factor: Option<f64>,
203 pub(crate) is_mobile: Option<bool>,
204 pub(crate) has_touch: Option<bool>,
205 pub(crate) color_scheme: Option<ColorScheme>,
206 pub(crate) accept_downloads: Option<bool>,
207 pub(crate) chromium_sandbox: Option<bool>,
208 pub(crate) record_video: Option<RecordVideo<'j>>,
209 pub(crate) record_har: Option<RecordHar<'k>>,
210
211 pub(crate) channel: Option<BrowserChannel>,
212}
213
214#[skip_serializing_none]
215#[derive(Debug, Serialize, Clone)]
216#[serde(rename_all = "camelCase")]
217pub struct RecordVideo<'a> {
218 pub dir: &'a Path,
219 pub size: Option<Viewport>,
220}
221
222#[skip_serializing_none]
223#[derive(Debug, Serialize, Clone)]
224#[serde(rename_all = "camelCase")]
225pub struct RecordHar<'a> {
226 pub path: &'a Path,
227 pub omit_content: Option<bool>,
228}
229
230impl<'a> LaunchPersistentContextArgs<'a, '_, '_, '_, '_, '_, '_, '_, '_, '_, '_> {
231 pub(crate) fn new(user_data_dir: &'a Path) -> Self {
232 let sdk_language = "rust";
233 Self {
234 user_data_dir,
235 sdk_language,
236 executable: None,
237 args: None,
238 ignore_all_default_args: None,
239 handle_sigint: None,
240 handle_sigterm: None,
241 handle_sighup: None,
242 timeout: Some(30000.0),
243 env: None,
244 headless: None,
245 devtools: None,
246 proxy: None,
247 downloads: None,
248 slowmo: None,
249 viewport: None,
250 screen: None,
251 no_viewport: None,
252 ignore_https_errors: None,
253 js_enabled: None,
254 bypass_csp: None,
255 user_agent: None,
256 locale: None,
257 timezone_id: None,
258 geolocation: None,
259 permissions: None,
260 extra_http_headers: None,
261 offline: None,
262 http_credentials: None,
263 device_scale_factor: None,
264 is_mobile: None,
265 has_touch: None,
266 color_scheme: None,
267 accept_downloads: None,
268 chromium_sandbox: None,
269 record_video: None,
270 record_har: None,
271 channel: None,
272 }
273 }
274}
275
276#[skip_serializing_none]
277#[derive(Debug, Serialize)]
278#[serde(rename_all = "camelCase")]
279pub(crate) struct ConnectArgs<'a> {
280 ws_endpoint: &'a str,
281 pub(crate) timeout: Option<f64>,
282 #[serde(rename = "slowMo")]
283 pub(crate) slowmo: Option<f64>,
284}
285
286impl<'a> ConnectArgs<'a> {
287 pub(crate) fn new(ws_endpoint: &'a str) -> Self {
288 Self {
289 ws_endpoint,
290 timeout: Some(30000.0),
291 slowmo: None,
292 }
293 }
294}
295
296#[skip_serializing_none]
297#[derive(Debug, Serialize)]
298#[serde(rename_all = "camelCase")]
299pub(crate) struct ConnectOverCdpArgs<'a> {
300 sdk_language: &'static str,
301 #[serde(rename = "endpointURL")]
302 endpoint_url: &'a str,
303 pub(crate) headers: Option<HashMap<String, String>>,
304 pub(crate) timeout: Option<f64>,
305 #[serde(rename = "slowMo")]
306 pub(crate) slowmo: Option<f64>,
307}
308
309impl<'a> ConnectOverCdpArgs<'a> {
310 pub(crate) fn new(endpoint_url: &'a str) -> Self {
311 Self {
312 sdk_language: "rust",
313 endpoint_url,
314 headers: None,
315 timeout: Some(30000.0),
316 slowmo: None,
317 }
318 }
319}
320
321#[cfg(test)]
322mod tests {
323 use super::*;
324 use crate::imp::playwright::Playwright;
325
326 crate::runtime_test!(launch, {
327 let driver = Driver::install().unwrap();
328 let conn = Connection::run(&driver).unwrap();
329 let p = Playwright::wait_initial_object(&conn).await.unwrap();
330 let p = p.upgrade().unwrap();
331 let chromium = p.chromium().upgrade().unwrap();
332 let res = chromium.launch(LaunchArgs::default()).await;
333 dbg!(&res);
334 res.unwrap();
335 });
336
337 crate::runtime_test!(typo, {
338 let driver = Driver::install().unwrap();
339 let conn = Connection::run(&driver).unwrap();
340 let p = Playwright::wait_initial_object(&conn).await.unwrap();
341 let p = p.upgrade().unwrap();
342 let chromium = p.chromium().upgrade().unwrap();
343 async fn send(c: &BrowserType) -> Result<Arc<Value>, Error> {
344 Ok(send_message!(c, "nonExistentMethod", Map::default()))
345 }
346 match send(&chromium).await {
347 Err(Error::ErrorResponded(e)) => dbg!(e),
348 x => {
349 dbg!(&x);
350 unreachable!()
351 }
352 }
353 });
354}