mirror of
https://gitlab.com/gabmus/envision.git
synced 2025-09-25 10:48: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::{
|
use super::alert::alert;
|
||||||
alert::alert,
|
|
||||||
job_worker::{
|
|
||||||
internal_worker::JobWorkerOut,
|
|
||||||
job::{FuncWorkerOut, WorkerJob},
|
|
||||||
JobWorker,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
async_process::async_process,
|
||||||
dependencies::adb_dep::adb_dep,
|
dependencies::adb_dep::adb_dep,
|
||||||
downloader::download_file_sync,
|
downloader::{cache_file, cache_file_path},
|
||||||
paths::wivrn_apk_download_path,
|
|
||||||
profile::{Profile, XRServiceType},
|
profile::{Profile, XRServiceType},
|
||||||
};
|
};
|
||||||
use gtk::{glib::clone, prelude::*};
|
use gtk::prelude::*;
|
||||||
use relm4::{new_action_group, new_stateless_action, 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)]
|
#[derive(PartialEq, Eq, Debug, Clone)]
|
||||||
pub enum InstallWivrnStatus {
|
pub enum InstallWivrnStatus {
|
||||||
|
@ -30,10 +69,6 @@ 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]
|
||||||
install_runner: Option<JobWorker>,
|
|
||||||
#[tracker::do_not_track]
|
|
||||||
install_runner_log: String,
|
|
||||||
#[tracker::do_not_track]
|
|
||||||
root_win: gtk::Window,
|
root_win: gtk::Window,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,9 +76,10 @@ pub struct InstallWivrnBox {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum InstallWivrnBoxMsg {
|
pub enum InstallWivrnBoxMsg {
|
||||||
UpdateSelectedProfile(Profile),
|
UpdateSelectedProfile(Profile),
|
||||||
InstallWivrnApk(String),
|
/// prepares state for async action, calls DoInstall
|
||||||
OnInstallRunnerLog(Vec<String>),
|
InstallWivrnApk,
|
||||||
OnInstallRunnerExit(i32),
|
/// dowloads, installs, sets state back to what it needs to be
|
||||||
|
DoInstall(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -94,9 +130,7 @@ impl AsyncComponent for InstallWivrnBox {
|
||||||
#[track = "model.changed(Self::install_wivrn_status())"]
|
#[track = "model.changed(Self::install_wivrn_status())"]
|
||||||
set_sensitive: model.install_wivrn_status != InstallWivrnStatus::InProgress,
|
set_sensitive: model.install_wivrn_status != InstallWivrnStatus::InProgress,
|
||||||
connect_clicked[sender] => move |_| {
|
connect_clicked[sender] => move |_| {
|
||||||
sender.input(Self::Input::InstallWivrnApk(
|
sender.input(Self::Input::InstallWivrnApk)
|
||||||
"https://github.com/WiVRn/WiVRn/releases/latest/download/WiVRn-standard-release.apk".into()
|
|
||||||
))
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
gtk::Label {
|
gtk::Label {
|
||||||
|
@ -131,96 +165,98 @@ impl AsyncComponent for InstallWivrnBox {
|
||||||
self.reset();
|
self.reset();
|
||||||
|
|
||||||
match message {
|
match message {
|
||||||
Self::Input::InstallWivrnApk(link) => {
|
Self::Input::InstallWivrnApk => {
|
||||||
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));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.set_install_wivrn_status(InstallWivrnStatus::InProgress);
|
self.set_install_wivrn_status(InstallWivrnStatus::InProgress);
|
||||||
self.install_runner_log = String::default();
|
|
||||||
let mut jobs = VecDeque::new();
|
match get_wivrn_apk_ref(&self.selected_profile) {
|
||||||
let wivrn_apk_path = wivrn_apk_download_path();
|
Err(GetWivrnApkRefErr::NotWivrn) => {
|
||||||
jobs.push_back(WorkerJob::new_func(Box::new(clone!(
|
eprintln!("This is not a WiVRn profile, how did you get here?");
|
||||||
#[strong]
|
}
|
||||||
wivrn_apk_path,
|
Err(GetWivrnApkRefErr::RepoDirNotFound) => {
|
||||||
move || {
|
self.set_install_wivrn_status(InstallWivrnStatus::Done(Some(
|
||||||
if download_file_sync(&link, &wivrn_apk_path).is_err() {
|
"Could not open WiVRn repository. Please build the profile before attempting to install the client APK".into()
|
||||||
FuncWorkerOut {
|
)));
|
||||||
out: vec![DOWNLOAD_ERROR.into()],
|
}
|
||||||
success: false,
|
Err(GetWivrnApkRefErr::RepoManipulationFailed(giterr)) => {
|
||||||
}
|
eprintln!("Error: failed to manipulate WiVRn repo: {giterr}, falling back to latest release APK");
|
||||||
} else if wivrn_apk_path.is_file() {
|
let existing = cache_file_path(WIVRN_LATEST_RELEASE_APK_URL, Some("apk"));
|
||||||
FuncWorkerOut {
|
if existing.is_file() {
|
||||||
out: Vec::default(),
|
if let Err(e) = remove_file(&existing) {
|
||||||
success: true,
|
eprintln!(
|
||||||
}
|
"Failed to remove file {}: {e}",
|
||||||
} else {
|
existing.to_string_lossy()
|
||||||
FuncWorkerOut {
|
);
|
||||||
out: vec![format!(
|
|
||||||
"Provided apk path {} does not exist",
|
|
||||||
wivrn_apk_path.to_string_lossy()
|
|
||||||
)],
|
|
||||||
success: false,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
sender.input(Self::Input::DoInstall(WIVRN_LATEST_RELEASE_APK_URL.into()));
|
||||||
}
|
}
|
||||||
))));
|
Ok(WivrnApkRef::Tag(tag)) => {
|
||||||
jobs.push_back(WorkerJob::new_cmd(
|
sender.input(Self::Input::DoInstall(
|
||||||
None,
|
format!("https://github.com/WiVRn/WiVRn/releases/download/{tag}/WiVRn-standard-release.apk")
|
||||||
"adb".into(),
|
));
|
||||||
Some(vec![
|
}
|
||||||
"install".into(),
|
Ok(WivrnApkRef::Commit(commit)) => {
|
||||||
wivrn_apk_path.to_string_lossy().to_string(),
|
sender.input(Self::Input::DoInstall(
|
||||||
]),
|
format!("https://github.com/WiVRn/WiVRn-APK/releases/download/apk-${commit}/org.meumeu.wivrn-standard-release.apk")
|
||||||
));
|
));
|
||||||
let runner = JobWorker::new(
|
}
|
||||||
jobs,
|
};
|
||||||
sender.input_sender(),
|
}
|
||||||
Box::new(move |e| match e {
|
Self::Input::DoInstall(url) => {
|
||||||
JobWorkerOut::Log(log) => Self::Input::OnInstallRunnerLog(log),
|
// TODO: we gonna cache or just download async every time?
|
||||||
JobWorkerOut::Exit(code) => Self::Input::OnInstallRunnerExit(code),
|
match cache_file(&url, Some("apk")).await {
|
||||||
}),
|
Err(e) => {
|
||||||
);
|
eprintln!("Failed to download apk: {e}");
|
||||||
runner.start();
|
self.set_install_wivrn_status(InstallWivrnStatus::Done(Some(
|
||||||
self.install_runner = Some(runner);
|
"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::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)))
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,8 +268,6 @@ impl AsyncComponent 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),
|
||||||
install_runner: None,
|
|
||||||
install_runner_log: String::default(),
|
|
||||||
root_win: init.root_win,
|
root_win: init.root_win,
|
||||||
tracker: 0,
|
tracker: 0,
|
||||||
};
|
};
|
||||||
|
@ -246,4 +280,3 @@ impl AsyncComponent for InstallWivrnBox {
|
||||||
|
|
||||||
new_action_group!(pub InstallWivrnActionGroup, "installwivrn");
|
new_action_group!(pub InstallWivrnActionGroup, "installwivrn");
|
||||||
new_stateless_action!(pub WivrnApkStandardAction, InstallWivrnActionGroup, "apkoculus");
|
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