mirror of
https://gitlab.com/gabmus/envision.git
synced 2025-09-25 02:38:36 +00:00
feat!: installing wivrn apk will use a version matching the server
This commit is contained in:
parent
ee6520ccdd
commit
7daa5987b5
1 changed files with 137 additions and 104 deletions
|
@ -1,22 +1,61 @@
|
|||
use super::{
|
||||
alert::alert,
|
||||
job_worker::{
|
||||
internal_worker::JobWorkerOut,
|
||||
job::{FuncWorkerOut, WorkerJob},
|
||||
JobWorker,
|
||||
},
|
||||
};
|
||||
use super::alert::alert;
|
||||
use crate::{
|
||||
async_process::async_process,
|
||||
dependencies::adb_dep::adb_dep,
|
||||
downloader::download_file_sync,
|
||||
paths::wivrn_apk_download_path,
|
||||
downloader::{cache_file, cache_file_path},
|
||||
profile::{Profile, XRServiceType},
|
||||
};
|
||||
use gtk::{glib::clone, prelude::*};
|
||||
use gtk::prelude::*;
|
||||
use relm4::{new_action_group, new_stateless_action, prelude::*};
|
||||
use std::collections::VecDeque;
|
||||
use std::fs::remove_file;
|
||||
|
||||
const DOWNLOAD_ERROR: &str = "download error";
|
||||
const ADB_ERR_NO_DEV: &str = "no devices/emulators found";
|
||||
|
||||
const WIVRN_LATEST_RELEASE_APK_URL: &str =
|
||||
"https://github.com/WiVRn/WiVRn/releases/latest/download/WiVRn-standard-release.apk";
|
||||
|
||||
#[derive(Debug)]
|
||||
enum GetWivrnApkRefErr {
|
||||
NotWivrn,
|
||||
RepoDirNotFound,
|
||||
RepoManipulationFailed(git2::Error),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
enum WivrnApkRef {
|
||||
Tag(String),
|
||||
Commit(String),
|
||||
}
|
||||
|
||||
fn get_wivrn_apk_ref(p: &Profile) -> Result<WivrnApkRef, GetWivrnApkRefErr> {
|
||||
if p.xrservice_type != XRServiceType::Wivrn {
|
||||
Err(GetWivrnApkRefErr::NotWivrn)
|
||||
} else if !p.xrservice_path.is_dir() {
|
||||
Err(GetWivrnApkRefErr::RepoDirNotFound)
|
||||
} else {
|
||||
let repo = git2::Repository::open(&p.xrservice_path)
|
||||
.map_err(GetWivrnApkRefErr::RepoManipulationFailed)?;
|
||||
if let Ok(tag) = repo
|
||||
.describe(
|
||||
git2::DescribeOptions::new()
|
||||
.describe_tags()
|
||||
.max_candidates_tags(0),
|
||||
)
|
||||
.and_then(|d| d.format(None))
|
||||
{
|
||||
Ok(WivrnApkRef::Tag(tag))
|
||||
} else {
|
||||
Ok(WivrnApkRef::Commit(
|
||||
repo.head()
|
||||
.map_err(GetWivrnApkRefErr::RepoManipulationFailed)?
|
||||
.peel_to_commit()
|
||||
.map_err(GetWivrnApkRefErr::RepoManipulationFailed)?
|
||||
.id()
|
||||
.to_string(),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Debug, Clone)]
|
||||
pub enum InstallWivrnStatus {
|
||||
|
@ -30,10 +69,6 @@ pub struct InstallWivrnBox {
|
|||
selected_profile: Profile,
|
||||
install_wivrn_status: InstallWivrnStatus,
|
||||
#[tracker::do_not_track]
|
||||
install_runner: Option<JobWorker>,
|
||||
#[tracker::do_not_track]
|
||||
install_runner_log: String,
|
||||
#[tracker::do_not_track]
|
||||
root_win: gtk::Window,
|
||||
}
|
||||
|
||||
|
@ -41,9 +76,10 @@ pub struct InstallWivrnBox {
|
|||
#[derive(Debug)]
|
||||
pub enum InstallWivrnBoxMsg {
|
||||
UpdateSelectedProfile(Profile),
|
||||
InstallWivrnApk(String),
|
||||
OnInstallRunnerLog(Vec<String>),
|
||||
OnInstallRunnerExit(i32),
|
||||
/// prepares state for async action, calls DoInstall
|
||||
InstallWivrnApk,
|
||||
/// dowloads, installs, sets state back to what it needs to be
|
||||
DoInstall(String),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -94,9 +130,7 @@ impl AsyncComponent for InstallWivrnBox {
|
|||
#[track = "model.changed(Self::install_wivrn_status())"]
|
||||
set_sensitive: model.install_wivrn_status != InstallWivrnStatus::InProgress,
|
||||
connect_clicked[sender] => move |_| {
|
||||
sender.input(Self::Input::InstallWivrnApk(
|
||||
"https://github.com/WiVRn/WiVRn/releases/latest/download/WiVRn-standard-release.apk".into()
|
||||
))
|
||||
sender.input(Self::Input::InstallWivrnApk)
|
||||
},
|
||||
},
|
||||
gtk::Label {
|
||||
|
@ -131,96 +165,98 @@ impl AsyncComponent for InstallWivrnBox {
|
|||
self.reset();
|
||||
|
||||
match message {
|
||||
Self::Input::InstallWivrnApk(link) => {
|
||||
Self::Input::InstallWivrnApk => {
|
||||
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));
|
||||
return;
|
||||
}
|
||||
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,
|
||||
|
||||
match get_wivrn_apk_ref(&self.selected_profile) {
|
||||
Err(GetWivrnApkRefErr::NotWivrn) => {
|
||||
eprintln!("This is not a WiVRn profile, how did you get here?");
|
||||
}
|
||||
Err(GetWivrnApkRefErr::RepoDirNotFound) => {
|
||||
self.set_install_wivrn_status(InstallWivrnStatus::Done(Some(
|
||||
"Could not open WiVRn repository. Please build the profile before attempting to install the client APK".into()
|
||||
)));
|
||||
}
|
||||
Err(GetWivrnApkRefErr::RepoManipulationFailed(giterr)) => {
|
||||
eprintln!("Error: failed to manipulate WiVRn repo: {giterr}, falling back to latest release APK");
|
||||
let existing = cache_file_path(WIVRN_LATEST_RELEASE_APK_URL, Some("apk"));
|
||||
if existing.is_file() {
|
||||
if let Err(e) = remove_file(&existing) {
|
||||
eprintln!(
|
||||
"Failed to remove file {}: {e}",
|
||||
existing.to_string_lossy()
|
||||
);
|
||||
}
|
||||
}
|
||||
sender.input(Self::Input::DoInstall(WIVRN_LATEST_RELEASE_APK_URL.into()));
|
||||
}
|
||||
))));
|
||||
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);
|
||||
Ok(WivrnApkRef::Tag(tag)) => {
|
||||
sender.input(Self::Input::DoInstall(
|
||||
format!("https://github.com/WiVRn/WiVRn/releases/download/{tag}/WiVRn-standard-release.apk")
|
||||
));
|
||||
}
|
||||
Ok(WivrnApkRef::Commit(commit)) => {
|
||||
sender.input(Self::Input::DoInstall(
|
||||
format!("https://github.com/WiVRn/WiVRn-APK/releases/download/apk-${commit}/org.meumeu.wivrn-standard-release.apk")
|
||||
));
|
||||
}
|
||||
};
|
||||
}
|
||||
Self::Input::DoInstall(url) => {
|
||||
// TODO: we gonna cache or just download async every time?
|
||||
match cache_file(&url, Some("apk")).await {
|
||||
Err(e) => {
|
||||
eprintln!("Failed to download apk: {e}");
|
||||
self.set_install_wivrn_status(InstallWivrnStatus::Done(Some(
|
||||
"Error downloading WiVRn client APK".into(),
|
||||
)));
|
||||
}
|
||||
Ok(apk_path) => {
|
||||
self.set_install_wivrn_status(match async_process(
|
||||
"adb",
|
||||
Some(&["install", apk_path.to_string_lossy().to_string().as_str()]),
|
||||
None,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(out) if out.exit_code == 0 => {
|
||||
InstallWivrnStatus::Success
|
||||
}
|
||||
Ok(out) => {
|
||||
if out.stdout.contains(ADB_ERR_NO_DEV)
|
||||
|| out.stderr.contains(ADB_ERR_NO_DEV)
|
||||
{
|
||||
InstallWivrnStatus::Done(Some(
|
||||
concat!(
|
||||
"No devices connected. Make sure your headset is connected ",
|
||||
"to this computer and USB debugging is turned on."
|
||||
)
|
||||
.into(),
|
||||
))
|
||||
} else {
|
||||
eprintln!("Error: ADB failed with code {}.\nstdout:\n{}\n======\nstderr:\n{}", out.exit_code, out.stdout, out.stderr);
|
||||
InstallWivrnStatus::Done(Some(
|
||||
format!("ADB exited with code \"{}\"", out.exit_code)
|
||||
))
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Error: failed to run ADB: {e}");
|
||||
InstallWivrnStatus::Done(Some(
|
||||
"Failed to run ADB".into()
|
||||
))
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
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)))
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -232,8 +268,6 @@ impl AsyncComponent for InstallWivrnBox {
|
|||
let model = Self {
|
||||
selected_profile: init.selected_profile,
|
||||
install_wivrn_status: InstallWivrnStatus::Done(None),
|
||||
install_runner: None,
|
||||
install_runner_log: String::default(),
|
||||
root_win: init.root_win,
|
||||
tracker: 0,
|
||||
};
|
||||
|
@ -246,4 +280,3 @@ impl AsyncComponent for InstallWivrnBox {
|
|||
|
||||
new_action_group!(pub InstallWivrnActionGroup, "installwivrn");
|
||||
new_stateless_action!(pub WivrnApkStandardAction, InstallWivrnActionGroup, "apkoculus");
|
||||
new_stateless_action!(pub WivrnApkPicoAction, InstallWivrnActionGroup, "apkpico");
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue