tokio_watchdog/
lib.rs

1#![deny(missing_docs)]
2
3//! Docs are on the way. API is unstable, submit your ideas though Github issues.
4//! Otherwise see README for API excerpt and example.
5//!
6//! Main struct is `Watchdog`.
7
8extern crate tokio_timer;
9extern crate futures;
10
11
12use tokio_timer::Delay;
13use futures::Future;
14use futures::Async;
15
16use std::sync::Arc;
17use std::sync::Mutex;
18
19use std::time::{Duration, Instant};
20
21struct Impl {
22    /// the main thing
23    del : Option<Delay>,
24    /// saved duration for petting and rearming
25    dur : Duration,
26    /// used to track pets when `del` is None (unarmed)
27    ins : Instant,
28}
29
30type H = Arc<Mutex<Impl>>;
31//type H = Rc<RefCell<Impl>>>;
32
33/// The main struct. A wrapper over `tokio_timer::Delay` that has handles that can `reset` it periodically.
34///
35/// TODO: example
36pub struct Watchdog(H);
37
38impl Watchdog {
39    /// constructor
40    pub fn new(dur: Duration) -> Self {
41        let ins = Instant::now() + dur;
42        let del = Delay::new(ins);
43        let i = Impl { del:Some(del), dur, ins };
44        Watchdog(Arc::new(Mutex::new(i)))
45    }
46    /// Get the duration. Returns 0 on internal error.
47    pub fn duration(&self) -> Duration {
48        if let Ok(g) = self.0.lock() {
49            g.dur
50        } else {
51            Duration::from_secs(0)
52        }
53    }
54    /// Set new duration, also adjusting the timer state
55    pub fn set_duration(&mut self, dur: Duration) {
56        if let Ok(mut g) = self.0.lock() {
57            g.ins = g.ins - g.dur + dur;
58            g.dur = dur;
59            let i = g.ins;
60            if let Some(ref mut d) = g.del {
61                d.reset(i);
62            }
63        }
64    }
65    /// Get the handle for keeping the watchdog from firing
66    pub fn handle(&self) -> Pet {
67        self.into()
68    }
69}
70
71/// Reset/restart the watchdog, so it don't activate
72#[derive(Clone)]
73pub struct Pet(H);
74impl Pet {
75    /// Reset/restart the watchdog, so it don't activate
76    ///
77    /// Call it periodically from various places
78    pub fn pet(&self) {
79        if let Ok(mut g) = self.0.lock() {
80            let i = Instant::now() + g.dur;
81            g.ins = i;
82            if let Some(ref mut x) = g.del {
83                x.reset(i);
84            }
85        } else {
86            // don't know what to do here
87            // XXX
88        }
89    }
90    
91    /// Get how much time remains before the watchdog activates
92    ///
93    /// None means it is already active
94    ///
95    /// Some(0) is returned on internal error
96    pub fn get_remaining_time(&self) -> Option<Duration> {
97        if let Ok(g) = self.0.lock() {
98            let now = Instant::now();
99            let i = g.ins;
100            if now > i {
101                None
102            } else {
103                Some(i - now)
104            }
105        } else {
106            Some(Duration::from_secs(0))
107        }
108    }
109}
110
111impl<'a> From<&'a Watchdog> for Pet {
112    fn from(w : &'a Watchdog) -> Pet {
113        Pet(w.0.clone())
114    }
115}
116
117/// Result returned from a fired Watchdog.
118///
119/// Can be used to rewind (activate again) watchdog, preserving `Pet` handles pointing to it.
120pub struct Rearm(H);
121impl Rearm {
122    /// Rearm with previously used timeout value
123    pub fn rearm(self) -> Watchdog {
124        Watchdog(self.0)
125    }
126    
127    /// Rearm with new timeout value.
128    pub fn rearm_with_duration(self, dur: Duration) -> Watchdog {
129        let mut w = Watchdog(self.0);
130        w.set_duration(dur);
131        w
132    }
133}
134
135impl Future for Watchdog {
136    type Item = Rearm;
137    /// at_capacity error may also be returned on internal Mutex problems
138    type Error = tokio_timer::Error;
139    
140    fn poll(&mut self) -> futures::Poll<Rearm, tokio_timer::Error> {
141        if let Ok(mut g) = self.0.lock() {
142            if let Some(ref mut d) = g.del {
143                match d.poll() {
144                    Ok(Async::Ready(())) => Ok(Async::Ready(
145                        Rearm(self.0.clone())
146                    )),
147                    Ok(Async::NotReady) => Ok(Async::NotReady),
148                    Err(x) => Err(x),
149                }
150            } else {
151                Ok(Async::Ready(Rearm(self.0.clone())))
152            }
153        } else {
154            // unlikely to happen, just some filler
155            Err(tokio_timer::Error::at_capacity())
156        }
157    }
158}
159
160#[cfg(test)]
161mod tests {
162    #[test]
163    fn it_works() {
164    }
165}