Handle some unexpected keys in Steam data

This commit is contained in:
mtkennerly 2024-04-20 17:54:21 -04:00
parent 629b5c5942
commit 97683408c5
No known key found for this signature in database
GPG key ID: E764BE00BE6E6408
2 changed files with 53 additions and 3 deletions

View file

@ -18,6 +18,21 @@ fn styles() -> clap::builder::styling::Styles {
.placeholder(AnsiColor::Green.on_default()) .placeholder(AnsiColor::Green.on_default())
} }
fn parse_games(games: Vec<String>) -> Vec<String> {
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)] #[derive(clap::Parser, Clone, Debug, PartialEq, Eq)]
#[clap(name = "ludusavi-manifest", version, max_term_width = 100, next_line_help = true, styles = styles())] #[clap(name = "ludusavi-manifest", version, max_term_width = 100, next_line_help = true, styles = styles())]
pub struct Cli { pub struct Cli {
@ -115,6 +130,7 @@ pub async fn run(
schema::validate_manifest(manifest)?; schema::validate_manifest(manifest)?;
} }
Subcommand::Solo { local, games } => { Subcommand::Solo { local, games } => {
let games = parse_games(games);
let outdated_only = false; let outdated_only = false;
if !local { if !local {

View file

@ -202,6 +202,40 @@ mod product_info {
Ok(s == "1") Ok(s == "1")
} }
fn parse_vec<'de, D, T>(deserializer: D) -> Result<Vec<T>, D::Error>
where
D: serde::Deserializer<'de>,
T: serde::de::DeserializeOwned,
{
use serde::de::Deserialize;
let mut out = vec![];
let raw = match BTreeMap::<String, serde_json::Value>::deserialize(deserializer) {
Ok(x) => x,
Err(e) => {
println!(" parse_vec: total failure - {e:?}");
return Err(e);
}
};
for (key, value) in raw {
if key.parse::<u32>().is_err() {
println!(" parse_vec: unexpected key '{}'", key);
continue;
}
match serde_json::from_value::<T>(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)] #[derive(Debug, Default, Clone, serde::Deserialize)]
pub struct Response { pub struct Response {
pub apps: BTreeMap<String, App>, pub apps: BTreeMap<String, App>,
@ -251,8 +285,8 @@ mod product_info {
#[derive(Debug, Default, Clone, serde::Deserialize)] #[derive(Debug, Default, Clone, serde::Deserialize)]
#[serde(default)] #[serde(default)]
pub struct AppUfs { pub struct AppUfs {
#[serde(rename = "savefiles")] #[serde(rename = "savefiles", deserialize_with = "parse_vec")]
pub save_files: BTreeMap<String, AppUfsSaveFile>, pub save_files: Vec<AppUfsSaveFile>,
#[serde(rename = "rootoverrides")] #[serde(rename = "rootoverrides")]
pub root_overrides: BTreeMap<String, AppUfsRootOverride>, pub root_overrides: BTreeMap<String, AppUfsRootOverride>,
} }
@ -374,7 +408,7 @@ impl SteamCacheEntry {
saves: app saves: app
.ufs .ufs
.save_files .save_files
.into_values() .into_iter()
.map(|x| CloudSave { .map(|x| CloudSave {
path: x.path, path: x.path,
pattern: x.pattern, pattern: x.pattern,