dstar_gateway_core/session/client/
event.rs1use std::convert::Infallible;
10use std::marker::PhantomData;
11use std::net::SocketAddr;
12
13use crate::header::DStarHeader;
14use crate::types::StreamId;
15use crate::validator::Diagnostic;
16use crate::voice::VoiceFrame;
17
18use super::protocol::Protocol;
19
20#[non_exhaustive]
31#[derive(Debug, Clone)]
32pub enum Event<P: Protocol> {
33 Connected {
35 peer: SocketAddr,
37 },
38
39 Disconnected {
41 reason: DisconnectReason,
43 },
44
45 PollEcho {
47 peer: SocketAddr,
49 },
50
51 VoiceStart {
53 stream_id: StreamId,
55 header: DStarHeader,
57 diagnostics: Vec<Diagnostic>,
59 },
60
61 VoiceFrame {
63 stream_id: StreamId,
65 seq: u8,
67 frame: VoiceFrame,
69 },
70
71 VoiceEnd {
73 stream_id: StreamId,
75 reason: VoiceEndReason,
77 },
78
79 #[doc(hidden)]
86 __Phantom {
87 never: Infallible,
89 _protocol: PhantomData<P>,
91 },
92}
93
94#[non_exhaustive]
96#[derive(Debug, Clone, Copy, PartialEq, Eq)]
97pub enum DisconnectReason {
98 Rejected,
100 UnlinkAcked,
102 KeepaliveInactivity,
104 DisconnectTimeout,
106}
107
108#[non_exhaustive]
110#[derive(Debug, Clone, Copy, PartialEq, Eq)]
111pub enum VoiceEndReason {
112 Eot,
114 Inactivity,
117}
118
119#[cfg(test)]
120mod tests {
121 use super::*;
122 use crate::session::client::protocol::{DExtra, DPlus, Dcs};
123 use std::net::{IpAddr, Ipv4Addr};
124
125 const ADDR_DEXTRA: SocketAddr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 30001);
126 const ADDR_DPLUS: SocketAddr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 20001);
127 const ADDR_DCS: SocketAddr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 30051);
128
129 #[test]
130 fn event_connected_constructible_dextra() {
131 let e: Event<DExtra> = Event::Connected { peer: ADDR_DEXTRA };
132 assert!(matches!(e, Event::Connected { .. }));
133 }
134
135 #[test]
136 fn event_connected_constructible_dplus() {
137 let e: Event<DPlus> = Event::Connected { peer: ADDR_DPLUS };
138 assert!(matches!(e, Event::Connected { .. }));
139 }
140
141 #[test]
142 fn event_connected_constructible_dcs() {
143 let e: Event<Dcs> = Event::Connected { peer: ADDR_DCS };
144 assert!(matches!(e, Event::Connected { .. }));
145 }
146
147 #[test]
148 fn event_disconnected_carries_reason() {
149 let e: Event<DExtra> = Event::Disconnected {
150 reason: DisconnectReason::KeepaliveInactivity,
151 };
152 assert!(
153 matches!(e, Event::Disconnected { reason } if reason == DisconnectReason::KeepaliveInactivity),
154 "expected Disconnected/KeepaliveInactivity, got {e:?}"
155 );
156 }
157
158 #[test]
159 fn event_poll_echo_carries_peer() {
160 let e: Event<DExtra> = Event::PollEcho { peer: ADDR_DEXTRA };
161 assert!(
162 matches!(e, Event::PollEcho { peer } if peer == ADDR_DEXTRA),
163 "expected PollEcho, got {e:?}"
164 );
165 }
166
167 #[test]
168 fn disconnect_reason_variants_distinct() {
169 assert_ne!(DisconnectReason::Rejected, DisconnectReason::UnlinkAcked);
170 assert_ne!(
171 DisconnectReason::KeepaliveInactivity,
172 DisconnectReason::DisconnectTimeout
173 );
174 }
175
176 #[test]
177 fn voice_end_reason_variants_distinct() {
178 assert_ne!(VoiceEndReason::Eot, VoiceEndReason::Inactivity);
179 }
180}