feat: per-profile autostart command

This commit is contained in:
Gabriele Musco 2024-02-04 17:17:26 +01:00
commit bf96a54675
No known key found for this signature in database
GPG key ID: 1068D795C80E51DE
5 changed files with 81 additions and 18 deletions

View file

@ -1,9 +1,6 @@
use crate::{
file_utils::get_writer,
paths::{
data_monado_path, data_opencomposite_path, get_data_dir, get_ipc_file_path,
BWRAP_SYSTEM_PREFIX, SYSTEM_PREFIX,
},
paths::{get_data_dir, get_ipc_file_path, BWRAP_SYSTEM_PREFIX, SYSTEM_PREFIX},
};
use serde::{Deserialize, Serialize};
use std::{collections::HashMap, fmt::Display, fs::File, io::BufReader, path::Path, slice::Iter};
@ -230,6 +227,7 @@ pub struct Profile {
pub lighthouse_driver: LighthouseDriver,
#[serde(default = "String::default")]
pub xrservice_launch_options: String,
pub autostart_command: Option<String>,
}
impl Display for Profile {
@ -284,6 +282,7 @@ impl Default for Profile {
lighthouse_driver: LighthouseDriver::default(),
xrservice_launch_options: String::default(),
uuid,
autostart_command: None,
}
}
}

View file

@ -92,6 +92,8 @@ pub struct App {
#[tracker::do_not_track]
xrservice_worker: Option<JobWorker>,
#[tracker::do_not_track]
autostart_worker: Option<JobWorker>,
#[tracker::do_not_track]
restart_xrservice: bool,
#[tracker::do_not_track]
build_worker: Option<JobWorker>,
@ -112,6 +114,7 @@ pub struct App {
pub enum Msg {
OnServiceLog(Vec<String>),
OnServiceExit(i32),
OnAutostartExit(i32),
OnBuildLog(Vec<String>),
OnBuildExit(i32),
ClockTicking,
@ -197,6 +200,23 @@ impl App {
debug,
);
worker.start();
if let Some(autostart_cmd) = prof.autostart_command {
let autostart_worker = JobWorker::new_with_timer(
Duration::from_secs(5),
WorkerJob::new_cmd(
Some(prof.environment.clone()),
"sh".into(),
Some(vec!["-c".into(), autostart_cmd.clone()]),
),
sender.input_sender(),
|msg| match msg {
JobWorkerOut::Log(rows) => Msg::OnServiceLog(rows),
JobWorkerOut::Exit(code) => Msg::OnAutostartExit(code),
},
);
autostart_worker.start();
self.autostart_worker = Some(autostart_worker)
}
self.xrservice_worker = Some(worker);
self.main_view
.sender()
@ -242,6 +262,9 @@ impl App {
if let Some(worker) = self.xrservice_worker.as_ref() {
worker.stop();
}
if let Some(worker) = self.autostart_worker.as_ref() {
worker.stop();
}
self.libmonado = None;
self.restore_openxr_openvr_files();
self.main_view
@ -325,15 +348,13 @@ impl SimpleComponent for App {
.emit(DebugViewMsg::LogUpdated(rows));
}
}
Msg::OnServiceExit(_) => {
Msg::OnServiceExit(code) => {
self.main_view
.sender()
.emit(MainViewMsg::XRServiceActiveChanged(false, None));
self.debug_view
.sender()
.emit(DebugViewMsg::XRServiceActiveChanged(false));
if let Some(worker) = self.xrservice_worker.as_ref() {
if let Some(code) = worker.exit_code() {
if code != 0 && code != 15 {
// 15 is SIGTERM
sender.input(Msg::OnServiceLog(vec![format!(
@ -342,14 +363,13 @@ impl SimpleComponent for App {
code
)]));
}
}
}
self.xrservice_worker = None;
if self.restart_xrservice {
self.restart_xrservice = false;
self.start_xrservice(sender, false);
}
}
Msg::OnAutostartExit(_) => self.autostart_worker = None,
Msg::ClockTicking => {
self.main_view.sender().emit(MainViewMsg::ClockTicking);
if let Some(w) = self.xrservice_worker.as_ref() {
@ -798,6 +818,7 @@ impl SimpleComponent for App {
config,
profiles,
xrservice_worker: None,
autostart_worker: None,
build_worker: None,
xr_devices: vec![],
fbt_config_editor: None,

View file

@ -7,12 +7,21 @@ pub struct CmdWorkerData {
pub args: Vec<String>,
}
#[derive(Debug, Clone, Default)]
#[derive(Debug, Clone)]
pub struct FuncWorkerOut {
pub success: bool,
pub out: Vec<String>,
}
impl Default for FuncWorkerOut {
fn default() -> Self {
Self {
success: true,
out: vec![],
}
}
}
pub struct FuncWorkerData {
pub func: Box<dyn FnOnce() -> FuncWorkerOut + Send + Sync + 'static>,
}

View file

@ -1,6 +1,6 @@
use self::{
internal_worker::{InternalJobWorker, JobWorkerInit, JobWorkerMsg, JobWorkerOut},
job::WorkerJob,
job::{FuncWorkerOut, WorkerJob},
state::JobWorkerState,
};
use crate::profile::Profile;
@ -44,6 +44,32 @@ impl JobWorker {
}
}
pub fn new_with_timer<X: 'static, F: (Fn(JobWorkerOut) -> X) + 'static>(
duration: Duration,
job: WorkerJob,
sender: &Sender<X>,
transform: F,
) -> Self {
let timer_job = WorkerJob::new_func(Box::new(move || {
thread::sleep(duration);
FuncWorkerOut::default()
}));
let mut jobs = VecDeque::new();
let state = Arc::new(Mutex::new(JobWorkerState::default()));
jobs.push_back(timer_job);
jobs.push_back(job);
let init = JobWorkerInit {
jobs,
state: state.clone(),
};
Self {
worker: InternalJobWorker::builder()
.detach_worker(init)
.forward(sender, transform),
state,
}
}
pub fn xrservice_worker_wrap_from_profile<X: 'static, F: (Fn(JobWorkerOut) -> X) + 'static>(
prof: &Profile,
sender: &Sender<X>,

View file

@ -113,6 +113,14 @@ impl SimpleComponent for ProfileEditor {
prof.borrow_mut().prefix = n_path.unwrap_or_default()
}),
),
add: &entry_row("Autostart Command",
model.profile.borrow().autostart_command.as_ref().unwrap_or(&String::default()),
clone!(@strong prof => move |row| {
let txt = row.text().trim().to_string();
prof.borrow_mut().autostart_command =
if txt.is_empty() {None} else {Some(txt)};
})
)
},
add: xrservicegrp = &adw::PreferencesGroup {
set_title: "XR Service",