From 97683408c5ce54047536d40c5a49ce9e188d1ea4 Mon Sep 17 00:00:00 2001 From: mtkennerly Date: Sat, 20 Apr 2024 17:54:21 -0400 Subject: [PATCH] Handle some unexpected keys in Steam data --- src/cli.rs | 16 ++++++++++++++++ src/steam.rs | 40 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/src/cli.rs b/src/cli.rs index ad2f03a7..d745a76c 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -18,6 +18,21 @@ fn styles() -> clap::builder::styling::Styles { .placeholder(AnsiColor::Green.on_default()) } +fn parse_games(games: Vec) -> Vec { + if !games.is_empty() { + games + } else { + use std::io::IsTerminal; + + let stdin = std::io::stdin(); + if stdin.is_terminal() { + vec![] + } else { + stdin.lines().map_while(Result::ok).collect() + } + } +} + #[derive(clap::Parser, Clone, Debug, PartialEq, Eq)] #[clap(name = "ludusavi-manifest", version, max_term_width = 100, next_line_help = true, styles = styles())] pub struct Cli { @@ -115,6 +130,7 @@ pub async fn run( schema::validate_manifest(manifest)?; } Subcommand::Solo { local, games } => { + let games = parse_games(games); let outdated_only = false; if !local { diff --git a/src/steam.rs b/src/steam.rs index 9adab300..92cb125c 100644 --- a/src/steam.rs +++ b/src/steam.rs @@ -202,6 +202,40 @@ mod product_info { Ok(s == "1") } + fn parse_vec<'de, D, T>(deserializer: D) -> Result, D::Error> + where + D: serde::Deserializer<'de>, + T: serde::de::DeserializeOwned, + { + use serde::de::Deserialize; + + let mut out = vec![]; + let raw = match BTreeMap::::deserialize(deserializer) { + Ok(x) => x, + Err(e) => { + println!(" parse_vec: total failure - {e:?}"); + return Err(e); + } + }; + + for (key, value) in raw { + if key.parse::().is_err() { + println!(" parse_vec: unexpected key '{}'", key); + continue; + } + + match serde_json::from_value::(value) { + Ok(value) => out.push(value), + Err(e) => { + println!(" parse_vec: type failure - {e:?}"); + return Err(serde::de::Error::custom("parse_vec: type failure - {e:?}")); + } + } + } + + Ok(out) + } + #[derive(Debug, Default, Clone, serde::Deserialize)] pub struct Response { pub apps: BTreeMap, @@ -251,8 +285,8 @@ mod product_info { #[derive(Debug, Default, Clone, serde::Deserialize)] #[serde(default)] pub struct AppUfs { - #[serde(rename = "savefiles")] - pub save_files: BTreeMap, + #[serde(rename = "savefiles", deserialize_with = "parse_vec")] + pub save_files: Vec, #[serde(rename = "rootoverrides")] pub root_overrides: BTreeMap, } @@ -374,7 +408,7 @@ impl SteamCacheEntry { saves: app .ufs .save_files - .into_values() + .into_iter() .map(|x| CloudSave { path: x.path, pattern: x.pattern,