rak_rs/protocol/packet/
mod.rs

1//! This module contains all the packets that are used by the RakNet protocol.
2//! This module is split into two submodules:
3//! - [`offline`]: Any packet that is not sent within a [`Frame`].
4//! - [`online`]: Any packet considered to be online, which is sent within a [`Frame`].
5//!
6//! [`offline`]: crate::protocol::packet::offline
7//! [`online`]: crate::protocol::packet::online
8// /// Handlers for both online & offline packets!
9// /// This is used by the connection struct to handle packets.
10// pub(crate) mod handler;
11
12pub mod offline;
13pub mod online;
14
15use binary_util::interfaces::{Reader, Writer};
16
17use self::offline::OfflinePacket;
18use self::online::OnlinePacket;
19
20/// A wrapper or helper for both online and offline packets.
21/// This allows for a single type to be read with `Reader` and written with `Writer`,
22/// traits provided by `binary_util`.
23///
24/// All packets sent are wrapped in this type, and can be unwrapped with the `get_offline` or `get_online`
25#[derive(Debug, Clone)]
26pub enum RakPacket {
27    Offline(OfflinePacket),
28    Online(OnlinePacket),
29}
30
31impl RakPacket {
32    pub fn is_online(&self) -> bool {
33        match self {
34            RakPacket::Online(_) => true,
35            _ => false,
36        }
37    }
38
39    pub fn get_offline(&self) -> Option<&OfflinePacket> {
40        match self {
41            RakPacket::Offline(packet) => Some(packet),
42            _ => None,
43        }
44    }
45
46    pub fn get_online(&self) -> Option<&OnlinePacket> {
47        match self {
48            RakPacket::Online(packet) => Some(packet),
49            _ => None,
50        }
51    }
52}
53
54impl Writer for RakPacket {
55    fn write(&self, buf: &mut binary_util::io::ByteWriter) -> Result<(), std::io::Error> {
56        match self {
57            RakPacket::Offline(packet) => packet.write(buf),
58            RakPacket::Online(packet) => packet.write(buf),
59        }
60    }
61}
62
63impl Reader<RakPacket> for RakPacket {
64    fn read(buf: &mut binary_util::ByteReader) -> Result<RakPacket, std::io::Error> {
65        if let Ok(packet) = OfflinePacket::read(buf) {
66            return Ok(RakPacket::Offline(packet));
67        }
68        if let Ok(packet) = OnlinePacket::read(buf) {
69            return Ok(RakPacket::Online(packet));
70        }
71
72        Err(std::io::Error::new(
73            std::io::ErrorKind::InvalidData,
74            "Invalid packet",
75        ))
76    }
77}
78
79impl From<OfflinePacket> for RakPacket {
80    fn from(packet: OfflinePacket) -> Self {
81        RakPacket::Offline(packet)
82    }
83}
84
85impl From<OnlinePacket> for RakPacket {
86    fn from(packet: OnlinePacket) -> Self {
87        RakPacket::Online(packet)
88    }
89}
90
91impl From<RakPacket> for OnlinePacket {
92    fn from(packet: RakPacket) -> Self {
93        match packet {
94            RakPacket::Online(packet) => packet,
95            _ => panic!("Invalid packet conversion"),
96        }
97    }
98}
99
100impl From<RakPacket> for OfflinePacket {
101    fn from(packet: RakPacket) -> Self {
102        match packet {
103            RakPacket::Offline(packet) => packet,
104            _ => panic!("Invalid packet conversion"),
105        }
106    }
107}
108
109/// A utility macro that adds the implementation for any `OnlinePacket(Pk)` where
110/// `Pk` can be converted to `RakPacket`, `OnlinePacket` or `OfflinePacket`
111/// and vice versa.
112///
113/// For example, we want unconnected pong to be unwrapped, we can do this without
114/// a match statement like this:
115/// ```rust ignore
116/// use raknet::packet::RakPacket;
117/// use raknet::packet::online::OnlinePacket;
118/// use raknet::packet::online::UnconnectedPing;
119/// let some_packet = RakPacket::from(&source)?;
120/// let connected_ping: UnconnectedPing = some_packet.into();
121/// ```
122///
123/// This macro also allows for converting any `OnlinePacket(Pk)` to a `RakPacket`, where `Pk` can
124/// be directly converted into a packet. For example:
125/// ```rust ignore
126/// use raknet::packet::Packet;
127/// use raknet::packet::online::OnlinePacket;
128/// use raknet::packet::online::UnconnectedPong;
129///
130/// let packet: Packet = UnconnectedPong {
131///     magic: Magic::new(),
132///     timestamp: SystemTime::now(),
133///     client_id: -129
134/// }.into();
135/// ```
136///
137/// The macro can be expressed in the following way:
138/// ```rust ignore
139/// register_packets! {
140///     Online is OnlinePacket,
141///     UnconnectedPing,
142///     // etc...
143/// }
144/// ```
145#[macro_export]
146macro_rules! register_packets {
147    ($name: ident is $kind: ident, $($packet: ident),*) => {
148        $(
149            impl From<$packet> for $kind {
150                fn from(packet: $packet) -> Self {
151                    $kind::$packet(packet)
152                }
153            }
154
155            impl From<$packet> for RakPacket {
156                fn from(packet: $packet) -> Self {
157                    $kind::$packet(packet).into()
158                }
159            }
160
161            impl From<$kind> for $packet {
162                fn from(packet: $kind) -> Self {
163                    match packet {
164                        $kind::$packet(packet) => packet.into(),
165                        _ => panic!("Invalid packet conversion"),
166                    }
167                }
168            }
169
170            impl From<RakPacket> for $packet {
171                fn from(packet: RakPacket) -> Self {
172                    match packet {
173                        RakPacket::$name(packet) => packet.into(),
174                        _ => panic!("Invalid packet conversion"),
175                    }
176                }
177            }
178        )*
179    };
180}