diff --git a/.github/workflows/deployment.yml b/.github/workflows/deployment.yml index f332ac0..97e89de 100644 --- a/.github/workflows/deployment.yml +++ b/.github/workflows/deployment.yml @@ -6,6 +6,11 @@ on: branches: [ main ] types: - completed + + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: build_and_deploy: diff --git a/Cargo.toml b/Cargo.toml index f576df4..975446c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ members = [ "crates/error", "crates/id-generator", "crates/structs", - "crates/telemetry", + "crates/f1-telemetry", "crates/token_manager", "crates/utils", "crates/discord", @@ -34,7 +34,7 @@ id-generator = { path = "crates/id-generator" } intelli-core = { path = "crates/intelli-core" } password-hash = { path = "crates/password-hash" } structs = { path = "crates/structs" } -telemetry = { path = "crates/telemetry" } +f1-telemetry = { path = "crates/f1-telemetry" } token_manager = { path = "crates/token_manager" } utils = { path = "crates/utils" } diff --git a/crates/api/Cargo.toml b/crates/api/Cargo.toml index 2998a97..cb6bc97 100644 --- a/crates/api/Cargo.toml +++ b/crates/api/Cargo.toml @@ -20,7 +20,7 @@ token_manager.workspace = true error.workspace = true structs.workspace = true entities.workspace = true -telemetry.workspace = true +f1-telemetry.workspace = true intelli-core.workspace = true ntex.workspace = true tokio.workspace = true diff --git a/crates/api/src/config/local_tracing.rs b/crates/api/src/config/local_tracing.rs index 6afc1b5..0902214 100644 --- a/crates/api/src/config/local_tracing.rs +++ b/crates/api/src/config/local_tracing.rs @@ -1,4 +1,4 @@ -use telemetry::FirewallService; +use f1_telemetry::FirewallService; use tokio::runtime::Builder; use tracing::error; use tracing_log::LogTracer; diff --git a/crates/api/src/main.rs b/crates/api/src/main.rs index 1cfece6..e52ec41 100644 --- a/crates/api/src/main.rs +++ b/crates/api/src/main.rs @@ -13,8 +13,8 @@ use tracing::info; use config::{initialize_tracing_subscriber, setup_panic_handler}; use db::Database; +use f1_telemetry::FirewallService; use states::AppState; -use telemetry::FirewallService; #[cfg(not(test))] #[global_allocator] @@ -71,7 +71,7 @@ async fn main() -> std::io::Result<()> { }) .await?; - info!("Stoping service, cleaning up firewall rules"); + info!("Stopping service, cleaning up firewall rules"); firewall_svc.close_all().await.unwrap(); Ok(()) diff --git a/crates/api/src/states/app.rs b/crates/api/src/states/app.rs index 4ad337a..65696e2 100644 --- a/crates/api/src/states/app.rs +++ b/crates/api/src/states/app.rs @@ -1,6 +1,7 @@ use db::Database; use error::AppResult; +use f1_telemetry::{F1ChampionshipManager, F1State, FirewallService}; use intelli_core::{ repositories::{ ChampionshipRepository, DiscordRepository, DriverRepository, ServerRepository, @@ -8,11 +9,8 @@ use intelli_core::{ }, services::{ChampionshipService, DriverService, EmailService, UserService}, }; -use telemetry::{F1ServiceHandler, F1State, FirewallService}; use token_manager::TokenManager; -// F1ServiceHandler, FirewallService - #[derive(Clone)] pub struct AppState { pub user_svc: &'static UserService, @@ -25,7 +23,7 @@ pub struct AppState { #[allow(unused)] pub driver_svc: &'static DriverService, pub email_svc: EmailService, - pub f1_svc: F1ServiceHandler, + pub f1_svc: F1ChampionshipManager, pub discord_repo: &'static DiscordRepository, pub server_repo: ServerRepository, } @@ -59,7 +57,7 @@ impl AppState { Ok(Self { user_svc, - f1_svc: F1ServiceHandler::new(f1_state), + f1_svc: F1ChampionshipManager::new(f1_state), user_repo, token_mgr, championship_svc, diff --git a/crates/telemetry/Cargo.toml b/crates/f1-telemetry/Cargo.toml similarity index 90% rename from crates/telemetry/Cargo.toml rename to crates/f1-telemetry/Cargo.toml index 0428494..f72014d 100644 --- a/crates/telemetry/Cargo.toml +++ b/crates/f1-telemetry/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "telemetry" +name = "f1-telemetry" version = "0.1.0" edition = "2021" @@ -7,7 +7,7 @@ edition = "2021" workspace = true [lib] -path = "src/telemetry.rs" +path = "src/championship.rs" doctest = false [build-dependencies] diff --git a/crates/telemetry/build.rs b/crates/f1-telemetry/build.rs similarity index 100% rename from crates/telemetry/build.rs rename to crates/f1-telemetry/build.rs diff --git a/crates/telemetry/protos/f1.proto b/crates/f1-telemetry/protos/f1.proto similarity index 100% rename from crates/telemetry/protos/f1.proto rename to crates/f1-telemetry/protos/f1.proto diff --git a/crates/telemetry/src/telemetry.rs b/crates/f1-telemetry/src/championship.rs similarity index 88% rename from crates/telemetry/src/telemetry.rs rename to crates/f1-telemetry/src/championship.rs index 301362a..3d5cc31 100644 --- a/crates/telemetry/src/telemetry.rs +++ b/crates/f1-telemetry/src/championship.rs @@ -1,7 +1,7 @@ -mod f1; mod firewall; -mod manager; -mod service; +mod handler; +mod live_service; +mod types; use dashmap::DashMap; use intelli_core::{ @@ -16,17 +16,17 @@ use tokio::sync::{ use tracing::{info, warn}; use error::{AppResult, F1ServiceError}; -use manager::F1SessionDataManager; -use service::{F1Service, F1ServiceData}; +use handler::F1TelemetryPacketHandler; +use live_service::{F1LiveTelemetryService, F1SessionBroadcaster}; use structs::ServiceStatus; pub use firewall::FirewallService; -pub use manager::DriverInfo; +pub use handler::DriverInfo; /// Manages F1 championship services, including caching, subscriptions, and service lifecycle. #[derive(Clone)] -pub struct F1ServiceHandler { - services: &'static DashMap, +pub struct F1ChampionshipManager { + services: &'static DashMap, f1_state: &'static F1State, } @@ -39,7 +39,7 @@ pub struct F1State { pub championship_svc: &'static ChampionshipService, } -impl F1ServiceHandler { +impl F1ChampionshipManager { /// Creates a new F1ServiceHandler instance. pub fn new(f1_state: &'static F1State) -> Self { let services = Box::leak(Box::new(DashMap::with_capacity(10))); @@ -102,9 +102,10 @@ impl F1ServiceHandler { let (otx, orx) = oneshot::channel::<()>(); let (tx, _) = channel::(50); - let session_manager = F1SessionDataManager::new(tx.clone()); - let service_data = F1ServiceData::new(session_manager.clone(), tx, otx); - let mut service = F1Service::new(session_manager, orx, self.services, self.f1_state).await; + let session_manager = F1TelemetryPacketHandler::new(tx.clone()); + let service_data = F1SessionBroadcaster::new(session_manager.clone(), tx, otx); + let mut service = + F1LiveTelemetryService::new(session_manager, orx, self.services, self.f1_state).await; service.initialize(port, championship_id, 0).await?; diff --git a/crates/telemetry/src/firewall.rs b/crates/f1-telemetry/src/firewall.rs similarity index 100% rename from crates/telemetry/src/firewall.rs rename to crates/f1-telemetry/src/firewall.rs diff --git a/crates/telemetry/src/manager.rs b/crates/f1-telemetry/src/handler.rs similarity index 98% rename from crates/telemetry/src/manager.rs rename to crates/f1-telemetry/src/handler.rs index cb2d83a..2b2d7ad 100644 --- a/crates/telemetry/src/manager.rs +++ b/crates/f1-telemetry/src/handler.rs @@ -13,7 +13,7 @@ use tokio::sync::{ }; use tracing::{error, warn}; -use crate::f1::{ +use crate::types::{ CarDamageData as F1CarDamageData, CarMotionData as F1CarMotionData, CarStatusData as F1CarStatusData, CarTelemetryData as F1CarTelemetryData, EventCode, EventDataDetails as F1EventDataDetails, FinalClassificationData as F1FinalClassificationData, @@ -50,8 +50,13 @@ pub struct DriverInfo { pub team_id: u8, } +#[derive(Clone)] +pub struct F1TelemetryPacketHandler { + inner: Arc, +} + #[derive(Debug)] -pub struct F1SessionDataManagerInner { +pub struct F1TelemetryPacketHandlerInner { driver_info: RwLock>, general: RwLock, telemetry: RwLock, @@ -62,24 +67,19 @@ pub struct F1SessionDataManagerInner { stop_sender: Mutex>>, } -#[derive(Clone)] -pub struct F1SessionDataManager { - inner: Arc, -} - // Implementations -impl Deref for F1SessionDataManager { - type Target = F1SessionDataManagerInner; +impl Deref for F1TelemetryPacketHandler { + type Target = F1TelemetryPacketHandlerInner; fn deref(&self) -> &Self::Target { &self.inner } } -impl F1SessionDataManager { - /// Creates a new F1SessionDataManager instance +impl F1TelemetryPacketHandler { + /// Creates a new F1TelemetryPacketHandler instance pub fn new(tx: Sender) -> Self { - let inner = Arc::new(F1SessionDataManagerInner { + let inner = Arc::new(F1TelemetryPacketHandlerInner { driver_info: RwLock::new(AHashMap::new()), general: RwLock::new(F1GeneralInfo::default()), telemetry: RwLock::new(F1TelemetryInfo::default()), @@ -298,7 +298,7 @@ impl F1SessionDataManager { /// Sends general updates #[inline] - fn send_general_updates(inner: &Arc, tx: &Sender) { + fn send_general_updates(inner: &Arc, tx: &Sender) { if tx.receiver_count() == 0 { return; } @@ -319,7 +319,7 @@ impl F1SessionDataManager { /// Sends telemetry updates #[inline] - fn send_telemetry_updates(inner: &Arc) { + fn send_telemetry_updates(inner: &Arc) { let driver_info = inner.driver_info.read(); let telemetry = inner.telemetry.read(); let mut last_telemetry = inner.last_telemetry.write(); @@ -391,7 +391,7 @@ impl F1SessionDataManager { } } -impl Drop for F1SessionDataManager { +impl Drop for F1TelemetryPacketHandler { fn drop(&mut self) { if let Some(sender) = self.stop_sender.lock().take() { let _ = sender.send(()); diff --git a/crates/telemetry/src/service.rs b/crates/f1-telemetry/src/live_service.rs similarity index 85% rename from crates/telemetry/src/service.rs rename to crates/f1-telemetry/src/live_service.rs index fb76b54..ddf455f 100644 --- a/crates/telemetry/src/service.rs +++ b/crates/f1-telemetry/src/live_service.rs @@ -28,7 +28,7 @@ use error::{AppResult, CommonError, F1ServiceError}; use intelli_core::services::{ChampionshipServiceOperations, DriverServiceOperations}; use crate::{ - f1::{ + types::{ PacketCarDamageData, PacketCarStatusData, PacketCarTelemetryData, PacketEventData, PacketFinalClassificationData, PacketHeader, PacketIds, PacketMotionData, PacketParticipantsData, PacketSessionData, PacketSessionHistoryData, SessionType, @@ -36,7 +36,7 @@ use crate::{ F1State, }; -use super::manager::F1SessionDataManager; +use super::handler::F1TelemetryPacketHandler; // Constants const BUFFER_SIZE: usize = 1460; @@ -49,7 +49,7 @@ const MOTION_INTERVAL: Duration = Duration::from_millis(700); const PARTICIPANTS_TICK_UPDATE: u8 = 6; /// Enum representing different types of F1 packet data -enum F1PacketData<'a> { +enum F1TelemetryPacket<'a> { Motion(&'a PacketMotionData), Session(&'a PacketSessionData), Event(&'a PacketEventData), @@ -62,37 +62,37 @@ enum F1PacketData<'a> { } /// Represents an F1 service that processes and manages F1 telemetry data -pub struct F1Service { +pub struct F1LiveTelemetryService { port: i32, race_id: i32, tick_counter: u8, championship_id: i32, port_partially_opened: bool, - last_updates: LastUpdates, + last_updates: PacketProcessingTimestamps, socket: UdpSocket, shutdown: oneshot::Receiver<()>, session_type: Option, - data_manager: F1SessionDataManager, - services: &'static DashMap, + data_manager: F1TelemetryPacketHandler, + services: &'static DashMap, f1_state: &'static F1State, } /// Holds data related to an F1 service instance -pub struct F1ServiceData { - inner: Arc, - session_manager: F1SessionDataManager, +pub struct F1SessionBroadcaster { + inner: Arc, + session_manager: F1TelemetryPacketHandler, shutdown: Option>, } -/// Internal data structure for F1ServiceData -pub struct F1ServiceDataInner { +/// Internal data structure for F1SessionBroadcaster +pub struct F1SessionBroadcasterInner { global_channel: Sender, global_subscribers: AtomicU32, team_subscribers: RwLock>, } /// Tracks the last update times for various packet types -struct LastUpdates { +struct PacketProcessingTimestamps { session: Instant, car_motion: Instant, car_status: Instant, @@ -102,30 +102,33 @@ struct LastUpdates { car_lap: [Instant; 22], } -impl F1PacketData<'_> { - /// Attempts to create an F1PacketData from raw bytes and packet ID +impl F1TelemetryPacket<'_> { + /// Attempts to create an F1TelemetryPacket from raw bytes and packet ID #[inline] - pub fn try_from_bytes(data: &[u8], packet_id: u8) -> AppResult { + pub fn try_from_bytes(data: &[u8], packet_id: u8) -> AppResult { let packet_id = PacketIds::try_from(packet_id).unwrap(); let packet = match packet_id { - PacketIds::Event => cast::(data).map(F1PacketData::Event), - PacketIds::Motion => cast::(data).map(F1PacketData::Motion), - PacketIds::Session => cast::(data).map(F1PacketData::Session), - PacketIds::CarDamage => cast::(data).map(F1PacketData::CarDamage), - PacketIds::CarStatus => cast::(data).map(F1PacketData::CarStatus), + PacketIds::Event => cast::(data).map(F1TelemetryPacket::Event), + PacketIds::Motion => cast::(data).map(F1TelemetryPacket::Motion), + PacketIds::Session => cast::(data).map(F1TelemetryPacket::Session), + PacketIds::CarDamage => { + cast::(data).map(F1TelemetryPacket::CarDamage) + } + PacketIds::CarStatus => { + cast::(data).map(F1TelemetryPacket::CarStatus) + } PacketIds::CarTelemetry => { - cast::(data).map(F1PacketData::CarTelemetry) + cast::(data).map(F1TelemetryPacket::CarTelemetry) } PacketIds::Participants => { - cast::(data).map(F1PacketData::Participants) + cast::(data).map(F1TelemetryPacket::Participants) } PacketIds::SessionHistory => { - cast::(data).map(F1PacketData::SessionHistory) - } - PacketIds::FinalClassification => { - cast::(data).map(F1PacketData::FinalClassification) + cast::(data).map(F1TelemetryPacket::SessionHistory) } + PacketIds::FinalClassification => cast::(data) + .map(F1TelemetryPacket::FinalClassification), _ => Err(F1ServiceError::InvalidPacketType)?, }?; @@ -134,21 +137,21 @@ impl F1PacketData<'_> { } } -impl F1Service { - /// Creates a new F1Service instance +impl F1LiveTelemetryService { + /// Creates a new F1LiveTelemetryService instance pub async fn new( - data_manager: F1SessionDataManager, + data_manager: F1TelemetryPacketHandler, shutdown: oneshot::Receiver<()>, - services: &'static DashMap, + services: &'static DashMap, f1_state: &'static F1State, ) -> Self { - F1Service { + F1LiveTelemetryService { port: 0, race_id: 0, championship_id: 0, tick_counter: 10, port_partially_opened: false, - last_updates: LastUpdates::new(), + last_updates: PacketProcessingTimestamps::new(), shutdown, socket: UdpSocket::bind("0.0.0.0:0").await.unwrap(), session_type: None, @@ -263,7 +266,7 @@ impl F1Service { Err(_) => return Ok(()), }; - let packet = match F1PacketData::try_from_bytes(buf, header.packet_id) { + let packet = match F1TelemetryPacket::try_from_bytes(buf, header.packet_id) { Ok(p) => p, Err(_) => return Ok(()), }; @@ -277,25 +280,29 @@ impl F1Service { } match packet { - F1PacketData::Motion(motion_data) => self.handle_motion_packet(motion_data, now), - F1PacketData::Session(session_data) => { + F1TelemetryPacket::Motion(motion_data) => self.handle_motion_packet(motion_data, now), + F1TelemetryPacket::Session(session_data) => { self.handle_session_packet(session_data, now).await } - F1PacketData::Participants(participants_data) => { + F1TelemetryPacket::Participants(participants_data) => { self.handle_participants_packet(participants_data, now) .await? } - F1PacketData::Event(event_data) => self.handle_event_packet(event_data), - F1PacketData::SessionHistory(session_history_data) => { + F1TelemetryPacket::Event(event_data) => self.handle_event_packet(event_data), + F1TelemetryPacket::SessionHistory(session_history_data) => { self.handle_session_history_packet(session_history_data, now) } - F1PacketData::FinalClassification(final_classification) => { + F1TelemetryPacket::FinalClassification(final_classification) => { self.handle_final_classification_packet(final_classification) .await? } - F1PacketData::CarDamage(car_damage) => self.handle_car_damage_packet(car_damage, now), - F1PacketData::CarStatus(car_status) => self.handle_car_status_packet(car_status, now), - F1PacketData::CarTelemetry(car_telemetry) => { + F1TelemetryPacket::CarDamage(car_damage) => { + self.handle_car_damage_packet(car_damage, now) + } + F1TelemetryPacket::CarStatus(car_status) => { + self.handle_car_status_packet(car_status, now) + } + F1TelemetryPacket::CarTelemetry(car_telemetry) => { self.handle_car_telemetry_packet(car_telemetry, now) } } @@ -510,14 +517,14 @@ impl F1Service { } } -impl F1ServiceData { - /// Creates a new F1ServiceData instance +impl F1SessionBroadcaster { + /// Creates a new F1SessionBroadcaster instance pub fn new( - session_manager: F1SessionDataManager, + session_manager: F1TelemetryPacketHandler, global_channel: Sender, shutdown: oneshot::Sender<()>, ) -> Self { - let inner = Arc::new(F1ServiceDataInner { + let inner = Arc::new(F1SessionBroadcasterInner { global_channel, global_subscribers: AtomicU32::new(0), team_subscribers: RwLock::new(AHashMap::new()), @@ -587,16 +594,16 @@ impl F1ServiceData { } } -impl Deref for F1ServiceData { - type Target = F1ServiceDataInner; +impl Deref for F1SessionBroadcaster { + type Target = F1SessionBroadcasterInner; fn deref(&self) -> &Self::Target { &self.inner } } -impl LastUpdates { - /// Creates a new LastUpdates instance with current time for all fields +impl PacketProcessingTimestamps { + /// Creates a new PacketProcessingTimestamps instance with current time for all fields fn new() -> Self { let time = Instant::now(); diff --git a/crates/f1-telemetry/src/types/custom.rs b/crates/f1-telemetry/src/types/custom.rs new file mode 100644 index 0000000..86b25f3 --- /dev/null +++ b/crates/f1-telemetry/src/types/custom.rs @@ -0,0 +1,510 @@ +use core::str; + +use error::{AppError, ChampionshipError}; + +use super::ParticipantData; + +pub enum PacketIds { + Motion, + Session, + LapData, + Event, + Participants, + CarSetups, + CarTelemetry, + CarStatus, + FinalClassification, + LobbyInfo, + CarDamage, + SessionHistory, + TyreSets, + MotionEx, + TimeTrial, +} + +#[derive(Debug, PartialEq)] +pub enum EventCode { + SessionStarted, + SessionEnded, + FastestLap, + Retirement, + DRSEnabled, + DRSDisabled, + TeamMateInPits, + ChequeredFlag, + RaceWinner, + PenaltyIssued, + SpeedTrapTriggered, + StartLights, + LightsOut, + DriveThroughServed, + StopGoServed, + Flashback, + ButtonStatus, + RedFlag, + Overtake, + SafetyCar, + Collision, +} + +#[derive(Debug, PartialEq)] +pub enum SessionType { + Unknown, + Practice1, + Practice2, + Practice3, + ShortPractice, + Q1, + Q2, + Q3, + SQ, + Osq, + SprintShootout1, + SprintShootout2, + SprintShootout3, + ShortSprintShootout, + OneShotSprintShootout, + R, + R2, + R3, + TimeTrial, +} + +pub enum Tracks { + Melbourne, + PaulRicard, + Shangai, + Sakhir, + Catalunya, + Monaco, + Montreal, + Silverstone, + Hockenheim, + Hungaroring, + Spa, + Monza, + Singapore, + Suzuka, + AbuDhabi, + Texas, + Brazil, + Austria, + Sochi, + Mexico, + Baku, + SakhirShort, + SilverstoneShort, + TexasShort, + SuzukaShort, + Hanoi, + Zandvoort, + Imola, + Portimao, + Jeddah, + Miami, + LasVegas, + Losail, +} + +pub enum PenaltyTypes { + DriveThrough, + StopGo, + GridPenalty, + PenaltyReminder, + TimePenalty, + Warning, + Disqualified, + RemovedFromFormationLap, + ParkedTooLongTimer, + TyreRegulations, + ThisLapInvalidated, + ThisAndNextLapInvalidated, + ThisLapInvalidatedWithoutReason, + ThisAndNextLapInvalidatedWithoutReason, + ThisAndPreviousLapInvalidated, + ThisAndPreviousLapInvalidatedWithoutReason, + Retired, + BlackFlagTimer, +} + +pub enum InfringementType { + BlockingBySlowDriving, + BlockingByWrongWayDriving, + ReversingOffTheStartLine, + BigCollision, + SmallCollision, + CollisionFailedToHandBackPositionSingle, + CollisionFailedToHandBackPositionMultiple, + CornerCuttingGainedTime, + CornerCuttingOvertakeSingle, + CornerCuttingOvertakeMultiple, + CrossedPitExitLane, + IgnoringBlueFlags, + IgnoringYellowFlags, + IgnoringDriveThrough, + TooManyDriveThroughs, + DriveThroughReminderServeWithinNLaps, + DriveThroughReminderServeThisLap, + PitLaneSpeeding, + ParkedForTooLong, + IgnoringTyreRegulations, + TooManyPenalties, + MultipleWarnings, + ApproachingDisqualification, + TyreRegulationsSelectSingle, + TyreRegulationsSelectMultiple, + LapInvalidatedCornerCutting, + LapInvalidatedRunningWide, + CornerCuttingRanWideGainedTimeMinor, + CornerCuttingRanWideGainedTimeSignificant, + CornerCuttingRanWideGainedTimeExtreme, + LapInvalidatedWallRiding, + LapInvalidatedFlashbackUsed, + LapInvalidatedResetToTrack, + BlockingThePitlane, + JumpStart, + SafetyCarToCarCollision, + SafetyCarIllegalOvertake, + SafetyCarExceedingAllowedPace, + VirtualSafetyCarExceedingAllowedPace, + FormationLapBelowAllowedSpeed, + FormationLapParking, + RetiredMechanicalFailure, + RetiredTerminallyDamaged, + SafetyCarFallingTooFarBack, + BlackFlagTimer, + UnservedStopGoPenalty, + UnservedDriveThroughPenalty, + EngineComponentChange, + GearboxChange, + ParcFermeChange, + LeagueGridPenalty, + RetryPenalty, + IllegalTimeGain, + MandatoryPitstop, + AttributeAssigned, +} + +pub enum Ruleset { + PracticeAndQualifying, + Race, + TimeTrial, + TimeAttack, + CheckpointChallenge, + Autocross, + Drift, + AverageSpeedZone, + RivalDuel, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +#[repr(i16)] +pub enum TeamIds { + Mercedes = 0, + Ferrari = 1, + RedBullRacing = 2, + Williams = 3, + AstonMartin = 4, + Alpine = 5, + RB = 6, + Haas = 7, + McLaren = 8, + Sauber = 9, + F1Generic = 41, + F1CustomTeam = 104, + ArtGP2023 = 143, + Campos2023 = 144, + Carlin2023 = 145, + PHM2023 = 146, + Dams2023 = 147, + Hitech2023 = 148, + MPMotorsport2023 = 149, + Prema2023 = 150, + Trident2023 = 151, + VanAmersfoortRacing2023 = 152, + Virtuosi2023 = 153, +} + +impl TryFrom for TeamIds { + type Error = AppError; + + fn try_from(v: i16) -> Result { + match v { + v if v == Self::Mercedes as i16 => Ok(Self::Mercedes), + v if v == Self::Ferrari as i16 => Ok(Self::Ferrari), + v if v == Self::RedBullRacing as i16 => Ok(Self::RedBullRacing), + v if v == Self::Williams as i16 => Ok(Self::Williams), + v if v == Self::AstonMartin as i16 => Ok(Self::AstonMartin), + v if v == Self::Alpine as i16 => Ok(Self::Alpine), + v if v == Self::RB as i16 => Ok(Self::RB), + v if v == Self::Haas as i16 => Ok(Self::Haas), + v if v == Self::McLaren as i16 => Ok(Self::McLaren), + v if v == Self::Sauber as i16 => Ok(Self::Sauber), + v if v == Self::F1Generic as i16 => Ok(Self::F1Generic), + v if v == Self::F1CustomTeam as i16 => Ok(Self::F1CustomTeam), + v if v == Self::ArtGP2023 as i16 => Ok(Self::ArtGP2023), + v if v == Self::Campos2023 as i16 => Ok(Self::Campos2023), + v if v == Self::Carlin2023 as i16 => Ok(Self::Carlin2023), + v if v == Self::PHM2023 as i16 => Ok(Self::PHM2023), + v if v == Self::Dams2023 as i16 => Ok(Self::Dams2023), + v if v == Self::Hitech2023 as i16 => Ok(Self::Hitech2023), + v if v == Self::MPMotorsport2023 as i16 => Ok(Self::MPMotorsport2023), + v if v == Self::Prema2023 as i16 => Ok(Self::Prema2023), + v if v == Self::Trident2023 as i16 => Ok(Self::Trident2023), + v if v == Self::VanAmersfoortRacing2023 as i16 => Ok(Self::VanAmersfoortRacing2023), + v if v == Self::Virtuosi2023 as i16 => Ok(Self::Virtuosi2023), + _ => Err(ChampionshipError::InvalidTeamId)?, + } + } +} + +impl TryFrom for SessionType { + type Error = &'static str; + + fn try_from(value: u8) -> Result { + match value { + 0 => Ok(Self::Unknown), + 1 => Ok(Self::Practice1), + 2 => Ok(Self::Practice2), + 3 => Ok(Self::Practice3), + 4 => Ok(Self::ShortPractice), + 5 => Ok(Self::Q1), + 6 => Ok(Self::Q2), + 7 => Ok(Self::Q3), + 8 => Ok(Self::SQ), + 9 => Ok(Self::Osq), + 10 => Ok(Self::SprintShootout1), + 11 => Ok(Self::SprintShootout2), + 12 => Ok(Self::SprintShootout3), + 13 => Ok(Self::ShortSprintShootout), + 14 => Ok(Self::OneShotSprintShootout), + 15 => Ok(Self::R), + 16 => Ok(Self::R2), + 17 => Ok(Self::R3), + 18 => Ok(Self::TimeTrial), + + _ => Err("Unknown session type"), + } + } +} + +impl TryFrom for PenaltyTypes { + type Error = &'static str; + + fn try_from(value: u8) -> Result { + match value { + 0 => Ok(Self::DriveThrough), + 1 => Ok(Self::StopGo), + 2 => Ok(Self::GridPenalty), + 3 => Ok(Self::PenaltyReminder), + 4 => Ok(Self::TimePenalty), + 5 => Ok(Self::Warning), + 6 => Ok(Self::Disqualified), + 7 => Ok(Self::RemovedFromFormationLap), + 8 => Ok(Self::ParkedTooLongTimer), + 9 => Ok(Self::TyreRegulations), + 10 => Ok(Self::ThisLapInvalidated), + 11 => Ok(Self::ThisAndNextLapInvalidated), + 12 => Ok(Self::ThisLapInvalidatedWithoutReason), + 13 => Ok(Self::ThisAndNextLapInvalidatedWithoutReason), + 14 => Ok(Self::ThisAndPreviousLapInvalidated), + 15 => Ok(Self::ThisAndPreviousLapInvalidatedWithoutReason), + 16 => Ok(Self::Retired), + 17 => Ok(Self::BlackFlagTimer), + _ => Err("Unknown penalty type"), + } + } +} + +impl TryFrom for InfringementType { + type Error = &'static str; + + fn try_from(value: u8) -> Result { + match value { + 0 => Ok(Self::BlockingBySlowDriving), + 1 => Ok(Self::BlockingByWrongWayDriving), + 2 => Ok(Self::ReversingOffTheStartLine), + 3 => Ok(Self::BigCollision), + 4 => Ok(Self::SmallCollision), + 5 => Ok(Self::CollisionFailedToHandBackPositionSingle), + 6 => Ok(Self::CollisionFailedToHandBackPositionMultiple), + 7 => Ok(Self::CornerCuttingGainedTime), + 8 => Ok(Self::CornerCuttingOvertakeSingle), + 9 => Ok(Self::CornerCuttingOvertakeMultiple), + 10 => Ok(Self::CrossedPitExitLane), + 11 => Ok(Self::IgnoringBlueFlags), + 12 => Ok(Self::IgnoringYellowFlags), + 13 => Ok(Self::IgnoringDriveThrough), + 14 => Ok(Self::TooManyDriveThroughs), + 15 => Ok(Self::DriveThroughReminderServeWithinNLaps), + 16 => Ok(Self::DriveThroughReminderServeThisLap), + 17 => Ok(Self::PitLaneSpeeding), + 18 => Ok(Self::ParkedForTooLong), + 19 => Ok(Self::IgnoringTyreRegulations), + 20 => Ok(Self::TooManyPenalties), + 21 => Ok(Self::MultipleWarnings), + 22 => Ok(Self::ApproachingDisqualification), + 23 => Ok(Self::TyreRegulationsSelectSingle), + 24 => Ok(Self::TyreRegulationsSelectMultiple), + 25 => Ok(Self::LapInvalidatedCornerCutting), + 26 => Ok(Self::LapInvalidatedRunningWide), + 27 => Ok(Self::CornerCuttingRanWideGainedTimeMinor), + 28 => Ok(Self::CornerCuttingRanWideGainedTimeSignificant), + 29 => Ok(Self::CornerCuttingRanWideGainedTimeExtreme), + 30 => Ok(Self::LapInvalidatedWallRiding), + 31 => Ok(Self::LapInvalidatedFlashbackUsed), + 32 => Ok(Self::LapInvalidatedResetToTrack), + 33 => Ok(Self::BlockingThePitlane), + 34 => Ok(Self::JumpStart), + 35 => Ok(Self::SafetyCarToCarCollision), + 36 => Ok(Self::SafetyCarIllegalOvertake), + 37 => Ok(Self::SafetyCarExceedingAllowedPace), + 38 => Ok(Self::VirtualSafetyCarExceedingAllowedPace), + 39 => Ok(Self::FormationLapBelowAllowedSpeed), + 40 => Ok(Self::FormationLapParking), + 41 => Ok(Self::RetiredMechanicalFailure), + 42 => Ok(Self::RetiredTerminallyDamaged), + 43 => Ok(Self::SafetyCarFallingTooFarBack), + 44 => Ok(Self::BlackFlagTimer), + 45 => Ok(Self::UnservedStopGoPenalty), + 46 => Ok(Self::UnservedDriveThroughPenalty), + 47 => Ok(Self::EngineComponentChange), + 48 => Ok(Self::GearboxChange), + 49 => Ok(Self::ParcFermeChange), + 50 => Ok(Self::LeagueGridPenalty), + 51 => Ok(Self::RetryPenalty), + 52 => Ok(Self::IllegalTimeGain), + 53 => Ok(Self::MandatoryPitstop), + 54 => Ok(Self::AttributeAssigned), + _ => Err("Unknown infringement type"), + } + } +} + +impl TryFrom for Tracks { + type Error = &'static str; + + fn try_from(value: i8) -> Result { + match value { + 0 => Ok(Self::Melbourne), + 1 => Ok(Self::PaulRicard), + 2 => Ok(Self::Shangai), + 3 => Ok(Self::Sakhir), + 4 => Ok(Self::Catalunya), + 5 => Ok(Self::Monaco), + 6 => Ok(Self::Montreal), + 7 => Ok(Self::Silverstone), + 8 => Ok(Self::Hockenheim), + 9 => Ok(Self::Hungaroring), + 10 => Ok(Self::Spa), + 11 => Ok(Self::Monza), + 12 => Ok(Self::Singapore), + 13 => Ok(Self::Suzuka), + 14 => Ok(Self::AbuDhabi), + 15 => Ok(Self::Texas), + 16 => Ok(Self::Brazil), + 17 => Ok(Self::Austria), + 18 => Ok(Self::Sochi), + 19 => Ok(Self::Mexico), + 20 => Ok(Self::Baku), + 21 => Ok(Self::SakhirShort), + 22 => Ok(Self::SilverstoneShort), + 23 => Ok(Self::TexasShort), + 24 => Ok(Self::SuzukaShort), + 25 => Ok(Self::Hanoi), + 26 => Ok(Self::Zandvoort), + 27 => Ok(Self::Imola), + 28 => Ok(Self::Portimao), + 29 => Ok(Self::Jeddah), + 30 => Ok(Self::Miami), + 31 => Ok(Self::LasVegas), + 32 => Ok(Self::Losail), + _ => Err("Unknown track id"), + } + } +} + +impl TryFrom for Ruleset { + type Error = &'static str; + + fn try_from(value: u8) -> Result { + match value { + 0 => Ok(Self::PracticeAndQualifying), + 1 => Ok(Self::Race), + 2 => Ok(Self::TimeTrial), + 4 => Ok(Self::TimeAttack), + 6 => Ok(Self::CheckpointChallenge), + 8 => Ok(Self::Autocross), + 9 => Ok(Self::Drift), + 10 => Ok(Self::AverageSpeedZone), + 11 => Ok(Self::RivalDuel), + _ => Err("Unknown ruleset id"), + } + } +} + +impl TryFrom<&[u8; 4]> for EventCode { + type Error = &'static str; + + fn try_from(value: &[u8; 4]) -> Result { + match value { + b"SSTA" => Ok(Self::SessionStarted), + b"SEND" => Ok(Self::SessionEnded), + b"FTLP" => Ok(Self::FastestLap), + b"RTMT" => Ok(Self::Retirement), + b"DRSE" => Ok(Self::DRSEnabled), + b"DRSD" => Ok(Self::DRSDisabled), + b"TMPT" => Ok(Self::TeamMateInPits), + b"CHQF" => Ok(Self::ChequeredFlag), + b"RCWN" => Ok(Self::RaceWinner), + b"PENA" => Ok(Self::PenaltyIssued), + b"SPTP" => Ok(Self::SpeedTrapTriggered), + b"STLG" => Ok(Self::StartLights), + b"LGOT" => Ok(Self::LightsOut), + b"DTSV" => Ok(Self::DriveThroughServed), + b"SGSV" => Ok(Self::StopGoServed), + b"FLBK" => Ok(Self::Flashback), + b"BUTN" => Ok(Self::ButtonStatus), + b"RFGO" => Ok(Self::RedFlag), + b"OVTK" => Ok(Self::Overtake), + b"SCAR" => Ok(Self::SafetyCar), + b"COLL" => Ok(Self::Collision), + _ => Err("Unknown event code"), + } + } +} + +impl TryFrom for PacketIds { + type Error = &'static str; + + fn try_from(value: u8) -> Result { + match value { + 0 => Ok(PacketIds::Motion), + 1 => Ok(PacketIds::Session), + 2 => Ok(PacketIds::LapData), + 3 => Ok(PacketIds::Event), + 4 => Ok(PacketIds::Participants), + 5 => Ok(PacketIds::CarSetups), + 6 => Ok(PacketIds::CarTelemetry), + 7 => Ok(PacketIds::CarStatus), + 8 => Ok(PacketIds::FinalClassification), + 9 => Ok(PacketIds::LobbyInfo), + 10 => Ok(PacketIds::CarDamage), + 11 => Ok(PacketIds::SessionHistory), + 12 => Ok(PacketIds::TyreSets), + 13 => Ok(PacketIds::MotionEx), + 14 => Ok(PacketIds::TimeTrial), + _ => Err("Unknown packet id"), + } + } +} + +impl ParticipantData { + #[inline] + pub fn steam_name(&self) -> Option<&str> { + let nul_position = memchr::memchr(0, &self.name)?; + str::from_utf8(&self.name[..nul_position]) + .ok() + .filter(|s| !s.is_empty()) + } +} diff --git a/crates/telemetry/src/f1.rs b/crates/f1-telemetry/src/types/game.rs similarity index 56% rename from crates/telemetry/src/f1.rs rename to crates/f1-telemetry/src/types/game.rs index 44915f9..ca7b92e 100644 --- a/crates/telemetry/src/f1.rs +++ b/crates/f1-telemetry/src/types/game.rs @@ -1,11 +1,3 @@ -// --------------------------------------------- -// -------------- ORIGINAL GAME ---------------- -// --------------------------------------------- - -use std::str; - -use error::{AppError, ChampionshipError}; - #[repr(C, packed)] pub struct PacketHeader { pub packet_format: u16, // 2024 @@ -451,512 +443,3 @@ pub struct CarDamageData { pub engine_blown: u8, // Engine blown, 0 = OK, 1 = fault pub engine_seized: u8, // Engine seized, 0 = OK, 1 = fault } - -// --------------------------------------------- -// ------------ CUSTOM GAME TYPES -------------- -// --------------------------------------------- - -pub enum PacketIds { - Motion, - Session, - LapData, - Event, - Participants, - CarSetups, - CarTelemetry, - CarStatus, - FinalClassification, - LobbyInfo, - CarDamage, - SessionHistory, - TyreSets, - MotionEx, - TimeTrial, -} - -#[derive(Debug, PartialEq)] -pub enum EventCode { - SessionStarted, - SessionEnded, - FastestLap, - Retirement, - DRSEnabled, - DRSDisabled, - TeamMateInPits, - ChequeredFlag, - RaceWinner, - PenaltyIssued, - SpeedTrapTriggered, - StartLights, - LightsOut, - DriveThroughServed, - StopGoServed, - Flashback, - ButtonStatus, - RedFlag, - Overtake, - SafetyCar, - Collision, -} - -#[derive(Debug, PartialEq)] -pub enum SessionType { - Unknown, - Practice1, - Practice2, - Practice3, - ShortPractice, - Q1, - Q2, - Q3, - SQ, - Osq, - SprintShootout1, - SprintShootout2, - SprintShootout3, - ShortSprintShootout, - OneShotSprintShootout, - R, - R2, - R3, - TimeTrial, -} - -pub enum Tracks { - Melbourne, - PaulRicard, - Shangai, - Sakhir, - Catalunya, - Monaco, - Montreal, - Silverstone, - Hockenheim, - Hungaroring, - Spa, - Monza, - Singapore, - Suzuka, - AbuDhabi, - Texas, - Brazil, - Austria, - Sochi, - Mexico, - Baku, - SakhirShort, - SilverstoneShort, - TexasShort, - SuzukaShort, - Hanoi, - Zandvoort, - Imola, - Portimao, - Jeddah, - Miami, - LasVegas, - Losail, -} - -pub enum PenaltyTypes { - DriveThrough, - StopGo, - GridPenalty, - PenaltyReminder, - TimePenalty, - Warning, - Disqualified, - RemovedFromFormationLap, - ParkedTooLongTimer, - TyreRegulations, - ThisLapInvalidated, - ThisAndNextLapInvalidated, - ThisLapInvalidatedWithoutReason, - ThisAndNextLapInvalidatedWithoutReason, - ThisAndPreviousLapInvalidated, - ThisAndPreviousLapInvalidatedWithoutReason, - Retired, - BlackFlagTimer, -} - -pub enum InfringementType { - BlockingBySlowDriving, - BlockingByWrongWayDriving, - ReversingOffTheStartLine, - BigCollision, - SmallCollision, - CollisionFailedToHandBackPositionSingle, - CollisionFailedToHandBackPositionMultiple, - CornerCuttingGainedTime, - CornerCuttingOvertakeSingle, - CornerCuttingOvertakeMultiple, - CrossedPitExitLane, - IgnoringBlueFlags, - IgnoringYellowFlags, - IgnoringDriveThrough, - TooManyDriveThroughs, - DriveThroughReminderServeWithinNLaps, - DriveThroughReminderServeThisLap, - PitLaneSpeeding, - ParkedForTooLong, - IgnoringTyreRegulations, - TooManyPenalties, - MultipleWarnings, - ApproachingDisqualification, - TyreRegulationsSelectSingle, - TyreRegulationsSelectMultiple, - LapInvalidatedCornerCutting, - LapInvalidatedRunningWide, - CornerCuttingRanWideGainedTimeMinor, - CornerCuttingRanWideGainedTimeSignificant, - CornerCuttingRanWideGainedTimeExtreme, - LapInvalidatedWallRiding, - LapInvalidatedFlashbackUsed, - LapInvalidatedResetToTrack, - BlockingThePitlane, - JumpStart, - SafetyCarToCarCollision, - SafetyCarIllegalOvertake, - SafetyCarExceedingAllowedPace, - VirtualSafetyCarExceedingAllowedPace, - FormationLapBelowAllowedSpeed, - FormationLapParking, - RetiredMechanicalFailure, - RetiredTerminallyDamaged, - SafetyCarFallingTooFarBack, - BlackFlagTimer, - UnservedStopGoPenalty, - UnservedDriveThroughPenalty, - EngineComponentChange, - GearboxChange, - ParcFermeChange, - LeagueGridPenalty, - RetryPenalty, - IllegalTimeGain, - MandatoryPitstop, - AttributeAssigned, -} - -pub enum Ruleset { - PracticeAndQualifying, - Race, - TimeTrial, - TimeAttack, - CheckpointChallenge, - Autocross, - Drift, - AverageSpeedZone, - RivalDuel, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[repr(i16)] -pub enum TeamIds { - Mercedes = 0, - Ferrari = 1, - RedBullRacing = 2, - Williams = 3, - AstonMartin = 4, - Alpine = 5, - RB = 6, - Haas = 7, - McLaren = 8, - Sauber = 9, - F1Generic = 41, - F1CustomTeam = 104, - ArtGP2023 = 143, - Campos2023 = 144, - Carlin2023 = 145, - PHM2023 = 146, - Dams2023 = 147, - Hitech2023 = 148, - MPMotorsport2023 = 149, - Prema2023 = 150, - Trident2023 = 151, - VanAmersfoortRacing2023 = 152, - Virtuosi2023 = 153, -} - -impl TryFrom for TeamIds { - type Error = AppError; - - fn try_from(v: i16) -> Result { - match v { - v if v == Self::Mercedes as i16 => Ok(Self::Mercedes), - v if v == Self::Ferrari as i16 => Ok(Self::Ferrari), - v if v == Self::RedBullRacing as i16 => Ok(Self::RedBullRacing), - v if v == Self::Williams as i16 => Ok(Self::Williams), - v if v == Self::AstonMartin as i16 => Ok(Self::AstonMartin), - v if v == Self::Alpine as i16 => Ok(Self::Alpine), - v if v == Self::RB as i16 => Ok(Self::RB), - v if v == Self::Haas as i16 => Ok(Self::Haas), - v if v == Self::McLaren as i16 => Ok(Self::McLaren), - v if v == Self::Sauber as i16 => Ok(Self::Sauber), - v if v == Self::F1Generic as i16 => Ok(Self::F1Generic), - v if v == Self::F1CustomTeam as i16 => Ok(Self::F1CustomTeam), - v if v == Self::ArtGP2023 as i16 => Ok(Self::ArtGP2023), - v if v == Self::Campos2023 as i16 => Ok(Self::Campos2023), - v if v == Self::Carlin2023 as i16 => Ok(Self::Carlin2023), - v if v == Self::PHM2023 as i16 => Ok(Self::PHM2023), - v if v == Self::Dams2023 as i16 => Ok(Self::Dams2023), - v if v == Self::Hitech2023 as i16 => Ok(Self::Hitech2023), - v if v == Self::MPMotorsport2023 as i16 => Ok(Self::MPMotorsport2023), - v if v == Self::Prema2023 as i16 => Ok(Self::Prema2023), - v if v == Self::Trident2023 as i16 => Ok(Self::Trident2023), - v if v == Self::VanAmersfoortRacing2023 as i16 => Ok(Self::VanAmersfoortRacing2023), - v if v == Self::Virtuosi2023 as i16 => Ok(Self::Virtuosi2023), - _ => Err(ChampionshipError::InvalidTeamId)?, - } - } -} - -impl TryFrom for SessionType { - type Error = &'static str; - - fn try_from(value: u8) -> Result { - match value { - 0 => Ok(Self::Unknown), - 1 => Ok(Self::Practice1), - 2 => Ok(Self::Practice2), - 3 => Ok(Self::Practice3), - 4 => Ok(Self::ShortPractice), - 5 => Ok(Self::Q1), - 6 => Ok(Self::Q2), - 7 => Ok(Self::Q3), - 8 => Ok(Self::SQ), - 9 => Ok(Self::Osq), - 10 => Ok(Self::SprintShootout1), - 11 => Ok(Self::SprintShootout2), - 12 => Ok(Self::SprintShootout3), - 13 => Ok(Self::ShortSprintShootout), - 14 => Ok(Self::OneShotSprintShootout), - 15 => Ok(Self::R), - 16 => Ok(Self::R2), - 17 => Ok(Self::R3), - 18 => Ok(Self::TimeTrial), - - _ => Err("Unknown session type"), - } - } -} - -impl TryFrom for PenaltyTypes { - type Error = &'static str; - - fn try_from(value: u8) -> Result { - match value { - 0 => Ok(Self::DriveThrough), - 1 => Ok(Self::StopGo), - 2 => Ok(Self::GridPenalty), - 3 => Ok(Self::PenaltyReminder), - 4 => Ok(Self::TimePenalty), - 5 => Ok(Self::Warning), - 6 => Ok(Self::Disqualified), - 7 => Ok(Self::RemovedFromFormationLap), - 8 => Ok(Self::ParkedTooLongTimer), - 9 => Ok(Self::TyreRegulations), - 10 => Ok(Self::ThisLapInvalidated), - 11 => Ok(Self::ThisAndNextLapInvalidated), - 12 => Ok(Self::ThisLapInvalidatedWithoutReason), - 13 => Ok(Self::ThisAndNextLapInvalidatedWithoutReason), - 14 => Ok(Self::ThisAndPreviousLapInvalidated), - 15 => Ok(Self::ThisAndPreviousLapInvalidatedWithoutReason), - 16 => Ok(Self::Retired), - 17 => Ok(Self::BlackFlagTimer), - _ => Err("Unknown penalty type"), - } - } -} - -impl TryFrom for InfringementType { - type Error = &'static str; - - fn try_from(value: u8) -> Result { - match value { - 0 => Ok(Self::BlockingBySlowDriving), - 1 => Ok(Self::BlockingByWrongWayDriving), - 2 => Ok(Self::ReversingOffTheStartLine), - 3 => Ok(Self::BigCollision), - 4 => Ok(Self::SmallCollision), - 5 => Ok(Self::CollisionFailedToHandBackPositionSingle), - 6 => Ok(Self::CollisionFailedToHandBackPositionMultiple), - 7 => Ok(Self::CornerCuttingGainedTime), - 8 => Ok(Self::CornerCuttingOvertakeSingle), - 9 => Ok(Self::CornerCuttingOvertakeMultiple), - 10 => Ok(Self::CrossedPitExitLane), - 11 => Ok(Self::IgnoringBlueFlags), - 12 => Ok(Self::IgnoringYellowFlags), - 13 => Ok(Self::IgnoringDriveThrough), - 14 => Ok(Self::TooManyDriveThroughs), - 15 => Ok(Self::DriveThroughReminderServeWithinNLaps), - 16 => Ok(Self::DriveThroughReminderServeThisLap), - 17 => Ok(Self::PitLaneSpeeding), - 18 => Ok(Self::ParkedForTooLong), - 19 => Ok(Self::IgnoringTyreRegulations), - 20 => Ok(Self::TooManyPenalties), - 21 => Ok(Self::MultipleWarnings), - 22 => Ok(Self::ApproachingDisqualification), - 23 => Ok(Self::TyreRegulationsSelectSingle), - 24 => Ok(Self::TyreRegulationsSelectMultiple), - 25 => Ok(Self::LapInvalidatedCornerCutting), - 26 => Ok(Self::LapInvalidatedRunningWide), - 27 => Ok(Self::CornerCuttingRanWideGainedTimeMinor), - 28 => Ok(Self::CornerCuttingRanWideGainedTimeSignificant), - 29 => Ok(Self::CornerCuttingRanWideGainedTimeExtreme), - 30 => Ok(Self::LapInvalidatedWallRiding), - 31 => Ok(Self::LapInvalidatedFlashbackUsed), - 32 => Ok(Self::LapInvalidatedResetToTrack), - 33 => Ok(Self::BlockingThePitlane), - 34 => Ok(Self::JumpStart), - 35 => Ok(Self::SafetyCarToCarCollision), - 36 => Ok(Self::SafetyCarIllegalOvertake), - 37 => Ok(Self::SafetyCarExceedingAllowedPace), - 38 => Ok(Self::VirtualSafetyCarExceedingAllowedPace), - 39 => Ok(Self::FormationLapBelowAllowedSpeed), - 40 => Ok(Self::FormationLapParking), - 41 => Ok(Self::RetiredMechanicalFailure), - 42 => Ok(Self::RetiredTerminallyDamaged), - 43 => Ok(Self::SafetyCarFallingTooFarBack), - 44 => Ok(Self::BlackFlagTimer), - 45 => Ok(Self::UnservedStopGoPenalty), - 46 => Ok(Self::UnservedDriveThroughPenalty), - 47 => Ok(Self::EngineComponentChange), - 48 => Ok(Self::GearboxChange), - 49 => Ok(Self::ParcFermeChange), - 50 => Ok(Self::LeagueGridPenalty), - 51 => Ok(Self::RetryPenalty), - 52 => Ok(Self::IllegalTimeGain), - 53 => Ok(Self::MandatoryPitstop), - 54 => Ok(Self::AttributeAssigned), - _ => Err("Unknown infringement type"), - } - } -} - -impl TryFrom for Tracks { - type Error = &'static str; - - fn try_from(value: i8) -> Result { - match value { - 0 => Ok(Self::Melbourne), - 1 => Ok(Self::PaulRicard), - 2 => Ok(Self::Shangai), - 3 => Ok(Self::Sakhir), - 4 => Ok(Self::Catalunya), - 5 => Ok(Self::Monaco), - 6 => Ok(Self::Montreal), - 7 => Ok(Self::Silverstone), - 8 => Ok(Self::Hockenheim), - 9 => Ok(Self::Hungaroring), - 10 => Ok(Self::Spa), - 11 => Ok(Self::Monza), - 12 => Ok(Self::Singapore), - 13 => Ok(Self::Suzuka), - 14 => Ok(Self::AbuDhabi), - 15 => Ok(Self::Texas), - 16 => Ok(Self::Brazil), - 17 => Ok(Self::Austria), - 18 => Ok(Self::Sochi), - 19 => Ok(Self::Mexico), - 20 => Ok(Self::Baku), - 21 => Ok(Self::SakhirShort), - 22 => Ok(Self::SilverstoneShort), - 23 => Ok(Self::TexasShort), - 24 => Ok(Self::SuzukaShort), - 25 => Ok(Self::Hanoi), - 26 => Ok(Self::Zandvoort), - 27 => Ok(Self::Imola), - 28 => Ok(Self::Portimao), - 29 => Ok(Self::Jeddah), - 30 => Ok(Self::Miami), - 31 => Ok(Self::LasVegas), - 32 => Ok(Self::Losail), - _ => Err("Unknown track id"), - } - } -} - -impl TryFrom for Ruleset { - type Error = &'static str; - - fn try_from(value: u8) -> Result { - match value { - 0 => Ok(Self::PracticeAndQualifying), - 1 => Ok(Self::Race), - 2 => Ok(Self::TimeTrial), - 4 => Ok(Self::TimeAttack), - 6 => Ok(Self::CheckpointChallenge), - 8 => Ok(Self::Autocross), - 9 => Ok(Self::Drift), - 10 => Ok(Self::AverageSpeedZone), - 11 => Ok(Self::RivalDuel), - _ => Err("Unknown ruleset id"), - } - } -} - -impl TryFrom<&[u8; 4]> for EventCode { - type Error = &'static str; - - fn try_from(value: &[u8; 4]) -> Result { - match value { - b"SSTA" => Ok(Self::SessionStarted), - b"SEND" => Ok(Self::SessionEnded), - b"FTLP" => Ok(Self::FastestLap), - b"RTMT" => Ok(Self::Retirement), - b"DRSE" => Ok(Self::DRSEnabled), - b"DRSD" => Ok(Self::DRSDisabled), - b"TMPT" => Ok(Self::TeamMateInPits), - b"CHQF" => Ok(Self::ChequeredFlag), - b"RCWN" => Ok(Self::RaceWinner), - b"PENA" => Ok(Self::PenaltyIssued), - b"SPTP" => Ok(Self::SpeedTrapTriggered), - b"STLG" => Ok(Self::StartLights), - b"LGOT" => Ok(Self::LightsOut), - b"DTSV" => Ok(Self::DriveThroughServed), - b"SGSV" => Ok(Self::StopGoServed), - b"FLBK" => Ok(Self::Flashback), - b"BUTN" => Ok(Self::ButtonStatus), - b"RFGO" => Ok(Self::RedFlag), - b"OVTK" => Ok(Self::Overtake), - b"SCAR" => Ok(Self::SafetyCar), - b"COLL" => Ok(Self::Collision), - _ => Err("Unknown event code"), - } - } -} - -impl TryFrom for PacketIds { - type Error = &'static str; - - fn try_from(value: u8) -> Result { - match value { - 0 => Ok(PacketIds::Motion), - 1 => Ok(PacketIds::Session), - 2 => Ok(PacketIds::LapData), - 3 => Ok(PacketIds::Event), - 4 => Ok(PacketIds::Participants), - 5 => Ok(PacketIds::CarSetups), - 6 => Ok(PacketIds::CarTelemetry), - 7 => Ok(PacketIds::CarStatus), - 8 => Ok(PacketIds::FinalClassification), - 9 => Ok(PacketIds::LobbyInfo), - 10 => Ok(PacketIds::CarDamage), - 11 => Ok(PacketIds::SessionHistory), - 12 => Ok(PacketIds::TyreSets), - 13 => Ok(PacketIds::MotionEx), - 14 => Ok(PacketIds::TimeTrial), - _ => Err("Unknown packet id"), - } - } -} - -impl ParticipantData { - #[inline] - pub fn steam_name(&self) -> Option<&str> { - let nul_position = memchr::memchr(0, &self.name)?; - str::from_utf8(&self.name[..nul_position]) - .ok() - .filter(|s| !s.is_empty()) - } -} diff --git a/crates/f1-telemetry/src/types/mod.rs b/crates/f1-telemetry/src/types/mod.rs new file mode 100644 index 0000000..8c2de3f --- /dev/null +++ b/crates/f1-telemetry/src/types/mod.rs @@ -0,0 +1,5 @@ +mod custom; +mod game; + +pub use custom::*; +pub use game::*; diff --git a/crates/token_manager/src/persistence.rs b/crates/token_manager/src/persistence.rs index e0750c8..3d67236 100644 --- a/crates/token_manager/src/persistence.rs +++ b/crates/token_manager/src/persistence.rs @@ -21,21 +21,18 @@ impl TokenManagerPersistence { pub fn save(token_manager: &TokenManager) -> std::io::Result<()> { let mut buffer = Vec::with_capacity(Self::calculate_total_size(token_manager)); - // Write header let header = Header { tokens_count: token_manager.tokens.len() as u64, user_tokens_count: token_manager.user_tokens.len() as u64, }; buffer.extend_from_slice(header.as_bytes()); - // Write tokens for entry in token_manager.tokens.iter() { let (token, token_entry) = entry.pair(); buffer.extend_from_slice(token.as_bytes()); buffer.extend_from_slice(token_entry.as_bytes()); } - // Write user_tokens for entry in token_manager.user_tokens.iter() { let (user_id, tokens) = entry.pair(); buffer.extend_from_slice(&user_id.to_le_bytes()); @@ -45,7 +42,6 @@ impl TokenManagerPersistence { } } - // Write the entire buffer to file in one go let mut file = OpenOptions::new() .write(true) .create(true) @@ -63,16 +59,13 @@ impl TokenManagerPersistence { match File::open(PATH) { Ok(mut file) => { - // Get the file size let file_size = file.metadata()?.len() as usize; - // Read the entire file into a single buffer buffer = vec![0u8; file_size]; file.read_exact(&mut buffer)?; } Err(ref e) if e.kind() == std::io::ErrorKind::NotFound => { - // Create new file with header initialized to zeros let mut file = File::create(PATH)?; let header = Header { tokens_count: 0, @@ -81,7 +74,6 @@ impl TokenManagerPersistence { let header_bytes = header.as_bytes(); file.write_all(header_bytes)?; - // Return an empty TokenManager since there's nothing else to load return Ok(TokenManager { tokens: DashMap::new(), user_tokens: DashMap::new(), @@ -92,7 +84,6 @@ impl TokenManagerPersistence { let mut offset = 0; - // Read header let header = Header::from_bytes(&buffer[offset..offset + size_of::
()]); offset += size_of::
(); @@ -101,7 +92,6 @@ impl TokenManagerPersistence { let now = current_timestamp_s(); - // Read tokens for _ in 0..header.tokens_count { let token = *Token::from_bytes(&buffer[offset..offset + size_of::()]); offset += size_of::(); @@ -115,7 +105,6 @@ impl TokenManagerPersistence { } } - // Read user_tokens for _ in 0..header.user_tokens_count { let user_id = i32::from_le_bytes(buffer[offset..offset + 4].try_into().unwrap()); offset += 4; diff --git a/crates/token_manager/src/token.rs b/crates/token_manager/src/token.rs index 411ad8d..479e856 100644 --- a/crates/token_manager/src/token.rs +++ b/crates/token_manager/src/token.rs @@ -5,7 +5,7 @@ use ring::rand::{SecureRandom, SystemRandom}; use error::{AppResult, TokenError}; -#[repr(C)] +#[repr(transparent)] #[derive(Clone, Copy, PartialEq, Eq, Hash)] pub struct Token([u8; 16]);