1use crate::{SshError, SshResult};
2use std::time::{Duration, Instant};
3
4#[cfg(not(target_arch = "wasm32"))]
5const NANOS_PER_SEC: u64 = 1_000_000_000;
6
7pub(crate) struct Timeout {
8 instant: Instant,
9 timeout: Option<Duration>,
10 wait_tick: u64,
11}
12
13impl Timeout {
14 pub fn new(timeout: Option<Duration>) -> Self {
15 Timeout {
16 instant: Instant::now(),
17 timeout,
18 wait_tick: 1,
19 }
20 }
21
22 fn wait(&mut self) -> u64 {
23 #[cfg(not(target_arch = "wasm32"))]
24 {
25 let sleep_time = Duration::from_nanos(self.wait_tick);
26 std::thread::sleep(sleep_time);
27 if self.wait_tick < NANOS_PER_SEC {
28 self.wait_tick <<= 1;
29 }
30
31 if let Some(timemout) = self.timeout {
32 let timeout_nanos = timemout.as_nanos();
33 let used_nanos = self.instant.elapsed().as_nanos();
34
35 self.wait_tick = {
36 if timeout_nanos > used_nanos
37 && timeout_nanos - used_nanos < self.wait_tick as u128
38 {
39 (timeout_nanos - used_nanos) as u64
40 } else {
41 self.wait_tick
42 }
43 };
44 }
45 }
46 self.wait_tick
47 }
48
49 pub fn till_next_tick(&mut self) -> SshResult<()> {
50 if let Some(t) = self.timeout {
51 if self.instant.elapsed() > t {
52 tracing::error!("time out.");
53 Err(SshError::TimeoutError)
54 } else {
55 self.wait();
56 Ok(())
57 }
58 } else {
59 self.wait();
60 Ok(())
61 }
62 }
63
64 pub fn renew(&mut self) {
65 self.wait_tick = 1
66 }
67}