1use std::net::SocketAddr;
2
3use crate::client::RaknetClientEvent;
4use crate::proxy::RaknetRelayProxyEvent;
5use crate::server::{PeerId, RaknetServerEvent};
6use crate::transport::TransportMetricsSnapshot;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum RaknetEventSource {
10 Server,
11 Client,
12 Proxy,
13}
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub enum RaknetEventKind {
17 Connected,
18 Disconnected,
19 Packet,
20 OfflinePacket,
21 Forwarded,
22 Dropped,
23 ReceiptAcked,
24 DecodeError,
25 RateLimited,
26 SessionLimitReached,
27 ProxyDropped,
28 WorkerError,
29 WorkerStopped,
30 Metrics,
31}
32
33#[derive(Debug)]
34pub enum RaknetEvent {
35 Server(RaknetServerEvent),
36 Client(RaknetClientEvent),
37 Proxy(RaknetRelayProxyEvent),
38}
39
40impl RaknetEvent {
41 pub fn source(&self) -> RaknetEventSource {
42 match self {
43 Self::Server(_) => RaknetEventSource::Server,
44 Self::Client(_) => RaknetEventSource::Client,
45 Self::Proxy(_) => RaknetEventSource::Proxy,
46 }
47 }
48
49 pub fn kind(&self) -> RaknetEventKind {
50 match self {
51 Self::Server(event) => match event {
52 RaknetServerEvent::PeerConnected { .. } => RaknetEventKind::Connected,
53 RaknetServerEvent::PeerDisconnected { .. } => RaknetEventKind::Disconnected,
54 RaknetServerEvent::Packet { .. } => RaknetEventKind::Packet,
55 RaknetServerEvent::OfflinePacket { .. } => RaknetEventKind::OfflinePacket,
56 RaknetServerEvent::ReceiptAcked { .. } => RaknetEventKind::ReceiptAcked,
57 RaknetServerEvent::PeerRateLimited { .. } => RaknetEventKind::RateLimited,
58 RaknetServerEvent::SessionLimitReached { .. } => {
59 RaknetEventKind::SessionLimitReached
60 }
61 RaknetServerEvent::ProxyDropped { .. } => RaknetEventKind::ProxyDropped,
62 RaknetServerEvent::DecodeError { .. } => RaknetEventKind::DecodeError,
63 RaknetServerEvent::WorkerError { .. } => RaknetEventKind::WorkerError,
64 RaknetServerEvent::WorkerStopped { .. } => RaknetEventKind::WorkerStopped,
65 RaknetServerEvent::Metrics { .. } => RaknetEventKind::Metrics,
66 },
67 Self::Client(event) => match event {
68 RaknetClientEvent::Connected { .. } => RaknetEventKind::Connected,
69 RaknetClientEvent::Packet { .. } => RaknetEventKind::Packet,
70 RaknetClientEvent::ReceiptAcked { .. } => RaknetEventKind::ReceiptAcked,
71 RaknetClientEvent::DecodeError { .. } => RaknetEventKind::DecodeError,
72 RaknetClientEvent::Disconnected { .. } => RaknetEventKind::Disconnected,
73 },
74 Self::Proxy(event) => match event {
75 RaknetRelayProxyEvent::SessionStarted { .. } => RaknetEventKind::Connected,
76 RaknetRelayProxyEvent::Forwarded { .. } => RaknetEventKind::Forwarded,
77 RaknetRelayProxyEvent::Dropped { .. } => RaknetEventKind::Dropped,
78 RaknetRelayProxyEvent::DecodeError { .. } => RaknetEventKind::DecodeError,
79 RaknetRelayProxyEvent::SessionClosed { .. } => RaknetEventKind::Disconnected,
80 RaknetRelayProxyEvent::DownstreamRateLimited { .. } => RaknetEventKind::RateLimited,
81 RaknetRelayProxyEvent::DownstreamSessionLimitReached { .. } => {
82 RaknetEventKind::SessionLimitReached
83 }
84 RaknetRelayProxyEvent::DownstreamProxyDropped { .. } => {
85 RaknetEventKind::ProxyDropped
86 }
87 RaknetRelayProxyEvent::DownstreamDecodeError { .. } => RaknetEventKind::DecodeError,
88 RaknetRelayProxyEvent::DownstreamWorkerError { .. } => RaknetEventKind::WorkerError,
89 RaknetRelayProxyEvent::DownstreamWorkerStopped { .. } => {
90 RaknetEventKind::WorkerStopped
91 }
92 },
93 }
94 }
95
96 pub fn peer_id(&self) -> Option<PeerId> {
97 match self {
98 Self::Server(event) => match event {
99 RaknetServerEvent::PeerConnected { peer_id, .. }
100 | RaknetServerEvent::PeerDisconnected { peer_id, .. }
101 | RaknetServerEvent::Packet { peer_id, .. }
102 | RaknetServerEvent::ReceiptAcked { peer_id, .. } => Some(*peer_id),
103 RaknetServerEvent::OfflinePacket { .. }
104 | RaknetServerEvent::PeerRateLimited { .. }
105 | RaknetServerEvent::SessionLimitReached { .. }
106 | RaknetServerEvent::ProxyDropped { .. }
107 | RaknetServerEvent::DecodeError { .. }
108 | RaknetServerEvent::WorkerError { .. }
109 | RaknetServerEvent::WorkerStopped { .. }
110 | RaknetServerEvent::Metrics { .. } => None,
111 },
112 Self::Client(_) => None,
113 Self::Proxy(event) => match event {
114 RaknetRelayProxyEvent::SessionStarted { peer_id, .. }
115 | RaknetRelayProxyEvent::Forwarded { peer_id, .. }
116 | RaknetRelayProxyEvent::Dropped { peer_id, .. }
117 | RaknetRelayProxyEvent::DecodeError { peer_id, .. }
118 | RaknetRelayProxyEvent::SessionClosed { peer_id, .. } => Some(*peer_id),
119 RaknetRelayProxyEvent::DownstreamRateLimited { .. }
120 | RaknetRelayProxyEvent::DownstreamSessionLimitReached { .. }
121 | RaknetRelayProxyEvent::DownstreamProxyDropped { .. }
122 | RaknetRelayProxyEvent::DownstreamDecodeError { .. }
123 | RaknetRelayProxyEvent::DownstreamWorkerError { .. }
124 | RaknetRelayProxyEvent::DownstreamWorkerStopped { .. } => None,
125 },
126 }
127 }
128
129 pub fn primary_addr(&self) -> Option<SocketAddr> {
130 match self {
131 Self::Server(event) => match event {
132 RaknetServerEvent::PeerConnected { addr, .. }
133 | RaknetServerEvent::PeerDisconnected { addr, .. }
134 | RaknetServerEvent::Packet { addr, .. }
135 | RaknetServerEvent::OfflinePacket { addr, .. }
136 | RaknetServerEvent::ReceiptAcked { addr, .. }
137 | RaknetServerEvent::PeerRateLimited { addr }
138 | RaknetServerEvent::SessionLimitReached { addr }
139 | RaknetServerEvent::ProxyDropped { addr }
140 | RaknetServerEvent::DecodeError { addr, .. } => Some(*addr),
141 RaknetServerEvent::WorkerError { .. }
142 | RaknetServerEvent::WorkerStopped { .. }
143 | RaknetServerEvent::Metrics { .. } => None,
144 },
145 Self::Client(event) => match event {
146 RaknetClientEvent::Connected { server_addr, .. } => Some(*server_addr),
147 RaknetClientEvent::Packet { .. }
148 | RaknetClientEvent::ReceiptAcked { .. }
149 | RaknetClientEvent::DecodeError { .. }
150 | RaknetClientEvent::Disconnected { .. } => None,
151 },
152 Self::Proxy(event) => match event {
153 RaknetRelayProxyEvent::SessionStarted {
154 downstream_addr, ..
155 }
156 | RaknetRelayProxyEvent::DownstreamRateLimited {
157 addr: downstream_addr,
158 }
159 | RaknetRelayProxyEvent::DownstreamSessionLimitReached {
160 addr: downstream_addr,
161 }
162 | RaknetRelayProxyEvent::DownstreamProxyDropped {
163 addr: downstream_addr,
164 }
165 | RaknetRelayProxyEvent::DownstreamDecodeError {
166 addr: downstream_addr,
167 ..
168 } => Some(*downstream_addr),
169 RaknetRelayProxyEvent::Forwarded { .. }
170 | RaknetRelayProxyEvent::Dropped { .. }
171 | RaknetRelayProxyEvent::DecodeError { .. }
172 | RaknetRelayProxyEvent::SessionClosed { .. }
173 | RaknetRelayProxyEvent::DownstreamWorkerError { .. }
174 | RaknetRelayProxyEvent::DownstreamWorkerStopped { .. } => None,
175 },
176 }
177 }
178
179 pub fn payload_len(&self) -> Option<usize> {
180 match self {
181 Self::Server(event) => match event {
182 RaknetServerEvent::Packet { payload, .. } => Some(payload.len()),
183 _ => None,
184 },
185 Self::Client(event) => match event {
186 RaknetClientEvent::Packet { payload, .. } => Some(payload.len()),
187 _ => None,
188 },
189 Self::Proxy(event) => match event {
190 RaknetRelayProxyEvent::Forwarded { payload_len, .. } => Some(*payload_len),
191 _ => None,
192 },
193 }
194 }
195
196 pub fn decode_error(&self) -> Option<&str> {
197 match self {
198 Self::Server(event) => match event {
199 RaknetServerEvent::DecodeError { error, .. } => Some(error.as_str()),
200 _ => None,
201 },
202 Self::Client(event) => match event {
203 RaknetClientEvent::DecodeError { error } => Some(error.as_str()),
204 _ => None,
205 },
206 Self::Proxy(event) => match event {
207 RaknetRelayProxyEvent::DecodeError { error, .. }
208 | RaknetRelayProxyEvent::DownstreamDecodeError { error, .. } => {
209 Some(error.as_str())
210 }
211 _ => None,
212 },
213 }
214 }
215
216 pub fn metrics_snapshot(&self) -> Option<(usize, &TransportMetricsSnapshot, u64)> {
217 match self {
218 Self::Server(RaknetServerEvent::Metrics {
219 shard_id,
220 snapshot,
221 dropped_non_critical_events,
222 }) => Some((*shard_id, snapshot.as_ref(), *dropped_non_critical_events)),
223 _ => None,
224 }
225 }
226
227 pub fn as_server(&self) -> Option<&RaknetServerEvent> {
228 match self {
229 Self::Server(event) => Some(event),
230 _ => None,
231 }
232 }
233
234 pub fn as_client(&self) -> Option<&RaknetClientEvent> {
235 match self {
236 Self::Client(event) => Some(event),
237 _ => None,
238 }
239 }
240
241 pub fn as_proxy(&self) -> Option<&RaknetRelayProxyEvent> {
242 match self {
243 Self::Proxy(event) => Some(event),
244 _ => None,
245 }
246 }
247}
248
249impl From<RaknetServerEvent> for RaknetEvent {
250 fn from(value: RaknetServerEvent) -> Self {
251 Self::Server(value)
252 }
253}
254
255impl From<RaknetClientEvent> for RaknetEvent {
256 fn from(value: RaknetClientEvent) -> Self {
257 Self::Client(value)
258 }
259}
260
261impl From<RaknetRelayProxyEvent> for RaknetEvent {
262 fn from(value: RaknetRelayProxyEvent) -> Self {
263 Self::Proxy(value)
264 }
265}
266
267#[cfg(test)]
268mod tests {
269 use bytes::Bytes;
270
271 use super::{RaknetEvent, RaknetEventKind, RaknetEventSource};
272 use crate::client::RaknetClientEvent;
273 use crate::handshake::{OfflinePacket, UnconnectedPing};
274 use crate::protocol::constants::DEFAULT_UNCONNECTED_MAGIC;
275 use crate::protocol::reliability::Reliability;
276 use crate::proxy::{
277 RaknetRelayProxyEvent, RelayDirection, RelayDropReason, RelaySessionCloseReason,
278 };
279 use crate::server::{PeerDisconnectReason, PeerId, RaknetServerEvent};
280 use crate::transport::TransportMetricsSnapshot;
281
282 #[test]
283 fn server_packet_maps_to_common_fields() {
284 let peer_id = PeerId::from_u64(7);
285 let addr = "127.0.0.1:19132".parse().expect("valid socket addr");
286 let event = RaknetEvent::from(RaknetServerEvent::Packet {
287 peer_id,
288 addr,
289 payload: Bytes::from_static(b"abc"),
290 reliability: Reliability::ReliableOrdered,
291 reliable_index: None,
292 sequence_index: None,
293 ordering_index: None,
294 ordering_channel: Some(0),
295 });
296
297 assert_eq!(event.source(), RaknetEventSource::Server);
298 assert_eq!(event.kind(), RaknetEventKind::Packet);
299 assert_eq!(event.peer_id(), Some(peer_id));
300 assert_eq!(event.primary_addr(), Some(addr));
301 assert_eq!(event.payload_len(), Some(3));
302 }
303
304 #[test]
305 fn client_decode_error_is_exposed() {
306 let event = RaknetEvent::from(RaknetClientEvent::DecodeError {
307 error: "bad packet".to_string(),
308 });
309
310 assert_eq!(event.source(), RaknetEventSource::Client);
311 assert_eq!(event.kind(), RaknetEventKind::DecodeError);
312 assert_eq!(event.decode_error(), Some("bad packet"));
313 assert!(event.peer_id().is_none());
314 assert!(event.primary_addr().is_none());
315 }
316
317 #[test]
318 fn proxy_drop_maps_to_common_kind_and_peer() {
319 let peer_id = PeerId::from_u64(99);
320 let event = RaknetEvent::from(RaknetRelayProxyEvent::Dropped {
321 peer_id,
322 direction: RelayDirection::DownstreamToUpstream,
323 reason: RelayDropReason::NoSession,
324 });
325
326 assert_eq!(event.source(), RaknetEventSource::Proxy);
327 assert_eq!(event.kind(), RaknetEventKind::Dropped);
328 assert_eq!(event.peer_id(), Some(peer_id));
329 assert!(event.primary_addr().is_none());
330 }
331
332 #[test]
333 fn server_metrics_can_be_extracted() {
334 let snapshot = TransportMetricsSnapshot {
335 session_count: 3,
336 ..TransportMetricsSnapshot::default()
337 };
338
339 let event = RaknetEvent::from(RaknetServerEvent::Metrics {
340 shard_id: 2,
341 snapshot: Box::new(snapshot),
342 dropped_non_critical_events: 17,
343 });
344
345 let (shard_id, extracted_snapshot, dropped) =
346 event.metrics_snapshot().expect("metrics must be present");
347 assert_eq!(shard_id, 2);
348 assert_eq!(dropped, 17);
349 assert_eq!(extracted_snapshot.session_count, 3);
350 }
351
352 #[test]
353 fn disconnected_kind_is_normalized_across_sources() {
354 let server_peer_id = PeerId::from_u64(1);
355 let server_addr = "127.0.0.1:19132".parse().expect("valid socket addr");
356 let server_event = RaknetEvent::from(RaknetServerEvent::PeerDisconnected {
357 peer_id: server_peer_id,
358 addr: server_addr,
359 reason: PeerDisconnectReason::Requested,
360 });
361 assert_eq!(server_event.kind(), RaknetEventKind::Disconnected);
362
363 let client_event = RaknetEvent::from(RaknetClientEvent::Disconnected {
364 reason: crate::client::ClientDisconnectReason::Requested,
365 });
366 assert_eq!(client_event.kind(), RaknetEventKind::Disconnected);
367
368 let proxy_event = RaknetEvent::from(RaknetRelayProxyEvent::SessionClosed {
369 peer_id: server_peer_id,
370 reason: RelaySessionCloseReason::ProxyShutdown,
371 });
372 assert_eq!(proxy_event.kind(), RaknetEventKind::Disconnected);
373 }
374
375 #[test]
376 fn server_offline_packet_maps_to_common_fields() {
377 let addr = "127.0.0.1:19132".parse().expect("valid socket addr");
378 let event = RaknetEvent::from(RaknetServerEvent::OfflinePacket {
379 addr,
380 packet: OfflinePacket::UnconnectedPing(UnconnectedPing {
381 ping_time: 123,
382 client_guid: 456,
383 magic: DEFAULT_UNCONNECTED_MAGIC,
384 }),
385 });
386
387 assert_eq!(event.source(), RaknetEventSource::Server);
388 assert_eq!(event.kind(), RaknetEventKind::OfflinePacket);
389 assert_eq!(event.primary_addr(), Some(addr));
390 assert!(event.peer_id().is_none());
391 assert!(event.payload_len().is_none());
392 }
393}