Skip to main content

freeswitch_types/sofia/
gateway.rs

1//! Gateway registration state and ping status enums.
2
3use std::fmt;
4use std::str::FromStr;
5
6/// Error returned when parsing an unrecognized gateway registration state.
7#[derive(Debug, Clone, PartialEq, Eq)]
8pub struct ParseGatewayRegStateError(pub String);
9
10impl fmt::Display for ParseGatewayRegStateError {
11    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
12        write!(f, "unknown gateway reg state: {}", self.0)
13    }
14}
15
16impl std::error::Error for ParseGatewayRegStateError {}
17
18/// Gateway registration state from `sofia::gateway_state` events.
19///
20/// The `State` header value, mapping to `reg_state_t` / `sofia_state_names[]`
21/// in mod_sofia.
22#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
23#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
24#[non_exhaustive]
25#[allow(missing_docs)]
26pub enum GatewayRegState {
27    Unreged,
28    Trying,
29    Register,
30    Reged,
31    Unregister,
32    Failed,
33    FailWait,
34    Expired,
35    Noreg,
36    Down,
37    Timeout,
38}
39
40impl GatewayRegState {
41    /// Wire-format string matching `sofia_state_names[]`.
42    pub const fn as_str(&self) -> &'static str {
43        match self {
44            Self::Unreged => "UNREGED",
45            Self::Trying => "TRYING",
46            Self::Register => "REGISTER",
47            Self::Reged => "REGED",
48            Self::Unregister => "UNREGISTER",
49            Self::Failed => "FAILED",
50            Self::FailWait => "FAIL_WAIT",
51            Self::Expired => "EXPIRED",
52            Self::Noreg => "NOREG",
53            Self::Down => "DOWN",
54            Self::Timeout => "TIMEOUT",
55        }
56    }
57}
58
59impl fmt::Display for GatewayRegState {
60    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61        f.write_str(self.as_str())
62    }
63}
64
65impl FromStr for GatewayRegState {
66    type Err = ParseGatewayRegStateError;
67
68    fn from_str(s: &str) -> Result<Self, Self::Err> {
69        match s {
70            "UNREGED" => Ok(Self::Unreged),
71            "TRYING" => Ok(Self::Trying),
72            "REGISTER" => Ok(Self::Register),
73            "REGED" => Ok(Self::Reged),
74            "UNREGISTER" => Ok(Self::Unregister),
75            "FAILED" => Ok(Self::Failed),
76            "FAIL_WAIT" => Ok(Self::FailWait),
77            "EXPIRED" => Ok(Self::Expired),
78            "NOREG" => Ok(Self::Noreg),
79            "DOWN" => Ok(Self::Down),
80            "TIMEOUT" => Ok(Self::Timeout),
81            _ => Err(ParseGatewayRegStateError(s.to_string())),
82        }
83    }
84}
85
86/// Error returned when parsing an unrecognized gateway ping status.
87#[derive(Debug, Clone, PartialEq, Eq)]
88pub struct ParseGatewayPingStatusError(pub String);
89
90impl fmt::Display for ParseGatewayPingStatusError {
91    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
92        write!(f, "unknown gateway ping status: {}", self.0)
93    }
94}
95
96impl std::error::Error for ParseGatewayPingStatusError {}
97
98/// Gateway ping status from `sofia::gateway_state` events.
99///
100/// The `Ping-Status` header value, mapping to `sofia_gateway_status_name()`.
101#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
102#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
103#[non_exhaustive]
104#[allow(missing_docs)]
105pub enum GatewayPingStatus {
106    Down,
107    Up,
108    Invalid,
109}
110
111impl GatewayPingStatus {
112    /// Wire-format string.
113    pub const fn as_str(&self) -> &'static str {
114        match self {
115            Self::Down => "DOWN",
116            Self::Up => "UP",
117            Self::Invalid => "INVALID",
118        }
119    }
120}
121
122impl fmt::Display for GatewayPingStatus {
123    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
124        f.write_str(self.as_str())
125    }
126}
127
128impl FromStr for GatewayPingStatus {
129    type Err = ParseGatewayPingStatusError;
130
131    fn from_str(s: &str) -> Result<Self, Self::Err> {
132        match s {
133            "DOWN" => Ok(Self::Down),
134            "UP" => Ok(Self::Up),
135            "INVALID" => Ok(Self::Invalid),
136            _ => Err(ParseGatewayPingStatusError(s.to_string())),
137        }
138    }
139}
140
141#[cfg(test)]
142mod tests {
143    use super::*;
144
145    const ALL_REG_STATES: &[GatewayRegState] = &[
146        GatewayRegState::Unreged,
147        GatewayRegState::Trying,
148        GatewayRegState::Register,
149        GatewayRegState::Reged,
150        GatewayRegState::Unregister,
151        GatewayRegState::Failed,
152        GatewayRegState::FailWait,
153        GatewayRegState::Expired,
154        GatewayRegState::Noreg,
155        GatewayRegState::Down,
156        GatewayRegState::Timeout,
157    ];
158
159    #[test]
160    fn reg_state_round_trip() {
161        for &state in ALL_REG_STATES {
162            let wire = state.to_string();
163            let parsed: GatewayRegState = wire
164                .parse()
165                .unwrap();
166            assert_eq!(parsed, state, "round-trip failed for {wire}");
167        }
168    }
169
170    #[test]
171    fn reg_state_count() {
172        assert_eq!(ALL_REG_STATES.len(), 11);
173    }
174
175    #[test]
176    fn reg_state_rejects_unknown() {
177        assert!("BOGUS"
178            .parse::<GatewayRegState>()
179            .is_err());
180        assert!("reged"
181            .parse::<GatewayRegState>()
182            .is_err());
183    }
184
185    const ALL_PING_STATUSES: &[GatewayPingStatus] = &[
186        GatewayPingStatus::Down,
187        GatewayPingStatus::Up,
188        GatewayPingStatus::Invalid,
189    ];
190
191    #[test]
192    fn ping_status_round_trip() {
193        for &status in ALL_PING_STATUSES {
194            let wire = status.to_string();
195            let parsed: GatewayPingStatus = wire
196                .parse()
197                .unwrap();
198            assert_eq!(parsed, status, "round-trip failed for {wire}");
199        }
200    }
201
202    #[test]
203    fn ping_status_rejects_unknown() {
204        assert!("BOGUS"
205            .parse::<GatewayPingStatus>()
206            .is_err());
207        assert!("up"
208            .parse::<GatewayPingStatus>()
209            .is_err());
210    }
211}