record-daemon: refactor to record raw league data
This commit is contained in:
+47
-171
@@ -354,24 +354,16 @@ impl Daemon {
|
||||
// Handle recording start/stop
|
||||
match transition {
|
||||
StateTransition::GameStarted => {
|
||||
// Extract data from the GameStart event that was stored in the timeline
|
||||
let (game_id, queue_type, queue_id, game_mode, map_name, session) =
|
||||
if let GameEvent::GameStart(ref info) = event {
|
||||
(
|
||||
info.game_id,
|
||||
info.queue_type.clone(),
|
||||
info.queue_id,
|
||||
info.game_mode.clone(),
|
||||
info.map_name.clone(),
|
||||
info.session.clone(),
|
||||
)
|
||||
} else {
|
||||
(0, None, None, None, None, None)
|
||||
};
|
||||
// Extract game_id from the GameStart event
|
||||
let game_id = if let GameEvent::GameStart(ref info) = event {
|
||||
info.game_id
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
info!(
|
||||
"[EVENT_HANDLER] GameStarted transition - game_id: {}, queue_type: {:?}, game_mode: {:?}",
|
||||
game_id, queue_type, game_mode
|
||||
"[EVENT_HANDLER] GameStarted transition - game_id: {}",
|
||||
game_id
|
||||
);
|
||||
|
||||
// If already recording, stop the current recording first
|
||||
@@ -387,110 +379,34 @@ impl Daemon {
|
||||
|
||||
info!("[EVENT_HANDLER] Calling start_recording...");
|
||||
|
||||
// Fetch player game metadata (puuid, runes, summoner spells)
|
||||
let player_metadata =
|
||||
self.lqp_client.fetch_player_game_metadata().await.ok();
|
||||
let (puuid, runes, summoner_spells, champion_id, team, summoner_name) =
|
||||
player_metadata.map_or((None, None, None, None, None, None), |m| {
|
||||
(
|
||||
m.puuid,
|
||||
m.runes,
|
||||
m.summoner_spells,
|
||||
m.champion_id,
|
||||
m.team,
|
||||
m.summoner_name,
|
||||
)
|
||||
});
|
||||
|
||||
// If we have puuid and session, extract player-specific data from session
|
||||
let (champion, final_team, final_summoner_name, final_summoner_spells) =
|
||||
if let Some(ref p) = puuid {
|
||||
if let Some(ref sess) = session {
|
||||
let champ_id = sess.get_champion_id(p);
|
||||
let champ_name =
|
||||
champ_id.and_then(record_daemon::lqp::champion_id_to_name);
|
||||
let team_id = sess.get_team(p);
|
||||
let summoner = sess.get_summoner_name(p).map(|s| s.to_string());
|
||||
|
||||
// Extract summoner spells from session's player_champion_selections
|
||||
let spells_from_session =
|
||||
sess.get_player_selection(p).map(|selection| {
|
||||
record_daemon::lqp::SummonerSpells {
|
||||
spell1_id: selection.spell1_id,
|
||||
spell2_id: selection.spell2_id,
|
||||
spell1_name: None,
|
||||
spell2_name: None,
|
||||
}
|
||||
});
|
||||
|
||||
(
|
||||
champ_name.or_else(|| {
|
||||
champion_id
|
||||
.and_then(record_daemon::lqp::champion_id_to_name)
|
||||
}),
|
||||
team_id.or(team),
|
||||
summoner.or(summoner_name),
|
||||
spells_from_session.or(summoner_spells),
|
||||
)
|
||||
} else {
|
||||
(
|
||||
champion_id
|
||||
.and_then(record_daemon::lqp::champion_id_to_name),
|
||||
team,
|
||||
summoner_name,
|
||||
summoner_spells,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
(
|
||||
champion_id.and_then(record_daemon::lqp::champion_id_to_name),
|
||||
team,
|
||||
summoner_name,
|
||||
summoner_spells,
|
||||
)
|
||||
};
|
||||
|
||||
info!(
|
||||
"[EVENT_HANDLER] Final values: puuid={:?}, runes={:?}, summoner_spells={:?}",
|
||||
puuid, runes, final_summoner_spells
|
||||
// Fetch raw API data in parallel
|
||||
let (
|
||||
raw_session,
|
||||
raw_summoner,
|
||||
raw_champion_select,
|
||||
raw_rune_page,
|
||||
raw_live_client_data,
|
||||
) = tokio::join!(
|
||||
self.lqp_client.fetch_raw_session(),
|
||||
self.lqp_client.fetch_raw_summoner(),
|
||||
self.lqp_client.fetch_raw_champion_select(),
|
||||
self.lqp_client.fetch_raw_rune_page(),
|
||||
self.lqp_client.fetch_raw_live_client_data()
|
||||
);
|
||||
|
||||
// Fetch all players identities for puuid mapping
|
||||
let all_players_identities =
|
||||
self.lqp_client.fetch_all_players_identities().await.ok();
|
||||
let all_players_info: Vec<record_daemon::timeline::PlayerIdentityInfo> =
|
||||
all_players_identities
|
||||
.unwrap_or_default()
|
||||
.into_iter()
|
||||
.map(|p| record_daemon::timeline::PlayerIdentityInfo {
|
||||
puuid: p.puuid,
|
||||
summoner_name: p.summoner_name,
|
||||
champion_name: p.champion_name,
|
||||
team: p.team,
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Build game metadata for timeline
|
||||
// Build game metadata for timeline with raw JSON
|
||||
let metadata_update = record_daemon::timeline::MetadataUpdate {
|
||||
queue_type,
|
||||
queue_id,
|
||||
game_mode,
|
||||
map_name,
|
||||
team: final_team,
|
||||
summoner_name: final_summoner_name,
|
||||
puuid,
|
||||
runes,
|
||||
summoner_spells: final_summoner_spells,
|
||||
all_players: all_players_info,
|
||||
..Default::default()
|
||||
game_id: Some(game_id),
|
||||
raw_session: raw_session.ok(),
|
||||
raw_summoner: raw_summoner.ok(),
|
||||
raw_champion_select: raw_champion_select.ok(),
|
||||
raw_rune_page: raw_rune_page.ok(),
|
||||
raw_live_client_data: raw_live_client_data.ok(),
|
||||
raw_end_game_stats: None,
|
||||
};
|
||||
|
||||
if let Err(e) = self
|
||||
.start_recording_with_metadata(
|
||||
game_id,
|
||||
champion.as_deref(),
|
||||
metadata_update,
|
||||
)
|
||||
.start_recording_with_metadata(game_id, metadata_update)
|
||||
.await
|
||||
{
|
||||
error!("[EVENT_HANDLER] Failed to start recording: {}", e);
|
||||
@@ -503,15 +419,17 @@ impl Daemon {
|
||||
StateTransition::GameEnded => {
|
||||
info!("[EVENT_HANDLER] GameEnded transition");
|
||||
|
||||
// Fetch end-of-game stats from API
|
||||
let game_end_stats = self.lqp_client.fetch_game_end_stats().await.ok();
|
||||
// Fetch raw end-of-game stats from API
|
||||
let raw_end_game_stats =
|
||||
self.lqp_client.fetch_raw_end_game_stats().await.ok();
|
||||
|
||||
info!(
|
||||
"[EVENT_HANDLER] Game end stats from API: {:?}",
|
||||
game_end_stats
|
||||
raw_end_game_stats.is_some()
|
||||
);
|
||||
|
||||
if let Err(e) = self.stop_recording_with_metadata(game_end_stats).await {
|
||||
if let Err(e) = self.stop_recording_with_metadata(raw_end_game_stats).await
|
||||
{
|
||||
error!("[EVENT_HANDLER] Failed to stop recording: {}", e);
|
||||
|
||||
// Don't propagate error - keep daemon running
|
||||
@@ -539,19 +457,18 @@ impl Daemon {
|
||||
async fn start_recording_with_metadata(
|
||||
&self,
|
||||
game_id: u64,
|
||||
champion: Option<&str>,
|
||||
metadata_update: record_daemon::timeline::MetadataUpdate,
|
||||
) -> Result<()> {
|
||||
info!(
|
||||
"Daemon::start_recording_with_metadata called - game {} ({:?})",
|
||||
game_id, champion
|
||||
"Daemon::start_recording_with_metadata called - game {}",
|
||||
game_id
|
||||
);
|
||||
|
||||
// Create a recording entry in the timeline store first
|
||||
let recording_id = self
|
||||
.timeline_store
|
||||
.write()
|
||||
.start_recording_entry(Some(game_id), champion.map(|s| s.to_string()));
|
||||
.start_recording_entry(Some(game_id), None);
|
||||
|
||||
// Update metadata immediately with game start info
|
||||
if let Err(e) = self
|
||||
@@ -569,7 +486,6 @@ impl Daemon {
|
||||
// Clone Arc references for use in spawn_blocking
|
||||
let recording_engine = self.recording_engine.clone();
|
||||
let event_mapper = self.event_mapper.clone();
|
||||
let champion_owned = champion.map(|s| s.to_string());
|
||||
|
||||
// Use spawn_blocking to avoid blocking the async runtime
|
||||
tokio::task::spawn_blocking(move || {
|
||||
@@ -579,7 +495,7 @@ impl Daemon {
|
||||
|
||||
if let Some(ref mut engine) = *engine_guard {
|
||||
info!("Calling engine.start_recording...");
|
||||
engine.start_recording(Some(game_id), champion_owned.as_deref())?;
|
||||
engine.start_recording(Some(game_id), None)?;
|
||||
info!("engine.start_recording returned successfully");
|
||||
event_mapper.write().start();
|
||||
info!("Event mapper started");
|
||||
@@ -604,10 +520,10 @@ impl Daemon {
|
||||
self.stop_recording_with_metadata(None).await
|
||||
}
|
||||
|
||||
/// Stop recording with optional game end stats.
|
||||
/// Stop recording with optional raw game end stats JSON.
|
||||
async fn stop_recording_with_metadata(
|
||||
&self,
|
||||
game_end_stats: Option<record_daemon::lqp::EndOfGameStatsResponse>,
|
||||
raw_end_game_stats: Option<serde_json::Value>,
|
||||
) -> Result<()> {
|
||||
info!("Stopping recording");
|
||||
|
||||
@@ -618,7 +534,6 @@ impl Daemon {
|
||||
let recording_engine = self.recording_engine.clone();
|
||||
let event_mapper = self.event_mapper.clone();
|
||||
let timeline_store = self.timeline_store.clone();
|
||||
let pregame_data = self.pregame_data.read().clone();
|
||||
|
||||
// Use spawn_blocking to avoid blocking the async runtime
|
||||
tokio::task::spawn_blocking(move || {
|
||||
@@ -642,50 +557,11 @@ impl Daemon {
|
||||
}
|
||||
};
|
||||
|
||||
// Update metadata if we have it
|
||||
let mut update = record_daemon::timeline::MetadataUpdate::default();
|
||||
|
||||
// Add pre-game data
|
||||
if let Some(pregame) = pregame_data {
|
||||
// Convert champion_id to name if available
|
||||
if let Some(champion_id) = pregame.champion_id() {
|
||||
update.champion =
|
||||
record_daemon::lqp::champion_id_to_name(champion_id as u32);
|
||||
}
|
||||
update.summoner_name = pregame.summoner_name().map(|s| s.to_string());
|
||||
update.queue_id = pregame.queue_id().map(|id| id as u32);
|
||||
update.game_mode = pregame.game_mode().map(|s| s.to_string());
|
||||
update.map_name = pregame.map_name().map(|s| s.to_string());
|
||||
update.team = pregame.team().map(|id| id as u32);
|
||||
}
|
||||
|
||||
// Add game end stats from API response
|
||||
if let Some(stats) = game_end_stats {
|
||||
update.victory = Some(stats.is_victory());
|
||||
update.match_id = stats.match_id.map(|id| id.to_string());
|
||||
|
||||
// Store raw end-of-game stats as JSON
|
||||
update.raw_end_game_stats = serde_json::to_value(&stats).ok();
|
||||
|
||||
// Get local player stats
|
||||
if let Some(player) = stats.get_local_player() {
|
||||
if let Some(player_stats) = &player.stats {
|
||||
update.final_stats = Some(record_daemon::timeline::GameFinalStats {
|
||||
kills: player_stats.champions_killed.unwrap_or(0) as u32,
|
||||
deaths: player_stats.num_deaths.unwrap_or(0) as u32,
|
||||
assists: player_stats.assists.unwrap_or(0) as u32,
|
||||
creep_score: player_stats.minions_killed.unwrap_or(0) as u32,
|
||||
gold_earned: player_stats.gold_earned.unwrap_or(0) as u32,
|
||||
damage_dealt: player_stats
|
||||
.total_damage_dealt_to_champions
|
||||
.unwrap_or(0),
|
||||
damage_taken: player_stats.total_damage_taken.unwrap_or(0),
|
||||
vision_score: player_stats.vision_score.unwrap_or(0.0),
|
||||
game_duration: stats.game_length.unwrap_or(0.0),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
// Update metadata with raw end game stats
|
||||
let update = record_daemon::timeline::MetadataUpdate {
|
||||
raw_end_game_stats,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
// Apply the update
|
||||
if let Err(e) = timeline_store.write().update_metadata(recording_id, update) {
|
||||
|
||||
Reference in New Issue
Block a user