f1_api/packet.rs
1//! Packets that are sent by modern F1 games
2//!
3//! This library implements a single packet format for all the F1 games it supports. The API
4//! specification has been slowly evolving from game to game, but without such significant changes
5//! that it would require a different packet format.
6
7use std::io::{Cursor, Error, ErrorKind};
8
9use bytes::{Buf, BytesMut};
10
11pub mod event;
12pub mod header;
13pub mod lap;
14pub mod motion;
15pub mod participants;
16pub mod session;
17pub mod setup;
18pub mod status;
19pub mod telemetry;
20
21/// A packet published by an F1 game.
22///
23/// The F1 games publish different packets with different data at different intervals. Each of these
24/// packets is decoded from UDP to their respective representation in this Rust crate. The `Packet`
25/// enum lists all packets that can be expected, and that a client should handle.
26#[derive(Debug, PartialEq, Clone, PartialOrd)]
27pub enum Packet {
28 /// The F1 games send event packets whenever certain events occur in a session. Some event
29 /// packets carry a payload with more information about the event.
30 Event(event::EventPacket),
31
32 /// Lap data packets provide information about each car in a session, and are sent at an
33 /// interval that can be configured in the game.
34 Lap(lap::LapPacket),
35
36 /// The motion data packet describes the movement and position of each car in the session, with
37 /// additional details being provided for the player's car.
38 Motion(motion::MotionPacket),
39
40 /// Packet with information on all participants in the session, for example their name, team,
41 /// and nationality.
42 Participants(participants::ParticipantsPacket),
43
44 /// The F1 games provide information about the current session on a regular basis.
45 Session(session::SessionPacket),
46
47 /// Car setup packets publish the setup of each car in the session. In multiplayer sessions, the
48 /// setups of other player's cars are redacted to enable a fair competition.
49 Setup(setup::CarSetupPacket),
50
51 /// The F1 games send packets with data about the status of each car in a session at a
52 /// configurable interval.
53 Status(status::CarStatusPacket),
54
55 /// Telemetry data is provided for all cars in the session.
56 Telemetry(telemetry::TelemetryPacket),
57}
58
59/// Ensure a packet has the expected size
60///
61/// Modern F1 games send their packets over UDP. Depending on their size, these packets might be
62/// split into multiple UDP fragments. The decoder collects these fragments, and asks the codec if
63/// enough data has been received to decode a packet.
64///
65/// The sizes of the packets sent by F1 games are part of the API specification, and can be used to
66/// determine if a full packet has ben received. This function takes a cursor to the raw data and
67/// the expected size of the packet, and returns an error if not enough data is ready to decode the
68/// complete packet.
69pub(crate) fn ensure_packet_size(
70 expected_size: usize,
71 cursor: &mut Cursor<&mut BytesMut>,
72) -> Result<(), Error> {
73 if cursor.remaining() < expected_size {
74 Err(Error::new(
75 ErrorKind::UnexpectedEof,
76 format!(
77 "Packet is expected to have a size of {} bytes, but was {}.",
78 expected_size,
79 cursor.remaining()
80 ),
81 ))
82 } else {
83 Ok(())
84 }
85}
86
87#[cfg(test)]
88mod tests {
89 use std::io::{Cursor, Error};
90
91 use bytes::{Buf, BufMut, BytesMut};
92
93 use crate::packet::ensure_packet_size;
94
95 struct Packet {
96 counter: u8,
97 }
98
99 const PACKET_SIZE: usize = 1;
100
101 fn decode_packet(cursor: &mut Cursor<&mut BytesMut>) -> Result<Packet, Error> {
102 ensure_packet_size(PACKET_SIZE, cursor)?;
103
104 Ok(Packet {
105 counter: cursor.get_u8(),
106 })
107 }
108
109 #[test]
110 fn ensure_packet_size_correctly() {
111 let mut bytes = BytesMut::with_capacity(1);
112 bytes.put_u8(0);
113
114 let mut cursor = Cursor::new(&mut bytes);
115
116 let packet = decode_packet(&mut cursor).unwrap();
117 assert_eq!(0, packet.counter);
118 }
119
120 #[test]
121 fn ensure_packet_size_with_error() {
122 let mut bytes = BytesMut::with_capacity(0);
123 let mut cursor = Cursor::new(&mut bytes);
124
125 let packet = decode_packet(&mut cursor);
126 assert!(packet.is_err());
127 }
128}