Skip to main content

portmapper/
observer.rs

1//! Optional lifecycle observations. Observers never authorize a mapping.
2use std::{
3    fmt,
4    net::{Ipv4Addr, SocketAddrV4},
5    sync::Arc,
6    time::Duration,
7};
8
9/// The gateway protocol chosen for an operation.
10#[derive(Clone, Copy, Debug, PartialEq, Eq)]
11pub enum MappingProtocol {
12    Pcp,
13    NatPmp,
14    Upnp,
15}
16
17/// An actual service transition, including renewals that keep the same address.
18#[derive(Clone, Debug)]
19#[non_exhaustive]
20pub enum Event {
21    Discovering,
22    Gateway {
23        local_ip: Ipv4Addr,
24        gateway: Ipv4Addr,
25    },
26    Discovered(super::ProbeOutput),
27    DiscoveryFailed(String),
28    Requesting {
29        protocol: MappingProtocol,
30        gateway: Ipv4Addr,
31        renewal: bool,
32    },
33    Active {
34        protocol: MappingProtocol,
35        external: SocketAddrV4,
36        lifetime: Duration,
37    },
38    MappingFailed(String),
39    Expired(SocketAddrV4),
40    Cancelled,
41    Releasing(SocketAddrV4),
42    /// `confirmed` is false for PCP/NAT-PMP, whose deletion is sent without
43    /// awaiting an acknowledgement, and true for a successful UPnP response.
44    Released {
45        external: SocketAddrV4,
46        confirmed: bool,
47    },
48    ReleaseFailed {
49        external: SocketAddrV4,
50        error: String,
51    },
52}
53
54/// A synchronous, non-blocking observer. Callbacks must not panic or call back
55/// into the service. Without an observer there is no event queue or task.
56#[derive(Clone, Default)]
57pub struct Observer(Option<Arc<dyn Fn(Event) + Send + Sync>>);
58
59impl Observer {
60    pub fn new(callback: impl Fn(Event) + Send + Sync + 'static) -> Self {
61        Self(Some(Arc::new(callback)))
62    }
63    pub(crate) fn emit(&self, event: Event) {
64        if let Some(callback) = &self.0 {
65            callback(event);
66        }
67    }
68}
69impl fmt::Debug for Observer {
70    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
71        f.debug_struct("Observer")
72            .field("enabled", &self.0.is_some())
73            .finish()
74    }
75}
76
77pub(crate) fn detail(error: impl fmt::Display) -> String {
78    error.to_string().chars().take(256).collect()
79}