mirror of
https://gitlab.com/gabmus/envision.git
synced 2025-04-20 11:35:48 +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},
|
||||
Method,
|
||||
};
|
||||
use std::{io::prelude::*, path::PathBuf, thread::JoinHandle};
|
||||
use std::{thread, time::Duration};
|
||||
use std::time::Duration;
|
||||
use std::{io::prelude::*, path::Path};
|
||||
|
||||
const TIMEOUT: Duration = Duration::from_secs(60);
|
||||
const CHUNK_SIZE: usize = 1024;
|
||||
|
@ -23,27 +23,21 @@ fn client() -> reqwest::blocking::Client {
|
|||
.expect("Failed to build reqwest::Client")
|
||||
}
|
||||
|
||||
pub fn download_file(url: String, path: PathBuf) -> JoinHandle<Result<(), reqwest::Error>> {
|
||||
thread::spawn(move || {
|
||||
let client = client();
|
||||
match client.request(Method::GET, url).send() {
|
||||
Ok(res) => {
|
||||
let status = res.status();
|
||||
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
|
||||
.bytes()
|
||||
.expect("Could not get HTTP response bytes")
|
||||
.chunks(CHUNK_SIZE)
|
||||
{
|
||||
writer.write_all(chunk).expect("Failed to write chunk");
|
||||
}
|
||||
writer.flush().expect("Failed to flush download writer");
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
})
|
||||
pub fn download_file_sync(url: &str, path: &Path) -> Result<(), reqwest::Error> {
|
||||
let client = client();
|
||||
let res = client.request(Method::GET, url).send()?;
|
||||
let status = res.status();
|
||||
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
|
||||
.bytes()
|
||||
.expect("Could not get HTTP response bytes")
|
||||
.chunks(CHUNK_SIZE)
|
||||
{
|
||||
writer.write_all(chunk).expect("Failed to write chunk");
|
||||
}
|
||||
writer.flush().expect("Failed to flush download writer");
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use std::env;
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
use std::env;
|
||||
|
||||
fn is_appimage() -> bool {
|
||||
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 ui::app::{App, AppInit};
|
||||
|
||||
pub mod adb;
|
||||
pub mod build_tools;
|
||||
pub mod builders;
|
||||
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::{
|
||||
adb::get_adb_install_runner,
|
||||
cmd_runner::CmdRunner,
|
||||
dependencies::adb_dep::adb_dep,
|
||||
downloader::download_file,
|
||||
downloader::download_file_sync,
|
||||
paths::wivrn_apk_download_path,
|
||||
profile::{Profile, XRServiceType},
|
||||
runner::{Runner, RunnerStatus},
|
||||
};
|
||||
use gtk::prelude::*;
|
||||
use gtk4::glib::clone;
|
||||
use relm4::{
|
||||
actions::{ActionGroupName, RelmAction, RelmActionGroup},
|
||||
new_action_group, new_stateless_action,
|
||||
prelude::*,
|
||||
};
|
||||
use std::thread::JoinHandle;
|
||||
use std::collections::VecDeque;
|
||||
|
||||
const DOWNLOAD_ERROR: &str = "download error";
|
||||
|
||||
#[derive(PartialEq, Eq, Debug, Clone)]
|
||||
pub enum InstallWivrnStatus {
|
||||
|
@ -28,9 +35,9 @@ pub struct InstallWivrnBox {
|
|||
selected_profile: Profile,
|
||||
install_wivrn_status: InstallWivrnStatus,
|
||||
#[tracker::do_not_track]
|
||||
download_thread: Option<JoinHandle<Result<(), reqwest::Error>>>,
|
||||
install_runner: Option<JobWorker>,
|
||||
#[tracker::do_not_track]
|
||||
install_runner: Option<CmdRunner>,
|
||||
install_runner_log: String,
|
||||
#[tracker::do_not_track]
|
||||
root_win: gtk::Window,
|
||||
}
|
||||
|
@ -38,10 +45,10 @@ pub struct InstallWivrnBox {
|
|||
#[allow(clippy::large_enum_variant)]
|
||||
#[derive(Debug)]
|
||||
pub enum InstallWivrnBoxMsg {
|
||||
ClockTicking,
|
||||
UpdateSelectedProfile(Profile),
|
||||
DownloadWivrn(String),
|
||||
InstallWivrnApk,
|
||||
InstallWivrnApk(String),
|
||||
OnInstallRunnerLog(Vec<String>),
|
||||
OnInstallRunnerExit(i32),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -128,70 +135,96 @@ impl SimpleComponent for InstallWivrnBox {
|
|||
self.reset();
|
||||
|
||||
match message {
|
||||
Self::Input::ClockTicking => {
|
||||
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) => {
|
||||
Self::Input::InstallWivrnApk(link) => {
|
||||
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));
|
||||
} else {
|
||||
self.set_install_wivrn_status(InstallWivrnStatus::InProgress);
|
||||
self.download_thread = Some(download_file(link, wivrn_apk_download_path()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
Self::Input::InstallWivrnApk => {
|
||||
let mut runner = get_adb_install_runner(&wivrn_apk_download_path());
|
||||
self.set_install_wivrn_status(InstallWivrnStatus::InProgress);
|
||||
self.install_runner_log = String::default();
|
||||
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();
|
||||
self.install_runner = Some(runner);
|
||||
}
|
||||
Self::Input::UpdateSelectedProfile(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 {
|
||||
selected_profile: init.selected_profile,
|
||||
install_wivrn_status: InstallWivrnStatus::Done(None),
|
||||
download_thread: None,
|
||||
install_runner: None,
|
||||
install_runner_log: String::default(),
|
||||
root_win: init.root_win,
|
||||
tracker: 0,
|
||||
};
|
||||
|
@ -216,7 +249,7 @@ impl SimpleComponent for InstallWivrnBox {
|
|||
let apk_oculus_action = {
|
||||
let oculus_sender = sender.clone();
|
||||
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()
|
||||
));
|
||||
})
|
||||
|
@ -225,7 +258,7 @@ impl SimpleComponent for InstallWivrnBox {
|
|||
let apk_pico_action = {
|
||||
let pico_sender = sender.clone();
|
||||
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()
|
||||
));
|
||||
})
|
||||
|
|
|
@ -436,11 +436,7 @@ impl SimpleComponent for MainView {
|
|||
self.reset();
|
||||
|
||||
match message {
|
||||
Self::Input::ClockTicking => {
|
||||
self.install_wivrn_box
|
||||
.sender()
|
||||
.emit(InstallWivrnBoxMsg::ClockTicking);
|
||||
}
|
||||
Self::Input::ClockTicking => {}
|
||||
Self::Input::StartStopClicked => {
|
||||
sender
|
||||
.output(Self::Output::DoStartStopXRService)
|
||||
|
|
Loading…
Add table
Reference in a new issue