playwright/imp/
browser.rs

1use crate::imp::{
2    browser_context::BrowserContext,
3    browser_type::{RecordHar, RecordVideo},
4    core::*,
5    prelude::*,
6    utils::{ColorScheme, Geolocation, HttpCredentials, ProxySettings, StorageState, Viewport},
7};
8
9#[derive(Debug)]
10pub(crate) struct Browser {
11    channel: ChannelOwner,
12    version: String,
13    var: Mutex<Variable>,
14}
15
16#[derive(Debug, Default)]
17pub(crate) struct Variable {
18    contexts: Vec<Weak<BrowserContext>>,
19    is_remote: bool,
20}
21
22impl Browser {
23    pub(crate) fn try_new(channel: ChannelOwner) -> Result<Self, Error> {
24        let Initializer { version } = serde_json::from_value(channel.initializer.clone())?;
25        Ok(Self {
26            channel,
27            version,
28            var: Mutex::new(Variable {
29                contexts: Vec::new(),
30                is_remote: false,
31            }),
32        })
33    }
34    pub(crate) fn version(&self) -> &str {
35        &self.version
36    }
37
38    pub(crate) async fn close(&self) -> Result<(), Arc<Error>> {
39        let _ = send_message!(self, "close", Map::new());
40        Ok(())
41    }
42
43    // Responds newtype `OwnerPage` of `SinglePageBrowserContext`.
44    // There are different behavior in BrowserContext::new_page
45    // async fn new_page(
46}
47
48// mutable
49impl Browser {
50    pub(crate) fn contexts(&self) -> Vec<Weak<BrowserContext>> {
51        self.var.lock().unwrap().contexts.to_owned()
52    }
53
54    pub(crate) fn push_context(&self, c: Weak<BrowserContext>) {
55        self.var.lock().unwrap().contexts.push(c);
56    }
57
58    pub(super) fn remove_context(&self, c: &Weak<BrowserContext>) {
59        let contexts = &mut self.var.lock().unwrap().contexts;
60        contexts.remove_one(|v| v.ptr_eq(c));
61    }
62
63    pub(crate) fn is_remote(&self) -> bool {
64        self.var.lock().unwrap().is_remote
65    }
66
67    pub(crate) fn set_is_remote_true(&self) {
68        self.var.lock().unwrap().is_remote = true;
69    }
70
71    pub(crate) async fn new_context(
72        &self,
73        args: NewContextArgs<'_, '_, '_, '_, '_, '_, '_>,
74    ) -> Result<Weak<BrowserContext>, Arc<Error>> {
75        let res = send_message!(self, "newContext", args);
76        let guid = only_guid(&res)?;
77        let c = get_object!(self.context()?.lock().unwrap(), guid, BrowserContext)?;
78        self.register_new_context(c.clone())?;
79        Ok(c)
80    }
81
82    fn register_new_context(&self, c: Weak<BrowserContext>) -> Result<(), Arc<Error>> {
83        self.push_context(c);
84        // TODO: options
85        // let this = get_object!(self.context()?.lock().unwrap(), &self.guid(), Browser)?;
86        // let bc = upgrade(&c)?;
87        // bc._options = params
88        Ok(())
89    }
90}
91
92impl RemoteObject for Browser {
93    fn channel(&self) -> &ChannelOwner {
94        &self.channel
95    }
96    fn channel_mut(&mut self) -> &mut ChannelOwner {
97        &mut self.channel
98    }
99}
100
101#[derive(Debug, Deserialize)]
102#[serde(rename_all = "camelCase")]
103struct Initializer {
104    version: String,
105}
106
107#[skip_serializing_none]
108#[derive(Debug, Serialize)]
109#[serde(rename_all = "camelCase")]
110pub(crate) struct NewContextArgs<'e, 'f, 'g, 'h, 'i, 'j, 'k> {
111    sdk_language: &'static str,
112
113    pub(crate) timeout: Option<f64>,
114    pub(crate) proxy: Option<ProxySettings>,
115
116    pub(crate) viewport: Option<Option<Viewport>>,
117    pub(crate) screen: Option<Viewport>,
118    pub(crate) no_viewport: Option<bool>,
119    #[serde(rename = "ignoreHTTPSErrors")]
120    pub(crate) ignore_https_errors: Option<bool>,
121    #[serde(rename = "javaScriptEnabled")]
122    pub(crate) js_enabled: Option<bool>,
123    #[serde(rename = "bypassCSP")]
124    pub(crate) bypass_csp: Option<bool>,
125    pub(crate) user_agent: Option<&'e str>,
126    pub(crate) locale: Option<&'f str>,
127    pub(crate) timezone_id: Option<&'g str>,
128    pub(crate) geolocation: Option<Geolocation>,
129    pub(crate) permissions: Option<&'h [String]>,
130    #[serde(rename = "extraHTTPHeaders")]
131    pub(crate) extra_http_headers: Option<HashMap<String, String>>,
132    pub(crate) offline: Option<bool>,
133    pub(crate) http_credentials: Option<&'i HttpCredentials>,
134    pub(crate) device_scale_factor: Option<f64>,
135    pub(crate) is_mobile: Option<bool>,
136    pub(crate) has_touch: Option<bool>,
137    pub(crate) color_scheme: Option<ColorScheme>,
138    pub(crate) accept_downloads: Option<bool>,
139    pub(crate) chromium_sandbox: Option<bool>,
140    pub(crate) record_video: Option<RecordVideo<'j>>,
141    pub(crate) record_har: Option<RecordHar<'k>>,
142
143    pub(crate) storage_state: Option<StorageState>,
144}
145
146impl<'e, 'f, 'g, 'h, 'i, 'j, 'k> Default for NewContextArgs<'e, 'f, 'g, 'h, 'i, 'j, 'k> {
147    fn default() -> Self {
148        Self {
149            sdk_language: "rust",
150            timeout: Some(30000.0),
151            proxy: None,
152            viewport: None,
153            screen: None,
154            no_viewport: None,
155            ignore_https_errors: None,
156            js_enabled: None,
157            bypass_csp: None,
158            user_agent: None,
159            locale: None,
160            timezone_id: None,
161            geolocation: None,
162            permissions: None,
163            extra_http_headers: None,
164            offline: None,
165            http_credentials: None,
166            device_scale_factor: None,
167            is_mobile: None,
168            has_touch: None,
169            color_scheme: None,
170            accept_downloads: None,
171            chromium_sandbox: None,
172            record_video: None,
173            record_har: None,
174            storage_state: None,
175        }
176    }
177}
178
179#[cfg(test)]
180mod tests {
181    use super::*;
182    use crate::imp::{browser_type::*, playwright::Playwright};
183
184    crate::runtime_test!(new_context, {
185        let driver = Driver::install().unwrap();
186        let conn = Connection::run(&driver).unwrap();
187        let p = Playwright::wait_initial_object(&conn).await.unwrap();
188        let p = p.upgrade().unwrap();
189        let chromium = p.chromium().upgrade().unwrap();
190        let b = chromium.launch(LaunchArgs::default()).await.unwrap();
191        let b = b.upgrade().unwrap();
192        b.new_context(NewContextArgs::default()).await.unwrap();
193    });
194}