Change demoid to String and now use uuidV7 for it. Also add timestamps of demo uploads

This commit is contained in:
Lol3rrr
2024-10-10 12:46:41 +02:00
parent 539adecf5d
commit 351b4e016d
17 changed files with 112 additions and 77 deletions

View File

@@ -3,21 +3,38 @@ use std::path::PathBuf;
use diesel::prelude::*;
use diesel_async::RunQueryDsl;
pub mod perround;
pub mod base;
pub mod heatmap;
pub mod perround;
pub trait Analysis {
fn analyse(&self, input: AnalysisInput) -> Result<Box<dyn FnOnce(&mut diesel_async::pg::AsyncPgConnection) -> core::pin::Pin<Box<(dyn core::future::Future<Output = Result<(), diesel::result::Error>> + Send + '_)>> + Send>, ()>;
fn analyse(
&self,
input: AnalysisInput,
) -> Result<
Box<
dyn FnOnce(
&mut diesel_async::pg::AsyncPgConnection,
) -> core::pin::Pin<
Box<
(dyn core::future::Future<Output = Result<(), diesel::result::Error>>
+ Send
+ '_),
>,
> + Send,
>,
(),
>;
}
pub static ANALYSIS_METHODS: std::sync::LazyLock<[std::sync::Arc<dyn Analysis + Send + Sync>; 3]> = std::sync::LazyLock::new(|| {
[
std::sync::Arc::new(base::BaseAnalysis::new()),
std::sync::Arc::new(heatmap::HeatmapAnalysis::new()),
std::sync::Arc::new(perround::PerRoundAnalysis::new()),
]
});
pub static ANALYSIS_METHODS: std::sync::LazyLock<[std::sync::Arc<dyn Analysis + Send + Sync>; 3]> =
std::sync::LazyLock::new(|| {
[
std::sync::Arc::new(base::BaseAnalysis::new()),
std::sync::Arc::new(heatmap::HeatmapAnalysis::new()),
std::sync::Arc::new(perround::PerRoundAnalysis::new()),
]
});
pub async fn poll_next_task(
upload_folder: &std::path::Path,
@@ -45,7 +62,7 @@ pub async fn poll_next_task(
diesel::dsl::delete(crate::schema::analysis_queue::dsl::analysis_queue)
.filter(
crate::schema::analysis_queue::dsl::demo_id
.eq(final_result.demo_id),
.eq(final_result.demo_id.clone()),
)
.filter(
crate::schema::analysis_queue::dsl::steam_id
@@ -82,7 +99,7 @@ pub async fn poll_next_task(
#[derive(Debug, Clone)]
pub struct AnalysisInput {
pub steamid: String,
pub demoid: i64,
pub demoid: String,
pub path: PathBuf,
}

View File

@@ -41,14 +41,14 @@ impl Analysis for BaseAnalysis {
.map(|(info, stats)| {
(
crate::models::DemoPlayer {
demo_id: input.demoid,
demo_id: input.demoid.clone(),
name: info.name,
steam_id: info.steam_id.clone(),
team: info.team as i16,
color: info.color as i16,
},
crate::models::DemoPlayerStats {
demo_id: input.demoid,
demo_id: input.demoid.clone(),
steam_id: info.steam_id,
deaths: stats.deaths as i16,
kills: stats.kills as i16,
@@ -60,7 +60,7 @@ impl Analysis for BaseAnalysis {
.unzip();
let demo_info = crate::models::DemoInfo {
demo_id: input.demoid,
demo_id: input.demoid.clone(),
map: base_result.map,
};

View File

@@ -38,7 +38,7 @@ impl Analysis for HeatmapAnalysis {
tracing::trace!("HeatMap for Player: {:?}", player);
crate::models::DemoPlayerHeatmap {
demo_id: input.demoid,
demo_id: input.demoid.clone(),
steam_id: player,
data: serde_json::to_string(&heatmap).unwrap(),
}

View File

@@ -18,7 +18,7 @@ impl Analysis for PerRoundAnalysis {
let values: Vec<crate::models::DemoRound> = result.rounds.into_iter().enumerate().map(|(i, r)| {
crate::models::DemoRound {
demo_id: input.demoid,
demo_id: input.demoid.clone(),
round_number: i as i16,
start_tick: r.start as i64,
end_tick: r.end as i64,

View File

@@ -1,6 +1,7 @@
use crate::UserSession;
use axum::extract::{Path, State};
use diesel::prelude::*;
use diesel::JoinOnDsl;
use diesel_async::RunQueryDsl;
use std::sync::Arc;
@@ -40,7 +41,9 @@ async fn list(
tracing::info!("SteamID: {:?}", steam_id);
let query = crate::schema::demos::dsl::demos
.inner_join(crate::schema::demo_info::dsl::demo_info)
.inner_join(crate::schema::demo_info::table.on(
crate::schema::demos::dsl::demo_id.eq(crate::schema::demo_info::dsl::demo_id),
))
.select((
crate::models::Demo::as_select(),
crate::models::DemoInfo::as_select(),
@@ -60,7 +63,7 @@ async fn list(
))
}
#[tracing::instrument(skip(state, session))]
#[tracing::instrument(skip(state, session, form))]
async fn upload(
State(state): State<Arc<DemoState>>,
session: crate::UserSession,
@@ -81,17 +84,17 @@ async fn upload(
}
};
let raw_demo_id = uuid::Uuid::now_v7();
let demo_id = raw_demo_id.to_string();
tracing::debug!(?demo_id, "Upload Size: {:?}", file_content.len());
let user_folder = std::path::Path::new(&state.upload_folder).join(format!("{}/", steam_id));
if !tokio::fs::try_exists(&user_folder).await.unwrap_or(false) {
tokio::fs::create_dir_all(&user_folder).await.unwrap();
}
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));
let demo_file_path = user_folder.join(format!("{}.dem", demo_id));
tokio::fs::write(&demo_file_path, file_content)
.await
@@ -102,15 +105,15 @@ async fn upload(
// Turn all of this into a single transaction
let query =
diesel::dsl::insert_into(crate::schema::demos::dsl::demos).values(crate::models::Demo {
demo_id,
diesel::dsl::insert_into(crate::schema::demos::dsl::demos).values(crate::models::NewDemo {
demo_id: demo_id.clone(),
steam_id: steam_id.to_string(),
});
query.execute(&mut db_con).await.unwrap();
let queue_query = diesel::dsl::insert_into(crate::schema::analysis_queue::dsl::analysis_queue)
.values(crate::models::AddAnalysisTask {
demo_id,
demo_id: demo_id.clone(),
steam_id: steam_id.to_string(),
});
queue_query.execute(&mut db_con).await.unwrap();
@@ -126,7 +129,7 @@ async fn upload(
#[tracing::instrument(skip(session))]
async fn analyise(
session: crate::UserSession,
Path(demo_id): Path<i64>,
Path(demo_id): Path<String>,
) -> Result<(), (axum::http::StatusCode, &'static str)> {
let steam_id = session
.data()
@@ -139,7 +142,7 @@ async fn analyise(
let query = crate::schema::demos::dsl::demos
.filter(crate::schema::demos::dsl::steam_id.eq(steam_id.to_string()))
.filter(crate::schema::demos::dsl::demo_id.eq(demo_id));
.filter(crate::schema::demos::dsl::demo_id.eq(demo_id.clone()));
let result: Vec<_> = query
.load::<crate::models::Demo>(&mut db_con)
.await
@@ -165,7 +168,7 @@ async fn analyise(
#[tracing::instrument(skip(_session))]
async fn info(
_session: UserSession,
Path(demo_id): Path<i64>,
Path(demo_id): Path<String>,
) -> Result<axum::response::Json<common::DemoInfo>, axum::http::StatusCode> {
tracing::info!("Get info for Demo: {:?}", demo_id);
@@ -191,7 +194,7 @@ async fn info(
#[tracing::instrument(skip(session))]
async fn scoreboard(
session: UserSession,
Path(demo_id): Path<i64>,
Path(demo_id): Path<String>,
) -> Result<axum::response::Json<common::demo_analysis::ScoreBoard>, axum::http::StatusCode> {
let query = crate::schema::demo_players::dsl::demo_players
.inner_join(
@@ -251,13 +254,13 @@ async fn scoreboard(
#[tracing::instrument(skip(session))]
async fn heatmap(
session: UserSession,
Path(demo_id): Path<i64>,
Path(demo_id): Path<String>,
) -> Result<axum::response::Json<Vec<common::demo_analysis::PlayerHeatmap>>, axum::http::StatusCode> {
use base64::prelude::Engine;
let mut db_con = crate::db_connection().await;
let demo_info_query = crate::schema::demo_info::dsl::demo_info.filter(crate::schema::demo_info::dsl::demo_id.eq(demo_id));
let demo_info_query = crate::schema::demo_info::dsl::demo_info.filter(crate::schema::demo_info::dsl::demo_id.eq(demo_id.clone()));
let demo_info: crate::models::DemoInfo = match demo_info_query.first(&mut db_con).await {
Ok(i) => i,
Err(e) => {
@@ -309,9 +312,9 @@ async fn heatmap(
#[tracing::instrument(skip(session))]
async fn perround(
session: UserSession,
Path(demo_id): Path<i64>,
Path(demo_id): Path<String>,
) -> Result<axum::response::Json<Vec<common::demo_analysis::DemoRound>>, axum::http::StatusCode> {
let rounds_query = crate::schema::demo_round::dsl::demo_round.filter(crate::schema::demo_round::dsl::demo_id.eq(demo_id));
let rounds_query = crate::schema::demo_round::dsl::demo_round.filter(crate::schema::demo_round::dsl::demo_id.eq(demo_id.clone()));
let round_players_query = crate::schema::demo_players::dsl::demo_players.filter(crate::schema::demo_players::dsl::demo_id.eq(demo_id));
let mut db_con = crate::db_connection().await;

View File

@@ -66,8 +66,8 @@ pub async fn run_api(
"/api/",
crate::api::router(crate::api::RouterConfig {
steam_api_key: steam_api_key.into(),
// steam_callback_base_url: "http://localhost:3000".into(),
steam_callback_base_url: "http://192.168.0.156:3000".into(),
steam_callback_base_url: "http://localhost:3000".into(),
// steam_callback_base_url: "http://192.168.0.156:3000".into(),
steam_callback_path: "/api/steam/callback".into(),
upload_dir: upload_folder.clone(),
}),
@@ -99,7 +99,7 @@ pub async fn run_analysis(upload_folder: impl Into<std::path::PathBuf>) {
}
};
let demo_id = input.demoid;
let demo_id = input.demoid.clone();
let mut store_result_fns = Vec::new();
for analysis in analysis::ANALYSIS_METHODS.iter().map(|a| a.clone()) {

View File

@@ -9,12 +9,21 @@ pub struct Session {
pub expiry_date: String,
}
#[derive(Queryable, Selectable, Insertable, Debug)]
#[derive(Insertable, Debug)]
#[diesel(table_name = crate::schema::demos)]
#[diesel(check_for_backend(diesel::pg::Pg))]
pub struct NewDemo {
pub steam_id: String,
pub demo_id: String,
}
#[derive(Selectable, Queryable, Debug)]
#[diesel(table_name = crate::schema::demos)]
#[diesel(check_for_backend(diesel::pg::Pg))]
pub struct Demo {
pub steam_id: String,
pub demo_id: i64,
pub demo_id: String,
pub uploaded_at: diesel::data_types::PgTimestamp
}
#[derive(Queryable, Selectable, Insertable, Debug)]
@@ -29,7 +38,7 @@ pub struct User {
#[diesel(table_name = crate::schema::demo_info)]
#[diesel(check_for_backend(diesel::pg::Pg))]
pub struct DemoInfo {
pub demo_id: i64,
pub demo_id: String,
pub map: String,
}
@@ -37,7 +46,7 @@ pub struct DemoInfo {
#[diesel(table_name = crate::schema::demo_players)]
#[diesel(check_for_backend(diesel::pg::Pg))]
pub struct DemoPlayer {
pub demo_id: i64,
pub demo_id: String,
pub steam_id: String,
pub name: String,
pub team: i16,
@@ -48,7 +57,7 @@ pub struct DemoPlayer {
#[diesel(table_name = crate::schema::demo_player_stats)]
#[diesel(check_for_backend(diesel::pg::Pg))]
pub struct DemoPlayerStats {
pub demo_id: i64,
pub demo_id: String,
pub steam_id: String,
pub kills: i16,
pub deaths: i16,
@@ -60,7 +69,7 @@ pub struct DemoPlayerStats {
#[diesel(table_name = crate::schema::processing_status)]
#[diesel(check_for_backend(diesel::pg::Pg))]
pub struct ProcessingStatus {
pub demo_id: i64,
pub demo_id: String,
pub info: i16,
}
@@ -68,7 +77,7 @@ pub struct ProcessingStatus {
#[diesel(table_name = crate::schema::analysis_queue)]
#[diesel(check_for_backend(diesel::pg::Pg))]
pub struct AddAnalysisTask {
pub demo_id: i64,
pub demo_id: String,
pub steam_id: String,
}
@@ -76,7 +85,7 @@ pub struct AddAnalysisTask {
#[diesel(table_name = crate::schema::analysis_queue)]
#[diesel(check_for_backend(diesel::pg::Pg))]
pub struct AnalysisTask {
pub demo_id: i64,
pub demo_id: String,
pub steam_id: String,
}
@@ -84,7 +93,7 @@ pub struct AnalysisTask {
#[diesel(table_name = crate::schema::demo_heatmaps)]
#[diesel(check_for_backend(diesel::pg::Pg))]
pub struct DemoPlayerHeatmap {
pub demo_id: i64,
pub demo_id: String,
pub steam_id: String,
pub data: String,
}
@@ -93,7 +102,7 @@ pub struct DemoPlayerHeatmap {
#[diesel(table_name = crate::schema::demo_round)]
#[diesel(check_for_backend(diesel::pg::Pg))]
pub struct DemoRound {
pub demo_id: i64,
pub demo_id: String,
pub round_number: i16,
pub start_tick: i64,
pub end_tick: i64,

View File

@@ -2,7 +2,7 @@
diesel::table! {
analysis_queue (demo_id) {
demo_id -> Int8,
demo_id -> Text,
steam_id -> Text,
created_at -> Timestamp,
}
@@ -10,7 +10,7 @@ diesel::table! {
diesel::table! {
demo_heatmaps (demo_id, steam_id) {
demo_id -> Int8,
demo_id -> Text,
steam_id -> Text,
data -> Text,
}
@@ -18,14 +18,14 @@ diesel::table! {
diesel::table! {
demo_info (demo_id) {
demo_id -> Int8,
demo_id -> Text,
map -> Text,
}
}
diesel::table! {
demo_player_stats (demo_id, steam_id) {
demo_id -> Int8,
demo_id -> Text,
steam_id -> Text,
kills -> Int2,
deaths -> Int2,
@@ -36,7 +36,7 @@ diesel::table! {
diesel::table! {
demo_players (demo_id, steam_id) {
demo_id -> Int8,
demo_id -> Text,
steam_id -> Text,
name -> Text,
team -> Int2,
@@ -46,7 +46,7 @@ diesel::table! {
diesel::table! {
demo_round (demo_id, round_number) {
demo_id -> Int8,
demo_id -> Text,
round_number -> Int2,
start_tick -> Int8,
end_tick -> Int8,
@@ -56,15 +56,16 @@ diesel::table! {
}
diesel::table! {
demos (demo_id) {
demos (steam_id, demo_id) {
steam_id -> Text,
demo_id -> Int8,
demo_id -> Text,
uploaded_at -> Timestamptz,
}
}
diesel::table! {
processing_status (demo_id) {
demo_id -> Int8,
demo_id -> Text,
info -> Int2,
}
}
@@ -77,6 +78,13 @@ diesel::table! {
}
}
diesel::table! {
user_demos (steam_id, demo_id) {
steam_id -> Text,
demo_id -> Text,
}
}
diesel::table! {
users (steamid) {
steamid -> Text,
@@ -84,14 +92,6 @@ diesel::table! {
}
}
diesel::joinable!(analysis_queue -> demos (demo_id));
diesel::joinable!(demo_heatmaps -> demo_info (demo_id));
diesel::joinable!(demo_info -> demos (demo_id));
diesel::joinable!(demo_player_stats -> demo_info (demo_id));
diesel::joinable!(demo_players -> demo_info (demo_id));
diesel::joinable!(demo_round -> demo_info (demo_id));
diesel::joinable!(processing_status -> demos (demo_id));
diesel::allow_tables_to_appear_in_same_query!(
analysis_queue,
demo_heatmaps,
@@ -102,5 +102,6 @@ diesel::allow_tables_to_appear_in_same_query!(
demos,
processing_status,
sessions,
user_demos,
users,
);