ssh/model/
timeout.rs

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}