Merge branch 'mod_management'

This commit is contained in:
SpikeHD
2022-07-26 20:39:54 -07:00
43 changed files with 2100 additions and 275 deletions

159
src-tauri/Cargo.lock generated
View File

@@ -75,7 +75,7 @@ dependencies = [
"asn1-rs-impl",
"displaydoc",
"nom",
"num-traits",
"num-traits 0.2.15",
"rusticata-macros",
"thiserror",
"time 0.3.11",
@@ -736,6 +736,7 @@ dependencies = [
"tokio-rustls",
"tokio-tungstenite",
"tracing",
"unrar",
"zip 0.6.2",
"zip-extract",
]
@@ -820,8 +821,8 @@ dependencies = [
"asn1-rs",
"displaydoc",
"nom",
"num-bigint",
"num-traits",
"num-bigint 0.4.3",
"num-traits 0.2.15",
"rusticata-macros",
]
@@ -948,6 +949,15 @@ dependencies = [
"cfg-if 1.0.0",
]
[[package]]
name = "enum_primitive"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be4551092f4d519593039259a9ed8daedf0da12e5109c5280338073eaeb81180"
dependencies = [
"num-traits 0.1.43",
]
[[package]]
name = "error-chain"
version = "0.12.4"
@@ -1041,6 +1051,12 @@ dependencies = [
"percent-encoding",
]
[[package]]
name = "fuchsia-cprng"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
[[package]]
name = "futf"
version = "0.1.5"
@@ -1699,8 +1715,8 @@ dependencies = [
"byteorder",
"color_quant",
"num-iter",
"num-rational",
"num-traits",
"num-rational 0.4.1",
"num-traits 0.2.15",
]
[[package]]
@@ -2171,6 +2187,32 @@ dependencies = [
"winapi",
]
[[package]]
name = "num"
version = "0.1.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e"
dependencies = [
"num-bigint 0.1.44",
"num-complex",
"num-integer",
"num-iter",
"num-rational 0.1.42",
"num-traits 0.2.15",
]
[[package]]
name = "num-bigint"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e63899ad0da84ce718c14936262a41cee2c79c981fc0a0e7c7beb47d5a07e8c1"
dependencies = [
"num-integer",
"num-traits 0.2.15",
"rand 0.4.6",
"rustc-serialize",
]
[[package]]
name = "num-bigint"
version = "0.4.3"
@@ -2179,7 +2221,17 @@ checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
"num-traits 0.2.15",
]
[[package]]
name = "num-complex"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b288631d7878aaf59442cffd36910ea604ecd7745c36054328595114001c9656"
dependencies = [
"num-traits 0.2.15",
"rustc-serialize",
]
[[package]]
@@ -2189,7 +2241,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
dependencies = [
"autocfg",
"num-traits",
"num-traits 0.2.15",
]
[[package]]
@@ -2200,7 +2252,19 @@ checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
"num-traits 0.2.15",
]
[[package]]
name = "num-rational"
version = "0.1.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee314c74bd753fc86b4780aa9475da469155f3848473a261d2d18e35245a784e"
dependencies = [
"num-bigint 0.1.44",
"num-integer",
"num-traits 0.2.15",
"rustc-serialize",
]
[[package]]
@@ -2211,7 +2275,16 @@ checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
"num-traits 0.2.15",
]
[[package]]
name = "num-traits"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31"
dependencies = [
"num-traits 0.2.15",
]
[[package]]
@@ -2831,6 +2904,19 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
dependencies = [
"fuchsia-cprng",
"libc",
"rand_core 0.3.1",
"rdrand",
"winapi",
]
[[package]]
name = "rand"
version = "0.7.3"
@@ -2876,6 +2962,21 @@ dependencies = [
"rand_core 0.6.3",
]
[[package]]
name = "rand_core"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
dependencies = [
"rand_core 0.4.2",
]
[[package]]
name = "rand_core"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
[[package]]
name = "rand_core"
version = "0.5.1"
@@ -2967,6 +3068,15 @@ dependencies = [
"yasna",
]
[[package]]
name = "rdrand"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
dependencies = [
"rand_core 0.3.1",
]
[[package]]
name = "redox_syscall"
version = "0.2.13"
@@ -3113,6 +3223,12 @@ dependencies = [
"winapi",
]
[[package]]
name = "rustc-serialize"
version = "0.3.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
[[package]]
name = "rustc_version"
version = "0.3.3"
@@ -4289,6 +4405,31 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04"
[[package]]
name = "unrar"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "433cea4f0b7bec88d47becb380887b8786a3cfb1c82e1ef9d32a682ba6801814"
dependencies = [
"bitflags",
"enum_primitive",
"lazy_static",
"num",
"regex",
"unrar_sys",
]
[[package]]
name = "unrar_sys"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0009399408dc0bcc5c8910672544fceceeba18b91f741ff943916e917d982c60"
dependencies = [
"cc",
"libc",
"winapi",
]
[[package]]
name = "untrusted"
version = "0.7.1"

View File

@@ -31,6 +31,7 @@ sysinfo = "0.24.6"
# ZIP-archive library.
zip-extract = "0.1.1"
unrar = "0.4.4"
zip = "0.6.2"
# For creating a "global" downloads list.

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

View File

@@ -70,7 +70,11 @@
"patch_metadata": "Patch and unpatch your game metadata automatically. Unless playing with old/non-official versions, or you have manually patched your metadata, this should be enabled."
},
"swag": {
"akebi_name": "Akebi",
"migoto_name": "Migoto",
"reshade_name": "Reshade",
"akebi": "Set Akebi Executable",
"migoto": "Set 3dMigoto Executable"
"migoto": "Set 3DMigoto Executable",
"reshade": "Set Reshade Injector"
}
}

View File

@@ -0,0 +1,88 @@
use crate::file_helpers;
use crate::web;
use std::collections::HashMap;
use std::fs::read_dir;
use std::io::Read;
use std::path::PathBuf;
static SITE_URL: &str = "https://gamebanana.com";
#[tauri::command]
pub async fn get_download_links(mod_id: String) -> String {
let res = web::query(format!("{}/apiv9/Mod/{}/DownloadPage", SITE_URL, mod_id).as_str()).await;
res
}
#[tauri::command]
pub async fn list_submissions(mode: String) -> String {
let res = web::query(
format!(
"{}/apiv9/Util/Game/Submissions?_idGameRow=8552&_nPage=1&_nPerpage=50&_sMode={}",
SITE_URL, mode
)
.as_str(),
)
.await;
res
}
#[tauri::command]
pub async fn list_mods(path: String) -> HashMap<String, String> {
let mut path_buf = PathBuf::from(path);
// If the path includes a file, remove it
if path_buf.file_name().is_some() {
path_buf.pop();
}
// Ensure we are in the Mods folder
path_buf.push("Mods");
// Check if dir is empty
if file_helpers::dir_is_empty(path_buf.to_str().unwrap()) {
return HashMap::new();
}
let mut mod_info_files = vec![];
let mut mod_info_strings = HashMap::new();
for entry in read_dir(path_buf).unwrap() {
let entry = entry.unwrap();
let path = entry.path();
// Check each dir for a modinfo.json file
if path.is_dir() {
let mut mod_info_path = path.clone();
mod_info_path.push("modinfo.json");
if mod_info_path.exists() {
// Push path AND file contents into the hashmap using path as key
mod_info_files.push(mod_info_path.to_str().unwrap().to_string());
} else {
// No modinfo, but we can still push a JSON obj with the folder name
mod_info_strings.insert(
path.to_str().unwrap().to_string(),
format!(
"{{ \"name\": \"{}\" }}",
path.file_name().unwrap().to_str().unwrap()
),
);
}
}
}
// Read each modinfo.json file
for mod_info_file in mod_info_files {
let mut mod_info_string = String::new();
// It is safe to unwrap here since we *know* that the file exists
let mut file = std::fs::File::open(&mod_info_file).unwrap();
file.read_to_string(&mut mod_info_string).unwrap();
// Push into hashmap using path as key
mod_info_strings.insert(mod_info_file, mod_info_string);
}
mod_info_strings
}

View File

@@ -12,6 +12,7 @@ use sysinfo::{System, SystemExt};
mod downloader;
mod file_helpers;
mod gamebanana;
mod lang;
mod metadata_patcher;
mod proxy;
@@ -59,6 +60,9 @@ fn main() {
lang::get_languages,
web::valid_url,
web::web_get,
gamebanana::get_download_links,
gamebanana::list_submissions,
gamebanana::list_mods,
metadata_patcher::patch_metadata
])
.run(tauri::generate_context!())

View File

@@ -1,12 +1,30 @@
use duct::cmd;
#[tauri::command]
pub fn run_program(path: String) {
// Open in new thread to prevent blocking.
std::thread::spawn(move || {
// Without unwrap_or, this can crash when UAC prompt is denied
open::that(&path).unwrap_or(());
});
pub fn run_program(path: String, args: Option<String>) {
// Without unwrap_or, this can crash when UAC prompt is denied
open::that(format!("{} {}", &path, &args.unwrap_or("".into()))).unwrap_or(());
}
#[tauri::command]
pub fn run_program_relative(path: String, args: Option<String>) {
// Save the current working directory
let cwd = std::env::current_dir().unwrap();
// Set the new working directory to the path before the executable
let mut path_buf = std::path::PathBuf::from(&path);
path_buf.pop();
// Set new working directory
std::env::set_current_dir(&path_buf).unwrap();
println!("Opening {} {}", &path, args.clone().unwrap_or("".into()));
// Without unwrap_or, this can crash when UAC prompt is denied
open::that(format!("{} {}", &path, args.unwrap_or("".into()))).unwrap_or(());
// Restore the original working directory
std::env::set_current_dir(&cwd).unwrap();
}
#[tauri::command]
@@ -30,7 +48,13 @@ pub fn run_program_relative(path: String) {
#[tauri::command]
pub fn run_command(program: &str, args: Vec<&str>) {
cmd(program, args).run().expect("Failed to run command");
let prog = program.to_string();
let args = args.iter().map(|s| s.to_string()).collect::<Vec<String>>();
// Commands should not block (this is for the reshade injector mostly)
std::thread::spawn(move || {
cmd(prog, args).run().unwrap();
});
}
#[tauri::command]

View File

@@ -1,9 +1,16 @@
use std::fs::File;
use std::fs::{read_dir, File};
use std::path;
use std::thread;
use unrar::archive::{Archive, OpenArchive};
#[tauri::command]
pub fn unzip(window: tauri::Window, zipfile: String, destpath: String) {
pub fn unzip(
window: tauri::Window,
zipfile: String,
destpath: String,
top_level: Option<bool>,
folder_if_loose: Option<bool>,
) {
// Read file TODO: replace test file
let f = match File::open(&zipfile) {
Ok(f) => f,
@@ -15,40 +22,80 @@ pub fn unzip(window: tauri::Window, zipfile: String, destpath: String) {
let write_path = path::PathBuf::from(&destpath);
// Get a list of all current directories
let mut dirs = vec![];
for entry in read_dir(&write_path).unwrap() {
let entry = entry.unwrap();
let entry_path = entry.path();
if entry_path.is_dir() {
dirs.push(entry_path);
}
}
// Run extraction in seperate thread
thread::spawn(move || {
let full_path = write_path;
let mut full_path = write_path.clone();
window.emit("extract_start", &zipfile).unwrap();
match zip_extract::extract(&f, &full_path, true) {
Ok(_) => {
println!(
"Extracted zip file to: {}",
full_path.to_str().unwrap_or("Error")
);
}
Err(e) => {
println!("Failed to extract zip file: {}", e);
let mut res_hash = std::collections::HashMap::new();
if folder_if_loose.unwrap_or(false) {
// Create a new folder with the same name as the zip file
let mut file_name = path::Path::new(&zipfile)
.file_name()
.unwrap()
.to_str()
.unwrap();
res_hash.insert("error".to_string(), e.to_string());
// remove ".zip" from the end of the file name
file_name = &file_name[..file_name.len() - 4];
res_hash.insert("path".to_string(), zipfile.to_string());
let new_path = full_path.join(file_name);
match std::fs::create_dir_all(&new_path) {
Ok(_) => {}
Err(e) => {
println!("Failed to create directory: {}", e);
return;
}
};
window.emit("download_error", &res_hash).unwrap();
}
};
full_path = new_path.clone();
}
// Get the name of the inenr file in the zip file
let mut zip = zip::ZipArchive::new(&f).unwrap();
let file = zip.by_index(0).unwrap();
let name = file.name();
println!("Is rar file? {}", zipfile.ends_with(".rar"));
let mut name = "".into();
// If file ends in zip, OR is unknown, extract as zip, otherwise extract as rar
if zipfile.ends_with(".rar") {
extract_rar(
&window,
&zipfile,
&f,
&full_path,
top_level.unwrap_or(false),
);
let archive = Archive::new(zipfile.clone());
name = archive.list().unwrap().next().unwrap().unwrap().filename;
} else {
extract_zip(
&window,
&zipfile,
&f,
&full_path,
top_level.unwrap_or(false),
);
// Get the name of the inenr file in the zip file
let mut zip = zip::ZipArchive::new(&f).unwrap();
let file = zip.by_index(0).unwrap();
name = file.name().to_string().clone();
}
// If the contents is a jar file, emit that we have extracted a new jar file
if name.ends_with(".jar") {
window
.emit("jar_extracted", destpath.to_string() + name)
.emit("jar_extracted", destpath.to_string() + name.as_str())
.unwrap();
}
@@ -62,6 +109,80 @@ pub fn unzip(window: tauri::Window, zipfile: String, destpath: String) {
}
};
window.emit("extract_end", &zipfile).unwrap();
// Get any new directory that could have been created
let mut new_dir: String = String::new();
for entry in read_dir(&write_path).unwrap() {
let entry = entry.unwrap();
let entry_path = entry.path();
if entry_path.is_dir() {
if !dirs.contains(&entry_path) {
new_dir = entry_path.to_str().unwrap().to_string();
}
}
}
let mut res_hash = std::collections::HashMap::new();
res_hash.insert("file", zipfile.to_string());
res_hash.insert("new_folder", new_dir.to_string());
window.emit("extract_end", &res_hash).unwrap();
});
}
fn extract_rar(
window: &tauri::Window,
rarfile: &String,
f: &File,
full_path: &path::PathBuf,
top_level: bool,
) {
let archive = Archive::new(rarfile.clone());
let mut open_archive = archive
.extract_to(full_path.to_str().unwrap().to_string())
.unwrap();
match open_archive.process() {
Ok(_) => {
println!(
"Extracted rar file to: {}",
full_path.to_str().unwrap_or("Error")
);
}
Err(e) => {
println!("Failed to extract rar file: {}", e);
let mut res_hash = std::collections::HashMap::new();
res_hash.insert("error".to_string(), e.to_string());
res_hash.insert("path".to_string(), rarfile.to_string());
window.emit("download_error", &res_hash).unwrap();
}
}
}
fn extract_zip(
window: &tauri::Window,
zipfile: &String,
f: &File,
full_path: &path::PathBuf,
top_level: bool,
) {
match zip_extract::extract(f, full_path, top_level) {
Ok(_) => {
println!(
"Extracted zip file to: {}",
full_path.to_str().unwrap_or("Error")
);
}
Err(e) => {
println!("Failed to extract zip file: {}", e);
let mut res_hash = std::collections::HashMap::new();
res_hash.insert("error".to_string(), e.to_string());
res_hash.insert("path".to_string(), zipfile.to_string());
window.emit("download_error", &res_hash).unwrap();
}
};
}

View File

@@ -1,4 +1,4 @@
use reqwest::header::USER_AGENT;
use reqwest::header::{CONTENT_TYPE, USER_AGENT};
pub(crate) async fn query(site: &str) -> String {
let client = reqwest::Client::new();
@@ -6,6 +6,7 @@ pub(crate) async fn query(site: &str) -> String {
let response = client
.get(site)
.header(USER_AGENT, "cultivation")
.header(CONTENT_TYPE, "application/json")
.send()
.await
.unwrap();