diff --git a/src/file_builders/active_runtime_json.rs b/src/file_builders/active_runtime_json.rs index 3f5e73f..f3461ae 100644 --- a/src/file_builders/active_runtime_json.rs +++ b/src/file_builders/active_runtime_json.rs @@ -1,7 +1,10 @@ use crate::{ paths::{get_backup_dir, SYSTEM_PREFIX}, profile::Profile, - util::file_utils::{copy_file, deserialize_file, get_writer, set_file_readonly}, + util::{ + file_utils::{copy_file, deserialize_file, get_writer, set_file_readonly}, + steam_library_folder::SteamLibraryFolder, + }, xdg::XDG, }; use serde::{Deserialize, Serialize}; @@ -9,6 +12,7 @@ use std::{ fs::remove_file, path::{Path, PathBuf}, }; +use tracing::error; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct ActiveRuntimeInnerRuntime { @@ -38,6 +42,23 @@ pub fn is_steam(active_runtime: &ActiveRuntime) -> bool { matches!(active_runtime.runtime.valve_runtime_is_steamvr, Some(true)) } +pub const STEAMVR_STEAM_APPID: u32 = 250820; + +pub fn find_steam_openxr_json() -> Option { + match SteamLibraryFolder::get_folders() { + Ok(libraryfolders) => libraryfolders + .iter() + .find(|(_, folder)| folder.apps.contains_key(&STEAMVR_STEAM_APPID)) + .map(|(_, folder)| { + PathBuf::from(&folder.path).join("steamapps/common/SteamVR/steamxr_linux64.json") + }), + Err(e) => { + error!("unable to find steam openxr json: unable to load steam libraryfolders: {e}"); + None + } + } +} + fn get_backup_steam_active_runtime_path() -> PathBuf { get_backup_dir().join("active_runtime.json.steam.bak") } diff --git a/src/main.rs b/src/main.rs index 2c94efd..a13a2ce 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,7 +5,6 @@ use file_builders::{ openvrpaths_vrpath::{get_current_openvrpaths, set_current_openvrpaths_to_steam}, }; use gettextrs::LocaleCategory; -use tracing::warn; use relm4::{ adw, gtk::{self, gdk, gio, glib, prelude::*}, @@ -13,6 +12,7 @@ use relm4::{ }; use std::env; use steam_linux_runtime_injector::restore_runtime_entrypoint; +use tracing::warn; use tracing_subscriber::{filter::LevelFilter, EnvFilter}; use ui::{ app::{App, AppInit, Msg}, diff --git a/src/steam_linux_runtime_injector.rs b/src/steam_linux_runtime_injector.rs index 098be3e..97f50c5 100644 --- a/src/steam_linux_runtime_injector.rs +++ b/src/steam_linux_runtime_injector.rs @@ -1,76 +1,33 @@ use crate::{ - paths::{get_backup_dir, get_home_dir}, + paths::get_backup_dir, profile::Profile, - util::file_utils::{copy_file, get_writer}, + util::{ + file_utils::{copy_file, get_writer}, + steam_library_folder::SteamLibraryFolder, + }, }; use anyhow::bail; use lazy_static::lazy_static; -use tracing::error; -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, -} +use tracing::error; 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 { - 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() { - error!( - "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) - .join("steamapps/common/SteamLinuxRuntime_sniper/_v2-entry-point") - }) - } + match SteamLibraryFolder::get_folders() { + Ok(libraryfolders) => libraryfolders + .iter() + .find(|(_, folder)| folder.apps.contains_key(&PRESSURE_VESSEL_STEAM_APPID)) + .map(|(_, folder)| { + PathBuf::from(&folder.path) + .join("steamapps/common/SteamLinuxRuntime_sniper/_v2-entry-point") + }), Err(e) => { - error!("Error getting steam root path: {e}"); + error!("unable to get runtime entrypoint path: {e}"); None } } @@ -126,22 +83,3 @@ pub fn set_runtime_entrypoint_launch_opts_from_profile(profile: &Profile) -> any } 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/src/ui/app.rs b/src/ui/app.rs index 35db15c..34c5549 100644 --- a/src/ui/app.rs +++ b/src/ui/app.rs @@ -47,7 +47,6 @@ use crate::{ }; use adw::{prelude::*, ResponseAppearance}; use gtk::glib::{self, clone}; -use tracing::error; use notify_rust::NotificationHandle; use relm4::{ actions::{AccelsPlus, ActionGroupName, RelmAction, RelmActionGroup}, @@ -55,6 +54,7 @@ use relm4::{ prelude::*, }; use std::{collections::VecDeque, fs::remove_file, time::Duration}; +use tracing::error; pub struct App { application: adw::Application, diff --git a/src/ui/install_wivrn_box.rs b/src/ui/install_wivrn_box.rs index 31459c7..e8abc36 100644 --- a/src/ui/install_wivrn_box.rs +++ b/src/ui/install_wivrn_box.rs @@ -6,9 +6,9 @@ use crate::{ profile::{Profile, XRServiceType}, }; use gtk::prelude::*; -use tracing::error; use relm4::{new_action_group, new_stateless_action, prelude::*}; use std::fs::remove_file; +use tracing::error; const WIVRN_LATEST_RELEASE_APK_URL: &str = "https://github.com/WiVRn/WiVRn/releases/latest/download/WiVRn-standard-release.apk"; @@ -185,10 +185,7 @@ impl AsyncComponent for InstallWivrnBox { let existing = cache_file_path(WIVRN_LATEST_RELEASE_APK_URL, Some("apk")); if existing.is_file() { if let Err(e) = remove_file(&existing) { - error!( - "failed to remove file {}: {e}", - existing.to_string_lossy() - ); + error!("failed to remove file {}: {e}", existing.to_string_lossy()); } } sender.input(Self::Input::DoInstall(WIVRN_LATEST_RELEASE_APK_URL.into())); diff --git a/src/ui/job_worker/mod.rs b/src/ui/job_worker/mod.rs index 4915ed1..c50ab21 100644 --- a/src/ui/job_worker/mod.rs +++ b/src/ui/job_worker/mod.rs @@ -4,7 +4,6 @@ use self::{ state::JobWorkerState, }; use crate::profile::Profile; -use tracing::{error, warn}; use nix::sys::signal::{ kill, Signal::{SIGKILL, SIGTERM}, @@ -16,6 +15,7 @@ use std::{ thread::{self, sleep}, time::Duration, }; +use tracing::{error, warn}; pub mod internal_worker; pub mod job; diff --git a/src/ui/main_view.rs b/src/ui/main_view.rs index 460d937..28ec87a 100644 --- a/src/ui/main_view.rs +++ b/src/ui/main_view.rs @@ -30,13 +30,13 @@ use crate::{ }; use adw::{prelude::*, ResponseAppearance}; use gtk::glib::clone; -use tracing::{error, warn}; use relm4::{ actions::{ActionGroupName, RelmAction, RelmActionGroup}, new_action_group, new_stateless_action, prelude::*, }; use std::{fs::read_to_string, io::Write}; +use tracing::{error, warn}; #[tracker::track] pub struct MainView { diff --git a/src/ui/openhmd_calibration_box.rs b/src/ui/openhmd_calibration_box.rs index fbd44e9..6258ad1 100644 --- a/src/ui/openhmd_calibration_box.rs +++ b/src/ui/openhmd_calibration_box.rs @@ -1,9 +1,9 @@ use crate::{constants::APP_NAME, xdg::XDG}; -use tracing::{debug, error}; use relm4::{ gtk::{self, prelude::*}, ComponentParts, ComponentSender, SimpleComponent, }; +use tracing::{debug, error}; #[tracker::track] pub struct OpenHmdCalibrationBox { diff --git a/src/ui/steamvr_calibration_box.rs b/src/ui/steamvr_calibration_box.rs index 4d7c250..f2f9c7d 100644 --- a/src/ui/steamvr_calibration_box.rs +++ b/src/ui/steamvr_calibration_box.rs @@ -4,7 +4,6 @@ use super::job_worker::{ JobWorker, }; use crate::paths::get_steamvr_bin_dir_path; -use tracing::error; use relm4::{ gtk::{self, prelude::*}, ComponentParts, ComponentSender, RelmWidgetExt, SimpleComponent, @@ -15,6 +14,7 @@ use std::{ thread::sleep, time::Duration, }; +use tracing::error; #[tracker::track] pub struct SteamVrCalibrationBox { diff --git a/src/ui/wivrn_conf_editor.rs b/src/ui/wivrn_conf_editor.rs index edf5d52..1c6d6d4 100644 --- a/src/ui/wivrn_conf_editor.rs +++ b/src/ui/wivrn_conf_editor.rs @@ -20,8 +20,8 @@ use crate::{ }; use adw::prelude::*; use gtk::glib::clone; -use tracing::error; use relm4::{factory::AsyncFactoryVecDeque, prelude::*}; +use tracing::error; #[tracker::track] pub struct WivrnConfEditor { diff --git a/src/ui/wivrn_wired_start_box.rs b/src/ui/wivrn_wired_start_box.rs index 1918b4f..503bcac 100644 --- a/src/ui/wivrn_wired_start_box.rs +++ b/src/ui/wivrn_wired_start_box.rs @@ -6,8 +6,8 @@ use crate::{ profile::{Profile, XRServiceType}, }; use gtk::prelude::*; -use tracing::error; use relm4::prelude::*; +use tracing::error; #[derive(PartialEq, Eq, Debug, Clone)] pub enum StartClientStatus { diff --git a/src/util/file_utils.rs b/src/util/file_utils.rs index f802fac..04ef1bc 100644 --- a/src/util/file_utils.rs +++ b/src/util/file_utils.rs @@ -1,6 +1,5 @@ use crate::{async_process::async_process, profile::Profile}; use anyhow::bail; -use tracing::{debug, error}; use nix::{ errno::Errno, sys::statvfs::{statvfs, FsFlags}, @@ -10,6 +9,7 @@ use std::{ io::{BufReader, BufWriter}, path::Path, }; +use tracing::{debug, error}; pub fn get_writer(path: &Path) -> anyhow::Result> { if let Some(parent) = path.parent() { diff --git a/src/util/mod.rs b/src/util/mod.rs index 10902df..0aded2a 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -1,3 +1,4 @@ pub mod file_utils; pub mod hash; +pub mod steam_library_folder; pub mod steamvr_utils; diff --git a/src/util/steam_library_folder.rs b/src/util/steam_library_folder.rs new file mode 100644 index 0000000..253ed12 --- /dev/null +++ b/src/util/steam_library_folder.rs @@ -0,0 +1,69 @@ +use crate::paths::get_home_dir; +use anyhow::bail; +use serde::Deserialize; +use std::{ + collections::HashMap, + fs::read_to_string, + path::{Path, PathBuf}, +}; + +#[derive(Deserialize)] +pub struct SteamLibraryFolder { + pub path: String, + pub apps: HashMap, +} + +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() + ) + } +} + +impl SteamLibraryFolder { + pub fn get_folders() -> anyhow::Result> { + let libraryfolders_path = get_steam_main_dir_path()?.join("steamapps/libraryfolders.vdf"); + if !libraryfolders_path.is_file() { + bail!( + "Steam libraryfolders.vdf does not exist in its canonical location {}", + libraryfolders_path.to_string_lossy() + ); + } + Self::get_folders_from_path(&libraryfolders_path) + } + + /// Do not use this: use get_folders() instead as it always uses Steam's + /// canonical root path. This is intended to be directly used only for + /// unit tests + pub fn get_folders_from_path(p: &Path) -> anyhow::Result> { + Ok(keyvalues_serde::from_str(read_to_string(p)?.as_str())?) + } +} + +#[cfg(test)] +mod tests { + use super::SteamLibraryFolder; + use std::path::Path; + + #[test] + fn deserialize_steam_libraryfolders_vdf() { + let lf = SteamLibraryFolder::get_folders_from_path(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/src/xr_devices.rs b/src/xr_devices.rs index c93df02..846759f 100644 --- a/src/xr_devices.rs +++ b/src/xr_devices.rs @@ -1,6 +1,6 @@ use libmonado::{self, BatteryStatus, DeviceRole}; -use tracing::error; use std::{collections::HashMap, fmt::Display, slice::Iter}; +use tracing::error; #[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] pub enum XRDeviceRole {