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 }
47
48impl 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 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}