From f6500ce2cd312f7c5d51f16e043d213390173153 Mon Sep 17 00:00:00 2001 From: Lol3rrr Date: Thu, 12 Sep 2024 00:13:26 +0200 Subject: [PATCH] Start with the analysis stuff --- Cargo.lock | 231 +++++++++++++++++- backend/Cargo.toml | 4 + backend/src/analysis.rs | 131 ++++++++++ backend/src/api.rs | 35 ++- backend/src/lib.rs | 2 + backend/src/main.rs | 30 ++- backend/src/models.rs | 16 ++ backend/src/schema.rs | 21 +- common/src/lib.rs | 1 + frontend/src/demo.rs | 25 +- frontend/src/lib.rs | 4 +- frontend/src/main.rs | 5 +- migrations/2024-09-07-151517_demos/up.sql | 3 +- .../2024-09-11-200628_demo_info/down.sql | 3 + migrations/2024-09-11-200628_demo_info/up.sql | 10 + 15 files changed, 498 insertions(+), 23 deletions(-) create mode 100644 backend/src/analysis.rs create mode 100644 migrations/2024-09-11-200628_demo_info/down.sql create mode 100644 migrations/2024-09-11-200628_demo_info/up.sql diff --git a/Cargo.lock b/Cargo.lock index a188f96..a9930d8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,19 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "getrandom", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "1.1.3" @@ -156,6 +169,7 @@ dependencies = [ name = "backend" version = "0.1.0" dependencies = [ + "ahash", "async-trait", "axum", "common", @@ -163,6 +177,8 @@ dependencies = [ "diesel-async", "diesel_async_migrations", "futures-util", + "memmap2", + "parser", "reqwest 0.12.7", "serde", "serde_json", @@ -202,6 +218,12 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "bit_reverse" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99528ca30abb9495c7e106bf7c3177b257c62040fc0f2909fe470b0f43097296" + [[package]] name = "bitflags" version = "1.3.2" @@ -214,6 +236,12 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +[[package]] +name = "bitter" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef3a13b71496a92e8c00ebe576b260655b56935cd5118d5a8949788b651b5e07" + [[package]] name = "block-buffer" version = "0.10.4" @@ -308,7 +336,7 @@ version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7328b20597b53c2454f0b1919720c25c7339051c02b72b7e05409e00b14132be" dependencies = [ - "convert_case", + "convert_case 0.6.0", "lazy_static", "nom", "pathdiff", @@ -336,6 +364,12 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + [[package]] name = "convert_case" version = "0.6.0" @@ -381,6 +415,31 @@ dependencies = [ "libc", ] +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + [[package]] name = "crunchy" version = "0.2.2" @@ -397,6 +456,17 @@ dependencies = [ "typenum", ] +[[package]] +name = "csgoproto" +version = "0.1.5" +source = "git+https://github.com/LaihoE/demoparser.git#60974266a0374000f83d31172ac823135e93482b" +dependencies = [ + "bytes", + "glob", + "proc-macro2", + "protobuf", +] + [[package]] name = "darling" version = "0.20.10" @@ -466,6 +536,19 @@ dependencies = [ "syn", ] +[[package]] +name = "derive_more" +version = "0.99.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" +dependencies = [ + "convert_case 0.4.0", + "proc-macro2", + "quote", + "rustc_version", + "syn", +] + [[package]] name = "diesel" version = "2.2.4" @@ -771,6 +854,12 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + [[package]] name = "gloo-net" version = "0.1.0" @@ -1160,6 +1249,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.11" @@ -1227,7 +1325,7 @@ dependencies = [ "getrandom", "html-escape", "indexmap", - "itertools", + "itertools 0.12.1", "js-sys", "leptos_reactive", "once_cell", @@ -1270,9 +1368,9 @@ checksum = "90eaea005cabb879c091c84cfec604687ececfd540469e5a30a60c93489a2f23" dependencies = [ "attribute-derive", "cfg-if", - "convert_case", + "convert_case 0.6.0", "html-escape", - "itertools", + "itertools 0.12.1", "leptos_hot_reload", "prettyplease", "proc-macro-error", @@ -1320,7 +1418,7 @@ checksum = "e5006e35b7c768905286dbea0d3525396cd39d961cb7b9fb664aa00b0c984ae6" dependencies = [ "cfg-if", "gloo-net 0.6.0", - "itertools", + "itertools 0.12.1", "js-sys", "lazy_static", "leptos", @@ -1453,6 +1551,15 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "memmap2" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322" +dependencies = [ + "libc", +] + [[package]] name = "mime" version = "0.3.17" @@ -1660,6 +1767,33 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "parser" +version = "0.1.1" +source = "git+https://github.com/LaihoE/demoparser.git#60974266a0374000f83d31172ac823135e93482b" +dependencies = [ + "ahash", + "bit_reverse", + "bitter", + "bytes", + "csgoproto", + "derive_more", + "itertools 0.13.0", + "lazy_static", + "libc", + "memmap2", + "phf", + "phf_macros", + "proc-macro2", + "protobuf", + "protobuf-support", + "rand", + "rayon", + "regex", + "serde", + "snap", +] + [[package]] name = "paste" version = "1.0.15" @@ -1687,6 +1821,29 @@ dependencies = [ "phf_shared", ] +[[package]] +name = "phf_generator" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +dependencies = [ + "phf_shared", + "rand", +] + +[[package]] +name = "phf_macros" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "phf_shared" version = "0.11.2" @@ -1855,6 +2012,27 @@ dependencies = [ "yansi", ] +[[package]] +name = "protobuf" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df67496db1a89596beaced1579212e9b7c53c22dca1d9745de00ead76573d514" +dependencies = [ + "bytes", + "once_cell", + "protobuf-support", + "thiserror", +] + +[[package]] +name = "protobuf-support" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e2d30ab1878b2e72d1e2fc23ff5517799c9929e2cf81a8516f9f4dcf2b9cf3" +dependencies = [ + "thiserror", +] + [[package]] name = "quote" version = "1.0.37" @@ -1916,6 +2094,26 @@ dependencies = [ "getrandom", ] +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + [[package]] name = "redox_syscall" version = "0.5.3" @@ -2087,6 +2285,15 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + [[package]] name = "rustix" version = "0.38.36" @@ -2224,6 +2431,12 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d369a96f978623eb3dc28807c4852d6cc617fed53da5d3c400feff1ef34a714a" +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + [[package]] name = "send_wrapper" version = "0.6.0" @@ -2374,7 +2587,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9cf0e6f71fc924df36e87f27dfbd447f0bedd092d365db3a5396878256d9f00c" dependencies = [ "const_format", - "convert_case", + "convert_case 0.6.0", "proc-macro2", "quote", "syn", @@ -2448,6 +2661,12 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +[[package]] +name = "snap" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b6b67fb9a61334225b5b790716f609cd58395f895b3fe8b328786812a40bc3b" + [[package]] name = "socket2" version = "0.5.7" diff --git a/backend/Cargo.toml b/backend/Cargo.toml index 8beca8a..4fd8b6e 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -24,3 +24,7 @@ diesel_async_migrations = { version = "0.15" } reqwest = { version = "0.12", features = ["json"] } common = { path = "../common/" } + +l_demoparser = { package = "parser", git = "https://github.com/LaihoE/demoparser.git", ref = "main" } +ahash = { version = "0.8" } +memmap2 = { version = "0.9" } diff --git a/backend/src/analysis.rs b/backend/src/analysis.rs new file mode 100644 index 0000000..369af50 --- /dev/null +++ b/backend/src/analysis.rs @@ -0,0 +1,131 @@ +use std::path::PathBuf; + +#[derive(Debug)] +pub struct AnalysisInput { + pub steamid: String, + pub demoid: i64, + pub path: PathBuf, +} + +#[derive(Debug)] +pub struct BaseInfo { + pub map: String, +} + +#[tracing::instrument(skip(input))] +pub fn analyse_base(input: AnalysisInput) -> BaseInfo { + tracing::info!("Performing Base analysis"); + + let huf = l_demoparser::second_pass::parser_settings::create_huffman_lookup_table(); + let settings = l_demoparser::first_pass::parser_settings::ParserInputs { + wanted_players: Vec::new(), + real_name_to_og_name: ahash::AHashMap::default(), + wanted_player_props: vec!["X".to_string(), "team_num".to_string()], + wanted_events: vec!["player_death".to_string(), "player_team".to_string(), "team_info".to_string(), "player_spawn".to_string(), "team_score".to_string(), "round_end".to_string(), "game_end".to_string(), "match_end_conditions".to_string(), "switch_team".to_string(), "player_given_c4".to_string()], + wanted_other_props: vec![], + parse_ents: true, + wanted_ticks: Vec::new(), + parse_projectiles: false, + only_header: false, + count_props: false, + only_convars: false, + huffman_lookup_table: &huf, + order_by_steamid: false, + }; + + let mut ds = l_demoparser::parse_demo::Parser::new(settings, l_demoparser::parse_demo::ParsingMode::ForceSingleThreaded); + let file = std::fs::File::open(&input.path).unwrap(); + let mmap = unsafe { memmap2::MmapOptions::new().map(&file).unwrap() }; + let output = ds.parse_demo(&mmap).unwrap(); + + let header = output.header.as_ref().unwrap(); + + tracing::info!("Header: {:?}", header); + + for event in output.game_events.iter() { + match event.name.as_str() { + "player_team" => { + let team = event.fields.iter().find_map(|f| match (f.name.as_str(), &f.data) { + ("team", Some(d)) => Some(d), + ("team", None) => { + tracing::warn!("'team' field without data"); + None + } + _ => None, + }); + let user_name = event.fields.iter().find_map(|f| match (f.name.as_str(), &f.data) { + ("user_name", Some(d)) => Some(d), + ("user_name", None) => { + tracing::warn!("'user_name' field without data"); + None + } + _ => None, + }); + let steamid = event.fields.iter().find_map(|f| match (f.name.as_str(), &f.data) { + ("user_steamid", Some(d)) => Some(d), + ("user_steamid", None) => { + tracing::warn!("'user_steamid' field without data"); + None + } + _ => None, + }); + + tracing::info!("'{:?}' ({:?}) -> {:?}", user_name, steamid, team); + } + "team_info" => { + tracing::info!("Team Info: {:?}", event); + } + "player_spawn" => { + // tracing::info!("Player Spawn: {:?}", event); + } + "team_score" => { + tracing::info!("Team Score: {:?}", event); + } + "round_end" => { + let winner = event.fields.iter().find_map(|f| match (f.name.as_str(), &f.data) { + ("winner", Some(d)) => Some(d), + ("winner", None) => { + tracing::warn!("'winner' field without data"); + None + } + _ => None, + }); + let round = event.fields.iter().find_map(|f| match (f.name.as_str(), &f.data) { + ("round", Some(d)) => Some(d), + ("round", None) => { + tracing::warn!("'round' field without data"); + None + } + _ => None, + }); + let reason = event.fields.iter().find_map(|f| match (f.name.as_str(), &f.data) { + ("reason", Some(d)) => Some(d), + ("reason", None) => { + tracing::warn!("'reason' field without data"); + None + } + _ => None, + }); + + tracing::info!(?winner, ?round, ?reason, "Round End"); + } + "game_end" => { + tracing::info!("Game End: {:?}", event); + } + "match_end_conditions" => { + tracing::info!("Match End Conditions: {:?}", event); + } + "switch_team" => { + tracing::info!("Switch Team: {:?}", event); + } + "player_given_c4" => { + tracing::info!("Player Given C4: {:?}", event); + } + _ => {} + }; + } + + BaseInfo { + map: header.get("map_name").cloned().unwrap_or_default() + } +} diff --git a/backend/src/api.rs b/backend/src/api.rs index 0fa0f44..0397a5d 100644 --- a/backend/src/api.rs +++ b/backend/src/api.rs @@ -7,15 +7,17 @@ pub mod demos { struct DemoState { upload_folder: std::path::PathBuf, + base_analysis: tokio::sync::mpsc::UnboundedSender } - pub fn router

(upload_folder: P) -> axum::Router where P: Into { + pub fn router

(upload_folder: P, base_analysis: tokio::sync::mpsc::UnboundedSender) -> axum::Router where P: Into { axum::Router::new() .route("/list", axum::routing::get(list)) .route("/upload", axum::routing::post(upload).layer(axum::extract::DefaultBodyLimit::max(500*1024*1024))) .route("/:id/info", axum::routing::get(info)) .with_state(Arc::new(DemoState { upload_folder: upload_folder.into(), + base_analysis, })) } @@ -24,11 +26,12 @@ pub mod demos { let steam_id = session.data().steam_id.ok_or_else(|| axum::http::StatusCode::UNAUTHORIZED)?; tracing::info!("SteamID: {:?}", steam_id); - let query = crate::schema::demos::dsl::demos.filter(crate::schema::demos::dsl::steam_id.eq(steam_id.to_string())); - let results: Vec = query.load(&mut crate::db_connection().await).await.unwrap(); + let query = crate::schema::demos::dsl::demos.inner_join(crate::schema::demo_info::dsl::demo_info).select((crate::models::Demo::as_select(), crate::models::DemoInfo::as_select())).filter(crate::schema::demos::dsl::steam_id.eq(steam_id.to_string())); + let results: Vec<(crate::models::Demo, crate::models::DemoInfo)> = query.load(&mut crate::db_connection().await).await.unwrap(); - Ok(axum::response::Json(results.into_iter().map(|demo| common::BaseDemoInfo { + Ok(axum::response::Json(results.into_iter().map(|(demo, info)| common::BaseDemoInfo { id: demo.demo_id, + map: info.map, }).collect::>())) } @@ -46,15 +49,29 @@ pub mod demos { } let timestamp_secs = std::time::SystemTime::now().duration_since(std::time::SystemTime::UNIX_EPOCH).unwrap().as_secs(); + let demo_id = timestamp_secs as i64; let demo_file_path = user_folder.join(format!("{}.dem", timestamp_secs)); - tokio::fs::write(demo_file_path, file_content).await.unwrap(); + tokio::fs::write(&demo_file_path, file_content).await.unwrap(); + + let mut db_con = crate::db_connection().await; let query = diesel::dsl::insert_into(crate::schema::demos::dsl::demos).values(crate::models::Demo { - demo_id: timestamp_secs as i64, + demo_id, steam_id: steam_id.to_string(), }); - query.execute(&mut crate::db_connection().await).await.unwrap(); + query.execute(&mut db_con).await.unwrap(); + + state.base_analysis.send(crate::analysis::AnalysisInput { + steamid: steam_id.to_string(), + demoid: demo_id, + path: demo_file_path, + }); + let processing_query = diesel::dsl::insert_into(crate::schema::processing_status::dsl::processing_status).values(crate::models::ProcessingStatus { + demo_id, + info: 0, + }); + processing_query.execute(&mut db_con).await.unwrap(); Ok(axum::response::Redirect::to("/")) } @@ -189,9 +206,9 @@ pub mod user { } } -pub fn router() -> axum::Router { +pub fn router(base_analysis: tokio::sync::mpsc::UnboundedSender) -> axum::Router { axum::Router::new() .nest("/steam/", steam::router("http://localhost:3000", "/api/steam/callback")) - .nest("/demos/", demos::router("uploads/")) + .nest("/demos/", demos::router("uploads/", base_analysis)) .nest("/user/", user::router()) } diff --git a/backend/src/lib.rs b/backend/src/lib.rs index 2379f64..ecf5f65 100644 --- a/backend/src/lib.rs +++ b/backend/src/lib.rs @@ -6,6 +6,8 @@ pub use usersession::{UserSessionData, UserSession}; pub mod diesel_sessionstore; +pub mod analysis; + pub async fn db_connection() -> diesel_async::AsyncPgConnection { use diesel_async::AsyncConnection; diff --git a/backend/src/main.rs b/backend/src/main.rs index 1993547..c732b22 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -26,6 +26,34 @@ async fn main() { run_migrations(&mut backend::db_connection().await).await; tracing::info!("Completed Migrations"); + let (base_analysis_tx, mut base_analysis_rx) = tokio::sync::mpsc::unbounded_channel::(); + tokio::task::spawn_blocking(move || { + while let Some(input) = base_analysis_rx.blocking_recv() { + let demo_id = input.demoid; + let result = backend::analysis::analyse_base(input); + + dbg!(&result); + + let handle = tokio::task::spawn( + async move { + let mut db_con = backend::db_connection().await; + + let store_info_query = diesel::dsl::insert_into(backend::schema::demo_info::dsl::demo_info).values(backend::models::DemoInfo { + demo_id, + map: result.map, + }); + let update_process_info = diesel::dsl::update(backend::schema::processing_status::dsl::processing_status).set(backend::schema::processing_status::dsl::info.eq(1)).filter(backend::schema::processing_status::dsl::demo_id.eq(demo_id)); + + tracing::trace!(?store_info_query, "Store demo info query"); + tracing::trace!(?update_process_info, "Update processing info query"); + + store_info_query.execute(&mut db_con).await.unwrap(); + update_process_info.execute(&mut db_con).await.unwrap(); + } + ); + } + }); + let session_store = backend::diesel_sessionstore::DieselStore::new(); let session_layer = tower_sessions::SessionManagerLayer::new(session_store) .with_secure(false) @@ -38,7 +66,7 @@ async fn main() { } let router = axum::Router::new() - .nest("/api/", backend::api::router()) + .nest("/api/", backend::api::router(base_analysis_tx)) .layer(session_layer) .nest_service("/", tower_http::services::ServeDir::new("frontend/dist/")); diff --git a/backend/src/models.rs b/backend/src/models.rs index ae82344..5a4e6f0 100644 --- a/backend/src/models.rs +++ b/backend/src/models.rs @@ -24,3 +24,19 @@ pub struct User { pub steamid: String, pub name: String, } + +#[derive(Queryable, Selectable, Insertable, Debug)] +#[diesel(table_name = crate::schema::demo_info)] +#[diesel(check_for_backend(diesel::pg::Pg))] +pub struct DemoInfo { + pub demo_id: i64, + pub map: String, +} + +#[derive(Queryable, Selectable, Insertable, Debug)] +#[diesel(table_name = crate::schema::processing_status)] +#[diesel(check_for_backend(diesel::pg::Pg))] +pub struct ProcessingStatus { + pub demo_id: i64, + pub info: i16, +} diff --git a/backend/src/schema.rs b/backend/src/schema.rs index dd9ec99..b16afa1 100644 --- a/backend/src/schema.rs +++ b/backend/src/schema.rs @@ -1,12 +1,26 @@ // @generated automatically by Diesel CLI. diesel::table! { - demos (steam_id, demo_id) { + demo_info (demo_id) { + demo_id -> Int8, + map -> Text, + } +} + +diesel::table! { + demos (demo_id) { steam_id -> Text, demo_id -> Int8, } } +diesel::table! { + processing_status (demo_id) { + demo_id -> Int8, + info -> Int2, + } +} + diesel::table! { sessions (id) { id -> Text, @@ -22,8 +36,13 @@ diesel::table! { } } +diesel::joinable!(demo_info -> demos (demo_id)); +diesel::joinable!(processing_status -> demos (demo_id)); + diesel::allow_tables_to_appear_in_same_query!( + demo_info, demos, + processing_status, sessions, users, ); diff --git a/common/src/lib.rs b/common/src/lib.rs index 0b74cef..4154d27 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -1,6 +1,7 @@ #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub struct BaseDemoInfo { pub id: i64, + pub map: String, } #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] diff --git a/frontend/src/demo.rs b/frontend/src/demo.rs index 402c76f..fbf3830 100644 --- a/frontend/src/demo.rs +++ b/frontend/src/demo.rs @@ -1,4 +1,5 @@ use leptos::*; +use leptos_router::{Route, Routes, Outlet, A}; #[leptos::component] pub fn demo() -> impl leptos::IntoView { @@ -12,6 +13,28 @@ pub fn demo() -> impl leptos::IntoView { }); view! { -

Demo - {id}

+

Demo - { id }

+ +
+ Scoreboard + Per Round +
+
+ +
+ } +} + +#[leptos::component] +pub fn scoreboard() -> impl leptos::IntoView { + view! { +

Scoreboard

+ } +} + +#[leptos::component] +pub fn per_round() -> impl leptos::IntoView { + view! { +

Per Round

} } diff --git a/frontend/src/lib.rs b/frontend/src/lib.rs index 2be2aa4..bfcebf0 100644 --- a/frontend/src/lib.rs +++ b/frontend/src/lib.rs @@ -1,7 +1,7 @@ use leptos::*; use leptos_router::A; -mod demo; +pub mod demo; pub use demo::Demo; mod navbar; @@ -17,7 +17,7 @@ pub enum DemoUploadStatus { pub fn demo_list_entry(demo: common::BaseDemoInfo) -> impl leptos::IntoView { view! {
  • - Demo: {demo.id} + Demo: {demo.map} - {demo.id}
  • } } diff --git a/frontend/src/main.rs b/frontend/src/main.rs index 16dc74b..d78e987 100644 --- a/frontend/src/main.rs +++ b/frontend/src/main.rs @@ -27,7 +27,10 @@ fn main() { - + + + + diff --git a/migrations/2024-09-07-151517_demos/up.sql b/migrations/2024-09-07-151517_demos/up.sql index 0575c0f..1ea90ff 100644 --- a/migrations/2024-09-07-151517_demos/up.sql +++ b/migrations/2024-09-07-151517_demos/up.sql @@ -1,6 +1,5 @@ -- Your SQL goes here CREATE TABLE IF NOT EXISTS demos ( steam_id TEXT NOT NULL, - demo_id bigint NOT NULL, - PRIMARY KEY(steam_id, demo_id) + demo_id bigint NOT NULL PRIMARY KEY ) diff --git a/migrations/2024-09-11-200628_demo_info/down.sql b/migrations/2024-09-11-200628_demo_info/down.sql new file mode 100644 index 0000000..3df2430 --- /dev/null +++ b/migrations/2024-09-11-200628_demo_info/down.sql @@ -0,0 +1,3 @@ +-- This file should undo anything in `up.sql` +DROP TABLE processing_status; +DROP TABLE demo_info diff --git a/migrations/2024-09-11-200628_demo_info/up.sql b/migrations/2024-09-11-200628_demo_info/up.sql new file mode 100644 index 0000000..b867458 --- /dev/null +++ b/migrations/2024-09-11-200628_demo_info/up.sql @@ -0,0 +1,10 @@ +-- Your SQL goes here +CREATE TABLE IF NOT EXISTS processing_status ( + demo_id bigint PRIMARY KEY REFERENCES demos(demo_id), + info int2 NOT NULL -- the processing_status of the basic demo info +); + +CREATE TABLE IF NOT EXISTS demo_info ( + demo_id bigint PRIMARY KEY REFERENCES demos(demo_id), + map TEXT NOT NULL +)