1use crate::imp::{
2 browser::Browser,
3 core::*,
4 page::Page,
5 prelude::*,
6 utils::{Cookie, Geolocation, Header, StorageState},
7};
8
9#[derive(Debug)]
10pub(crate) struct BrowserContext {
11 channel: ChannelOwner,
12 var: Mutex<Variable>,
13 tx: Mutex<Option<broadcast::Sender<Evt>>>,
14}
15
16#[derive(Debug, Default)]
17pub(crate) struct Variable {
18 browser: Option<Weak<Browser>>,
19 pages: Vec<Weak<Page>>,
20 timeout: Option<u32>,
21 navigation_timeout: Option<u32>,
22}
23
24impl BrowserContext {
25 const DEFAULT_TIMEOUT: u32 = 30000;
26
27 pub(crate) fn try_new(channel: ChannelOwner) -> Result<Self, Error> {
28 let Initializer {} = serde_json::from_value(channel.initializer.clone())?;
29 let browser = match &channel.parent {
30 Some(RemoteWeak::Browser(b)) => Some(b.clone()),
31 _ => None,
32 };
33 let var = Mutex::new(Variable {
34 browser,
35 ..Variable::default()
36 });
37 Ok(Self {
38 channel,
39 var,
40 tx: Mutex::default(),
41 })
42 }
43
44 pub(crate) async fn new_page(&self) -> Result<Weak<Page>, Arc<Error>> {
45 let res = send_message!(self, "newPage", Map::new());
46 let guid = only_guid(&res)?;
47 let p = get_object!(self.context()?.lock().unwrap(), guid, Page)?;
48 Ok(p)
49 }
50
51 pub(crate) async fn close(&self) -> Result<(), Arc<Error>> {
52 let _ = send_message!(self, "close", Map::new());
53 Ok(())
54 }
55
56 pub(crate) async fn storage_state(&self) -> ArcResult<StorageState> {
57 let v = send_message!(self, "storageState", Map::new());
58 let s = serde_json::from_value((*v).clone()).map_err(Error::Serde)?;
59 Ok(s)
60 }
61
62 pub(crate) async fn clear_cookies(&self) -> ArcResult<()> {
63 let _ = send_message!(self, "clearCookies", Map::new());
64 Ok(())
65 }
66
67 pub(crate) async fn cookies(&self, urls: &[String]) -> ArcResult<Vec<Cookie>> {
68 #[derive(Serialize)]
69 #[serde(rename_all = "camelCase")]
70 struct Args<'a> {
71 urls: &'a [String],
72 }
73 let args = Args { urls };
74 let v = send_message!(self, "cookies", args);
75 let cookies = first(&v).ok_or(Error::InvalidParams)?;
76 let cs: Vec<Cookie> = serde_json::from_value((*cookies).clone()).map_err(Error::Serde)?;
77 Ok(cs)
78 }
79
80 pub(crate) async fn add_cookies(&self, cookies: &[Cookie]) -> ArcResult<()> {
81 #[derive(Serialize)]
82 #[serde(rename_all = "camelCase")]
83 struct Args<'a> {
84 cookies: &'a [Cookie],
85 }
86 let args = Args { cookies };
87 let _ = send_message!(self, "addCookies", args);
88 Ok(())
89 }
90
91 pub(crate) async fn grant_permissions(
92 &self,
93 permissions: &[String],
94 origin: Option<&str>,
95 ) -> ArcResult<()> {
96 #[skip_serializing_none]
97 #[derive(Serialize)]
98 #[serde(rename_all = "camelCase")]
99 struct Args<'a, 'b> {
100 permissions: &'a [String],
101 origin: Option<&'b str>,
102 }
103 let args = Args {
104 permissions,
105 origin,
106 };
107 let _ = send_message!(self, "grantPermissions", args);
108 Ok(())
109 }
110
111 pub(crate) async fn clear_permissions(&self) -> ArcResult<()> {
112 let _ = send_message!(self, "clearPermissions", Map::new());
113 Ok(())
114 }
115
116 pub(crate) async fn set_geolocation(&self, geolocation: Option<&Geolocation>) -> ArcResult<()> {
117 #[skip_serializing_none]
118 #[derive(Serialize)]
119 #[serde(rename_all = "camelCase")]
120 struct Args<'a> {
121 geolocation: Option<&'a Geolocation>,
122 }
123 let args = Args { geolocation };
124 let _ = send_message!(self, "setGeolocation", args);
125 Ok(())
126 }
127
128 pub(crate) async fn set_offline(&self, offline: bool) -> ArcResult<()> {
129 let mut args = Map::new();
130 args.insert("offline".into(), offline.into());
131 let _ = send_message!(self, "setOffline", args);
132 Ok(())
133 }
134
135 pub(crate) async fn add_init_script(&self, script: &str) -> ArcResult<()> {
136 let mut args = HashMap::new();
137 args.insert("source", script);
138 let _ = send_message!(self, "addInitScript", args);
139 Ok(())
140 }
141
142 pub(crate) async fn set_extra_http_headers<T>(&self, headers: T) -> ArcResult<()>
143 where
144 T: IntoIterator<Item = (String, String)>,
145 {
146 #[derive(Serialize)]
147 #[serde(rename_all = "camelCase")]
148 struct Args {
149 headers: Vec<Header>,
150 }
151 let args = Args {
152 headers: headers.into_iter().map(Header::from).collect(),
153 };
154 let _ = send_message!(self, "setExtraHTTPHeaders", args);
155 Ok(())
156 }
157
158 }
168
169impl BrowserContext {
171 pub(crate) fn browser(&self) -> Option<Weak<Browser>> {
172 self.var.lock().unwrap().browser.clone()
173 }
174
175 pub(crate) fn set_browser(&self, browser: Weak<Browser>) {
176 self.var.lock().unwrap().browser = Some(browser);
177 }
178
179 pub(crate) fn pages(&self) -> Vec<Weak<Page>> {
180 self.var.lock().unwrap().pages.clone()
181 }
182
183 pub(super) fn push_page(&self, p: Weak<Page>) {
184 self.var.lock().unwrap().pages.push(p);
185 }
186
187 pub(super) fn remove_page(&self, page: &Weak<Page>) {
188 let pages = &mut self.var.lock().unwrap().pages;
189 pages.remove_one(|p| p.ptr_eq(page));
190 }
191
192 pub(crate) fn default_timeout(&self) -> u32 {
193 self.var
194 .lock()
195 .unwrap()
196 .timeout
197 .unwrap_or(Self::DEFAULT_TIMEOUT)
198 }
199
200 pub(crate) fn default_navigation_timeout(&self) -> u32 {
201 self.var
202 .lock()
203 .unwrap()
204 .navigation_timeout
205 .unwrap_or(Self::DEFAULT_TIMEOUT)
206 }
207
208 pub(crate) async fn set_default_timeout(&self, timeout: u32) -> ArcResult<()> {
209 let mut args = Map::new();
210 args.insert("timeout".into(), timeout.into());
211 let _ = send_message!(self, "setDefaultTimeoutNoReply", args);
212 self.var.lock().unwrap().timeout = Some(timeout);
213 Ok(())
214 }
215
216 pub(crate) async fn set_default_navigation_timeout(&self, timeout: u32) -> ArcResult<()> {
217 let mut args = Map::new();
218 args.insert("timeout".into(), timeout.into());
219 let _ = send_message!(self, "setDefaultNavigationTimeoutNoReply", args);
220 self.var.lock().unwrap().navigation_timeout = Some(timeout);
221 Ok(())
222 }
223
224 fn on_close(&self, ctx: &Context) -> Result<(), Error> {
225 let browser = match self.browser().and_then(|b| b.upgrade()) {
226 None => return Ok(()),
227 Some(b) => b,
228 };
229 let this = get_object!(ctx, self.guid(), BrowserContext)?;
230 browser.remove_context(&this);
231 self.emit_event(Evt::Close);
232 Ok(())
233 }
234
235 fn on_route(&self, _ctx: &Context, _parmas: Map<String, Value>) -> Result<(), Error> {
236 Ok(())
238 }
239}
240
241impl RemoteObject for BrowserContext {
242 fn channel(&self) -> &ChannelOwner {
243 &self.channel
244 }
245 fn channel_mut(&mut self) -> &mut ChannelOwner {
246 &mut self.channel
247 }
248
249 fn handle_event(
250 &self,
251 ctx: &Context,
252 method: Str<Method>,
253 params: Map<String, Value>,
254 ) -> Result<(), Error> {
255 match method.as_str() {
256 "page" => {
257 let first = first_object(¶ms).ok_or(Error::InvalidParams)?;
258 let OnlyGuid { guid } = serde_json::from_value((*first).clone())?;
259 let p = get_object!(ctx, &guid, Page)?;
260 self.push_page(p.clone());
261 self.emit_event(Evt::Page(p));
262 }
263 "close" => self.on_close(ctx)?,
264 "bindingCall" => {}
265 "route" => self.on_route(ctx, params)?,
266 _ => {}
267 }
268 Ok(())
269 }
270}
271
272#[derive(Debug, Clone)]
273pub(crate) enum Evt {
274 Close,
275 Page(Weak<Page>),
276}
277
278impl EventEmitter for BrowserContext {
279 type Event = Evt;
280
281 fn tx(&self) -> Option<broadcast::Sender<Self::Event>> {
282 self.tx.lock().unwrap().clone()
283 }
284
285 fn set_tx(&self, tx: broadcast::Sender<Self::Event>) {
286 *self.tx.lock().unwrap() = Some(tx);
287 }
288}
289
290#[derive(Debug, Clone, Copy, PartialEq)]
291pub enum EventType {
292 Close,
293 Page,
294}
295
296impl IsEvent for Evt {
297 type EventType = EventType;
298
299 fn event_type(&self) -> Self::EventType {
300 match self {
301 Self::Close => EventType::Close,
302 Self::Page(_) => EventType::Page,
303 }
304 }
305}
306
307#[derive(Debug, Deserialize)]
308#[serde(rename_all = "camelCase")]
309struct Initializer {}
310
311#[cfg(test)]
312mod tests {
313 use super::*;
314 use crate::imp::{browser::*, browser_type::*, playwright::Playwright};
315
316 crate::runtime_test!(storage_state, {
317 let driver = Driver::install().unwrap();
318 let conn = Connection::run(&driver).unwrap();
319 let p = Playwright::wait_initial_object(&conn).await.unwrap();
320 let p = p.upgrade().unwrap();
321 let chromium = p.chromium().upgrade().unwrap();
322 let b = chromium.launch(LaunchArgs::default()).await.unwrap();
323 let b = b.upgrade().unwrap();
324 let c = b.new_context(NewContextArgs::default()).await.unwrap();
325 let c = c.upgrade().unwrap();
326 c.storage_state().await.unwrap();
327 c.cookies(&[]).await.unwrap();
328 });
331}