mirror of
https://gitlab.com/gabmus/envision.git
synced 2025-08-05 15:48:45 +00:00
feat: refactor wivrn install around jobworker
This commit is contained in:
parent
7cb9e3c5c6
commit
5a9c03c11d
6 changed files with 123 additions and 114 deletions
12
src/adb.rs
12
src/adb.rs
|
@ -1,12 +0,0 @@
|
||||||
use std::path::Path;
|
|
||||||
|
|
||||||
use crate::cmd_runner::CmdRunner;
|
|
||||||
|
|
||||||
pub fn get_adb_install_runner(path: &Path) -> CmdRunner {
|
|
||||||
path.try_exists().expect("APK file provided does not exist");
|
|
||||||
CmdRunner::new(
|
|
||||||
None,
|
|
||||||
"adb".into(),
|
|
||||||
vec!["install".into(), path.to_string_lossy().to_string()],
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -3,8 +3,8 @@ use reqwest::{
|
||||||
header::{HeaderMap, USER_AGENT},
|
header::{HeaderMap, USER_AGENT},
|
||||||
Method,
|
Method,
|
||||||
};
|
};
|
||||||
use std::{io::prelude::*, path::PathBuf, thread::JoinHandle};
|
use std::time::Duration;
|
||||||
use std::{thread, time::Duration};
|
use std::{io::prelude::*, path::Path};
|
||||||
|
|
||||||
const TIMEOUT: Duration = Duration::from_secs(60);
|
const TIMEOUT: Duration = Duration::from_secs(60);
|
||||||
const CHUNK_SIZE: usize = 1024;
|
const CHUNK_SIZE: usize = 1024;
|
||||||
|
@ -23,27 +23,21 @@ fn client() -> reqwest::blocking::Client {
|
||||||
.expect("Failed to build reqwest::Client")
|
.expect("Failed to build reqwest::Client")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn download_file(url: String, path: PathBuf) -> JoinHandle<Result<(), reqwest::Error>> {
|
pub fn download_file_sync(url: &str, path: &Path) -> Result<(), reqwest::Error> {
|
||||||
thread::spawn(move || {
|
let client = client();
|
||||||
let client = client();
|
let res = client.request(Method::GET, url).send()?;
|
||||||
match client.request(Method::GET, url).send() {
|
let status = res.status();
|
||||||
Ok(res) => {
|
if status.is_client_error() || status.is_server_error() {
|
||||||
let status = res.status();
|
return Err(res.error_for_status().unwrap_err());
|
||||||
if status.is_client_error() || status.is_server_error() {
|
}
|
||||||
return Err(res.error_for_status().unwrap_err());
|
let mut writer = get_writer(path).expect("Unable to write to path");
|
||||||
}
|
for chunk in res
|
||||||
let mut writer = get_writer(&path).expect("Unable to write to path");
|
.bytes()
|
||||||
for chunk in res
|
.expect("Could not get HTTP response bytes")
|
||||||
.bytes()
|
.chunks(CHUNK_SIZE)
|
||||||
.expect("Could not get HTTP response bytes")
|
{
|
||||||
.chunks(CHUNK_SIZE)
|
writer.write_all(chunk).expect("Failed to write chunk");
|
||||||
{
|
}
|
||||||
writer.write_all(chunk).expect("Failed to write chunk");
|
writer.flush().expect("Failed to flush download writer");
|
||||||
}
|
Ok(())
|
||||||
writer.flush().expect("Failed to flush download writer");
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
Err(e) => Err(e),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use std::env;
|
|
||||||
|
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
|
use std::env;
|
||||||
|
|
||||||
fn is_appimage() -> bool {
|
fn is_appimage() -> bool {
|
||||||
env::var("APPIMAGE").is_ok_and(|s| !s.trim().is_empty())
|
env::var("APPIMAGE").is_ok_and(|s| !s.trim().is_empty())
|
||||||
|
|
|
@ -14,7 +14,6 @@ use relm4::{
|
||||||
use steam_linux_runtime_injector::restore_runtime_entrypoint;
|
use steam_linux_runtime_injector::restore_runtime_entrypoint;
|
||||||
use ui::app::{App, AppInit};
|
use ui::app::{App, AppInit};
|
||||||
|
|
||||||
pub mod adb;
|
|
||||||
pub mod build_tools;
|
pub mod build_tools;
|
||||||
pub mod builders;
|
pub mod builders;
|
||||||
pub mod cmd_runner;
|
pub mod cmd_runner;
|
||||||
|
|
|
@ -1,20 +1,27 @@
|
||||||
use super::alert::alert;
|
use super::{
|
||||||
|
alert::alert,
|
||||||
|
job_worker::{
|
||||||
|
internal_worker::JobWorkerOut,
|
||||||
|
job::{FuncWorkerOut, WorkerJob},
|
||||||
|
JobWorker,
|
||||||
|
},
|
||||||
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
adb::get_adb_install_runner,
|
|
||||||
cmd_runner::CmdRunner,
|
|
||||||
dependencies::adb_dep::adb_dep,
|
dependencies::adb_dep::adb_dep,
|
||||||
downloader::download_file,
|
downloader::download_file_sync,
|
||||||
paths::wivrn_apk_download_path,
|
paths::wivrn_apk_download_path,
|
||||||
profile::{Profile, XRServiceType},
|
profile::{Profile, XRServiceType},
|
||||||
runner::{Runner, RunnerStatus},
|
|
||||||
};
|
};
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
|
use gtk4::glib::clone;
|
||||||
use relm4::{
|
use relm4::{
|
||||||
actions::{ActionGroupName, RelmAction, RelmActionGroup},
|
actions::{ActionGroupName, RelmAction, RelmActionGroup},
|
||||||
new_action_group, new_stateless_action,
|
new_action_group, new_stateless_action,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
};
|
};
|
||||||
use std::thread::JoinHandle;
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
|
const DOWNLOAD_ERROR: &str = "download error";
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Debug, Clone)]
|
#[derive(PartialEq, Eq, Debug, Clone)]
|
||||||
pub enum InstallWivrnStatus {
|
pub enum InstallWivrnStatus {
|
||||||
|
@ -28,9 +35,9 @@ pub struct InstallWivrnBox {
|
||||||
selected_profile: Profile,
|
selected_profile: Profile,
|
||||||
install_wivrn_status: InstallWivrnStatus,
|
install_wivrn_status: InstallWivrnStatus,
|
||||||
#[tracker::do_not_track]
|
#[tracker::do_not_track]
|
||||||
download_thread: Option<JoinHandle<Result<(), reqwest::Error>>>,
|
install_runner: Option<JobWorker>,
|
||||||
#[tracker::do_not_track]
|
#[tracker::do_not_track]
|
||||||
install_runner: Option<CmdRunner>,
|
install_runner_log: String,
|
||||||
#[tracker::do_not_track]
|
#[tracker::do_not_track]
|
||||||
root_win: gtk::Window,
|
root_win: gtk::Window,
|
||||||
}
|
}
|
||||||
|
@ -38,10 +45,10 @@ pub struct InstallWivrnBox {
|
||||||
#[allow(clippy::large_enum_variant)]
|
#[allow(clippy::large_enum_variant)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum InstallWivrnBoxMsg {
|
pub enum InstallWivrnBoxMsg {
|
||||||
ClockTicking,
|
|
||||||
UpdateSelectedProfile(Profile),
|
UpdateSelectedProfile(Profile),
|
||||||
DownloadWivrn(String),
|
InstallWivrnApk(String),
|
||||||
InstallWivrnApk,
|
OnInstallRunnerLog(Vec<String>),
|
||||||
|
OnInstallRunnerExit(i32),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -128,70 +135,96 @@ impl SimpleComponent for InstallWivrnBox {
|
||||||
self.reset();
|
self.reset();
|
||||||
|
|
||||||
match message {
|
match message {
|
||||||
Self::Input::ClockTicking => {
|
Self::Input::InstallWivrnApk(link) => {
|
||||||
if self.download_thread.is_some() {
|
|
||||||
let finished = self.download_thread.as_ref().unwrap().is_finished();
|
|
||||||
if finished {
|
|
||||||
let joinh = self.download_thread.take().unwrap();
|
|
||||||
match joinh.join().unwrap() {
|
|
||||||
Ok(_) => {
|
|
||||||
sender.input(Self::Input::InstallWivrnApk);
|
|
||||||
}
|
|
||||||
Err(_) => self.set_install_wivrn_status(InstallWivrnStatus::Done(
|
|
||||||
Some("Error downloading WiVRn APK".into()),
|
|
||||||
)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if self.install_runner.is_some() {
|
|
||||||
let runner = self.install_runner.as_mut().unwrap();
|
|
||||||
let output = runner.consume_output().to_lowercase();
|
|
||||||
let fallback_msg =
|
|
||||||
|code: i32| Some(format!("ADB exited with code \"{}\"", code));
|
|
||||||
match runner.status() {
|
|
||||||
RunnerStatus::Running => {}
|
|
||||||
RunnerStatus::Stopped(status) => {
|
|
||||||
self.install_runner.take();
|
|
||||||
self.set_install_wivrn_status(match status {
|
|
||||||
None | Some(0) => InstallWivrnStatus::Success,
|
|
||||||
Some(255) => {
|
|
||||||
InstallWivrnStatus::Done(Some(concat!(
|
|
||||||
"You need to authorize this computer to run developer ",
|
|
||||||
"commands in your headset. Authorize it and try again.",
|
|
||||||
).into()))
|
|
||||||
}
|
|
||||||
Some(1) => {
|
|
||||||
if output.contains("no devices/emulators found") {
|
|
||||||
InstallWivrnStatus::Done(Some(concat!(
|
|
||||||
"No devices connected. Make sure your headset is connected ",
|
|
||||||
"to this computer and USB debugging is turned on."
|
|
||||||
).into()))
|
|
||||||
} else {
|
|
||||||
InstallWivrnStatus::Done(fallback_msg(1))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some(err_code) => InstallWivrnStatus::Done(fallback_msg(err_code)),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Self::Input::DownloadWivrn(link) => {
|
|
||||||
if !adb_dep().check() {
|
if !adb_dep().check() {
|
||||||
alert("ADB is not installed", Some("Please install ADB on your computer to install WiVRn on your Android headset"), Some(&self.root_win));
|
alert("ADB is not installed", Some("Please install ADB on your computer to install WiVRn on your Android headset"), Some(&self.root_win));
|
||||||
} else {
|
return;
|
||||||
self.set_install_wivrn_status(InstallWivrnStatus::InProgress);
|
|
||||||
self.download_thread = Some(download_file(link, wivrn_apk_download_path()));
|
|
||||||
}
|
}
|
||||||
}
|
self.set_install_wivrn_status(InstallWivrnStatus::InProgress);
|
||||||
Self::Input::InstallWivrnApk => {
|
self.install_runner_log = String::default();
|
||||||
let mut runner = get_adb_install_runner(&wivrn_apk_download_path());
|
let mut jobs = VecDeque::new();
|
||||||
|
let wivrn_apk_path = wivrn_apk_download_path();
|
||||||
|
jobs.push_back(WorkerJob::new_func(Box::new(clone!(
|
||||||
|
#[strong]
|
||||||
|
wivrn_apk_path,
|
||||||
|
move || {
|
||||||
|
if download_file_sync(&link, &wivrn_apk_path).is_err() {
|
||||||
|
FuncWorkerOut {
|
||||||
|
out: vec![DOWNLOAD_ERROR.into()],
|
||||||
|
success: false,
|
||||||
|
}
|
||||||
|
} else if wivrn_apk_path.is_file() {
|
||||||
|
FuncWorkerOut {
|
||||||
|
out: Vec::default(),
|
||||||
|
success: true,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
FuncWorkerOut {
|
||||||
|
out: vec![format!(
|
||||||
|
"Provided apk path {} does not exist",
|
||||||
|
wivrn_apk_path.to_string_lossy()
|
||||||
|
)],
|
||||||
|
success: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
))));
|
||||||
|
jobs.push_back(WorkerJob::new_cmd(
|
||||||
|
None,
|
||||||
|
"adb".into(),
|
||||||
|
Some(vec![
|
||||||
|
"install".into(),
|
||||||
|
wivrn_apk_path.to_string_lossy().to_string(),
|
||||||
|
]),
|
||||||
|
));
|
||||||
|
let runner = JobWorker::new(
|
||||||
|
jobs,
|
||||||
|
sender.input_sender(),
|
||||||
|
Box::new(move |e| match e {
|
||||||
|
JobWorkerOut::Log(log) => Self::Input::OnInstallRunnerLog(log),
|
||||||
|
JobWorkerOut::Exit(code) => Self::Input::OnInstallRunnerExit(code),
|
||||||
|
}),
|
||||||
|
);
|
||||||
runner.start();
|
runner.start();
|
||||||
self.install_runner = Some(runner);
|
self.install_runner = Some(runner);
|
||||||
}
|
}
|
||||||
Self::Input::UpdateSelectedProfile(p) => {
|
Self::Input::UpdateSelectedProfile(p) => {
|
||||||
self.set_selected_profile(p);
|
self.set_selected_profile(p);
|
||||||
}
|
}
|
||||||
|
Self::Input::OnInstallRunnerLog(rows) => {
|
||||||
|
self.install_runner_log.push('\n');
|
||||||
|
self.install_runner_log.push_str(&rows.join("\n"));
|
||||||
|
}
|
||||||
|
Self::Input::OnInstallRunnerExit(code) => {
|
||||||
|
self.set_install_wivrn_status(match code {
|
||||||
|
0 => InstallWivrnStatus::Success,
|
||||||
|
255 => InstallWivrnStatus::Done(Some(
|
||||||
|
concat!(
|
||||||
|
"You need to authorize this computer to run developer ",
|
||||||
|
"commands in your headset. Authorize it and try again.",
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
)),
|
||||||
|
1 if self.install_runner_log.contains(DOWNLOAD_ERROR) => {
|
||||||
|
InstallWivrnStatus::Done(Some("Error downloading WiVRn APK".into()))
|
||||||
|
}
|
||||||
|
1 if self
|
||||||
|
.install_runner_log
|
||||||
|
.contains("no devices/emulators found") =>
|
||||||
|
{
|
||||||
|
InstallWivrnStatus::Done(Some(
|
||||||
|
concat!(
|
||||||
|
"No devices connected. Make sure your headset is connected ",
|
||||||
|
"to this computer and USB debugging is turned on."
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
InstallWivrnStatus::Done(Some(format!("ADB exited with code \"{}\"", code)))
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,8 +236,8 @@ impl SimpleComponent for InstallWivrnBox {
|
||||||
let model = Self {
|
let model = Self {
|
||||||
selected_profile: init.selected_profile,
|
selected_profile: init.selected_profile,
|
||||||
install_wivrn_status: InstallWivrnStatus::Done(None),
|
install_wivrn_status: InstallWivrnStatus::Done(None),
|
||||||
download_thread: None,
|
|
||||||
install_runner: None,
|
install_runner: None,
|
||||||
|
install_runner_log: String::default(),
|
||||||
root_win: init.root_win,
|
root_win: init.root_win,
|
||||||
tracker: 0,
|
tracker: 0,
|
||||||
};
|
};
|
||||||
|
@ -216,7 +249,7 @@ impl SimpleComponent for InstallWivrnBox {
|
||||||
let apk_oculus_action = {
|
let apk_oculus_action = {
|
||||||
let oculus_sender = sender.clone();
|
let oculus_sender = sender.clone();
|
||||||
RelmAction::<WivrnApkStandardAction>::new_stateless(move |_| {
|
RelmAction::<WivrnApkStandardAction>::new_stateless(move |_| {
|
||||||
oculus_sender.input(Self::Input::DownloadWivrn(
|
oculus_sender.input(Self::Input::InstallWivrnApk(
|
||||||
"https://github.com/Meumeu/WiVRn/releases/latest/download/WiVRn-standard-release.apk".into()
|
"https://github.com/Meumeu/WiVRn/releases/latest/download/WiVRn-standard-release.apk".into()
|
||||||
));
|
));
|
||||||
})
|
})
|
||||||
|
@ -225,7 +258,7 @@ impl SimpleComponent for InstallWivrnBox {
|
||||||
let apk_pico_action = {
|
let apk_pico_action = {
|
||||||
let pico_sender = sender.clone();
|
let pico_sender = sender.clone();
|
||||||
RelmAction::<WivrnApkPicoAction>::new_stateless(move |_| {
|
RelmAction::<WivrnApkPicoAction>::new_stateless(move |_| {
|
||||||
pico_sender.input(Self::Input::DownloadWivrn(
|
pico_sender.input(Self::Input::InstallWivrnApk(
|
||||||
"https://github.com/Meumeu/WiVRn/releases/latest/download/WiVRn-pico-release.apk".into()
|
"https://github.com/Meumeu/WiVRn/releases/latest/download/WiVRn-pico-release.apk".into()
|
||||||
));
|
));
|
||||||
})
|
})
|
||||||
|
|
|
@ -436,11 +436,7 @@ impl SimpleComponent for MainView {
|
||||||
self.reset();
|
self.reset();
|
||||||
|
|
||||||
match message {
|
match message {
|
||||||
Self::Input::ClockTicking => {
|
Self::Input::ClockTicking => {}
|
||||||
self.install_wivrn_box
|
|
||||||
.sender()
|
|
||||||
.emit(InstallWivrnBoxMsg::ClockTicking);
|
|
||||||
}
|
|
||||||
Self::Input::StartStopClicked => {
|
Self::Input::StartStopClicked => {
|
||||||
sender
|
sender
|
||||||
.output(Self::Output::DoStartStopXRService)
|
.output(Self::Output::DoStartStopXRService)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue