Merge branch 'main' of github.com:Grasscutters/Cultivation

This commit is contained in:
SpikeHD
2022-07-11 19:45:29 -07:00
13 changed files with 615 additions and 823 deletions

View File

@@ -8,9 +8,9 @@ Consider Cultivation to be the bleeding-edge version of GrassClipper.
During this open-beta testing period, **helpful issues are appreciated**, while unhelpful ones will be closed. During this open-beta testing period, **helpful issues are appreciated**, while unhelpful ones will be closed.
## Fair Warning ## Fair Warning
Cultivation is **VERY MUCH IN BETA** and a majority of features do not work.\ Cultivation is **VERY MUCH IN BETA**.
There are **no official releases of Cultivation**. You are **required** to build the application from **scratch**.\ There are **no official releases of Cultivation**. You are **required** to build the application from **scratch** unless you want to deal with the alpha state of the current builds.
Please do **NOT install, download, or use pre-compiled versions of Cultivation**. Only use releases from this GitHub repository. Please do **NOT install, download, or use pre-compiled versions of Cultivation found elsewhere**. Only use releases from this GitHub repository.
# Cultivation # Cultivation
A game launcher designed to easily proxy traffic from anime game to private servers. A game launcher designed to easily proxy traffic from anime game to private servers.

View File

@@ -1,6 +1,6 @@
{ {
"name": "cultivation", "name": "cultivation",
"version": "1.0.1", "version": "1.0.2",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@tauri-apps/api": "^1.0.0-rc.5", "@tauri-apps/api": "^1.0.0-rc.5",

1255
src-tauri/Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -26,14 +26,14 @@ serde = { version = "1.0", features = ["derive"] }
tauri = { version = "1.0.0-rc.9", features = ["api-all"] } tauri = { version = "1.0.0-rc.9", features = ["api-all"] }
# Access system process info. # Access system process info.
sysinfo = "0.23.12" sysinfo = "0.24.6"
# ZIP-archive library. # ZIP-archive library.
zip-extract = "0.1.1" zip-extract = "0.1.1"
zip = "0.6.2" zip = "0.6.2"
# For creating a "global" downloads list. # For creating a "global" downloads list.
lazy_static = "1.4.0" once_cell = "1.13.0"
# Program opener. # Program opener.
open = "2.1.2" open = "2.1.2"
@@ -42,9 +42,6 @@ duct = "0.13.5"
# Serialization. # Serialization.
serde_json = "1" serde_json = "1"
# System process elevation.
runas = "0.2.1"
# Dependencies for the HTTP(S) proxy. # Dependencies for the HTTP(S) proxy.
http = "0.2" http = "0.2"
hudsucker = "0.17.2" hudsucker = "0.17.2"

View File

@@ -1,4 +1,4 @@
use lazy_static::lazy_static; use once_cell::sync::Lazy;
use std::sync::Mutex; use std::sync::Mutex;
use std::cmp::min; use std::cmp::min;
@@ -8,12 +8,7 @@ use std::io::Write;
use futures_util::StreamExt; use futures_util::StreamExt;
// This will create a downloads list that will be used to check if we should continue downloading the file // This will create a downloads list that will be used to check if we should continue downloading the file
lazy_static! { static DOWNLOADS: Lazy<Mutex<Vec<String>>> = Lazy::new(|| Mutex::new(Vec::new()));
static ref DOWNLOADS: Mutex<Vec<String>> = {
let m = Vec::new();
Mutex::new(m)
};
}
// Lots of help from: https://gist.github.com/giuliano-oliveira/4d11d6b3bb003dba3a1b53f43d81b30d // Lots of help from: https://gist.github.com/giuliano-oliveira/4d11d6b3bb003dba3a1b53f43d81b30d
// and docs ofc // and docs ofc
@@ -59,17 +54,17 @@ pub async fn download_file(window: tauri::Window, url: &str, path: &str) -> Resu
let chunk = match item { let chunk = match item {
Ok(itm) => itm, Ok(itm) => itm,
Err(e) => { Err(e) => {
emit_download_err(window, format!("Error while downloading file"), path); emit_download_err(window, "Error while downloading file".to_string(), path);
return Err(format!("Error while downloading file: {}", e)); return Err(format!("Error while downloading file: {}", e));
} }
}; };
let vect = &chunk.to_vec()[..]; let vect = &chunk.to_vec()[..];
// Write bytes // Write bytes
match file.write_all(&vect) { match file.write_all(vect) {
Ok(x) => x, Ok(x) => x,
Err(e) => { Err(e) => {
emit_download_err(window, format!("Error while writing file"), path); emit_download_err(window, "Error while writing file".to_string(), path);
return Err(format!("Error while writing file: {}", e)); return Err(format!("Error while writing file: {}", e));
} }
} }
@@ -78,7 +73,7 @@ pub async fn download_file(window: tauri::Window, url: &str, path: &str) -> Resu
let new = min(downloaded + (chunk.len() as u64), total_size); let new = min(downloaded + (chunk.len() as u64), total_size);
downloaded = new; downloaded = new;
total_downloaded = total_downloaded + chunk.len() as u64; total_downloaded += chunk.len() as u64;
let mut res_hash = std::collections::HashMap::new(); let mut res_hash = std::collections::HashMap::new();
@@ -110,15 +105,15 @@ pub async fn download_file(window: tauri::Window, url: &str, path: &str) -> Resu
window.emit("download_finished", &path).unwrap(); window.emit("download_finished", &path).unwrap();
// We are done // We are done
return Ok(()); Ok(())
} }
pub fn emit_download_err(window: tauri::Window, msg: std::string::String, path: &str) { pub fn emit_download_err(window: tauri::Window, msg: String, path: &str) {
let mut res_hash = std::collections::HashMap::new(); let mut res_hash = std::collections::HashMap::new();
res_hash.insert( res_hash.insert(
"error".to_string(), "error".to_string(),
msg.to_string(), msg,
); );
res_hash.insert( res_hash.insert(

View File

@@ -5,31 +5,51 @@ pub fn rename(path: String, new_name: String) {
let mut new_path = path.clone(); let mut new_path = path.clone();
// Check if file/folder to replace exists // Check if file/folder to replace exists
if !fs::metadata(&path).is_ok() { if fs::metadata(&path).is_err() {
return; return;
} }
// Check if path uses forward or back slashes // Check if path uses forward or back slashes
if new_path.contains("\\") { if new_path.contains('\\') {
new_path = path.replace("\\", "/"); new_path = path.replace('\\', "/");
} }
let path_replaced = &path.replace(&new_path.split("/").last().unwrap(), &new_name); let path_replaced = &path.replace(&new_path.split('/').last().unwrap(), &new_name);
fs::rename(path, &path_replaced).unwrap(); fs::rename(path, &path_replaced).unwrap();
} }
#[tauri::command] #[tauri::command]
pub fn dir_exists(path: &str) -> bool { pub fn dir_exists(path: &str) -> bool {
return fs::metadata(&path).is_ok(); fs::metadata(&path).is_ok()
} }
#[tauri::command] #[tauri::command]
pub fn dir_is_empty(path: &str) -> bool { pub fn dir_is_empty(path: &str) -> bool {
return fs::read_dir(&path).unwrap().count() == 0; fs::read_dir(&path).unwrap().count() == 0
} }
#[tauri::command] #[tauri::command]
pub fn dir_delete(path: &str) { pub fn dir_delete(path: &str) {
fs::remove_dir_all(path).unwrap(); fs::remove_dir_all(path).unwrap();
} }
#[tauri::command]
pub fn copy_file(path: String, new_path: String) -> bool {
let filename = &path.split("/").last().unwrap();
let mut new_path_buf = std::path::PathBuf::from(&new_path);
// If the new path doesn't exist, create it.
if !dir_exists(new_path_buf.pop().to_string().as_str()) {
std::fs::create_dir_all(&new_path).unwrap();
}
// Copy old to new
match std::fs::copy(&path, format!("{}/{}", new_path, filename)) {
Ok(_) => true,
Err(e) => {
println!("Failed to copy file: {}", e);
false
}
}
}

View File

@@ -7,15 +7,13 @@ pub async fn get_lang(window: tauri::Window, lang: String) -> String {
// Send contents of language file back // Send contents of language file back
let lang_path: PathBuf = [&install_location(), "lang", &format!("{}.json", lang)].iter().collect(); let lang_path: PathBuf = [&install_location(), "lang", &format!("{}.json", lang)].iter().collect();
let contents = match std::fs::read_to_string(&lang_path) { match std::fs::read_to_string(&lang_path) {
Ok(x) => x, Ok(x) => x,
Err(e) => { Err(e) => {
emit_lang_err(window, format!("Failed to read language file: {}", e)); emit_lang_err(window, format!("Failed to read language file: {}", e));
return "".to_string(); "".to_string()
} }
}; }
return contents;
} }
#[tauri::command] #[tauri::command]
@@ -23,9 +21,9 @@ pub async fn get_languages() -> std::collections::HashMap<String, String> {
// for each lang file, set the key as the filename and the value as the lang_name contained in the file // for each lang file, set the key as the filename and the value as the lang_name contained in the file
let mut languages = std::collections::HashMap::new(); let mut languages = std::collections::HashMap::new();
let mut lang_files = std::fs::read_dir(Path::new(&install_location()).join("lang")).unwrap(); let lang_files = std::fs::read_dir(Path::new(&install_location()).join("lang")).unwrap();
while let Some(entry) = lang_files.next() { for entry in lang_files {
let entry = entry.unwrap(); let entry = entry.unwrap();
let path = entry.path(); let path = entry.path();
let filename = path.file_name().unwrap().to_str().unwrap(); let filename = path.file_name().unwrap().to_str().unwrap();
@@ -41,15 +39,15 @@ pub async fn get_languages() -> std::collections::HashMap<String, String> {
languages.insert(filename.to_string(), content); languages.insert(filename.to_string(), content);
} }
return languages; languages
} }
pub fn emit_lang_err(window: tauri::Window, msg: std::string::String) { pub fn emit_lang_err(window: tauri::Window, msg: String) {
let mut res_hash = std::collections::HashMap::new(); let mut res_hash = std::collections::HashMap::new();
res_hash.insert( res_hash.insert(
"error".to_string(), "error".to_string(),
msg.to_string(), msg,
); );
window.emit("lang_error", &res_hash).unwrap(); window.emit("lang_error", &res_hash).unwrap();

View File

@@ -3,7 +3,7 @@ all(not(debug_assertions), target_os = "windows"),
windows_subsystem = "windows" windows_subsystem = "windows"
)] )]
use lazy_static::lazy_static; use once_cell::sync::Lazy;
use std::{sync::Mutex, collections::HashMap}; use std::{sync::Mutex, collections::HashMap};
use std::path::PathBuf; use std::path::PathBuf;
@@ -20,21 +20,12 @@ mod lang;
mod proxy; mod proxy;
mod web; mod web;
lazy_static! { static WATCH_GAME_PROCESS: Lazy<Mutex<String>> = Lazy::new(|| Mutex::new(String::new()));
static ref WATCH_GAME_PROCESS: Mutex<String> = {
let m = "".to_string();
Mutex::new(m)
};
}
fn main() { fn main() {
// Start the game process watcher. // Start the game process watcher.
process_watcher(); process_watcher();
// Make BG folder if it doesn't exist.
let bg_folder: PathBuf = [&system_helpers::install_location(), "bg"].iter().collect();
std::fs::create_dir_all(&bg_folder).unwrap();
tauri::Builder::default() tauri::Builder::default()
.invoke_handler(tauri::generate_handler![ .invoke_handler(tauri::generate_handler![
enable_process_watcher, enable_process_watcher,
@@ -48,7 +39,6 @@ fn main() {
system_helpers::run_program, system_helpers::run_program,
system_helpers::run_jar, system_helpers::run_jar,
system_helpers::open_in_browser, system_helpers::open_in_browser,
system_helpers::copy_file,
system_helpers::install_location, system_helpers::install_location,
system_helpers::is_elevated, system_helpers::is_elevated,
proxy::set_proxy_addr, proxy::set_proxy_addr,
@@ -58,6 +48,7 @@ fn main() {
file_helpers::dir_exists, file_helpers::dir_exists,
file_helpers::dir_is_empty, file_helpers::dir_is_empty,
file_helpers::dir_delete, file_helpers::dir_delete,
file_helpers::copy_file,
downloader::download_file, downloader::download_file,
downloader::stop_download, downloader::stop_download,
lang::get_lang, lang::get_lang,
@@ -84,14 +75,9 @@ fn process_watcher() {
// Grab the game process name // Grab the game process name
let proc = WATCH_GAME_PROCESS.lock().unwrap().to_string(); let proc = WATCH_GAME_PROCESS.lock().unwrap().to_string();
if !&proc.is_empty() { if !proc.is_empty() {
let proc_with_name = system.processes_by_exact_name(&proc); let mut proc_with_name = system.processes_by_exact_name(&proc);
let mut exists = false; let exists = proc_with_name.next().is_some();
for _p in proc_with_name {
exists = true;
break;
}
// If the game process closes, disable the proxy. // If the game process closes, disable the proxy.
if !exists { if !exists {
@@ -109,7 +95,7 @@ fn is_game_running() -> bool {
// Grab the game process name // Grab the game process name
let proc = WATCH_GAME_PROCESS.lock().unwrap().to_string(); let proc = WATCH_GAME_PROCESS.lock().unwrap().to_string();
return !proc.is_empty(); !proc.is_empty()
} }
#[tauri::command] #[tauri::command]
@@ -140,11 +126,8 @@ fn disconnect() {
#[tauri::command] #[tauri::command]
async fn req_get(url: String) -> String { async fn req_get(url: String) -> String {
// Send a GET request to the specified URL. // Send a GET request to the specified URL and send the response body back to the client.
let response = web::query(&url.to_string()).await; web::query(&url.to_string()).await
// Send the response body back to the client.
return response;
} }
#[tauri::command] #[tauri::command]
@@ -180,7 +163,7 @@ async fn get_theme_list(data_dir: String) -> Vec<HashMap<String, String>> {
} }
} }
return themes; themes
} }
#[tauri::command] #[tauri::command]
@@ -204,7 +187,7 @@ async fn get_bg_file(bg_path: String, appdata: String) -> String {
} }
// Now we check if the bg folder, which is one directory above the game_path, exists. // Now we check if the bg folder, which is one directory above the game_path, exists.
let bg_img_path = format!("{}\\{}", bg_path.clone().to_string(), file_name.as_str()); let bg_img_path = format!("{}\\{}", &bg_path, &file_name);
// If it doesn't, then we do not have backgrounds to grab. // If it doesn't, then we do not have backgrounds to grab.
if !file_helpers::dir_exists(&bg_path) { if !file_helpers::dir_exists(&bg_path) {
@@ -220,15 +203,15 @@ async fn get_bg_file(bg_path: String, appdata: String) -> String {
// The image exists, lets copy it to our local '\bg' folder. // The image exists, lets copy it to our local '\bg' folder.
let bg_img_path_local = format!("{}\\bg\\{}", copy_loc, file_name.as_str()); let bg_img_path_local = format!("{}\\bg\\{}", copy_loc, file_name.as_str());
return match std::fs::copy(bg_img_path, bg_img_path_local) { match std::fs::copy(bg_img_path, bg_img_path_local) {
Ok(_) => { Ok(_) => {
// Copy was successful, lets return true. // Copy was successful, lets return true.
format!("{}\\{}", copy_loc, response_data.bg_file.as_str()) format!("{}\\{}", copy_loc, response_data.bg_file)
} }
Err(e) => { Err(e) => {
// Copy failed, lets return false // Copy failed, lets return false
println!("Failed to copy background image: {}", e); println!("Failed to copy background image: {}", e);
"".to_string() "".to_string()
} }
}; }
} }

View File

@@ -3,7 +3,7 @@
* https://github.com/omjadas/hudsucker/blob/main/examples/log.rs * https://github.com/omjadas/hudsucker/blob/main/examples/log.rs
*/ */
use lazy_static::lazy_static; use once_cell::sync::Lazy;
use std::{sync::Mutex, str::FromStr}; use std::{sync::Mutex, str::FromStr};
use rcgen::*; use rcgen::*;
@@ -30,12 +30,7 @@ async fn shutdown_signal() {
} }
// Global ver for getting server address. // Global ver for getting server address.
lazy_static! { static SERVER: Lazy<Mutex<String>> = Lazy::new(|| Mutex::new("http://localhost:443".to_string()));
static ref SERVER: Mutex<String> = {
let m = "http://localhost:443".to_string();
Mutex::new(m)
};
}
#[derive(Clone)] #[derive(Clone)]
struct ProxyHandler; struct ProxyHandler;

View File

@@ -1,7 +1,3 @@
use std::thread;
use tauri;
use open;
use duct::cmd; use duct::cmd;
use crate::file_helpers; use crate::file_helpers;
@@ -9,11 +5,7 @@ use crate::file_helpers;
#[tauri::command] #[tauri::command]
pub fn run_program(path: String) { pub fn run_program(path: String) {
// Open the program from the specified path. // Open the program from the specified path.
open::that(&path).unwrap();
// Open in new thread to prevent blocking.
thread::spawn(move || {
open::that(&path).unwrap();
});
} }
#[tauri::command] #[tauri::command]
@@ -31,7 +23,7 @@ pub fn run_jar(path: String, execute_in: String, java_path: String) {
}; };
// Open the program from the specified path. // Open the program from the specified path.
match open::with(format!("/k cd /D \"{}\" & {}", &execute_in, &command).to_string(), "C:\\Windows\\System32\\cmd.exe") { match open::with(format!("/k cd /D \"{}\" & {}", &execute_in, &command), "C:\\Windows\\System32\\cmd.exe") {
Ok(_) => (), Ok(_) => (),
Err(e) => println!("Failed to open jar ({} from {}): {}", &path, &execute_in, e), Err(e) => println!("Failed to open jar ({} from {}): {}", &path, &execute_in, e),
}; };
@@ -46,25 +38,6 @@ pub fn open_in_browser(url: String) {
}; };
} }
#[tauri::command]
pub fn copy_file(path: String, new_path: String) -> bool {
let filename = &path.split("/").last().unwrap();
let mut new_path_buf = std::path::PathBuf::from(&new_path);
// If the new path doesn't exist, create it.
if !file_helpers::dir_exists(new_path_buf.pop().to_string().as_str()) {
std::fs::create_dir_all(&new_path).unwrap();
}
// Copy old to new
match std::fs::copy(&path, format!("{}/{}", new_path, filename)) {
Ok(_) => true,
Err(e) => {
println!("Failed to copy file: {}", e);
false
}
}
}
#[tauri::command] #[tauri::command]
pub fn install_location() -> String { pub fn install_location() -> String {

View File

@@ -1,5 +1,3 @@
use zip_extract;
use zip;
use std::fs::File; use std::fs::File;
use std::path; use std::path;
use std::thread; use std::thread;

View File

@@ -4,7 +4,7 @@ pub(crate) async fn query(site: &str) -> String {
let client = reqwest::Client::new(); let client = reqwest::Client::new();
let response = client.get(site).header(USER_AGENT, "cultivation").send().await.unwrap(); let response = client.get(site).header(USER_AGENT, "cultivation").send().await.unwrap();
return response.text().await.unwrap(); response.text().await.unwrap()
} }
#[tauri::command] #[tauri::command]
@@ -14,5 +14,5 @@ pub(crate) async fn valid_url(url: String) -> bool {
let response = client.get(url).header(USER_AGENT, "cultivation").send().await.unwrap(); let response = client.get(url).header(USER_AGENT, "cultivation").send().await.unwrap();
return response.status().as_str() == "200"; response.status().as_str() == "200"
} }

View File

@@ -7,7 +7,7 @@
}, },
"package": { "package": {
"productName": "Cultivation", "productName": "Cultivation",
"version": "1.0.1" "version": "1.0.2"
}, },
"tauri": { "tauri": {
"allowlist": { "allowlist": {