chromedriver_api/session/
tab.rs

1use crate::prelude::*;
2use super::SessionManager;
3
4use reqwest::Client;
5use serde_json::{ json, Value };
6
7// The window tab
8#[derive(Clone)]
9pub struct Tab {
10    pub(crate) client: Client,
11    pub(crate) port: u16,
12    pub(crate) session_id: String,
13    pub(crate) tab_id: String,
14    pub(crate) url: String,
15    pub(crate) manager: Arc<SessionManager>
16}
17
18impl Tab {
19    /// Returns chromederiver server port
20    pub fn get_port(&self) -> u16 {
21        self.port
22    }
23    
24    /// Returns tab id
25    pub fn get_id(&self) -> &str {
26        &self.tab_id
27    }
28    
29    /// Do tab active without locking other tasks
30    async fn active_without_lock(&self) -> Result<()> {
31        self.client
32            .post(&fmt!("http://127.0.0.1:{}/session/{}/window", self.port, self.session_id))
33            .json(&json!({"handle": self.tab_id }))
34            .send()
35            .await?;
36
37        Ok(())
38    }
39
40    /// Do tab active
41    pub async fn active(&self) -> Result<()> {
42        // lock other tasks:
43        self.manager.lock().await;
44        
45        // do tab active:
46        self.active_without_lock().await?;
47
48        // unlock other tasks:
49        self.manager.unlock().await;
50
51        Ok(())
52    }
53    
54    /// Open URL-address
55    pub async fn open<S>(&mut self, url: S) -> Result<()>
56    where
57        S: Into<String>
58    {
59        let url = url.into();
60
61        // lock other tasks:
62        self.manager.lock().await;
63
64        // do tab active:
65        self.active_without_lock().await?;
66
67        // loading URL:
68        self.client
69            .post(&fmt!("http://127.0.0.1:{}/session/{}/url", self.port, self.session_id))
70            .json(&json!({ "url": url }))
71            .send()
72            .await?;
73
74        // update url:
75        self.url = url;
76
77        // unlock other tasks:
78        self.manager.unlock().await;
79
80        Ok(())
81    }
82
83    /// Inject JavaScript to window tab
84    pub async fn inject<D: serde::de::DeserializeOwned>(&self, script: &str) -> Result<D> {
85        // lock other tasks:
86        self.manager.lock().await;
87        
88        // do tab active:
89        self.active_without_lock().await?;
90
91        // execute script:
92        let url = fmt!("http://127.0.0.1:{}/session/{}/execute/sync", self.port, self.session_id);
93        let response = self.client
94            .post(&url)
95            .json(&json!({
96                "script": script,
97                "args": []
98            }))
99            .send()
100            .await?
101            .json::<Value>()
102            .await?;
103
104        // unlock other tasks:
105        self.manager.unlock().await;
106
107        let value = response.get("value")
108            .ok_or(Error::UnexpectedResponse)?
109            .to_owned();
110        
111        Ok(serde_json::from_value::<D>(value)?)
112    }
113
114    /// Close window tab
115    pub async fn close(&self) -> Result<()> {
116        // lock other tasks:
117        self.manager.lock().await;
118
119        // do tab active:
120        self.active_without_lock().await?;
121
122        // close tab:
123        loop {
124            // do tab active (if tab not exists - break):
125            if let Err(_) = self.active_without_lock().await {
126                break;
127            }
128
129            // close tab:
130            self.client
131                .delete(&fmt!("http://127.0.0.1:{}/session/{}/window", self.port, self.session_id))
132                .send()
133                .await?;
134
135            // check tab for closed:
136            let handles = self.get_tabs_ids().await?;
137
138            // tab not exists - success!
139            if !handles.contains(&self.tab_id) {
140                break;
141            }
142        }
143
144        // unlock other tasks:
145        self.manager.unlock().await;
146
147        Ok(())
148    }
149
150    /// Returns all tab identifiers
151    async fn get_tabs_ids(&self) -> Result<Vec<String>> {
152        let handles_url = fmt!("http://127.0.0.1:{}/session/{}/window/handles", self.port, self.session_id);
153
154        let response = self.client
155            .get(&handles_url)
156            .send()
157            .await?
158            .error_for_status()?
159            .json::<Value>()
160            .await?;
161
162        let handles = response["value"]
163            .as_array()
164            .ok_or(Error::IncorrectWindowHandles)?
165            .iter()
166            .map(|v| {
167                v.as_str()
168                    .ok_or(Error::IncorrectWindowHandles)
169                    .map(|s| s.to_string())
170                    .map_err(|e| e.into())
171            })
172            .collect::<Result<Vec<_>>>()?;
173
174        Ok(handles)
175    }
176}