mirror of
https://gitlab.com/gabmus/envision.git
synced 2025-08-09 09:38:54 +00:00
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:
commit
8c79353e05
14 changed files with 149 additions and 35 deletions
|
@ -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())
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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<()> {
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
||||
|
|
80
src/steam_linux_runtime_injector.rs
Normal file
80
src/steam_linux_runtime_injector.rs
Normal 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");
|
||||
}
|
|
@ -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));
|
||||
|
|
|
@ -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) => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue