f1_api/codec.rs
1//! Codec for modern F1 games
2
3use std::io::{Cursor, Error, ErrorKind};
4
5use bytes::{Buf, BytesMut};
6use tokio_util::codec::Decoder;
7
8use crate::nineteen::decode_nineteen;
9use crate::packet::Packet;
10
11/// Codec to decode UDP packets published by modern F1 games.
12///
13/// This struct implements the `Decoder` trait for tokio-utils. It can be used to decode incoming
14/// UDP packets, and convert them into internal data representations. The F1 codec can decode the
15/// packets of all F1 games that are supported by this library.
16pub struct F1Codec;
17
18impl Decoder for F1Codec {
19 type Item = Packet;
20 type Error = Error;
21
22 /// Decode a UDP packet and return its data.
23 ///
24 /// The `decode` method is called whenever a new data frame is received on a UDP socket, and the
25 /// data frame is passed as an argument. This method has to make a few decisions then:
26 ///
27 /// 1. Does the data form a complete packet so that it can be decoded?
28 /// 2. Is the packet a valid packet sent by an F1 game?
29 /// 3. Can the packet be parsed?
30 ///
31 /// To answer these questions, the following process is used. First, the packet header is read
32 /// to determine the game that sent the packet. With the game and the packet type from the
33 /// header, the expected size of the packet can be determined by calling `buffer_size` from the
34 /// `FromBytes` trait. If the packet is too small, `Ok(None)` is returned to signal that more
35 /// data needs to be retrieved from the UDP socket.
36 ///
37 /// If the packet is complete, it is decoded using the `from_bytes` method in the `FromBytes`
38 /// trait. If the packet can be decoded successfully, it is returned. Otherwise, the error from
39 /// the decoding is returned, signaling that the UDP stream is corrupted and should be shut
40 /// down.
41 fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Error> {
42 let mut cursor = Cursor::new(src);
43
44 // Not enough data yet to decode the packet format.
45 if cursor.remaining() < 2 {
46 return Ok(None);
47 }
48
49 let packet_format = cursor.get_u16_le();
50
51 let packet = match packet_format {
52 2019 => decode_nineteen(&mut cursor),
53 format => Err(Error::new(
54 ErrorKind::InvalidData,
55 format!("Unknown packet format {}.", format),
56 )),
57 };
58
59 match packet {
60 Ok(packet) => Ok(Some(packet)),
61 Err(error) => match error.kind() {
62 ErrorKind::UnexpectedEof => Ok(None),
63 _ => Err(error),
64 },
65 }
66 }
67}