record-daemon: refactor to record raw league data

This commit is contained in:
2026-03-27 13:42:12 +01:00
parent b09f669e73
commit d67d52fa86
7 changed files with 191 additions and 951 deletions
+30 -214
View File
@@ -17,7 +17,6 @@ use super::api_types::{
use super::auth::LockfileCredentials;
use super::endpoints;
use super::events::GameEvent;
use super::mappings::{champion_id_to_name, spell_id_to_name};
use super::state::{ClientState, GameflowPhase};
use super::tls::create_insecure_tls_config;
use super::websocket::parse_websocket_message;
@@ -469,6 +468,36 @@ impl LqpClient {
// Metadata Fetching Methods
// =========================================================================
/// Fetch raw session data as JSON.
pub async fn fetch_raw_session(&self) -> Result<serde_json::Value> {
self.request("GET", endpoints::SESSION).await
}
/// Fetch raw summoner data as JSON.
pub async fn fetch_raw_summoner(&self) -> Result<serde_json::Value> {
self.request("GET", endpoints::SUMMONER).await
}
/// Fetch raw champion select data as JSON.
pub async fn fetch_raw_champion_select(&self) -> Result<serde_json::Value> {
self.request("GET", endpoints::CHAMPION_SELECT).await
}
/// Fetch raw rune page data as JSON.
pub async fn fetch_raw_rune_page(&self) -> Result<serde_json::Value> {
self.request("GET", endpoints::RUNE_PAGES).await
}
/// Fetch raw live client data as JSON.
pub async fn fetch_raw_live_client_data(&self) -> Result<serde_json::Value> {
self.request("GET", endpoints::LIVE_CLIENT_DATA).await
}
/// Fetch raw end-of-game stats as JSON.
pub async fn fetch_raw_end_game_stats(&self) -> Result<serde_json::Value> {
self.request("GET", endpoints::GAME_STATS).await
}
/// Fetch pre-game data (stores raw API responses directly).
pub async fn fetch_pregame_data(&self) -> Result<PreGameData> {
let mut data = PreGameData::default();
@@ -511,219 +540,6 @@ impl LqpClient {
pub async fn fetch_game_end_stats(&self) -> Result<EndOfGameStatsResponse> {
self.get_game_stats_typed().await
}
/// Fetch complete player game metadata including runes, summoner spells, and items.
pub async fn fetch_player_game_metadata(&self) -> Result<super::PlayerGameMetadata> {
use super::{RunePage, SummonerSpells};
let mut metadata = super::PlayerGameMetadata::default();
// Get summoner info (typed)
if let Ok(summoner) = self.get_summoner_typed().await {
metadata.puuid = summoner.puuid;
metadata.summoner_name = summoner
.display_name
.or(summoner.name)
.or(summoner.internal_name);
}
// Get rune page (typed)
if let Ok(rune_page) = self.get_rune_page_typed().await {
let primary_style_id = rune_page.primary_style_id.unwrap_or(0) as u32;
let secondary_style_id = rune_page.sub_style_id.unwrap_or(0) as u32;
let selected_perks = rune_page
.selected_perk_ids
.unwrap_or_default()
.iter()
.map(|id| *id as u32)
.collect();
if primary_style_id > 0 {
metadata.runes = Some(RunePage {
primary_style_id,
secondary_style_id,
selected_perks,
stat_modifiers: Vec::new(),
name: rune_page.name,
current: rune_page.current.unwrap_or(true),
});
}
}
// Get summoner spells from live client data (typed)
if let Ok(active_player) = self.get_live_client_active_player_typed().await {
debug!("[METADATA] Live client active player data received");
if let Some(ref spells) = active_player.summoner_spells {
let spell1_id = spells
.summoner_spell_one
.as_ref()
.and_then(|s| s.spell_id)
.or(spells.spell1_id)
.unwrap_or(0) as u32;
let spell2_id = spells
.summoner_spell_two
.as_ref()
.and_then(|s| s.spell_id)
.or(spells.spell2_id)
.unwrap_or(0) as u32;
if spell1_id > 0 || spell2_id > 0 {
metadata.summoner_spells = Some(SummonerSpells {
spell1_id,
spell2_id,
spell1_name: spell_id_to_name(spell1_id),
spell2_name: spell_id_to_name(spell2_id),
});
}
}
if metadata.summoner_name.is_none()
|| metadata.summoner_name.as_ref().is_none_or(|n| n.is_empty())
{
metadata.summoner_name = active_player
.summoner_name
.or(active_player.display_name)
.or(active_player.riot_id);
}
}
// Fallback: Get summoner spells from session gameData (typed)
if metadata.summoner_spells.is_none() {
if let Ok(session) = self.get_session_typed().await {
if let Some(local_puuid) = &metadata.puuid {
if let Some(ref game_data) = session.game_data {
// Check team one
if let Some(ref team) = game_data.team_one {
for player in team {
if player.puuid.as_deref() == Some(local_puuid.as_str()) {
let spell1_id = player.spell1_id.unwrap_or(0) as u32;
let spell2_id = player.spell2_id.unwrap_or(0) as u32;
if spell1_id > 0 || spell2_id > 0 {
metadata.summoner_spells = Some(SummonerSpells {
spell1_id,
spell2_id,
spell1_name: spell_id_to_name(spell1_id),
spell2_name: spell_id_to_name(spell2_id),
});
}
metadata.champion_id = player.champion_id.map(|id| id as u32);
metadata.team = player.team_id.map(|id| id as u32);
break;
}
}
}
// Check team two if not found
if metadata.summoner_spells.is_none() {
if let Some(ref team) = game_data.team_two {
for player in team {
if player.puuid.as_deref() == Some(local_puuid.as_str()) {
let spell1_id = player.spell1_id.unwrap_or(0) as u32;
let spell2_id = player.spell2_id.unwrap_or(0) as u32;
if spell1_id > 0 || spell2_id > 0 {
metadata.summoner_spells = Some(SummonerSpells {
spell1_id,
spell2_id,
spell1_name: spell_id_to_name(spell1_id),
spell2_name: spell_id_to_name(spell2_id),
});
}
metadata.champion_id =
player.champion_id.map(|id| id as u32);
metadata.team = player.team_id.map(|id| id as u32);
break;
}
}
}
}
}
}
}
}
if let Some(champ_id) = metadata.champion_id {
metadata.champion_name = champion_id_to_name(champ_id);
}
Ok(metadata)
}
/// Fetch all players' puuid to summoner name mapping.
pub async fn fetch_all_players_identities(&self) -> Result<Vec<super::PlayerIdentity>> {
let mut players = Vec::new();
// Try live client data first (typed)
if let Ok(player_list) = self.get_live_client_player_list_typed().await {
for player in &player_list.0 {
let summoner_name = player
.summoner_name
.as_deref()
.or(player.riot_id.as_deref())
.unwrap_or("");
if let Some(ref puuid) = player.puuid {
players.push(super::PlayerIdentity {
puuid: puuid.clone(),
summoner_name: summoner_name.to_string(),
summoner_id: player.summoner_id,
champion_name: player.champion_name.clone(),
team: player.team.map(|id| id as u32),
});
}
}
}
// Fallback: try from gameflow session (typed)
if players.is_empty() {
if let Ok(session) = self.get_session_typed().await {
if let Some(ref game_data) = session.game_data {
// Team one (team ID 100)
if let Some(ref team) = game_data.team_one {
for player in team {
if let (Some(ref puuid), Some(ref summoner_name)) =
(&player.puuid, &player.summoner_name)
{
let champion_id = player.champion_id.map(|id| id as u32);
let champion_name = champion_id.and_then(champion_id_to_name);
players.push(super::PlayerIdentity {
puuid: puuid.clone(),
summoner_name: summoner_name.clone(),
summoner_id: player.summoner_id,
champion_name,
team: Some(100),
});
}
}
}
// Team two (team ID 200)
if let Some(ref team) = game_data.team_two {
for player in team {
if let (Some(ref puuid), Some(ref summoner_name)) =
(&player.puuid, &player.summoner_name)
{
let champion_id = player.champion_id.map(|id| id as u32);
let champion_name = champion_id.and_then(champion_id_to_name);
players.push(super::PlayerIdentity {
puuid: puuid.clone(),
summoner_name: summoner_name.clone(),
summoner_id: player.summoner_id,
champion_name,
team: Some(200),
});
}
}
}
}
}
}
Ok(players)
}
}
impl Default for LqpClient {