1use std::sync::Arc;
18
19use crate::wdcmd::session::{FirefoxCapa, GeckoCapRequ, GeckoSessResult};
20use crate::wdcmd::session::{FirefoxCapaGetter, GeckoCapRequSetter};
21use crate::wdcmd::session::{W3cCapaGetter, W3cSessResultGetter};
22
23use crate::CreateW3cSession;
24use crate::CreateWebDrvClient;
25use crate::WdcError;
26
27use crate::genericdrv::WebDrvClient;
28
29use crate::httpp::HttpRequestParts;
30use crate::httpp::HttpResponseParts;
31
32use crate::genericdrv::check_fail_drvcmd;
33
34#[cfg(feature = "firefox")]
38#[cfg_attr(doc_cfg, doc(cfg(feature = "firefox")))]
39#[derive(Debug, Default)]
40pub struct GeckoDriver;
41
42impl CreateWebDrvClient for GeckoDriver {
45 fn new(rhost: &str, rport: u16) -> WebDrvClient<Self> {
46 WebDrvClient {
47 kind: GeckoDriver,
48 rhost: rhost.to_string(),
49 rport,
50 rstream: None,
51 ssids: vec![],
52 }
53 }
54}
55
56impl<'de, 'c1, 'c2> CreateW3cSession<'de, 'c1, 'c2> for GeckoDriver {
57 type CapRequ<'r> = GeckoCapRequ<'r>where 'c1: 'r, 'c2: 'r;
58 type Capa<'a> = FirefoxCapa<'a>;
59 type SessResult = GeckoSessResult<'de>;
60}
61
62#[cfg(feature = "firefox")]
68#[cfg_attr(doc_cfg, doc(cfg(feature = "firefox")))]
69pub fn init_singl_ff(
70 rhost: &str,
71 rport: u16,
72 capa: &(impl W3cCapaGetter + FirefoxCapaGetter),
73 ready_timeout: u32,
74) -> Result<WebDrvClient<GeckoDriver>, WdcError> {
75 let mut wdc = GeckoDriver::new(rhost, rport);
76
77 wdc.ensure_remote_connected()?;
78
79 let ready_timeout_in_micros = (ready_timeout * 1000000) as u64;
80 let mut already_wait = 0u64;
81 let wait_each_round = 100u64;
82 let mut ready_or_not = false;
83
84 while already_wait < ready_timeout_in_micros {
85 match wdc.is_ready() {
86 Ok(_) => {
87 break;
88 }
89 Err(WdcError::DriverNotReadyBusySession) => {
90 std::thread::sleep(std::time::Duration::from_micros(wait_each_round));
91 already_wait += wait_each_round;
92 continue;
93 }
94 Err(_e) => {
95 dbgg!(_e);
96 break;
97 }
98 }
99 }
100
101 while already_wait < ready_timeout_in_micros {
102 match wdc.ff_session_singl(capa) {
103 Ok(_) => {
104 ready_or_not = true;
105 break;
106 }
107 Err(WdcError::BusyCreateSession) => {
108 std::thread::sleep(std::time::Duration::from_micros(wait_each_round));
109 already_wait += wait_each_round;
110 continue;
111 }
112 Err(_e) => {
113 dbgg!(_e);
114 break;
115 }
116 }
117 }
118
119 dbgg!(already_wait);
120
121 if ready_or_not {
122 Ok(wdc)
123 } else {
124 Err(WdcError::WebDriverNotReady)
125 }
126}
127
128impl WebDrvClient<GeckoDriver> {
129 fn ff_session_singl(
130 &mut self,
131 capa: &(impl W3cCapaGetter + FirefoxCapaGetter),
132 ) -> Result<(), WdcError> {
133 if self.rstream.is_none() {
134 return Err(WdcError::WebDriverRemoteConnectionFailed);
135 };
136
137 let rs = Arc::clone(self.rstream.as_ref().unwrap());
138 let mut stream = rs.lock().unwrap();
139
140 let anycapa = FirefoxCapa::default(); let mut requ = GeckoCapRequ::default();
142
143 requ.allow(&anycapa); requ.mandate(capa);
146
147 let mut req = HttpRequestParts::from_scratch();
148
149 let mut mb = Vec::<u8>::new();
150 mb.extend(r#"{"capabilities":"#.as_bytes());
151 mb.extend(serde_json::to_vec(&requ).expect("ser"));
152 mb.extend(r#"}"#.as_bytes());
153
154 dbgg!(String::from_utf8_lossy(&mb));
155
156 req.http1p1()
157 .post("/session")
158 .host(&self.raddr())
159 .msgbody_from_slice(&mb)
160 .content_type("application/json")
161 .send_through(&mut stream)
162 .unwrap();
163
164 let resp = HttpResponseParts::from_stream(&mut stream, None, 0, 0).unwrap();
165
166 dbgg!(String::from_utf8_lossy(resp.msgbody()));
167
168 if resp.is_ok() {
169 let deser_result;
170
171 run_diag!("deser_resp", {
172 deser_result = serde_json::from_slice::<GeckoSessResult>(resp.msgbody())
173 });
174
175 match deser_result {
176 Ok(sess) => {
177 self.add_ssid(sess.session_id().to_string());
178 Ok(())
179 }
180 _ => Err(WdcError::Buggy),
181 }
182 } else {
183 check_fail_drvcmd(resp.msgbody())?;
184 Err(WdcError::Buggy) }
186 }
187}