viewpoint_core/context/emulation/
mod.rs1use std::collections::HashMap;
6
7use tracing::{debug, instrument};
8
9use viewpoint_cdp::protocol::emulation::{
10 ClearGeolocationOverrideParams, SetGeolocationOverrideParams,
11};
12use viewpoint_cdp::protocol::network::{EmulateNetworkConditionsParams, SetExtraHTTPHeadersParams};
13
14use super::BrowserContext;
15use crate::error::ContextError;
16
17impl BrowserContext {
18 #[instrument(level = "debug", skip(self))]
24 pub async fn clear_geolocation(&self) -> Result<(), ContextError> {
25 if self.is_closed() {
26 return Err(ContextError::Closed);
27 }
28
29 let pages = self.pages.read().await;
31 for page in pages.iter() {
32 if !page.session_id.is_empty() {
33 self.connection()
34 .send_command::<_, serde_json::Value>(
35 "Emulation.clearGeolocationOverride",
36 Some(ClearGeolocationOverrideParams::default()),
37 Some(&page.session_id),
38 )
39 .await?;
40 }
41 }
42
43 Ok(())
44 }
45
46 #[instrument(level = "debug", skip(self, headers))]
66 pub async fn set_extra_http_headers(
67 &self,
68 headers: HashMap<String, String>,
69 ) -> Result<(), ContextError> {
70 if self.is_closed() {
71 return Err(ContextError::Closed);
72 }
73
74 debug!(count = headers.len(), "Setting extra HTTP headers");
75
76 let pages = self.pages.read().await;
78 for page in pages.iter() {
79 if !page.session_id.is_empty() {
80 self.connection()
81 .send_command::<_, serde_json::Value>(
82 "Network.setExtraHTTPHeaders",
83 Some(SetExtraHTTPHeadersParams {
84 headers: headers.clone(),
85 }),
86 Some(&page.session_id),
87 )
88 .await?;
89 }
90 }
91
92 Ok(())
93 }
94
95 #[instrument(level = "debug", skip(self))]
116 pub async fn set_offline(&self, offline: bool) -> Result<(), ContextError> {
117 if self.is_closed() {
118 return Err(ContextError::Closed);
119 }
120
121 debug!(offline = offline, "Setting offline mode");
122
123 let params = if offline {
124 EmulateNetworkConditionsParams::offline()
125 } else {
126 EmulateNetworkConditionsParams::online()
127 };
128
129 let pages = self.pages.read().await;
131 for page in pages.iter() {
132 if !page.session_id.is_empty() {
133 self.connection()
134 .send_command::<_, serde_json::Value>(
135 "Network.emulateNetworkConditions",
136 Some(params.clone()),
137 Some(&page.session_id),
138 )
139 .await?;
140 }
141 }
142
143 Ok(())
144 }
145}
146
147#[derive(Debug)]
153pub struct SetGeolocationBuilder<'a> {
154 context: &'a BrowserContext,
155 latitude: f64,
156 longitude: f64,
157 accuracy: f64,
158}
159
160impl<'a> SetGeolocationBuilder<'a> {
161 pub(crate) fn new(context: &'a BrowserContext, latitude: f64, longitude: f64) -> Self {
162 Self {
163 context,
164 latitude,
165 longitude,
166 accuracy: 0.0,
167 }
168 }
169
170 #[must_use]
172 pub fn accuracy(mut self, accuracy: f64) -> Self {
173 self.accuracy = accuracy;
174 self
175 }
176
177 pub async fn await_(self) -> Result<(), ContextError> {
183 if self.context.is_closed() {
184 return Err(ContextError::Closed);
185 }
186
187 debug!(
188 latitude = self.latitude,
189 longitude = self.longitude,
190 accuracy = self.accuracy,
191 "Setting geolocation"
192 );
193
194 let params = SetGeolocationOverrideParams::with_accuracy(
195 self.latitude,
196 self.longitude,
197 self.accuracy,
198 );
199
200 let pages = self.context.pages.read().await;
202 for page in pages.iter() {
203 if !page.session_id.is_empty() {
204 self.context
205 .connection()
206 .send_command::<_, serde_json::Value>(
207 "Emulation.setGeolocationOverride",
208 Some(params.clone()),
209 Some(&page.session_id),
210 )
211 .await?;
212 }
213 }
214
215 Ok(())
216 }
217}
218
219impl<'a> std::future::IntoFuture for SetGeolocationBuilder<'a> {
221 type Output = Result<(), ContextError>;
222 type IntoFuture =
223 std::pin::Pin<Box<dyn std::future::Future<Output = Self::Output> + Send + 'a>>;
224
225 fn into_future(self) -> Self::IntoFuture {
226 Box::pin(self.await_())
227 }
228}