Merge branch 'feat/injectSteamEnvVarsInRuntime' into 'main'

feat: inject steam env vars in steam sniper runtime

See merge request gabmus/envision!47
This commit is contained in:
GabMus 2024-06-14 04:52:44 +00:00
commit 8c79353e05
14 changed files with 149 additions and 35 deletions

View file

@ -7,7 +7,7 @@ use nix::{
};
use crate::{
file_utils::get_writer,
file_utils::get_writer_legacy,
profile::{Profile, XRServiceType},
runner::{Runner, RunnerStatus},
};
@ -172,7 +172,7 @@ impl CmdRunner {
}
fn save_log(path_s: String, log: &[String]) -> Result<(), std::io::Error> {
let mut writer = get_writer(&path_s);
let mut writer = get_writer_legacy(&path_s);
let log_s = log.concat();
writer.write_all(log_s.as_ref())
}

View file

@ -1,7 +1,7 @@
use crate::{
constants::CMD_NAME,
device_prober::get_xr_usb_devices,
file_utils::get_writer,
file_utils::get_writer_legacy,
paths::get_config_dir,
profile::Profile,
profiles::{
@ -78,7 +78,7 @@ impl Config {
}
fn save_to_path(&self, path_s: &String) -> Result<(), serde_json::Error> {
let writer = get_writer(path_s);
let writer = get_writer_legacy(path_s);
serde_json::to_writer_pretty(writer, self)
}

View file

@ -1,4 +1,4 @@
use crate::{constants::APP_ID, file_utils::get_writer};
use crate::{constants::APP_ID, file_utils::get_writer_legacy};
use reqwest::{
header::{HeaderMap, USER_AGENT},
Method,
@ -32,7 +32,7 @@ pub fn download_file(url: String, path: String) -> JoinHandle<Result<(), reqwest
if status.is_client_error() || status.is_server_error() {
return Err(res.error_for_status().unwrap_err());
}
let mut writer = get_writer(&path);
let mut writer = get_writer_legacy(&path);
for chunk in res
.bytes()
.expect("Could not get HTTP response bytes")

View file

@ -1,5 +1,5 @@
use crate::{
file_utils::{copy_file, deserialize_file, get_writer, set_file_readonly},
file_utils::{copy_file, deserialize_file, get_writer_legacy, set_file_readonly},
paths::{get_backup_dir, get_xdg_config_dir, get_xdg_data_dir, SYSTEM_PREFIX},
profile::{Profile, XRServiceType},
};
@ -69,7 +69,7 @@ fn dump_active_runtime_to_path(
active_runtime: &ActiveRuntime,
path_s: &String,
) -> Result<(), serde_json::Error> {
let writer = get_writer(path_s);
let writer = get_writer_legacy(path_s);
serde_json::to_writer_pretty(writer, active_runtime)
}

View file

@ -1,5 +1,5 @@
use crate::{
file_utils::{deserialize_file, get_writer},
file_utils::{deserialize_file, get_writer_legacy},
paths::get_xdg_config_dir,
};
use serde::{Deserialize, Serialize};
@ -45,7 +45,7 @@ pub fn get_monado_autorun_config() -> MonadoAutorunConfig {
}
fn dump_monado_autorun_config_to_path(config: &MonadoAutorunConfig, path_s: &String) {
let writer = get_writer(path_s);
let writer = get_writer_legacy(path_s);
serde_json::to_writer_pretty(writer, config).expect("Unable to save Monado Autorun config");
}

View file

@ -1,5 +1,5 @@
use crate::{
file_utils::{deserialize_file, get_writer},
file_utils::{deserialize_file, get_writer_legacy},
paths::get_xdg_config_dir,
};
use serde::{Deserialize, Serialize};
@ -202,7 +202,7 @@ pub fn get_monado_config_v0() -> MonadoConfigV0 {
}
fn dump_monado_config_v0_to_path(config: &MonadoConfigV0, path_s: &String) {
let writer = get_writer(path_s);
let writer = get_writer_legacy(path_s);
serde_json::to_writer_pretty(writer, config).expect("Unable to save Monado config V0");
}

View file

@ -1,5 +1,5 @@
use crate::{
file_utils::{copy_file, deserialize_file, get_writer, set_file_readonly},
file_utils::{copy_file, deserialize_file, get_writer_legacy, set_file_readonly},
paths::{get_backup_dir, get_xdg_config_dir, get_xdg_data_dir},
profile::Profile,
};
@ -67,7 +67,7 @@ fn dump_openvrpaths_to_path(
ovr_paths: &OpenVrPaths,
path_s: &String,
) -> Result<(), serde_json::Error> {
let writer = get_writer(path_s);
let writer = get_writer_legacy(path_s);
serde_json::to_writer_pretty(writer, ovr_paths)
}

View file

@ -1,5 +1,5 @@
use crate::{
file_utils::{deserialize_file, get_writer},
file_utils::{deserialize_file, get_writer_legacy},
paths::get_xdg_config_dir,
};
use serde::{Deserialize, Serialize};
@ -136,7 +136,7 @@ pub fn get_wivrn_config() -> WivrnConfig {
}
fn dump_wivrn_config_to_path(config: &WivrnConfig, path_s: &String) {
let writer = get_writer(path_s);
let writer = get_writer_legacy(path_s);
serde_json::to_writer_pretty(writer, config).expect("Unable to save WiVRn config");
}

View file

@ -9,7 +9,23 @@ use std::{
path::Path,
};
pub fn get_writer(path_s: &String) -> BufWriter<std::fs::File> {
pub fn get_writer(path_s: &str) -> anyhow::Result<BufWriter<std::fs::File>> {
let path = Path::new(path_s);
if let Some(parent) = path.parent() {
if !parent.is_dir() {
create_dir_all(parent)?;
}
};
let file = OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.open(path)?;
Ok(BufWriter::new(file))
}
#[deprecated]
pub fn get_writer_legacy(path_s: &str) -> BufWriter<std::fs::File> {
let path = Path::new(path_s);
if let Some(parent) = path.parent() {
if !parent.is_dir() {
@ -52,7 +68,7 @@ pub fn deserialize_file<T: serde::de::DeserializeOwned>(path_s: &String) -> Opti
}
}
pub fn set_file_readonly(path_s: &String, readonly: bool) -> Result<(), std::io::Error> {
pub fn set_file_readonly(path_s: &str, readonly: bool) -> Result<(), std::io::Error> {
let path = Path::new(&path_s);
if !path.is_file() {
println!("WARN: trying to set readonly on a file that does not exist");
@ -81,7 +97,7 @@ pub fn rm_rf(path_s: &String) {
}
}
pub fn copy_file(source_s: &String, dest_s: &String) {
pub fn copy_file(source_s: &str, dest_s: &str) {
let source = Path::new(source_s);
let dest = Path::new(dest_s);
if let Some(parent) = dest.parent() {

View file

@ -11,6 +11,7 @@ use relm4::{
gtk::{self, gdk, gio, glib, prelude::*},
MessageBroker, RelmApp,
};
use steam_linux_runtime_injector::restore_runtime_entrypoint;
use ui::app::{App, AppInit};
pub mod adb;
@ -37,6 +38,7 @@ pub mod profile;
pub mod profiles;
pub mod runner;
pub mod runner_pipeline;
pub mod steam_linux_runtime_injector;
pub mod steamvr_utils;
pub mod ui;
pub mod xr_devices;
@ -60,6 +62,7 @@ fn restore_steam_xr_files() {
};
}
}
restore_runtime_entrypoint();
}
fn main() -> Result<()> {

View file

@ -1,5 +1,5 @@
use crate::{
file_utils::get_writer,
file_utils::get_writer_legacy,
paths::{get_data_dir, get_ipc_file_path, BWRAP_SYSTEM_PREFIX, SYSTEM_PREFIX},
};
use serde::{Deserialize, Serialize};
@ -288,14 +288,19 @@ impl Default for Profile {
}
impl Profile {
pub fn get_steam_launch_options(&self) -> String {
pub fn get_env_vars(&self) -> Vec<String> {
if self.can_be_built {
return vec![
"PRESSURE_VESSEL_FILESYSTEMS_RW=\"$XDG_RUNTIME_DIR/wivrn_comp_ipc:$XDG_RUNTIME_DIR/monado_comp_ipc\"".into(),
];
}
vec![
// format!(
// "VR_OVERRIDE={opencomp}/build",
// opencomp = self.opencomposite_path,
// ),
format!(
"XR_RUNTIME_JSON={prefix}/share/openxr/1/openxr_{runtime}.json",
"XR_RUNTIME_JSON=\"{prefix}/share/openxr/1/openxr_{runtime}.json\"",
prefix = match self.prefix.as_str() {
SYSTEM_PREFIX => BWRAP_SYSTEM_PREFIX,
other => other,
@ -306,12 +311,16 @@ impl Profile {
}
),
format!(
"PRESSURE_VESSEL_FILESYSTEMS_RW={path}",
"PRESSURE_VESSEL_FILESYSTEMS_RW=\"{path}\"",
path = get_ipc_file_path(&self.xrservice_type),
),
"%command%".into(),
]
.join(" ")
}
pub fn get_steam_launch_options(&self) -> String {
let mut vars = self.get_env_vars();
vars.push("%command%".into());
vars.join(" ")
}
pub fn get_survive_cli_path(&self) -> Option<String> {
@ -329,7 +338,7 @@ impl Profile {
}
pub fn dump_profile(&self, path_s: &String) {
let writer = get_writer(path_s);
let writer = get_writer_legacy(path_s);
serde_json::to_writer_pretty(writer, self).expect("Could not write profile")
}

View file

@ -0,0 +1,80 @@
use crate::{
file_utils::{copy_file, get_writer},
paths::{get_backup_dir, get_home_dir, get_xdg_data_dir},
profile::Profile,
};
use anyhow::bail;
use std::{
fs::read_to_string,
io::{Read, Write},
path::Path,
};
fn get_runtime_entrypoint_path() -> Option<String> {
let mut out = format!(
"{home}/.steam/steam/steamapps/common/SteamLinuxRuntime_sniper/_v2-entry-point",
home = get_home_dir(),
);
if Path::new(&out).is_file() {
return Some(out);
}
out = format!(
"{data}/Steam/ubuntu12_64/steam-runtime-sniper/_v2-entry-point",
data = get_xdg_data_dir()
);
if Path::new(&out).is_file() {
return Some(out);
}
None
}
fn get_backup_runtime_entrypoint_location() -> String {
format!("{backup}/_v2-entry-point.bak", backup = get_backup_dir())
}
fn backup_runtime_entrypoint(path: &str) {
copy_file(&path, &get_backup_runtime_entrypoint_location());
}
pub fn restore_runtime_entrypoint() {
if let Some(path) = get_runtime_entrypoint_path() {
let backup = get_backup_runtime_entrypoint_location();
if Path::new(&backup).is_file() {
copy_file(&backup, &path);
}
}
}
fn append_to_runtime_entrypoint(data: &str, path: &str) -> anyhow::Result<()> {
let existing = read_to_string(path)?;
let new = existing.replace(
"exec \"${here}/${run}\" \"$@\"\nexit 125",
&format!("\n\n# envision\n{data}\n\nexec \"${{here}}/${{run}}\" \"$@\"\nexit 125"),
);
let mut writer = get_writer(path)?;
writer.write(&new.as_bytes())?;
Ok(())
}
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);
append_to_runtime_entrypoint(
&profile
.get_env_vars()
.iter()
.map(|ev| "export ".to_string() + ev)
.collect::<Vec<String>>()
.join("\n"),
&dest,
)?;
return Ok(());
}
bail!("Could not find valid runtime entrypoint");
}

View file

@ -39,6 +39,9 @@ use crate::log_parser::MonadoLog;
use crate::paths::{get_data_dir, get_ipc_file_path};
use crate::profile::{Profile, XRServiceType};
use crate::stateless_action;
use crate::steam_linux_runtime_injector::{
restore_runtime_entrypoint, set_runtime_entrypoint_launch_opts_from_profile,
};
use crate::ui::build_window::{BuildWindowMsg, BuildWindowOutMsg};
use crate::ui::debug_view::{DebugViewInit, DebugViewOutMsg};
use crate::ui::libsurvive_setup_window::LibsurviveSetupMsg;
@ -199,7 +202,7 @@ impl App {
debug,
);
worker.start();
if let Some(autostart_cmd) = prof.autostart_command {
if let Some(autostart_cmd) = &prof.autostart_command {
let autostart_worker = JobWorker::new_with_timer(
Duration::from_secs(5),
WorkerJob::new_cmd(
@ -222,6 +225,8 @@ impl App {
.emit(MainViewMsg::XRServiceActiveChanged(
true,
Some(self.get_selected_profile()),
// show launch opts only if setting the runtime entrypoint fails
set_runtime_entrypoint_launch_opts_from_profile(&prof).is_err(),
));
self.debug_view
.sender()
@ -265,10 +270,9 @@ impl App {
worker.stop();
}
self.libmonado = None;
self.restore_openxr_openvr_files();
self.main_view
.sender()
.emit(MainViewMsg::XRServiceActiveChanged(false, None));
.emit(MainViewMsg::XRServiceActiveChanged(false, None, false));
self.debug_view
.sender()
.emit(DebugViewMsg::XRServiceActiveChanged(false));
@ -334,9 +338,11 @@ impl SimpleComponent for App {
}
}
Msg::OnServiceExit(code) => {
self.restore_openxr_openvr_files();
restore_runtime_entrypoint();
self.main_view
.sender()
.emit(MainViewMsg::XRServiceActiveChanged(false, None));
.emit(MainViewMsg::XRServiceActiveChanged(false, None, false));
self.debug_view
.sender()
.emit(DebugViewMsg::XRServiceActiveChanged(false));

View file

@ -55,7 +55,7 @@ pub enum MainViewMsg {
ClockTicking,
StartStopClicked,
RestartXRService,
XRServiceActiveChanged(bool, Option<Profile>),
XRServiceActiveChanged(bool, Option<Profile>, bool),
EnableDebugViewChanged(bool),
UpdateProfiles(Vec<Profile>, Config),
SetSelectedProfile(u32),
@ -450,7 +450,7 @@ impl SimpleComponent for MainView {
.output(Self::Output::RestartXRService)
.expect("Sender output failed");
}
Self::Input::XRServiceActiveChanged(active, profile) => {
Self::Input::XRServiceActiveChanged(active, profile, show_launch_opts) => {
self.set_xrservice_active(active);
self.steamvr_calibration_box
.sender()
@ -458,9 +458,9 @@ impl SimpleComponent for MainView {
if !active {
sender.input(Self::Input::UpdateDevices(vec![]));
}
self.steam_launch_options_box
.sender()
.emit(SteamLaunchOptionsBoxMsg::UpdateXRServiceActive(active));
self.steam_launch_options_box.sender().emit(
SteamLaunchOptionsBoxMsg::UpdateXRServiceActive(show_launch_opts),
);
match profile {
None => {}
Some(prof) => {