diff --git a/Cargo.lock b/Cargo.lock index beb59d6..779bca3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -322,6 +322,7 @@ dependencies = [ "gettext-rs", "git2", "gtk4", + "keyvalues-serde", "lazy_static", "libadwaita", "libmonado", @@ -1071,6 +1072,28 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "keyvalues-parser" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e4c8354918309196302015ac9cae43362f1a13d0d5c5539a33b4c2fd2cd6d25" +dependencies = [ + "pest", + "pest_derive", + "thiserror", +] + +[[package]] +name = "keyvalues-serde" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0447866c47c00f8bd1949618e8f63017cf93e985b4684dc28d784527e2882390" +dependencies = [ + "keyvalues-parser", + "serde", + "thiserror", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -1502,6 +1525,51 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +[[package]] +name = "pest" +version = "2.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d214365f632b123a47fd913301e14c946c61d1c183ee245fa76eb752e59a02dd" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb55586734301717aea2ac313f50b2eb8f60d2fc3dc01d190eefa2e625f60c4e" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pest_meta" +version = "2.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b75da2a70cf4d9cb76833c990ac9cd3923c9a8905a8929789ce347c84564d03d" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + [[package]] name = "pin-project" version = "1.1.5" @@ -2086,18 +2154,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.48" +version = "1.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7" +checksum = "5d11abd9594d9b38965ef50805c5e469ca9cc6f197f883f717e0269a3057b3d5" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.48" +version = "1.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" +checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602" dependencies = [ "proc-macro2", "quote", @@ -2305,6 +2373,12 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + [[package]] name = "unicode-bidi" version = "0.3.13" diff --git a/Cargo.toml b/Cargo.toml index fc0a614..37572ab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,7 @@ relm4-components = "0.9.1" reqwest = { version = "0.12.5", features = ["blocking"] } serde = { version = "1.0.204", features = ["derive"] } serde_json = "1.0.120" +keyvalues-serde = "0.2.1" tracker = "0.2.2" uuid = { version = "1.10.0", features = ["v4", "fast-rng"] } vte4 = { version = "0.8.0", features = ["v0_72"] } diff --git a/src/steam_linux_runtime_injector.rs b/src/steam_linux_runtime_injector.rs index d8e4aa6..3443b7a 100644 --- a/src/steam_linux_runtime_injector.rs +++ b/src/steam_linux_runtime_injector.rs @@ -4,18 +4,76 @@ use crate::{ util::file_utils::{copy_file, get_writer}, }; use anyhow::bail; +use lazy_static::lazy_static; +use serde::Deserialize; use std::{ + collections::HashMap, fs::read_to_string, io::Write, path::{Path, PathBuf}, }; +#[derive(Deserialize)] +struct LibraryFolder { + pub path: String, + pub apps: HashMap, +} + +pub const PRESSURE_VESSEL_STEAM_APPID: u32 = 1628350; + +fn get_steam_main_dir_path() -> anyhow::Result { + let steam_root: PathBuf = get_home_dir().join(".steam/root"); + + if steam_root.is_symlink() { + Ok(steam_root.read_link()?) + } else if steam_root.is_dir() { + Ok(steam_root) + } else { + bail!( + "Canonical steam root '{}' is not a dir nor a symlink!", + steam_root.to_string_lossy() + ) + } +} + +fn parse_steam_libraryfolders_vdf(path: &Path) -> anyhow::Result> { + Ok(keyvalues_serde::from_str(read_to_string(path)?.as_str())?) +} + fn get_runtime_entrypoint_path() -> Option { - Some( - get_home_dir() - .join(".steam/steam/steamapps/common/SteamLinuxRuntime_sniper/_v2-entry-point"), - ) - .filter(|p| p.is_file()) + match get_steam_main_dir_path() { + Ok(steam_root) => { + let steam_libraryfolders_path = steam_root.join("steamapps/libraryfolders.vdf"); + + if !steam_libraryfolders_path.is_file() { + eprintln!( + "Steam libraryfolders.vdf does not exist in its canonical location {}", + steam_libraryfolders_path.to_string_lossy() + ); + return None; + } + + let libraryfolders: HashMap = + parse_steam_libraryfolders_vdf(&steam_libraryfolders_path).ok()?; + + libraryfolders + .iter() + .find(|(_, libraryfolder)| { + libraryfolder + .apps + .contains_key(&PRESSURE_VESSEL_STEAM_APPID) + }) + .map(|(_, libraryfolder)| PathBuf::from(&libraryfolder.path)) + } + Err(e) => { + eprintln!("Error getting steam root path: {e}"); + None + } + } +} + +lazy_static! { + static ref STEAM_RUNTIME_ENTRYPOINT_PATH: Option = get_runtime_entrypoint_path(); } fn get_backup_runtime_entrypoint_location() -> PathBuf { @@ -27,10 +85,10 @@ fn backup_runtime_entrypoint(path: &Path) { } pub fn restore_runtime_entrypoint() { - if let Some(path) = get_runtime_entrypoint_path() { + if let Some(path) = STEAM_RUNTIME_ENTRYPOINT_PATH.as_ref() { let backup = get_backup_runtime_entrypoint_location(); if Path::new(&backup).is_file() { - copy_file(&backup, &path); + copy_file(&backup, path); } } } @@ -48,8 +106,8 @@ fn append_to_runtime_entrypoint(data: &str, path: &Path) -> anyhow::Result<()> { pub fn set_runtime_entrypoint_launch_opts_from_profile(profile: &Profile) -> anyhow::Result<()> { restore_runtime_entrypoint(); - if let Some(dest) = get_runtime_entrypoint_path() { - backup_runtime_entrypoint(&dest); + if let Some(dest) = STEAM_RUNTIME_ENTRYPOINT_PATH.as_ref() { + backup_runtime_entrypoint(dest); append_to_runtime_entrypoint( &profile .get_env_vars() @@ -57,10 +115,29 @@ pub fn set_runtime_entrypoint_launch_opts_from_profile(profile: &Profile) -> any .map(|ev| "export ".to_string() + ev) .collect::>() .join("\n"), - &dest, + dest, )?; return Ok(()); } bail!("Could not find valid runtime entrypoint"); } + +#[cfg(test)] +mod tests { + use std::path::Path; + + use super::parse_steam_libraryfolders_vdf; + + #[test] + fn deserialize_steam_libraryfolders_vdf() { + let lf = parse_steam_libraryfolders_vdf(Path::new("./test/files/steam_libraryfolders.vdf")) + .unwrap(); + assert_eq!(lf.len(), 1); + let first = lf.get(&0).unwrap(); + assert_eq!(first.path, "/home/gabmus/.local/share/Steam"); + assert_eq!(first.apps.len(), 10); + assert_eq!(first.apps.get(&228980).unwrap(), &29212173); + assert_eq!(first.apps.get(&632360).unwrap(), &0); + } +} diff --git a/test/files/steam_libraryfolders.vdf b/test/files/steam_libraryfolders.vdf new file mode 100755 index 0000000..fdf8bcc --- /dev/null +++ b/test/files/steam_libraryfolders.vdf @@ -0,0 +1,25 @@ +"libraryfolders" +{ + "0" + { + "path" "/home/gabmus/.local/share/Steam" + "label" "" + "contentid" "760750217583951648" + "totalsize" "0" + "update_clean_bytes_tally" "2149063455" + "time_last_update_verified" "1730413202" + "apps" + { + "228980" "29212173" + "427520" "1827889703" + "632360" "0" + "844590" "1141373655" + "1070560" "13004" + "1391110" "647029573" + "1493710" "1222765697" + "1628350" "768814815" + "2124120" "1434049913" + "2537200" "1681670599" + } + } +}