mirror of
https://gitlab.com/gabmus/envision.git
synced 2025-07-29 20:28:48 +00:00
feat: per-profile autostart command
This commit is contained in:
parent
e2ab73500d
commit
bf96a54675
5 changed files with 81 additions and 18 deletions
|
@ -1,9 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
file_utils::get_writer,
|
file_utils::get_writer,
|
||||||
paths::{
|
paths::{get_data_dir, get_ipc_file_path, BWRAP_SYSTEM_PREFIX, SYSTEM_PREFIX},
|
||||||
data_monado_path, data_opencomposite_path, get_data_dir, get_ipc_file_path,
|
|
||||||
BWRAP_SYSTEM_PREFIX, SYSTEM_PREFIX,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{collections::HashMap, fmt::Display, fs::File, io::BufReader, path::Path, slice::Iter};
|
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,
|
pub lighthouse_driver: LighthouseDriver,
|
||||||
#[serde(default = "String::default")]
|
#[serde(default = "String::default")]
|
||||||
pub xrservice_launch_options: String,
|
pub xrservice_launch_options: String,
|
||||||
|
pub autostart_command: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Profile {
|
impl Display for Profile {
|
||||||
|
@ -284,6 +282,7 @@ impl Default for Profile {
|
||||||
lighthouse_driver: LighthouseDriver::default(),
|
lighthouse_driver: LighthouseDriver::default(),
|
||||||
xrservice_launch_options: String::default(),
|
xrservice_launch_options: String::default(),
|
||||||
uuid,
|
uuid,
|
||||||
|
autostart_command: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,6 +92,8 @@ pub struct App {
|
||||||
#[tracker::do_not_track]
|
#[tracker::do_not_track]
|
||||||
xrservice_worker: Option<JobWorker>,
|
xrservice_worker: Option<JobWorker>,
|
||||||
#[tracker::do_not_track]
|
#[tracker::do_not_track]
|
||||||
|
autostart_worker: Option<JobWorker>,
|
||||||
|
#[tracker::do_not_track]
|
||||||
restart_xrservice: bool,
|
restart_xrservice: bool,
|
||||||
#[tracker::do_not_track]
|
#[tracker::do_not_track]
|
||||||
build_worker: Option<JobWorker>,
|
build_worker: Option<JobWorker>,
|
||||||
|
@ -112,6 +114,7 @@ pub struct App {
|
||||||
pub enum Msg {
|
pub enum Msg {
|
||||||
OnServiceLog(Vec<String>),
|
OnServiceLog(Vec<String>),
|
||||||
OnServiceExit(i32),
|
OnServiceExit(i32),
|
||||||
|
OnAutostartExit(i32),
|
||||||
OnBuildLog(Vec<String>),
|
OnBuildLog(Vec<String>),
|
||||||
OnBuildExit(i32),
|
OnBuildExit(i32),
|
||||||
ClockTicking,
|
ClockTicking,
|
||||||
|
@ -197,6 +200,23 @@ impl App {
|
||||||
debug,
|
debug,
|
||||||
);
|
);
|
||||||
worker.start();
|
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.xrservice_worker = Some(worker);
|
||||||
self.main_view
|
self.main_view
|
||||||
.sender()
|
.sender()
|
||||||
|
@ -242,6 +262,9 @@ impl App {
|
||||||
if let Some(worker) = self.xrservice_worker.as_ref() {
|
if let Some(worker) = self.xrservice_worker.as_ref() {
|
||||||
worker.stop();
|
worker.stop();
|
||||||
}
|
}
|
||||||
|
if let Some(worker) = self.autostart_worker.as_ref() {
|
||||||
|
worker.stop();
|
||||||
|
}
|
||||||
self.libmonado = None;
|
self.libmonado = None;
|
||||||
self.restore_openxr_openvr_files();
|
self.restore_openxr_openvr_files();
|
||||||
self.main_view
|
self.main_view
|
||||||
|
@ -325,24 +348,20 @@ impl SimpleComponent for App {
|
||||||
.emit(DebugViewMsg::LogUpdated(rows));
|
.emit(DebugViewMsg::LogUpdated(rows));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Msg::OnServiceExit(_) => {
|
Msg::OnServiceExit(code) => {
|
||||||
self.main_view
|
self.main_view
|
||||||
.sender()
|
.sender()
|
||||||
.emit(MainViewMsg::XRServiceActiveChanged(false, None));
|
.emit(MainViewMsg::XRServiceActiveChanged(false, None));
|
||||||
self.debug_view
|
self.debug_view
|
||||||
.sender()
|
.sender()
|
||||||
.emit(DebugViewMsg::XRServiceActiveChanged(false));
|
.emit(DebugViewMsg::XRServiceActiveChanged(false));
|
||||||
if let Some(worker) = self.xrservice_worker.as_ref() {
|
if code != 0 && code != 15 {
|
||||||
if let Some(code) = worker.exit_code() {
|
// 15 is SIGTERM
|
||||||
if code != 0 && code != 15 {
|
sender.input(Msg::OnServiceLog(vec![format!(
|
||||||
// 15 is SIGTERM
|
"{} exited with code {}",
|
||||||
sender.input(Msg::OnServiceLog(vec![format!(
|
self.get_selected_profile().xrservice_type,
|
||||||
"{} exited with code {}",
|
code
|
||||||
self.get_selected_profile().xrservice_type,
|
)]));
|
||||||
code
|
|
||||||
)]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
self.xrservice_worker = None;
|
self.xrservice_worker = None;
|
||||||
if self.restart_xrservice {
|
if self.restart_xrservice {
|
||||||
|
@ -350,6 +369,7 @@ impl SimpleComponent for App {
|
||||||
self.start_xrservice(sender, false);
|
self.start_xrservice(sender, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Msg::OnAutostartExit(_) => self.autostart_worker = None,
|
||||||
Msg::ClockTicking => {
|
Msg::ClockTicking => {
|
||||||
self.main_view.sender().emit(MainViewMsg::ClockTicking);
|
self.main_view.sender().emit(MainViewMsg::ClockTicking);
|
||||||
if let Some(w) = self.xrservice_worker.as_ref() {
|
if let Some(w) = self.xrservice_worker.as_ref() {
|
||||||
|
@ -798,6 +818,7 @@ impl SimpleComponent for App {
|
||||||
config,
|
config,
|
||||||
profiles,
|
profiles,
|
||||||
xrservice_worker: None,
|
xrservice_worker: None,
|
||||||
|
autostart_worker: None,
|
||||||
build_worker: None,
|
build_worker: None,
|
||||||
xr_devices: vec![],
|
xr_devices: vec![],
|
||||||
fbt_config_editor: None,
|
fbt_config_editor: None,
|
||||||
|
|
|
@ -7,12 +7,21 @@ pub struct CmdWorkerData {
|
||||||
pub args: Vec<String>,
|
pub args: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct FuncWorkerOut {
|
pub struct FuncWorkerOut {
|
||||||
pub success: bool,
|
pub success: bool,
|
||||||
pub out: Vec<String>,
|
pub out: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for FuncWorkerOut {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
success: true,
|
||||||
|
out: vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct FuncWorkerData {
|
pub struct FuncWorkerData {
|
||||||
pub func: Box<dyn FnOnce() -> FuncWorkerOut + Send + Sync + 'static>,
|
pub func: Box<dyn FnOnce() -> FuncWorkerOut + Send + Sync + 'static>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use self::{
|
use self::{
|
||||||
internal_worker::{InternalJobWorker, JobWorkerInit, JobWorkerMsg, JobWorkerOut},
|
internal_worker::{InternalJobWorker, JobWorkerInit, JobWorkerMsg, JobWorkerOut},
|
||||||
job::WorkerJob,
|
job::{FuncWorkerOut, WorkerJob},
|
||||||
state::JobWorkerState,
|
state::JobWorkerState,
|
||||||
};
|
};
|
||||||
use crate::profile::Profile;
|
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>(
|
pub fn xrservice_worker_wrap_from_profile<X: 'static, F: (Fn(JobWorkerOut) -> X) + 'static>(
|
||||||
prof: &Profile,
|
prof: &Profile,
|
||||||
sender: &Sender<X>,
|
sender: &Sender<X>,
|
||||||
|
|
|
@ -113,6 +113,14 @@ impl SimpleComponent for ProfileEditor {
|
||||||
prof.borrow_mut().prefix = n_path.unwrap_or_default()
|
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 {
|
add: xrservicegrp = &adw::PreferencesGroup {
|
||||||
set_title: "XR Service",
|
set_title: "XR Service",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue