Skip to content

Commit

Permalink
🔨 chore: marginally improve error handling
Browse files Browse the repository at this point in the history
Signed-off-by: Pauline <[email protected]>
  • Loading branch information
pauliesnug committed Jan 8, 2025
1 parent 2ca1966 commit 10f17f9
Show file tree
Hide file tree
Showing 7 changed files with 90 additions and 105 deletions.
35 changes: 35 additions & 0 deletions crates/libmoonlight/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#[derive(thiserror::Error, serde::Serialize, serde::Deserialize, Debug)]
pub enum MoonlightError {
#[error("failed to get windows file lock: {0}")]
WindowsFileLock(String),
#[error("failed to get macos file permission: {0}")]
MacOSNoPermission(String),
#[error("network request failed: {0}")]
NetworkFailed(String),
#[error("unknown error: {0}")]
Unknown(String),
}

pub type Result<T> = std::result::Result<T, MoonlightError>;

impl From<std::io::Error> for MoonlightError {
fn from(value: std::io::Error) -> Self {
match (value.raw_os_error(), std::env::consts::OS) {
(Some(32), "windows") => Self::WindowsFileLock(value.to_string()),
(Some(1), "macos") => Self::MacOSNoPermission(value.to_string()),
_ => Self::Unknown(value.to_string()),
}
}
}

impl From<Box<dyn std::error::Error>> for MoonlightError {
fn from(value: Box<dyn std::error::Error>) -> Self {
Self::Unknown(value.to_string())
}
}

impl From<reqwest::Error> for MoonlightError {
fn from(value: reqwest::Error) -> Self {
Self::NetworkFailed(value.to_string())
}
}
30 changes: 14 additions & 16 deletions crates/libmoonlight/src/installer.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
use super::types::{
Branch, DetectedInstall, GitHubRelease, InstallInfo, InstallerResult, MoonlightBranch,
};
use super::types::{Branch, DetectedInstall, GitHubRelease, InstallInfo, MoonlightBranch};
use super::util::get_download_dir;
use crate::{get_app_dir, get_moonlight_dir, PATCHED_ASAR};
use std::path::PathBuf;
Expand Down Expand Up @@ -28,7 +26,7 @@ impl Installer {
Self {}
}

pub fn download_moonlight(&self, branch: MoonlightBranch) -> InstallerResult<String> {
pub fn download_moonlight(&self, branch: MoonlightBranch) -> crate::Result<String> {
let dir = get_download_dir();

if dir.exists() {
Expand All @@ -43,7 +41,7 @@ impl Installer {
})
}

fn download_stable(&self, dir: PathBuf) -> InstallerResult<String> {
fn download_stable(&self, dir: PathBuf) -> crate::Result<String> {
let release = self.get_stable_release()?;
let asset = release
.assets
Expand All @@ -61,34 +59,34 @@ impl Installer {
Ok(release.name)
}

fn download_nightly(&self, dir: PathBuf) -> InstallerResult<String> {
fn download_nightly(&self, dir: PathBuf) -> crate::Result<String> {
let version = self.get_nightly_version()?;
let resp = reqwest::blocking::get(NIGHTLY_DIST_URL)?;
let mut archive = tar::Archive::new(flate2::read::GzDecoder::new(resp));
archive.unpack(dir)?;
Ok(version)
}

pub fn get_latest_moonlight_version(&self, branch: MoonlightBranch) -> InstallerResult<String> {
pub fn get_latest_moonlight_version(&self, branch: MoonlightBranch) -> crate::Result<String> {
match branch {
MoonlightBranch::Stable => self.get_stable_release().map(|x| x.name),
MoonlightBranch::Nightly => self.get_nightly_version(),
}
}

pub fn get_downloaded_version(&self) -> InstallerResult<Option<String>> {
pub fn get_downloaded_version(&self) -> crate::Result<Option<String>> {
let dir = get_moonlight_dir();
let version = std::fs::read_to_string(dir.join(INSTALLED_VERSION_FILE)).ok();
Ok(version)
}

pub fn set_downloaded_version(&self, version: &str) -> InstallerResult<()> {
pub fn set_downloaded_version(&self, version: &str) -> crate::Result<()> {
let dir = get_moonlight_dir();
std::fs::write(dir.join(INSTALLED_VERSION_FILE), version)?;
Ok(())
}

fn get_stable_release(&self) -> InstallerResult<GitHubRelease> {
fn get_stable_release(&self) -> crate::Result<GitHubRelease> {
let url = format!("https://api.github.com/repos/{GITHUB_REPO}/releases/latest");
let resp = reqwest::blocking::Client::new()
.get(url)
Expand All @@ -98,7 +96,7 @@ impl Installer {
Ok(resp)
}

fn get_nightly_version(&self) -> InstallerResult<String> {
fn get_nightly_version(&self) -> crate::Result<String> {
let resp = reqwest::blocking::get(NIGHTLY_REF_URL)?.text()?;
Ok(resp
.lines()
Expand All @@ -107,7 +105,7 @@ impl Installer {
.unwrap_or_default())
}

pub fn get_installs(&self) -> InstallerResult<Vec<InstallInfo>> {
pub fn get_installs(&self) -> crate::Result<Vec<InstallInfo>> {
self.detect_installs().map(|installs| {
installs
.into_iter()
Expand All @@ -125,7 +123,7 @@ impl Installer {
})
}

fn detect_installs(&self) -> InstallerResult<Vec<DetectedInstall>> {
fn detect_installs(&self) -> crate::Result<Vec<DetectedInstall>> {
match std::env::consts::OS {
"windows" => {
let appdata = std::env::var("LocalAppData").unwrap();
Expand Down Expand Up @@ -251,15 +249,15 @@ impl Installer {

// This will probably match other client mods that replace app.asar, but it
// will just prompt them to unpatch, so I think it's fine
fn is_install_patched(&self, install: &DetectedInstall) -> InstallerResult<bool> {
fn is_install_patched(&self, install: &DetectedInstall) -> crate::Result<bool> {
Ok(!get_app_dir(&install.path)?.join("app.asar").exists())
}

pub fn patch_install(
&self,
install: &DetectedInstall,
moonlight_dir: Option<PathBuf>,
) -> InstallerResult<()> {
) -> crate::Result<()> {
// TODO: flatpak and stuff
let app_dir = get_app_dir(&install.path)?;
let asar = app_dir.join("app.asar");
Expand All @@ -286,7 +284,7 @@ impl Installer {
Ok(())
}

pub fn unpatch_install(&self, install: &DetectedInstall) -> InstallerResult<()> {
pub fn unpatch_install(&self, install: &DetectedInstall) -> crate::Result<()> {
let app_dir = get_app_dir(&install.path)?;
let asar = app_dir.join(PATCHED_ASAR);
std::fs::rename(&asar, asar.with_file_name("app.asar"))?;
Expand Down
2 changes: 2 additions & 0 deletions crates/libmoonlight/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
mod error;
mod installer;
mod util;
pub use error::*;
pub use installer::Installer;
pub use util::*;
pub mod types;
57 changes: 1 addition & 56 deletions crates/libmoonlight/src/types.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
use crate::get_moonlight_dir;
use serde::{Deserialize, Serialize};
use std::fmt::Display;
use std::path::PathBuf;
use thiserror::Error;

use crate::get_moonlight_dir;

#[derive(Serialize, Deserialize, clap::ValueEnum, Debug, Clone, Copy, PartialEq, Eq)]
pub enum MoonlightBranch {
Expand Down Expand Up @@ -122,56 +120,3 @@ pub struct GitHubRelease {
pub name: String,
pub assets: Vec<GitHubReleaseAsset>,
}

#[derive(Serialize, Deserialize, Debug)]
pub enum ErrorCode {
Unknown,
WindowsFileLock,
MacOSNoPermission,
NetworkFailed,
}

pub type InstallerResult<T> = Result<T, InstallerError>;

#[derive(Serialize, Deserialize, Debug, Error)]
pub struct InstallerError {
pub message: String,
pub code: ErrorCode,
}

impl Display for InstallerError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} ({:?})", self.message, self.code)
}
}

impl From<std::io::Error> for InstallerError {
fn from(value: std::io::Error) -> Self {
Self {
message: value.to_string(),
code: match (value.raw_os_error(), std::env::consts::OS) {
(Some(32), "windows") => ErrorCode::WindowsFileLock,
(Some(1), "macos") => ErrorCode::MacOSNoPermission,
_ => ErrorCode::Unknown,
},
}
}
}

impl From<Box<dyn std::error::Error>> for InstallerError {
fn from(value: Box<dyn std::error::Error>) -> Self {
Self {
message: value.to_string(),
code: ErrorCode::Unknown,
}
}
}

impl From<reqwest::Error> for InstallerError {
fn from(value: reqwest::Error) -> Self {
Self {
message: value.to_string(),
code: ErrorCode::NetworkFailed,
}
}
}
40 changes: 22 additions & 18 deletions crates/libmoonlight/src/util.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,30 @@
use crate::types::{Branch, DetectedInstall, InstallInfo, InstallerResult};
use crate::types::{Branch, DetectedInstall, InstallInfo};
use std::path::{Path, PathBuf};

const DOWNLOAD_DIR: &str = "dist";
pub const PATCHED_ASAR: &str = "_app.asar";

pub fn get_moonlight_dir() -> PathBuf {
let dir = std::env::var_os("MOONLIGHT_DIR").map(PathBuf::from)
.or_else(|| Some(match std::env::consts::OS {
"windows" => {
let appdata = std::env::var("APPDATA").unwrap();
PathBuf::from(appdata).join("moonlight-mod")
}
"macos" => {
let home = std::env::var("HOME").unwrap();
PathBuf::from(home).join("Library/Application Support/moonlight-mod")
}
"linux" => {
let home = std::env::var("HOME").unwrap();
PathBuf::from(home).join(".config/moonlight-mod")
}
_ => unimplemented!("Unsupported OS"),
})).unwrap();
let dir = std::env::var_os("MOONLIGHT_DIR")
.map(PathBuf::from)
.or_else(|| {
Some(match std::env::consts::OS {
"windows" => {
let appdata = std::env::var("APPDATA").unwrap();
PathBuf::from(appdata).join("moonlight-mod")
}
"macos" => {
let home = std::env::var("HOME").unwrap();
PathBuf::from(home).join("Library/Application Support/moonlight-mod")
}
"linux" => {
let home = std::env::var("HOME").unwrap();
PathBuf::from(home).join(".config/moonlight-mod")
}
_ => unimplemented!("Unsupported OS"),
})
})
.unwrap();

if !dir.exists() {
let _ = std::fs::create_dir_all(&dir);
Expand Down Expand Up @@ -61,7 +65,7 @@ pub fn detect_install(exe: &Path) -> Option<InstallInfo> {
})
}

pub fn get_app_dir(path: &Path) -> InstallerResult<PathBuf> {
pub fn get_app_dir(path: &Path) -> crate::Result<PathBuf> {
match std::env::consts::OS {
"windows" | "linux" => Ok(path.join("resources")),
"macos" => Ok(path.to_path_buf()),
Expand Down
21 changes: 11 additions & 10 deletions crates/moonlight-installer/src/app.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::config::Config;
use crate::logic::{app_logic_thread, LogicCommand, LogicResponse};
use libmoonlight::types::{Branch, ErrorCode, InstallInfo, InstallerError, MoonlightBranch};
use libmoonlight::types::{Branch, InstallInfo, MoonlightBranch};
use libmoonlight::MoonlightError;
use std::time::Duration;

#[derive(Debug, Default)]
Expand All @@ -10,10 +11,10 @@ pub struct AppState {
installs: Option<Vec<InstallInfo>>,

downloading: bool,
downloading_error: Option<InstallerError>,
downloading_error: Option<MoonlightError>,

patching: bool,
patching_error: Option<InstallerError>,
patching_error: Option<MoonlightError>,
patching_branch: Option<Branch>,
}

Expand Down Expand Up @@ -149,11 +150,11 @@ impl App {
tx.send(cmd).unwrap();
}

fn draw_error(&self, ui: &mut egui::Ui, err: &InstallerError) {
fn draw_error(&self, ui: &mut egui::Ui, err: &MoonlightError) {
ui.heading(egui::RichText::new("Error").color(egui::Color32::RED));

match err.code {
ErrorCode::WindowsFileLock => {
match err {
MoonlightError::WindowsFileLock(_) => {
ui.label(WINDOWS_FILE_LOCK);

if ui.button("Force close Discord").clicked() {
Expand All @@ -163,17 +164,17 @@ impl App {
}
}

ErrorCode::MacOSNoPermission => {
MoonlightError::MacOSNoPermission(_) => {
ui.label(MACOS_NO_PERMISSION);
}

ErrorCode::NetworkFailed => {
MoonlightError::NetworkFailed(_) => {
ui.label(NETWORK_FAILED);
}

ErrorCode::Unknown => {
MoonlightError::Unknown(msg) => {
ui.label("An unknown error occurred. Please report this.");
ui.label(err.message.clone());
ui.label(msg);
}
}

Expand Down
10 changes: 5 additions & 5 deletions crates/moonlight-installer/src/logic.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use libmoonlight::types::{Branch, DetectedInstall, InstallInfo, InstallerResult, MoonlightBranch};
use libmoonlight::types::{Branch, DetectedInstall, InstallInfo, MoonlightBranch};
use libmoonlight::Installer;
use std::path::PathBuf;

Expand All @@ -16,10 +16,10 @@ pub enum LogicCommand {
pub enum LogicResponse {
Installs(Vec<InstallInfo>),
DownloadedVersion(Option<String>),
LatestVersion(InstallerResult<String>),
UpdateComplete(InstallerResult<String>),
PatchComplete(InstallerResult<PathBuf>),
UnpatchComplete(InstallerResult<PathBuf>),
LatestVersion(libmoonlight::Result<String>),
UpdateComplete(libmoonlight::Result<String>),
PatchComplete(libmoonlight::Result<PathBuf>),
UnpatchComplete(libmoonlight::Result<PathBuf>),
}

pub fn app_logic_thread(
Expand Down

0 comments on commit 10f17f9

Please sign in to comment.