From 5e95397450c6dfcbe6552eaf07a6287898be7aa1 Mon Sep 17 00:00:00 2001 From: Craig McLure Date: Sat, 23 Nov 2024 21:57:42 +0000 Subject: [PATCH] Added FIRMWARE_BASE URL, and manifest parse for file fetch --- daemon/src/firmware/firmware_update.rs | 58 +++++++++++++++++++------- daemon/src/main.rs | 3 ++ daemon/src/primary_worker.rs | 8 ++-- ipc/src/lib.rs | 1 + 4 files changed, 51 insertions(+), 19 deletions(-) diff --git a/daemon/src/firmware/firmware_update.rs b/daemon/src/firmware/firmware_update.rs index 3652a53c..cd997396 100644 --- a/daemon/src/firmware/firmware_update.rs +++ b/daemon/src/firmware/firmware_update.rs @@ -1,4 +1,5 @@ use crate::firmware::firmware_file::{check_firmware, FirmwareInfo}; +use crate::FIRMWARE_BASE; use anyhow::{bail, Result}; use futures_util::StreamExt; use goxlr_ipc::UpdateState; @@ -13,10 +14,14 @@ use std::path::PathBuf; use std::time::Duration; use tokio::sync::oneshot; use tokio::time::sleep; +use xmltree::Element; type Sender = tokio::sync::mpsc::Sender; type OneShot = oneshot::Sender; +const FAIL_BACK_FULL_FIRMWARE: &str = "GoXLR_Firmware.bin"; +const FAIL_BACK_MINI_FIRMWARE: &str = "GoXLR_MINI_Firmware.bin"; + pub struct FirmwareUpdateSettings { pub sender: Sender, pub device: FirmwareUpdateDevice, @@ -136,24 +141,45 @@ pub async fn do_firmware_update(settings: FirmwareUpdateSettings) { reboot_goxlr(&device.serial, sender.clone()).await; } -async fn download_firmware(device: &FirmwareUpdateDevice, sender: Sender) -> Result { - set_update_state(&device.serial, sender.clone(), UpdateState::Download).await?; - - let full_name = "GoXLR_Firmware.bin"; - let mini_name = "GoXLR_MINI_Firmware.bin"; +async fn get_firmware_file(device: &FirmwareUpdateDevice, sender: Sender) -> Result { + set_update_state(&device.serial, sender.clone(), UpdateState::Manifest).await?; + + let full_key = "fwFullFileName"; + let mini_key = "fwMiniFileName"; + + // We need to find out if the manifest has a path to the firmware file, otherwise we'll fall + // back to 'Legacy' behaviour. Note that we're not going to track the percentage on this + // download, as the manifest file is generally tiny. + let url = format!("{}{}", FIRMWARE_BASE, "UpdateManifest_v3.xml"); + if let Ok(response) = reqwest::get(url).await { + if let Ok(text) = response.text().await { + // Parse this into an XML tree... + if let Ok(root) = Element::parse(text.as_bytes()) { + return if device.device_type == DeviceType::Mini { + if root.attributes.contains_key(mini_key) { + Ok(root.attributes[mini_key].clone()) + } else { + Ok(String::from(FAIL_BACK_MINI_FIRMWARE)) + } + } else if root.attributes.contains_key(full_key) { + Ok(root.attributes[full_key].clone()) + } else { + Ok(String::from(FAIL_BACK_FULL_FIRMWARE)) + }; + } + } + } + bail!("Error Downloading Manifest from TC-Helicon Servers"); +} - let base_url = "https://mediadl.musictribe.com/media/PLM/sftp/incoming/hybris/import/GOXLR/"; - let url = match device.device_type { - DeviceType::Full => format!("{}{}", base_url, full_name), - DeviceType::Mini => format!("{}{}", base_url, mini_name), - DeviceType::Unknown => bail!("Unknown Device Type"), - }; +async fn download_firmware(device: &FirmwareUpdateDevice, sender: Sender) -> Result { + // First thing we're going to do, is determine which file to download + let file_name = get_firmware_file(device, sender.clone()).await?; - let output_path = std::env::temp_dir().join(match device.device_type { - DeviceType::Full => full_name, - DeviceType::Mini => mini_name, - DeviceType::Unknown => "wont_happen", - }); + // Now we'll grab and process that file + set_update_state(&device.serial, sender.clone(), UpdateState::Download).await?; + let url = format!("{}{}", FIRMWARE_BASE, file_name); + let output_path = std::env::temp_dir().join(file_name); if output_path.exists() && fs::remove_file(&output_path).is_err() { bail!("Error Cleaning old firmware"); diff --git a/daemon/src/main.rs b/daemon/src/main.rs index 02cfaae7..d30aef9f 100644 --- a/daemon/src/main.rs +++ b/daemon/src/main.rs @@ -56,6 +56,9 @@ mod tts; const VERSION: &str = env!("CARGO_PKG_VERSION"); const ICON: &[u8] = include_bytes!("../resources/goxlr-utility-large.png"); +const FIRMWARE_BASE: &str = + "https://mediadl.musictribe.com/media/PLM/sftp/incoming/hybris/import/GOXLR/"; + /** This is ugly, and I know it's ugly. I need to rework how the Primary Worker is constructed so that various variables can be easily passed through it down to the device level via a struct diff --git a/daemon/src/primary_worker.rs b/daemon/src/primary_worker.rs index bcd50a00..b5edd121 100644 --- a/daemon/src/primary_worker.rs +++ b/daemon/src/primary_worker.rs @@ -6,7 +6,9 @@ use crate::firmware::firmware_update::{ FirmwareUpdateSettings, }; use crate::platform::{get_ui_app_path, has_autostart, set_autostart}; -use crate::{FileManager, PatchEvent, SettingsHandle, Shutdown, SYSTEM_LOCALE, VERSION}; +use crate::{ + FileManager, PatchEvent, SettingsHandle, Shutdown, FIRMWARE_BASE, SYSTEM_LOCALE, VERSION, +}; use anyhow::{anyhow, Result}; use enum_map::EnumMap; use goxlr_ipc::{ @@ -842,10 +844,10 @@ async fn check_firmware_versions(x: Sender> = EnumMap::default(); debug!("Performing Firmware Version Check.."); - let url = "https://mediadl.musictribe.com/media/PLM/sftp/incoming/hybris/import/GOXLR/UpdateManifest_v3.xml"; + let url = format!("{}{}", FIRMWARE_BASE, "UpdateManifest_v3.xml"); if let Ok(response) = reqwest::get(url).await { if let Ok(text) = response.text().await { - // Parse this into an XML tree.. + // Parse this into an XML tree... if let Ok(root) = Element::parse(text.as_bytes()) { if root.attributes.contains_key(mini_key) { map[DeviceType::Mini] = diff --git a/ipc/src/lib.rs b/ipc/src/lib.rs index 7fb6b79a..4698a63f 100644 --- a/ipc/src/lib.rs +++ b/ipc/src/lib.rs @@ -72,6 +72,7 @@ pub enum UpdateState { Failed, Starting, + Manifest, Download, ClearNVR, UploadFirmware,