feat: plugins start on service launch

This commit is contained in:
Gabriele Musco 2024-08-20 00:15:25 +02:00
commit 01a61bc842
3 changed files with 67 additions and 16 deletions

View file

@ -43,7 +43,8 @@ use crate::{
restore_runtime_entrypoint, set_runtime_entrypoint_launch_opts_from_profile, restore_runtime_entrypoint, set_runtime_entrypoint_launch_opts_from_profile,
}, },
util::file_utils::{ util::file_utils::{
setcap_cap_sys_nice_eip, setcap_cap_sys_nice_eip_cmd, verify_cap_sys_nice_eip, mark_as_executable, setcap_cap_sys_nice_eip, setcap_cap_sys_nice_eip_cmd,
verify_cap_sys_nice_eip,
}, },
vulkaninfo::VulkanInfo, vulkaninfo::VulkanInfo,
wivrn_dbus, wivrn_dbus,
@ -80,6 +81,7 @@ pub struct App {
config: Config, config: Config,
xrservice_worker: Option<JobWorker>, xrservice_worker: Option<JobWorker>,
autostart_worker: Option<JobWorker>, autostart_worker: Option<JobWorker>,
plugins_worker: Option<JobWorker>,
restart_xrservice: bool, restart_xrservice: bool,
build_worker: Option<JobWorker>, build_worker: Option<JobWorker>,
profiles: Vec<Profile>, profiles: Vec<Profile>,
@ -102,6 +104,7 @@ pub enum Msg {
OnServiceLog(Vec<String>), OnServiceLog(Vec<String>),
OnServiceExit(i32), OnServiceExit(i32),
OnAutostartExit(i32), OnAutostartExit(i32),
OnPluginsExit(i32),
OnBuildLog(Vec<String>), OnBuildLog(Vec<String>),
OnBuildExit(i32), OnBuildExit(i32),
ClockTicking, ClockTicking,
@ -257,6 +260,39 @@ impl App {
autostart_worker.start(); autostart_worker.start();
self.autostart_worker = Some(autostart_worker); self.autostart_worker = Some(autostart_worker);
} }
let plugins_cmd = self
.config
.plugins
.values()
.filter_map(|cp| {
if cp.enabled {
if let Err(e) = mark_as_executable(&cp.exec_path) {
eprintln!("Failed to mark plugin {} as executable: {e}", cp.appid);
None
} else {
Some(format!("'{}'", cp.exec_path.to_string_lossy()))
}
} else {
None
}
})
.collect::<Vec<String>>()
.join(" & ");
if !plugins_cmd.is_empty() {
let mut jobs = VecDeque::new();
jobs.push_back(WorkerJob::new_cmd(
Some(prof.environment.clone()),
"sh".into(),
Some(vec!["-c".into(), plugins_cmd]),
));
let plugins_worker = JobWorker::new(jobs, sender.input_sender(), |msg| match msg {
JobWorkerOut::Log(rows) => Msg::OnServiceLog(rows),
JobWorkerOut::Exit(code) => Msg::OnPluginsExit(code),
});
plugins_worker.start();
self.plugins_worker = Some(plugins_worker);
}
} }
pub fn restore_openxr_openvr_files(&self) { pub fn restore_openxr_openvr_files(&self) {
@ -285,27 +321,20 @@ impl App {
} }
pub fn shutdown_xrservice(&mut self) { pub fn shutdown_xrservice(&mut self) {
if let Some(worker) = self.autostart_worker.as_ref() { if let Some(w) = self.autostart_worker.as_ref() {
worker.stop(); w.stop();
}
if let Some(w) = self.plugins_worker.as_ref() {
w.stop();
} }
self.xrservice_ready = false;
if let Some(w) = self.openxr_prober_worker.as_ref() { if let Some(w) = self.openxr_prober_worker.as_ref() {
w.stop(); w.stop();
// this can cause threads to remain hanging... // this can cause threads to remain hanging...
self.openxr_prober_worker = None; self.openxr_prober_worker = None;
} }
self.set_inhibit_session(false); if let Some(w) = self.xrservice_worker.as_ref() {
if let Some(worker) = self.xrservice_worker.as_ref() { w.stop();
worker.stop();
} }
self.libmonado = None;
self.main_view
.sender()
.emit(MainViewMsg::XRServiceActiveChanged(false, None, false));
self.debug_view
.sender()
.emit(DebugViewMsg::XRServiceActiveChanged(false));
self.xr_devices = vec![];
} }
} }
@ -371,6 +400,8 @@ impl AsyncComponent for App {
} }
} }
Msg::OnServiceExit(code) => { Msg::OnServiceExit(code) => {
self.set_inhibit_session(false);
self.xrservice_ready = false;
self.restore_openxr_openvr_files(); self.restore_openxr_openvr_files();
self.main_view self.main_view
.sender() .sender()
@ -378,6 +409,8 @@ impl AsyncComponent for App {
self.debug_view self.debug_view
.sender() .sender()
.emit(DebugViewMsg::XRServiceActiveChanged(false)); .emit(DebugViewMsg::XRServiceActiveChanged(false));
self.libmonado = None;
self.xr_devices = vec![];
if code != 0 && code != 15 { if code != 0 && code != 15 {
// 15 is SIGTERM // 15 is SIGTERM
sender.input(Msg::OnServiceLog(vec![format!( sender.input(Msg::OnServiceLog(vec![format!(
@ -393,6 +426,7 @@ impl AsyncComponent for App {
} }
} }
Msg::OnAutostartExit(_) => self.autostart_worker = None, Msg::OnAutostartExit(_) => self.autostart_worker = None,
Msg::OnPluginsExit(_) => self.plugins_worker = None,
Msg::ClockTicking => { Msg::ClockTicking => {
self.main_view.sender().emit(MainViewMsg::ClockTicking); self.main_view.sender().emit(MainViewMsg::ClockTicking);
let xrservice_worker_is_alive = self let xrservice_worker_is_alive = self
@ -998,6 +1032,7 @@ impl AsyncComponent for App {
profiles, profiles,
xrservice_worker: None, xrservice_worker: None,
autostart_worker: None, autostart_worker: None,
plugins_worker: None,
build_worker: None, build_worker: None,
xr_devices: vec![], xr_devices: vec![],
restart_xrservice: false, restart_xrservice: false,

View file

@ -2,7 +2,7 @@ pub mod store;
mod store_detail; mod store_detail;
mod store_row_factory; mod store_row_factory;
use crate::paths::get_plugins_dir; use crate::{paths::get_plugins_dir, util::file_utils::mark_as_executable};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::path::PathBuf; use std::path::PathBuf;
@ -41,4 +41,8 @@ impl Plugin {
pub fn is_installed(&self) -> bool { pub fn is_installed(&self) -> bool {
self.exec_path().exists() self.exec_path().exists()
} }
pub fn mark_as_executable(&self) -> anyhow::Result<()> {
mark_as_executable(&self.exec_path())
}
} }

View file

@ -7,6 +7,7 @@ use nix::{
use std::{ use std::{
fs::{self, copy, create_dir_all, remove_dir_all, File, OpenOptions}, fs::{self, copy, create_dir_all, remove_dir_all, File, OpenOptions},
io::{BufReader, BufWriter}, io::{BufReader, BufWriter},
os::unix::fs::PermissionsExt,
path::Path, path::Path,
}; };
use tracing::{debug, error}; use tracing::{debug, error};
@ -151,6 +152,17 @@ pub fn mount_has_nosuid(path: &Path) -> Result<bool, Errno> {
} }
} }
pub fn mark_as_executable(path: &Path) -> anyhow::Result<()> {
if !path.is_file() {
bail!("Path '{}' is not a file", path.to_string_lossy())
} else {
let mut perms = fs::metadata(path)?.permissions();
perms.set_mode(perms.mode() | 0o111);
fs::set_permissions(path, perms)?;
Ok(())
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::mount_has_nosuid; use super::mount_has_nosuid;