Handle some unexpected keys in Steam data
This commit is contained in:
parent
629b5c5942
commit
97683408c5
2 changed files with 53 additions and 3 deletions
16
src/cli.rs
16
src/cli.rs
|
@ -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 {
|
||||||
|
|
40
src/steam.rs
40
src/steam.rs
|
@ -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,
|
||||||
|
|
Reference in a new issue