Poll the page, stream each new raw stdout chunk, and resolve when the current eval finishes.
(tab: &headless_chrome::Tab, on_line: &mut F)
| 177 | |
| 178 | /// Poll the page, stream each new raw stdout chunk, and resolve when the current eval finishes. |
| 179 | fn drain<F: FnMut(&str)>(tab: &headless_chrome::Tab, on_line: &mut F) -> Result<Outcome> { |
| 180 | let mut printed = 0usize; |
| 181 | let deadline = Instant::now() + EVAL_TIMEOUT; |
| 182 | |
| 183 | loop { |
| 184 | if Instant::now() > deadline { |
| 185 | bail!("timed out after {}s waiting for the script", EVAL_TIMEOUT.as_secs()); |
| 186 | } |
| 187 | let raw = tab.evaluate(POLL_JS, false).map_err(|e| anyhow!("reading page state: {e}"))?; |
| 188 | let json = raw.value.as_ref().and_then(|v| v.as_str()).unwrap_or(""); |
| 189 | if json.is_empty() { |
| 190 | thread::sleep(Duration::from_millis(60)); |
| 191 | continue; |
| 192 | } |
| 193 | let state: State = serde_json::from_str(json).context("parsing page state")?; |
| 194 | for line in state.lines.iter().skip(printed) { |
| 195 | on_line(line); |
| 196 | } |
| 197 | printed = state.lines.len(); |
| 198 | if state.done { |
| 199 | return Ok(Outcome { err: if state.ok { None } else { Some(state.err) }, exit_code: state.code }); |
| 200 | } |
| 201 | thread::sleep(Duration::from_millis(60)); |
| 202 | } |
| 203 | } |
| 204 | |
| 205 | /// Serve the harness at `/` and the manifest at `/packages.json` on a free loopback port. The thread is a daemon. |
| 206 | fn serve(packages: String) -> Result<u16> { |