From 4ec5b98df40e9b0f35c9c494d9769ecfe44e3871 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Val=C3=A8re=20Plantevin?= Date: Mon, 4 May 2026 16:13:40 -0400 Subject: [PATCH] Add config and basic architecture for QUIC --- .idea/.gitignore | 10 +++ .idea/encodings.xml | 4 ++ .idea/inspectionProfiles/Project_Default.xml | 6 ++ .idea/modules.xml | 8 +++ .idea/prettier.xml | 6 ++ .idea/quic_ecs_dt.iml | 12 ++++ .idea/vcs.xml | 6 ++ Cargo.toml | 27 ++++++++ simulator/Cargo.toml | 4 ++ substrate/Cargo.toml | 10 +++ substrate/src/config.rs | 49 ++++++++++++++ substrate/src/main.rs | 18 ++++- substrate/src/transport/ecs.rs | 69 ++++++++++++++++++++ substrate/src/transport/mod.rs | 11 ++++ substrate/src/transport/server.rs | 8 +++ 15 files changed, 246 insertions(+), 2 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/encodings.xml create mode 100644 .idea/inspectionProfiles/Project_Default.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/prettier.xml create mode 100644 .idea/quic_ecs_dt.iml create mode 100644 .idea/vcs.xml create mode 100644 substrate/src/config.rs create mode 100644 substrate/src/transport/ecs.rs create mode 100644 substrate/src/transport/mod.rs create mode 100644 substrate/src/transport/server.rs diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..ab1f416 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,10 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Ignored default folder with query files +/queries/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..df87cf9 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..03d9549 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..ca74eb7 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/prettier.xml b/.idea/prettier.xml new file mode 100644 index 0000000..b0c1c68 --- /dev/null +++ b/.idea/prettier.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/quic_ecs_dt.iml b/.idea/quic_ecs_dt.iml new file mode 100644 index 0000000..0df299e --- /dev/null +++ b/.idea/quic_ecs_dt.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index c4fffb5..3a6c616 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,3 +1,30 @@ [workspace] resolver = "3" members = ["simulator", "substrate"] + +# Enable a small amount of optimization in the dev profile. +[profile.dev] +opt-level = 1 + +# Enable a large amount of optimization in the dev profile for dependencies. +[profile.dev.package."*"] +opt-level = 3 + +# Enable more optimization in the release profile at the cost of compile time. +[profile.release] +# Compile the entire crate as one unit. +# Slows compile times, marginal improvements. +codegen-units = 1 +# Do a second optimization pass over the entire program, including dependencies. +# Slows compile times, marginal improvements. +lto = "thin" + +# Optimize for size in the wasm-release profile to reduce load times and bandwidth usage on web. +[profile.wasm-release] +# Default to release profile values. +inherits = "release" +# Optimize with size in mind (also try "z", sometimes it is better). +# Slightly slows compile times, great improvements to file size and runtime performance. +opt-level = "s" +# Strip all debugging information from the binary to slightly reduce file size. +strip = "debuginfo" diff --git a/simulator/Cargo.toml b/simulator/Cargo.toml index 85d985e..7b9d63e 100644 --- a/simulator/Cargo.toml +++ b/simulator/Cargo.toml @@ -4,3 +4,7 @@ version = "0.1.0" edition = "2024" [dependencies] +thiserror = "2" +anyhow = "1" +bevy = "0.18" +game_sockets = { git = "https://github.com/VALERE91/game_sockets.git"} \ No newline at end of file diff --git a/substrate/Cargo.toml b/substrate/Cargo.toml index 00f83c3..25a5860 100644 --- a/substrate/Cargo.toml +++ b/substrate/Cargo.toml @@ -4,3 +4,13 @@ version = "0.1.0" edition = "2024" [dependencies] +bevy = "0.18" +thiserror = "2" +anyhow = "1" +tracing-subscriber = "0.3" +quinn = { version = "0.11" } +rustls = { version = "0.23" } +tokio = { version = "1", features = ["full"] } +uuid = { version = "1.23", features = ["v4"] } +figment = { version = "0.10", features = ["toml", "env"] } +serde = { version = "1", features = ["derive"] } \ No newline at end of file diff --git a/substrate/src/config.rs b/substrate/src/config.rs new file mode 100644 index 0000000..718f5e0 --- /dev/null +++ b/substrate/src/config.rs @@ -0,0 +1,49 @@ +use bevy::prelude::Resource; +use figment::Figment; +use figment::providers::{Env, Format, Serialized, Toml}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Resource, Serialize, Deserialize)] +pub struct AppConfig { + pub network: QuicConfig, + pub simulation: SimulationConfig, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct SimulationConfig { + pub tick_rate_hz: u32, + pub max_entities: usize, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct QuicConfig { + pub server_port: u16, + pub server_interface: String, + pub server_cert: String, +} + +impl Default for AppConfig { + fn default() -> Self { + Self { + network : QuicConfig { + server_port: 9000, + server_interface: "0.0.0.0".to_string(), + server_cert: "cert.pem".to_string(), + }, + simulation: SimulationConfig { + tick_rate_hz: 60, + max_entities: 10000, + }, + } + } +} + +impl AppConfig { + pub fn load(config_file: &str) -> Result { + Figment::new() + .merge(Serialized::defaults(Self::default())) // compiled-in defaults + .merge(Toml::file(config_file)) // config file + .merge(Env::prefixed("APP_")) // env overrides, e.g. APP_NETWORK__PORT=9000 + .extract() + } +} \ No newline at end of file diff --git a/substrate/src/main.rs b/substrate/src/main.rs index e7a11a9..170faa1 100644 --- a/substrate/src/main.rs +++ b/substrate/src/main.rs @@ -1,3 +1,17 @@ +mod transport; +mod config; + +use std::sync::Arc; +use bevy::prelude::*; +use crate::config::AppConfig; + fn main() { - println!("Hello, world!"); -} + let config = AppConfig::load("config.toml").expect("Failed to load config"); + println!("{:?}", config); + + App::new() + .insert_resource(config) + .add_plugins(MinimalPlugins) + .add_plugins(transport::ecs::EcsQuicTransportPlugin{}) + .run(); +} \ No newline at end of file diff --git a/substrate/src/transport/ecs.rs b/substrate/src/transport/ecs.rs new file mode 100644 index 0000000..e3e40ce --- /dev/null +++ b/substrate/src/transport/ecs.rs @@ -0,0 +1,69 @@ +use std::sync::{Arc, Mutex}; +use bevy::prelude::*; +use tokio::sync::mpsc; +use crate::config::QuicConfig; +use crate::transport::QuicMessage; +use crate::transport::server::run_substrate_server; + +const T1_CAPACITY: usize = 1024; +const T2_CAPACITY: usize = 512; +const T3_CAPACITY: usize = 256; + +pub struct EcsQuicTransportPlugin{} + +#[derive(Resource)] +struct BridgeReceivers { + t1: Mutex>, + t2: Mutex>, + t3: Mutex>, +} + +fn ingest_system(bridge: Res){ + let mut t1 = bridge.t1.lock().unwrap(); + // Tier 1: drain up to N messages, drop the rest + for _ in 0..T1_CAPACITY { + match t1.try_recv() { + Ok(msg) => { /* write RawSensorData */ } + Err(_) => break, + } + } + + // T2/T3: drain completely, these are low volume + let mut t2 = bridge.t2.lock().unwrap(); + while let Ok(msg) = t2.try_recv() { /* ... */ } + + let mut t3 = bridge.t3.lock().unwrap(); + while let Ok(msg) = t3.try_recv() { /* ... */ } +} + +impl Plugin for EcsQuicTransportPlugin{ + fn build(&self, app: &mut App) { + // Create the channels for multi-thread communication + let (t1_tx, t1_rx) = + mpsc::channel::(T1_CAPACITY); + let (t2_tx, t2_rx) = + mpsc::channel::(T2_CAPACITY); + let (t3_tx, t3_rx) = + mpsc::channel::(T3_CAPACITY); + + let quic_handle = std::thread::spawn(move || { + let rt = tokio::runtime::Builder::new_multi_thread() + .worker_threads(2) + .enable_all() + .build() + .unwrap(); + + rt.block_on(async move { + run_substrate_server(t1_tx, t2_tx, t3_tx).await; + }); + }); + + app.insert_resource(BridgeReceivers { + t1: Mutex::new(t1_rx), + t2: Mutex::new(t2_rx), + t3: Mutex::new(t3_rx), + }); + + app.add_systems(PreUpdate, ingest_system); + } +} \ No newline at end of file diff --git a/substrate/src/transport/mod.rs b/substrate/src/transport/mod.rs new file mode 100644 index 0000000..090b820 --- /dev/null +++ b/substrate/src/transport/mod.rs @@ -0,0 +1,11 @@ +pub mod ecs; +mod server; + +#[derive(Debug, Clone, Default, Copy, PartialEq)] +pub struct QuicMessage{ + pub device_id: uuid::Uuid, + pub data_stream_id: u16, + pub raw_value: f64, + pub timestamp_us: u64, + pub sequence_number: u32, +} \ No newline at end of file diff --git a/substrate/src/transport/server.rs b/substrate/src/transport/server.rs new file mode 100644 index 0000000..99d000f --- /dev/null +++ b/substrate/src/transport/server.rs @@ -0,0 +1,8 @@ +use tokio::sync::mpsc::Sender; +use crate::transport::QuicMessage; + +pub async fn run_substrate_server(t1_tx: Sender, + t2_tx: Sender, + t3_tx: Sender) { + +} \ No newline at end of file