1use crate::StunPacket;
2use log::warn;
3use std::time::Duration;
4use stun_rs::{StunMessage, TransactionId};
5
6#[derive(Debug)]
8pub enum StuntClientEvent {
9 OutputPacket(StunPacket),
11 RestransmissionTimeOut((TransactionId, Duration)),
17 Retry(TransactionId),
19 TransactionFailed((TransactionId, StunTransactionError)),
22 StunMessageReceived(StunMessage),
24}
25
26#[derive(Debug, Eq, PartialEq)]
28pub enum StunTransactionError {
29 DoNotRetry,
31 InvalidFingerprint,
33 NotFound,
35 ProtectionViolated,
37 TimedOut,
39}
40
41#[derive(Debug, Default)]
42pub struct TransactionEventHandler {
43 events: Vec<StuntClientEvent>,
44}
45
46impl TransactionEventHandler {
47 pub fn init(&mut self) -> TransactionEvents {
48 TransactionEvents {
49 handler: self,
50 events: Vec::new(),
51 }
52 }
53
54 pub fn events(&mut self) -> Vec<StuntClientEvent> {
55 std::mem::take(&mut self.events)
56 }
57}
58
59#[derive(Debug)]
60pub struct TransactionEvents<'a> {
61 handler: &'a mut TransactionEventHandler,
62 events: Vec<StuntClientEvent>,
63}
64
65impl TransactionEvents<'_> {
66 pub fn push(&mut self, event: StuntClientEvent) {
67 self.events.push(event);
68 }
69}
70
71impl Drop for TransactionEvents<'_> {
72 fn drop(&mut self) {
73 if self.events.is_empty() {
74 return;
76 }
77
78 std::mem::swap(&mut self.handler.events, &mut self.events);
79
80 if !self.events.is_empty() {
81 warn!(
82 "Transaction events were committed without consuming {} the events.",
83 self.events.len()
84 );
85 }
86 }
87}
88
89#[cfg(test)]
90mod stun_event_tests {
91 use stun_rs::TransactionId;
92
93 use super::*;
94
95 fn init_logging() {
96 let _ = env_logger::builder().is_test(true).try_init();
97 }
98
99 #[test]
100 fn test_transaction_events_drop() {
101 init_logging();
102
103 let mut handler = TransactionEventHandler::default();
104
105 let events = handler.events();
106 assert!(events.is_empty());
107
108 {
109 let mut events = handler.init();
110
111 events.push(StuntClientEvent::Retry(TransactionId::default()));
112 events.push(StuntClientEvent::Retry(TransactionId::default()));
113 }
114
115 let events = handler.events();
117 assert_eq!(events.len(), 2);
118
119 let events = handler.events();
121 assert_eq!(events.len(), 0);
122 }
123
124 #[test]
125 fn test_transaction_events_drop_no_events() {
126 init_logging();
127
128 let mut handler = TransactionEventHandler::default();
129 {
130 let mut _events = handler.init();
131 }
132
133 let events = handler.events();
134 assert!(events.is_empty());
135 }
136
137 #[test]
138 fn test_transaction_events_drop_no_commit() {
139 init_logging();
140
141 let mut handler = TransactionEventHandler::default();
142 {
143 let mut events = handler.init();
144 events.push(StuntClientEvent::Retry(TransactionId::default()));
145 }
146
147 {
148 let mut events = handler.init();
151 events.push(StuntClientEvent::Retry(TransactionId::default()));
152 events.push(StuntClientEvent::Retry(TransactionId::default()));
153 events.push(StuntClientEvent::Retry(TransactionId::default()));
154 }
155
156 let events = handler.events();
158 assert_eq!(events.len(), 3);
159 }
160}