diff --git a/config.toml b/config.toml index 5f49e8d..d633812 100644 --- a/config.toml +++ b/config.toml @@ -1,31 +1,2 @@ -[general] name = "yuzu" -installing_message = "Reminder: yuzu is an experimental emulator. Stuff will break!" - -[[packages]] -name = "yuzu Nightly" -description = "The nightly build of yuzu contains already reviewed and tested features." - [packages.source] - name = "github" - match = "^yuzu-#PLATFORM#(-mingw)?-[0-9]*-[0-9a-f]*.zip$" - [packages.source.config] - repo = "yuzu-emu/yuzu-nightly" - -[[packages]] -name = "yuzu Canary" -description = "The canary build of yuzu has additional features that are still waiting on review." - [packages.source] - name = "github" - match = "^yuzu-#PLATFORM#(-mingw)?-[0-9]*-[0-9a-f]*.zip$" - [packages.source.config] - repo = "yuzu-emu/yuzu-canary" - -[[packages]] -name = "Test package" -description = "Just a testing package" -default = true - [packages.source] - name = "github" - match = "^TestPackage.zip$" - [packages.source.config] - repo = "j-selby/test-installer" +target_url = "https://raw.githubusercontent.com/j-selby/test-installer/master/config.v1.toml" diff --git a/src/config.rs b/src/config.rs index 8f1a17c..b5eda7d 100644 --- a/src/config.rs +++ b/src/config.rs @@ -30,14 +30,26 @@ pub struct PackageDescription { /// Describes the application itself. #[derive(Debug, Deserialize, Serialize, Clone)] -pub struct GeneralConfig { +pub struct BaseAttributes { pub name: String, - pub installing_message: String, + pub target_url: String, +} + +impl BaseAttributes { + /// Serialises as a JSON string. + pub fn to_json_str(&self) -> Result { + serde_json::to_string(self) + } + + /// Builds a configuration from a specified TOML string. + pub fn from_toml_str(contents: &str) -> Result { + toml::from_str(contents) + } } #[derive(Debug, Deserialize, Serialize, Clone)] pub struct Config { - pub general: GeneralConfig, + pub installing_message: String, pub packages: Vec, } diff --git a/src/http.rs b/src/http.rs index 7ffc4a2..7fc831f 100644 --- a/src/http.rs +++ b/src/http.rs @@ -8,6 +8,19 @@ use reqwest; use std::io::Read; +/// Downloads a text file from the specified URL. +pub fn download_text(url: &str) -> Result { + // TODO: Decrease check time + let mut client = match reqwest::get(url) { + Ok(v) => v, + Err(v) => return Err(format!("Failed to GET resource: {:?}", v)), + }; + + client + .text() + .map_err(|v| format!("Failed to get text from resource: {:?}", v)) +} + /// Streams a file from a HTTP server. pub fn stream_file(url: &str, mut callback: F) -> Result<(), String> where diff --git a/src/installer.rs b/src/installer.rs index 219f5f0..4f35a47 100644 --- a/src/installer.rs +++ b/src/installer.rs @@ -13,6 +13,7 @@ use std::path::PathBuf; use std::sync::mpsc::Sender; +use config::BaseAttributes; use config::Config; use sources::types::Version; @@ -36,7 +37,8 @@ pub enum InstallMessage { /// The installer framework contains metadata about packages, what is installable, what isn't, /// etc. pub struct InstallerFramework { - pub config: Config, + pub base_attributes: BaseAttributes, + pub config: Option, pub database: Vec, pub install_path: Option, pub preexisting_install: bool, @@ -64,13 +66,13 @@ pub struct LocalInstallation { impl InstallerFramework { /// Returns a copy of the configuration. - pub fn get_config(&self) -> Config { + pub fn get_config(&self) -> Option { self.config.clone() } /// Returns the default install path. pub fn get_default_path(&self) -> Option { - let app_name = &self.config.general.name; + let app_name = &self.base_attributes.name; let base_dir = match var("LOCALAPPDATA") { Ok(path) => PathBuf::from(path), @@ -194,9 +196,10 @@ impl InstallerFramework { } /// Creates a new instance of the Installer Framework with a specified Config. - pub fn new(config: Config) -> Self { + pub fn new(attrs: BaseAttributes) -> Self { InstallerFramework { - config, + base_attributes: attrs, + config: None, database: Vec::new(), install_path: None, preexisting_install: false, @@ -207,7 +210,7 @@ impl InstallerFramework { /// Creates a new instance of the Installer Framework with a specified Config, managing /// a pre-existing installation. - pub fn new_with_db(config: Config, install_path: &Path) -> Result { + pub fn new_with_db(attrs: BaseAttributes, install_path: &Path) -> Result { let path = install_path.to_owned(); let metadata_path = path.join("metadata.json"); let metadata_file = match File::open(metadata_path) { @@ -221,7 +224,8 @@ impl InstallerFramework { }; Ok(InstallerFramework { - config, + base_attributes: attrs, + config: None, database, install_path: Some(path), preexisting_install: true, diff --git a/src/logging.rs b/src/logging.rs index 88e2720..b80ded6 100644 --- a/src/logging.rs +++ b/src/logging.rs @@ -17,7 +17,8 @@ pub fn setup_logger() -> Result<(), fern::InitError> { record.level(), message )) - }).level(log::LevelFilter::Info) + }) + .level(log::LevelFilter::Info) .chain(io::stdout()) .chain(fern::log_file("installer.log")?) .apply()?; @@ -31,6 +32,7 @@ where Self: Sized, { /// Unwraps this object. See `unwrap()`. + #[inline] fn log_unwrap(self) -> T { self.log_expect("Failed to unwrap") } @@ -40,6 +42,7 @@ where } impl LoggingErrors for Result { + #[inline] fn log_expect(self, msg: &str) -> T { match self { Ok(v) => v, @@ -52,6 +55,7 @@ impl LoggingErrors for Result { } impl LoggingErrors for Option { + #[inline] fn log_expect(self, msg: &str) -> T { match self { Some(v) => v, diff --git a/src/main.rs b/src/main.rs index 6cb4954..16797ca 100644 --- a/src/main.rs +++ b/src/main.rs @@ -50,8 +50,6 @@ mod tasks; use web_view::*; -use config::Config; - use installer::InstallerFramework; #[cfg(windows)] @@ -71,6 +69,8 @@ use clap::App; use clap::Arg; use log::Level; +use config::BaseAttributes; + // TODO: Fetch this over a HTTP request? static RAW_CONFIG: &'static str = include_str!("../config.toml"); @@ -83,9 +83,10 @@ enum CallbackType { fn main() { logging::setup_logger().expect("Unable to setup logging!"); - let config = Config::from_toml_str(RAW_CONFIG).log_expect("Config file could not be read"); + let config = + BaseAttributes::from_toml_str(RAW_CONFIG).log_expect("Config file could not be read"); - let app_name = config.general.name.clone(); + let app_name = config.name.clone(); let matches = App::new(format!("{} installer", app_name)) .version(env!("CARGO_PKG_VERSION")) @@ -96,7 +97,8 @@ fn main() { .value_name("TARGET") .help("Launches the specified executable after checking for updates") .takes_value(true), - ).get_matches(); + ) + .get_matches(); info!("{} installer", app_name); diff --git a/src/rest.rs b/src/rest.rs index 7f6fdcd..d874ec9 100644 --- a/src/rest.rs +++ b/src/rest.rs @@ -32,6 +32,10 @@ use installer::InstallerFramework; use logging::LoggingErrors; use std::process::Command; +use http; + +use config::Config; + #[derive(Serialize)] struct FileSelection { path: Option, @@ -55,7 +59,8 @@ impl WebServer { Ok(WebService { framework: framework.clone(), }) - }).log_expect("Failed to bind to port"); + }) + .log_expect("Failed to bind to port"); server.run().log_expect("Failed to run HTTP server"); }); @@ -79,16 +84,16 @@ impl Service for WebService { fn call(&self, req: Self::Request) -> Self::Future { Box::new(future::ok(match (req.method(), req.path()) { // This endpoint should be usable directly from a +