1
//! Helpers for reporting information about guard status to the guard manager.
2

            
3
use std::sync::Mutex;
4
use tor_guardmgr::{GuardMonitor, GuardStatus};
5
use tor_proto::ClockSkew;
6

            
7
/// A shareable object that we can use to report guard status to the guard
8
/// manager.
9
pub(crate) struct GuardStatusHandle {
10
    /// An inner guard monitor.
11
    ///
12
    /// If this is None, then either we aren't using the guard
13
    /// manager, or we already reported a status to it.
14
    mon: Mutex<Option<GuardMonitor>>,
15
}
16

            
17
impl From<Option<GuardMonitor>> for GuardStatusHandle {
18
16
    fn from(mon: Option<GuardMonitor>) -> Self {
19
16
        Self {
20
16
            mon: Mutex::new(mon),
21
16
        }
22
16
    }
23
}
24

            
25
impl GuardStatusHandle {
26
    /// Finalize this guard status handle, and report its pending status
27
    /// to the guard manager.
28
    ///
29
    /// Future calls to methods on this object will do nothing.
30
    pub(crate) fn commit(&self) {
31
        let mut mon = self.mon.lock().expect("Poisoned lock");
32
        if let Some(mon) = mon.take() {
33
            mon.commit();
34
        }
35
    }
36

            
37
    /// Change the pending status on this guard.
38
    ///
39
    /// Note that the pending status will not be sent to the guard manager
40
    /// immediately: only committing this GuardStatusHandle, or dropping it,
41
    /// will do so.
42
28
    pub(crate) fn pending(&self, status: GuardStatus) {
43
28
        let mut mon = self.mon.lock().expect("Poisoned lock");
44
28
        if let Some(mon) = mon.as_mut() {
45
            mon.pending_status(status);
46
28
        }
47
28
    }
48

            
49
    /// Change the pending clock skew for this guard.
50
    ///
51
    /// As with pending status, this value won't be sent to the guard manager
52
    /// until this `GuardStatusHandle` is dropped or committed.
53
    pub(crate) fn skew(&self, skew: ClockSkew) {
54
        let mut mon = self.mon.lock().expect("Poisoned lock");
55
        if let Some(mon) = mon.as_mut() {
56
            mon.skew(skew);
57
        }
58
    }
59

            
60
    /// Report the provided status to the guard manager.
61
    ///
62
    /// Future calls to methods on this object will do nothing.
63
    pub(crate) fn report(&self, status: GuardStatus) {
64
        let mut mon = self.mon.lock().expect("Poisoned lock");
65
        if let Some(mon) = mon.take() {
66
            mon.report(status);
67
        }
68
    }
69
}